]> err.no Git - varnish/commitdiff
Move parts of tcp.c out into libvarnish. Rename the API from "TCP" to "VSS"
authordes <des@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Wed, 6 Jun 2007 11:24:06 +0000 (11:24 +0000)
committerdes <des@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Wed, 6 Jun 2007 11:24:06 +0000 (11:24 +0000)
(Varnish Stream Sockets) as I intend to eventually add support for AF_UNIX
sockets.

This also moves the accept filter code out from VSS_listen() (previously
TCP_open()) and into a separate function in tcp.c

git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@1500 d4fa192b-c00b-0410-8231-f00ffab90ce4

varnish-cache/bin/varnishd/common.h
varnish-cache/bin/varnishd/heritage.h
varnish-cache/bin/varnishd/mgt_child.c
varnish-cache/bin/varnishd/mgt_cli.c
varnish-cache/bin/varnishd/mgt_param.c
varnish-cache/bin/varnishd/mgt_vcc.c
varnish-cache/bin/varnishd/tcp.c
varnish-cache/include/Makefile.am
varnish-cache/include/vss.h [new file with mode: 0644]
varnish-cache/lib/libvarnish/Makefile.am
varnish-cache/lib/libvarnish/vss.c [new file with mode: 0644]

index be83743f60fcf1e60356963c91c982fa1be4844e..59eb63d4f169ab6e5a681b3902cbf1748c2a4b54 100644 (file)
@@ -45,6 +45,4 @@ struct tcp_addr;
 
 void TCP_name(struct sockaddr *addr, unsigned l, char *abuf, unsigned alen, char *pbuf, unsigned plen);
 void TCP_myname(int sock, char *abuf, unsigned alen, char *pbuf, unsigned plen);
-int TCP_parse(const char *str, char **addr, char **port);
-int TCP_resolve(const char *addr, const char *port, struct tcp_addr ***ta);
-int TCP_open(const struct tcp_addr *addr, int http);
+int TCP_filter_http(int sock);
index a89cdff42020c6c2119892360a92be4b0e28b53a..65985d641df53f32d9d8e752d45a5d5b8d486715 100644 (file)
@@ -36,7 +36,7 @@
 struct listen_sock {
        TAILQ_ENTRY(listen_sock)        list;
        int                             sock;
-       struct tcp_addr                 *addr;
+       struct vss_addr                 *addr;
 };
 
 TAILQ_HEAD(listen_sock_head, listen_sock);
index dd09d482559d529067d610643d45d0fa346ee07a..726a46848fbdf05dd4aca8dc7769e2d882b52749 100644 (file)
@@ -54,6 +54,7 @@
 #include "cli_priv.h"
 #include "mgt_cli.h"
 #include "mgt_event.h"
+#include "vss.h"
 
 pid_t          mgt_pid;
 pid_t          child_pid = -1;
@@ -130,7 +131,8 @@ open_sockets(void)
        TAILQ_FOREACH(ls, &heritage.socks, list) {
                if (ls->sock >= 0)
                        continue;
-               ls->sock = TCP_open(ls->addr, 1);
+               ls->sock = VSS_listen(ls->addr, params->listen_depth);
+               TCP_filter_http(ls->sock);
                if (ls->sock < 0)
                        return (1);
        }
index 32cc376870ade5ba24148c3d5df99fb49a9c1608..c86ac79b9dfea26b28a28d9f95b78b5ccdc4aaaa 100644 (file)
@@ -54,6 +54,8 @@
 #include "mgt_event.h"
 #include "shmlog.h"
 
+#include "vss.h"
+
 static int             cli_i = -1, cli_o = -1;
 
 /*--------------------------------------------------------------------*/
@@ -389,12 +391,12 @@ telnet_accept(struct ev *ev, int what)
 int
 mgt_cli_telnet(const char *T_arg)
 {
-       struct tcp_addr **ta;
+       struct vss_addr **ta;
        char *addr, *port;
        int i, n;
 
-       XXXAZ(TCP_parse(T_arg, &addr, &port));
-       XXXAN(n = TCP_resolve(addr, port, &ta));
+       XXXAZ(VSS_parse(T_arg, &addr, &port));
+       XXXAN(n = VSS_resolve(addr, port, &ta));
        free(addr);
        free(port);
        if (n == 0) {
@@ -402,7 +404,7 @@ mgt_cli_telnet(const char *T_arg)
                exit(2);
        }
        for (i = 0; i < n; ++i) {
-               int sock = TCP_open(ta[i], 0);
+               int sock = VSS_listen(ta[i], 1);
                struct ev *ev = ev_new();
                XXXAN(ev);
                ev->fd = sock;
index 1a8b230a77e44d7b66e7c13d7d1700ba1172b2d4..648fe0ec9448791b4bcf8fa16640113fecc2dc17 100644 (file)
@@ -47,6 +47,8 @@
 
 #include "heritage.h"
 
+#include "vss.h"
+
 struct parspec;
 
 typedef void tweak_t(struct cli *, struct parspec *, const char *arg);
@@ -392,16 +394,16 @@ tweak_listen_address(struct cli *cli, struct parspec *par, const char *arg)
        }
        TAILQ_INIT(&lsh);
        for (i = 1; av[i] != NULL; i++) {
-               struct tcp_addr **ta;
+               struct vss_addr **ta;
                char *host, *port;
                int j, n;
 
-               if (TCP_parse(av[i], &host, &port) != 0) {
+               if (VSS_parse(av[i], &host, &port) != 0) {
                        cli_out(cli, "Invalid listen address \"%s\"", av[i]);
                        cli_result(cli, CLIS_PARAM);
                        break;
                }
-               n = TCP_resolve(host, port ? port : "http", &ta);
+               n = VSS_resolve(host, port ? port : "http", &ta);
                free(host);
                free(port);
                if (n == 0) {
index fb0624919700e8c934d3ee5e9a5d739a96ba3237..0241e74432bc347dc22585927a6a79844f676d23 100644 (file)
@@ -53,6 +53,8 @@
 #include "mgt.h"
 #include "mgt_cli.h"
 
+#include "vss.h"
+
 struct vclprog {
        TAILQ_ENTRY(vclprog)    list;
        char                    *name;
@@ -320,7 +322,7 @@ mgt_vcc_default(const char *b_arg, const char *f_arg, int C_flag)
                 * XXX: a bug for a backend to not reply at that time, so then
                 * XXX: again: we should check it here in the "trivial" case.
                 */
-               if (TCP_parse(b_arg, &addr, &port) != 0 || addr == NULL) {
+               if (VSS_parse(b_arg, &addr, &port) != 0 || addr == NULL) {
                        fprintf(stderr, "invalid backend address\n");
                        return (1);
                }
index 1056237fcfcd006f00e51fc08dee11368c7fbe3d..c116a3f26c0aeac477214172551764b3d09212c6 100644 (file)
 #include "cli.h"
 #include "cli_priv.h"
 
-/* lightweight addrinfo */
-struct tcp_addr {
-       int                      ta_family;
-       int                      ta_socktype;
-       int                      ta_protocol;
-       socklen_t                ta_addrlen;
-       struct sockaddr_storage  ta_addr;
-};
-
 /*--------------------------------------------------------------------*/
 
 void
@@ -100,166 +91,25 @@ TCP_myname(int sock, char *abuf, unsigned alen, char *pbuf, unsigned plen)
 
 /*--------------------------------------------------------------------*/
 
-#ifdef HAVE_ACCEPT_FILTERS
-static void
-accept_filter(int fd)
+int
+TCP_filter_http(int sock)
 {
+#ifdef HAVE_ACCEPT_FILTERS
        struct accept_filter_arg afa;
        int i;
 
        bzero(&afa, sizeof(afa));
        strcpy(afa.af_name, "httpready");
        errno = 0;
-       i = setsockopt(fd, SOL_SOCKET, SO_ACCEPTFILTER,
+       i = setsockopt(sock, SOL_SOCKET, SO_ACCEPTFILTER,
            &afa, sizeof(afa));
+       /* XXX ugly */
        if (i)
                printf("Acceptfilter(%d, httpready): %d %s\n",
-                   fd, i, strerror(errno));
-}
-#endif
-
-/*
- * Take a string provided by the user and break it up into address and
- * port parts.  Examples of acceptable input include:
- *
- * "localhost" - "localhost:80"
- * "127.0.0.1" - "127.0.0.1:80"
- * "0.0.0.0" - "0.0.0.0:80"
- * "[::1]" - "[::1]:80"
- * "[::]" - "[::]:80"
- */
-int
-TCP_parse(const char *str, char **addr, char **port)
-{
-       const char *p;
-
-       *addr = *port = NULL;
-
-       if (str[0] == '[') {
-               /* IPv6 address of the form [::1]:80 */
-               if ((p = strchr(str, ']')) == NULL ||
-                   p == str + 1 ||
-                   (p[1] != '\0' && p[1] != ':'))
-                       return (-1);
-               *addr = strndup(str + 1, p - (str + 1));
-               XXXAN(*addr);
-               if (p[1] == ':') {
-                       *port = strdup(p + 2);
-                       XXXAN(*port);
-               }
-       } else {
-               /* IPv4 address of the form 127.0.0.1:80, or non-numeric */
-               p = strchr(str, ':');
-               if (p == NULL) {
-                       *addr = strdup(str);
-                       XXXAN(*addr);
-               } else {
-                       if (p > str) {
-                               *addr = strndup(str, p - str);
-                               XXXAN(*addr);
-                       }
-                       *port = strdup(p + 1);
-                       XXXAN(*port);
-               }
-       }
-       return (0);
-}
-
-/*
- * For a given host and port, return a list of struct tcp_addr, which
- * contains all the information necessary to open and bind a socket.  One
- * tcp_addr is returned for each distinct address returned by
- * getaddrinfo().
- *
- * The value pointed to by the tap parameter receives a pointer to an
- * array of pointers to struct tcp_addr.  The caller is responsible for
- * freeing each individual struct tcp_addr as well as the array.
- *
- * The return value is the number of addresses resoved, or zero.
- */
-int
-TCP_resolve(const char *addr, const char *port, struct tcp_addr ***tap)
-{
-       struct addrinfo hints, *res0, *res;
-       struct tcp_addr **ta;
-       int i, ret;
-
-        memset(&hints, 0, sizeof hints);
-        hints.ai_socktype = SOCK_STREAM;
-        hints.ai_flags = AI_PASSIVE;
-        ret = getaddrinfo(addr, port, &hints, &res0);
-        if (ret != 0) {
-                fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(ret));
-                return (0);
-        }
-       for (res = res0, i = 0; res != NULL; res = res->ai_next)
-               ++i;
-       ta = calloc(i, sizeof *ta);
-       XXXAN(ta);
-       *tap = ta;
-       for (res = res0, i = 0; res != NULL; res = res->ai_next, ++i) {
-               ta[i] = calloc(1, sizeof *ta[i]);
-               XXXAN(ta[i]);
-               ta[i]->ta_family = res->ai_family;
-               ta[i]->ta_socktype = res->ai_socktype;
-               ta[i]->ta_protocol = res->ai_protocol;
-               ta[i]->ta_addrlen = res->ai_addrlen;
-               xxxassert(ta[i]->ta_addrlen <= sizeof ta[i]->ta_addr);
-               memcpy(&ta[i]->ta_addr, res->ai_addr, ta[i]->ta_addrlen);
-       }
-       freeaddrinfo(res0);
+                   sock, i, strerror(errno));
        return (i);
-}
-
-/*
- * Given a struct tcp_addr, open a socket of the appropriate type, bind it
- * to the requested address, and start listening.
- *
- * If the address is an IPv6 address, the IPV6_V6ONLY option is set to
- * avoid conflicts between INADDR_ANY and IN6ADDR_ANY.
- *
- * If the http parameter is non-zero and accept filters are available,
- * install an HTTP accept filter on the socket.
- */
-int
-TCP_open(const struct tcp_addr *ta, int http)
-{
-       int sd, val;
-
-       sd = socket(ta->ta_family, ta->ta_socktype, ta->ta_protocol);
-       if (sd < 0) {
-               perror("socket()");
-               return (-1);
-       }
-       val = 1;
-       if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val) != 0) {
-               perror("setsockopt(SO_REUSEADDR, 1)");
-               close(sd);
-               return (-1);
-       }
-#ifdef IPV6_V6ONLY
-       /* forcibly use separate sockets for IPv4 and IPv6 */
-       val = 1;
-       if (ta->ta_family == AF_INET6 &&
-           setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof val) != 0) {
-               perror("setsockopt(IPV6_V6ONLY, 1)");
-               close(sd);
-               return (-1);
-       }
-#endif
-       if (bind(sd, (const struct sockaddr *)&ta->ta_addr, ta->ta_addrlen) != 0) {
-               perror("bind()");
-               close(sd);
-               return (-1);
-       }
-       if (listen(sd, http ? params->listen_depth : 16) != 0) {
-               perror("listen()");
-               close(sd);
-               return (-1);
-       }
-#ifdef HAVE_ACCEPT_FILTERS
-       if (http)
-               accept_filter(sd);
+#else
+       (void)sock;
+       return (0);
 #endif
-       return (sd);
 }
index aaa8d2a8c0da66a7f335c63c4bf8aa51760cb332..5b62b62ed1ff3b9ef38c20e28790bd3a82657396 100644 (file)
@@ -30,5 +30,5 @@ noinst_HEADERS = \
        vcl.h \
        vcl_returns.h \
        vrt.h \
-       vrt_obj.h
-
+       vrt_obj.h \
+       vss.h
diff --git a/varnish-cache/include/vss.h b/varnish-cache/include/vss.h
new file mode 100644 (file)
index 0000000..7302a81
--- /dev/null
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006 Linpro AS
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+/* vss.c */
+struct vss_addr;
+
+int VSS_parse(const char *str, char **addr, char **port);
+int VSS_resolve(const char *addr, const char *port, struct vss_addr ***ta);
+int VSS_listen(const struct vss_addr *addr, int depth);
+int VSS_connect(const struct vss_addr *addr);
index d2d1e0cdddf8e1b4cc303fa3af361fdf6b982c44..f68a4fd1ccd56f98dea20a40ab427650919e1b1b 100644 (file)
@@ -15,6 +15,7 @@ libvarnish_la_SOURCES = \
        time.c \
        version.c \
        vpf.c \
-       vsb.c
+       vsb.c \
+       vss.c
 
 libvarnish_la_CFLAGS = -include config.h
diff --git a/varnish-cache/lib/libvarnish/vss.c b/varnish-cache/lib/libvarnish/vss.c
new file mode 100644 (file)
index 0000000..03cf8a4
--- /dev/null
@@ -0,0 +1,223 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006 Linpro AS
+ * All rights reserved.
+ *
+ * Author: Dag-Erling Smørgrav <des@linpro.no>
+ * Author: Cecilie Fritzvold <cecilihf@linpro.no>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef HAVE_STRLCPY
+#include "compat/strlcpy.h"
+#endif
+#ifndef HAVE_STRNDUP
+#include "compat/strndup.h"
+#endif
+
+#include "libvarnish.h"
+#include "vss.h"
+
+/* lightweight addrinfo */
+struct vss_addr {
+       int                      va_family;
+       int                      va_socktype;
+       int                      va_protocol;
+       socklen_t                va_addrlen;
+       struct sockaddr_storage  va_addr;
+};
+
+/*
+ * Take a string provided by the user and break it up into address and
+ * port parts.  Examples of acceptable input include:
+ *
+ * "localhost" - "localhost:80"
+ * "127.0.0.1" - "127.0.0.1:80"
+ * "0.0.0.0" - "0.0.0.0:80"
+ * "[::1]" - "[::1]:80"
+ * "[::]" - "[::]:80"
+ */
+int
+VSS_parse(const char *str, char **addr, char **port)
+{
+       const char *p;
+
+       *addr = *port = NULL;
+
+       if (str[0] == '[') {
+               /* IPv6 address of the form [::1]:80 */
+               if ((p = strchr(str, ']')) == NULL ||
+                   p == str + 1 ||
+                   (p[1] != '\0' && p[1] != ':'))
+                       return (-1);
+               *addr = strndup(str + 1, p - (str + 1));
+               XXXAN(*addr);
+               if (p[1] == ':') {
+                       *port = strdup(p + 2);
+                       XXXAN(*port);
+               }
+       } else {
+               /* IPv4 address of the form 127.0.0.1:80, or non-numeric */
+               p = strchr(str, ':');
+               if (p == NULL) {
+                       *addr = strdup(str);
+                       XXXAN(*addr);
+               } else {
+                       if (p > str) {
+                               *addr = strndup(str, p - str);
+                               XXXAN(*addr);
+                       }
+                       *port = strdup(p + 1);
+                       XXXAN(*port);
+               }
+       }
+       return (0);
+}
+
+/*
+ * For a given host and port, return a list of struct vss_addr, which
+ * contains all the information necessary to open and bind a socket.  One
+ * vss_addr is returned for each distinct address returned by
+ * getaddrinfo().
+ *
+ * The value pointed to by the tap parameter receives a pointer to an
+ * array of pointers to struct vss_addr.  The caller is responsible for
+ * freeing each individual struct vss_addr as well as the array.
+ *
+ * The return value is the number of addresses resoved, or zero.
+ */
+int
+VSS_resolve(const char *addr, const char *port, struct vss_addr ***vap)
+{
+       struct addrinfo hints, *res0, *res;
+       struct vss_addr **va;
+       int i, ret;
+
+        memset(&hints, 0, sizeof hints);
+        hints.ai_socktype = SOCK_STREAM;
+        hints.ai_flags = AI_PASSIVE;
+        ret = getaddrinfo(addr, port, &hints, &res0);
+        if (ret != 0) {
+                fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(ret));
+                return (0);
+        }
+       for (res = res0, i = 0; res != NULL; res = res->ai_next)
+               ++i;
+       va = calloc(i, sizeof *va);
+       XXXAN(va);
+       *vap = va;
+       for (res = res0, i = 0; res != NULL; res = res->ai_next, ++i) {
+               va[i] = calloc(1, sizeof *va[i]);
+               XXXAN(va[i]);
+               va[i]->va_family = res->ai_family;
+               va[i]->va_socktype = res->ai_socktype;
+               va[i]->va_protocol = res->ai_protocol;
+               va[i]->va_addrlen = res->ai_addrlen;
+               xxxassert(va[i]->va_addrlen <= sizeof va[i]->va_addr);
+               memcpy(&va[i]->va_addr, res->ai_addr, va[i]->va_addrlen);
+       }
+       freeaddrinfo(res0);
+       return (i);
+}
+
+/*
+ * Given a struct vss_addr, open a socket of the appropriate type, bind it
+ * to the requested address, and start listening.
+ *
+ * If the address is an IPv6 address, the IPV6_V6ONLY option is set to
+ * avoid conflicts between INADDR_ANY and IN6ADDR_ANY.
+ */
+int
+VSS_listen(const struct vss_addr *va, int depth)
+{
+       int sd, val;
+
+       sd = socket(va->va_family, va->va_socktype, va->va_protocol);
+       if (sd < 0) {
+               perror("socket()");
+               return (-1);
+       }
+       val = 1;
+       if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val) != 0) {
+               perror("setsockopt(SO_REUSEADDR, 1)");
+               close(sd);
+               return (-1);
+       }
+#ifdef IPV6_V6ONLY
+       /* forcibly use separate sockets for IPv4 and IPv6 */
+       val = 1;
+       if (va->va_family == AF_INET6 &&
+           setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof val) != 0) {
+               perror("setsockopt(IPV6_V6ONLY, 1)");
+               close(sd);
+               return (-1);
+       }
+#endif
+       if (bind(sd, (const struct sockaddr *)&va->va_addr, va->va_addrlen) != 0) {
+               perror("bind()");
+               close(sd);
+               return (-1);
+       }
+       if (listen(sd, depth) != 0) {
+               perror("listen()");
+               close(sd);
+               return (-1);
+       }
+       return (sd);
+}
+
+/*
+ * Connect to the socket specified by the address info in va.
+ * Return the socket.
+ */
+int
+VSS_connect(const struct vss_addr *va)
+{
+       int sd;
+
+       sd = socket(va->va_family, va->va_socktype, va->va_protocol);
+       if (sd < 0) {
+               perror("socket()");
+               return (-1);
+       }
+       if (connect(sd, (const struct sockaddr *)&va->va_addr, va->va_addrlen) != 0) {
+               perror("connect()");
+               close(sd);
+               return (-1);
+       }
+       return (sd);
+}