]> git.ipfire.org Git - thirdparty/openvpn.git/blobdiff - src/openvpn/socket.c
Fix various 'Uninitialized scalar variable' warnings from Coverity
[thirdparty/openvpn.git] / src / openvpn / socket.c
index 13c05e0762f73da5ad942a9259305807efcc2f68..480f4e51c7eea6062b45a92f80ccbbfa49a5902a 100644 (file)
@@ -5,7 +5,7 @@
  *             packet encryption, packet authentication, and
  *             packet compression.
  *
- *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ *  Copyright (C) 2002-2023 OpenVPN Inc <sales@openvpn.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program (see the file COPYING included with this
- *  distribution); if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
-#elif defined(_MSC_VER)
-#include "config-msvc.h"
 #endif
 
 #include "syshead.h"
 #include "gremlin.h"
 #include "plugin.h"
 #include "ps.h"
+#include "run_command.h"
 #include "manage.h"
 #include "misc.h"
 #include "manage.h"
 #include "openvpn.h"
+#include "forward.h"
 
 #include "memdbg.h"
 
-const int proto_overhead[] = { /* indexed by PROTO_x */
-  0,
-  IPv4_UDP_HEADER_SIZE, /* IPv4 */
-  IPv4_TCP_HEADER_SIZE,
-  IPv4_TCP_HEADER_SIZE,
-  IPv6_UDP_HEADER_SIZE, /* IPv6 */
-  IPv6_TCP_HEADER_SIZE,
-  IPv6_TCP_HEADER_SIZE,
-  IPv6_TCP_HEADER_SIZE,
-};
-
 /*
  * Convert sockflags/getaddr_flags into getaddr_flags
  */
@@ -61,217 +49,376 @@ static unsigned int
 sf2gaf(const unsigned int getaddr_flags,
        const unsigned int sockflags)
 {
-  if (sockflags & SF_HOST_RANDOMIZE)
-    return getaddr_flags | GETADDR_RANDOMIZE;
-  else
-    return getaddr_flags;
+    if (sockflags & SF_HOST_RANDOMIZE)
+    {
+        return getaddr_flags | GETADDR_RANDOMIZE;
+    }
+    else
+    {
+        return getaddr_flags;
+    }
 }
 
 /*
  * Functions related to the translation of DNS names to IP addresses.
  */
+static int
+get_addr_generic(sa_family_t af, unsigned int flags, const char *hostname,
+                 void *network, unsigned int *netbits,
+                 int resolve_retry_seconds, struct signal_info *sig_info,
+                 int msglevel)
+{
+    char *endp, *sep, *var_host = NULL;
+    struct addrinfo *ai = NULL;
+    unsigned long bits;
+    uint8_t max_bits;
+    int ret = -1;
 
-/*
- * Translate IP addr or hostname to in_addr_t.
- * If resolve error, try again for
- * resolve_retry_seconds seconds.
- */
-in_addr_t
-getaddr (unsigned int flags,
-         const char *hostname,
-         int resolve_retry_seconds,
-         bool *succeeded,
-         volatile int *signal_received)
-{
-  struct addrinfo *ai;
-  int status;
-  status = openvpn_getaddrinfo (flags & ~GETADDR_HOST_ORDER, hostname, NULL,
-                                resolve_retry_seconds, signal_received, AF_INET, &ai);
-  if(status==0) {
-    struct in_addr ia;
-    if(succeeded)
-      *succeeded=true;
-    ia = ((struct sockaddr_in*)ai->ai_addr)->sin_addr;
+    if (!hostname)
+    {
+        msg(M_NONFATAL, "Can't resolve null hostname!");
+        goto out;
+    }
+
+    /* assign family specific default values */
+    switch (af)
+    {
+        case AF_INET:
+            bits = 0;
+            max_bits = sizeof(in_addr_t) * 8;
+            break;
+
+        case AF_INET6:
+            bits = 64;
+            max_bits = sizeof(struct in6_addr) * 8;
+            break;
+
+        default:
+            msg(M_WARN,
+                "Unsupported AF family passed to getaddrinfo for %s (%d)",
+                hostname, af);
+            goto out;
+    }
+
+    /* we need to modify the hostname received as input, but we don't want to
+     * touch it directly as it might be a constant string.
+     *
+     * Therefore, we clone the string here and free it at the end of the
+     * function */
+    var_host = strdup(hostname);
+    if (!var_host)
+    {
+        msg(M_NONFATAL | M_ERRNO,
+            "Can't allocate hostname buffer for getaddrinfo");
+        goto out;
+    }
+
+    /* check if this hostname has a /bits suffix */
+    sep = strchr(var_host, '/');
+    if (sep)
+    {
+        bits = strtoul(sep + 1, &endp, 10);
+        if ((*endp != '\0') || (bits > max_bits))
+        {
+            msg(msglevel, "IP prefix '%s': invalid '/bits' spec (%s)", hostname,
+                sep + 1);
+            goto out;
+        }
+        *sep = '\0';
+    }
+
+    ret = openvpn_getaddrinfo(flags & ~GETADDR_HOST_ORDER, var_host, NULL,
+                              resolve_retry_seconds, sig_info, af, &ai);
+    if ((ret == 0) && network)
+    {
+        struct in6_addr *ip6;
+        in_addr_t *ip4;
+
+        switch (af)
+        {
+            case AF_INET:
+                ip4 = network;
+                *ip4 = ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr;
+
+                if (flags & GETADDR_HOST_ORDER)
+                {
+                    *ip4 = ntohl(*ip4);
+                }
+                break;
+
+            case AF_INET6:
+                ip6 = network;
+                *ip6 = ((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
+                break;
+
+            default:
+                /* can't get here because 'af' was previously checked */
+                msg(M_WARN,
+                    "Unsupported AF family for %s (%d)", var_host, af);
+                goto out;
+        }
+    }
+
+    if (netbits)
+    {
+        *netbits = bits;
+    }
+
+    /* restore '/' separator, if any */
+    if (sep)
+    {
+        *sep = '/';
+    }
+out:
     freeaddrinfo(ai);
-    return (flags & GETADDR_HOST_ORDER) ? ntohl (ia.s_addr) : ia.s_addr;
-  } else {
-    if(succeeded)
-      *succeeded =false;
-    return 0;
-  }
+    free(var_host);
+
+    return ret;
+}
+
+in_addr_t
+getaddr(unsigned int flags,
+        const char *hostname,
+        int resolve_retry_seconds,
+        bool *succeeded,
+        struct signal_info *sig_info)
+{
+    in_addr_t addr;
+    int status;
+
+    status = get_addr_generic(AF_INET, flags, hostname, &addr, NULL,
+                              resolve_retry_seconds, sig_info,
+                              M_WARN);
+    if (status==0)
+    {
+        if (succeeded)
+        {
+            *succeeded = true;
+        }
+        return addr;
+    }
+    else
+    {
+        if (succeeded)
+        {
+            *succeeded = false;
+        }
+        return 0;
+    }
+}
+
+bool
+get_ipv6_addr(const char *hostname, struct in6_addr *network,
+              unsigned int *netbits, int msglevel)
+{
+    if (get_addr_generic(AF_INET6, GETADDR_RESOLVE, hostname, network, netbits,
+                         0, NULL, msglevel) < 0)
+    {
+        return false;
+    }
+
+    return true;                /* parsing OK, values set */
 }
 
 static inline bool
-streqnull (const char* a, const char* b)
+streqnull(const char *a, const char *b)
 {
-  if (a == NULL && b == NULL)
-    return true;
-  else if (a == NULL || b == NULL)
-    return false;
-  else
-    return streq (a, b);
+    if (a == NULL && b == NULL)
+    {
+        return true;
+    }
+    else if (a == NULL || b == NULL)
+    {
+        return false;
+    }
+    else
+    {
+        return streq(a, b);
+    }
 }
 
 /*
-  get_cached_dns_entry return 0 on success and -1
-  otherwise. (like getaddrinfo)
* get_cached_dns_entry return 0 on success and -1
* otherwise. (like getaddrinfo)
  */
 static int
-get_cached_dns_entry (struct cached_dns_entry* dns_cache,
-                     const charhostname,
-                     const charservname,
-                     int ai_family,
-                     int resolve_flags,
-                     struct addrinfo **ai)
+get_cached_dns_entry(struct cached_dns_entry *dns_cache,
+                     const char *hostname,
+                     const char *servname,
+                     int ai_family,
+                     int resolve_flags,
+                     struct addrinfo **ai)
 {
-  struct cached_dns_entry *ph;
-  int flags;
+    struct cached_dns_entry *ph;
+    int flags;
 
-  /* Only use flags that are relevant for the structure */
-  flags = resolve_flags & GETADDR_CACHE_MASK;
+    /* Only use flags that are relevant for the structure */
+    flags = resolve_flags & GETADDR_CACHE_MASK;
 
-  for (ph = dns_cache; ph ; ph = ph->next)
+    for (ph = dns_cache; ph; ph = ph->next)
     {
-      if (streqnull (ph->hostname, hostname) &&
-         streqnull (ph->servname, servname) &&
-         ph->ai_family == ai_family &&
-         ph->flags == flags)
-       {
-         *ai = ph->ai;
-         return 0;
-       }
+        if (streqnull(ph->hostname, hostname)
+            && streqnull(ph->servname, servname)
+            && ph->ai_family == ai_family
+            && ph->flags == flags)
+        {
+            *ai = ph->ai;
+            return 0;
+        }
     }
-  return -1;
+    return -1;
 }
 
 
 static int
-do_preresolve_host (struct context *c,
-                   const char *hostname,
-                   const char *servname,
-                   const int af,
-                   const int flags)
+do_preresolve_host(struct context *c,
+                   const char *hostname,
+                   const char *servname,
+                   const int af,
+                   const int flags)
 {
-  struct addrinfo *ai;
-  int status;
+    struct addrinfo *ai;
+    int status;
 
-  if (get_cached_dns_entry(c->c1.dns_cache,
-                          hostname,
-                          servname,
-                          af,
-                          flags,
-                          &ai) == 0 )
+    if (get_cached_dns_entry(c->c1.dns_cache,
+                             hostname,
+                             servname,
+                             af,
+                             flags,
+                             &ai) == 0)
     {
-      /* entry already cached, return success */
-      return 0;
+        /* entry already cached, return success */
+        return 0;
     }
 
-  status = openvpn_getaddrinfo (flags, hostname, servname,
-                               c->options.resolve_retry_seconds, NULL,
-                               af, &ai);
-  if (status == 0)
+    status = openvpn_getaddrinfo(flags, hostname, servname,
+                                 c->options.resolve_retry_seconds, NULL,
+                                 af, &ai);
+    if (status == 0)
     {
-      struct cached_dns_entry *ph;
+        struct cached_dns_entry *ph;
 
-      ALLOC_OBJ_CLEAR_GC (ph, struct cached_dns_entry, &c->gc);
-      ph->ai = ai;
-      ph->hostname = hostname;
-      ph->servname = servname;
-      ph->flags = flags & GETADDR_CACHE_MASK;
+        ALLOC_OBJ_CLEAR_GC(ph, struct cached_dns_entry, &c->gc);
+        ph->ai = ai;
+        ph->hostname = hostname;
+        ph->servname = servname;
+        ph->flags = flags & GETADDR_CACHE_MASK;
 
-      if (!c->c1.dns_cache)
-       c->c1.dns_cache = ph;
-      else
-       {
-         struct cached_dns_entry *prev = c->c1.dns_cache;
-         while (prev->next)
-           prev = prev->next;
-         prev->next = ph;
-       }
+        if (!c->c1.dns_cache)
+        {
+            c->c1.dns_cache = ph;
+        }
+        else
+        {
+            struct cached_dns_entry *prev = c->c1.dns_cache;
+            while (prev->next)
+            {
+                prev = prev->next;
+            }
+            prev->next = ph;
+        }
 
-      gc_addspecial (ai, &gc_freeaddrinfo_callback, &c->gc);
+        gc_addspecial(ai, &gc_freeaddrinfo_callback, &c->gc);
 
     }
-  return status;
+    return status;
 }
 
 void
-do_preresolve (struct context *c)
-{
-  int i;
-  struct connection_list *l = c->options.connection_list;
-  const unsigned int preresolve_flags = GETADDR_RESOLVE|
-    GETADDR_UPDATE_MANAGEMENT_STATE|
-    GETADDR_MENTION_RESOLVE_RETRY|
-    GETADDR_FATAL;
-
-
-  for (i = 0; i < l->len; ++i)
-    {
-      int status;
-      const char *remote;
-      int flags = preresolve_flags;
-
-      struct connection_entry* ce = c->options.connection_list->array[i];
-
-      if (proto_is_dgram(ce->proto))
-         flags |= GETADDR_DATAGRAM;
-
-      if (c->options.sockflags & SF_HOST_RANDOMIZE)
-         flags |= GETADDR_RANDOMIZE;
-
-      if (c->options.ip_remote_hint)
-         remote = c->options.ip_remote_hint;
-      else
-         remote = ce->remote;
-
-      /* HTTP remote hostname does not need to be resolved */
-      if (! ce->http_proxy_options)
-       {
-         status = do_preresolve_host (c, remote, ce->remote_port, ce->af, flags);
-         if (status != 0)
-             goto err;
-       }
-
-      /* Preresolve proxy */
-      if (ce->http_proxy_options)
-       {
-         status = do_preresolve_host (c,
-                                      ce->http_proxy_options->server,
-                                      ce->http_proxy_options->port,
-                                      ce->af,
-                                      preresolve_flags);
-
-         if (status != 0)
-             goto err;
-       }
-
-      if (ce->socks_proxy_server)
-       {
-         status = do_preresolve_host (c,
-                                      ce->socks_proxy_server,
-                                      ce->socks_proxy_port,
-                                      ce->af,
-                                      flags);
-         if (status != 0)
-             goto err;
-       }
-
-      if (ce->bind_local)
-       {
-         flags |= GETADDR_PASSIVE;
-         flags &= ~GETADDR_RANDOMIZE;
-         status = do_preresolve_host (c, ce->local, ce->local_port, ce->af, flags);
-         if (status != 0)
-             goto err;
-
-       }
+do_preresolve(struct context *c)
+{
+    int i;
+    struct connection_list *l = c->options.connection_list;
+    const unsigned int preresolve_flags = GETADDR_RESOLVE
+                                          |GETADDR_UPDATE_MANAGEMENT_STATE
+                                          |GETADDR_MENTION_RESOLVE_RETRY
+                                          |GETADDR_FATAL;
+
+
+    for (i = 0; i < l->len; ++i)
+    {
+        int status;
+        const char *remote;
+        int flags = preresolve_flags;
+
+        struct connection_entry *ce = c->options.connection_list->array[i];
+
+        if (proto_is_dgram(ce->proto))
+        {
+            flags |= GETADDR_DATAGRAM;
+        }
+
+        if (c->options.sockflags & SF_HOST_RANDOMIZE)
+        {
+            flags |= GETADDR_RANDOMIZE;
+        }
+
+        if (c->options.ip_remote_hint)
+        {
+            remote = c->options.ip_remote_hint;
+        }
+        else
+        {
+            remote = ce->remote;
+        }
+
+        /* HTTP remote hostname does not need to be resolved */
+        if (!ce->http_proxy_options)
+        {
+            status = do_preresolve_host(c, remote, ce->remote_port,
+                                        ce->af, flags);
+            if (status != 0)
+            {
+                goto err;
+            }
+        }
+
+        /* Preresolve proxy */
+        if (ce->http_proxy_options)
+        {
+            status = do_preresolve_host(c,
+                                        ce->http_proxy_options->server,
+                                        ce->http_proxy_options->port,
+                                        ce->af,
+                                        preresolve_flags);
+
+            if (status != 0)
+            {
+                goto err;
+            }
+        }
+
+        if (ce->socks_proxy_server)
+        {
+            status = do_preresolve_host(c,
+                                        ce->socks_proxy_server,
+                                        ce->socks_proxy_port,
+                                        ce->af,
+                                        flags);
+            if (status != 0)
+            {
+                goto err;
+            }
+        }
+
+        if (ce->bind_local)
+        {
+            flags |= GETADDR_PASSIVE;
+            flags &= ~GETADDR_RANDOMIZE;
+            status = do_preresolve_host(c, ce->local, ce->local_port,
+                                        ce->af, flags);
+            if (status != 0)
+            {
+                goto err;
+            }
+
+        }
 
     }
     return;
 
- err:
-  throw_signal_soft (SIGHUP, "Preresolving failed");
+err:
+    throw_signal_soft(SIGHUP, "Preresolving failed");
 }
 
 /*
@@ -279,185 +426,232 @@ do_preresolve (struct context *c)
  * If resolve error, try again for resolve_retry_seconds seconds.
  */
 int
-openvpn_getaddrinfo (unsigned int flags,
-                     const char *hostname,
-                     const char *servname,
-                     int resolve_retry_seconds,
-                     volatile int *signal_received,
-                     int ai_family,
-                     struct addrinfo **res)
+openvpn_getaddrinfo(unsigned int flags,
+                    const char *hostname,
+                    const char *servname,
+                    int resolve_retry_seconds,
+                    struct signal_info *sig_info,
+                    int ai_family,
+                    struct addrinfo **res)
 {
-  struct addrinfo hints;
-  int status;
-  int sigrec = 0;
-  int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS;
-  struct gc_arena gc = gc_new ();
-  const char *print_hostname;
-  const char *print_servname;
+    struct addrinfo hints;
+    int status;
+    struct signal_info sigrec = {0};
+    int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS;
+    struct gc_arena gc = gc_new();
+    const char *print_hostname;
+    const char *print_servname;
 
-  ASSERT(res);
+    ASSERT(res);
 
-  ASSERT (hostname || servname);
-  ASSERT (!(flags & GETADDR_HOST_ORDER));
+    ASSERT(hostname || servname);
+    ASSERT(!(flags & GETADDR_HOST_ORDER));
 
-  if (hostname && (flags & GETADDR_RANDOMIZE))
-    hostname = hostname_randomize(hostname, &gc);
+    if (servname)
+    {
+        print_servname = servname;
+    }
+    else
+    {
+        print_servname = "";
+    }
 
-  if(hostname)
-    print_hostname = hostname;
-  else
-    print_hostname = "undefined";
+    if (flags & GETADDR_MSG_VIRT_OUT)
+    {
+        msglevel |= M_MSG_VIRT_OUT;
+    }
 
-  if(servname)
-    print_servname = servname;
-  else
-    print_servname = "";
+    if ((flags & (GETADDR_FATAL_ON_SIGNAL|GETADDR_WARN_ON_SIGNAL))
+        && !sig_info)
+    {
+        sig_info = &sigrec;
+    }
 
-  if (flags & GETADDR_MSG_VIRT_OUT)
-    msglevel |= M_MSG_VIRT_OUT;
+    /* try numeric ipv6 addr first */
+    CLEAR(hints);
+    hints.ai_family = ai_family;
+    hints.ai_flags = AI_NUMERICHOST;
 
-  if ((flags & (GETADDR_FATAL_ON_SIGNAL|GETADDR_WARN_ON_SIGNAL))
-      && !signal_received)
-    signal_received = &sigrec;
+    if (flags & GETADDR_PASSIVE)
+    {
+        hints.ai_flags |= AI_PASSIVE;
+    }
 
-  /* try numeric ipv6 addr first */
-  CLEAR(hints);
-  hints.ai_family = ai_family;
-  hints.ai_flags = AI_NUMERICHOST;
+    if (flags & GETADDR_DATAGRAM)
+    {
+        hints.ai_socktype = SOCK_DGRAM;
+    }
+    else
+    {
+        hints.ai_socktype = SOCK_STREAM;
+    }
 
-  if(flags & GETADDR_PASSIVE)
-      hints.ai_flags |= AI_PASSIVE;
+    status = getaddrinfo(hostname, servname, &hints, res);
 
-  if(flags & GETADDR_DATAGRAM)
-      hints.ai_socktype = SOCK_DGRAM;
-  else
-      hints.ai_socktype = SOCK_STREAM;
+    if (status != 0) /* parse as numeric address failed? */
+    {
+        const int fail_wait_interval = 5; /* seconds */
+        /* Add +4 to cause integer division rounding up (1 + 4) = 5, (0+4)/5=0 */
+        int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 :
+                              ((resolve_retry_seconds + 4)/ fail_wait_interval);
+        const char *fmt;
+        int level = 0;
 
-  status = getaddrinfo(hostname, servname, &hints, res);
+        if (hostname && (flags & GETADDR_RANDOMIZE))
+        {
+            hostname = hostname_randomize(hostname, &gc);
+        }
 
-  if (status != 0) /* parse as numeric address failed? */
-    {
-      const int fail_wait_interval = 5; /* seconds */
-      /* Add +4 to cause integer division rounding up (1 + 4) = 5, (0+4)/5=0 */
-      int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 :
-            ((resolve_retry_seconds + 4)/ fail_wait_interval);
-      const char *fmt;
-      int level = 0;
+        if (hostname)
+        {
+            print_hostname = hostname;
+        }
+        else
+        {
+            print_hostname = "undefined";
+        }
 
-      fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s)";
-      if ((flags & GETADDR_MENTION_RESOLVE_RETRY)
-          && !resolve_retry_seconds)
-        fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s) (I would have retried this name query if you had specified the --resolv-retry option.)";
+        fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s)";
+        if ((flags & GETADDR_MENTION_RESOLVE_RETRY)
+            && !resolve_retry_seconds)
+        {
+            fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s) "
+                  "(I would have retried this name query if you had "
+                  "specified the --resolv-retry option.)";
+        }
 
-      if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL)
+        if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL)
         {
-          msg (msglevel, "RESOLVE: Cannot parse IP address: %s:%s (%s)",
-               print_hostname,print_servname, gai_strerror(status));
-          goto done;
+            msg(msglevel, "RESOLVE: Cannot parse IP address: %s:%s (%s)",
+                print_hostname, print_servname, gai_strerror(status));
+            goto done;
         }
 
 #ifdef ENABLE_MANAGEMENT
-      if (flags & GETADDR_UPDATE_MANAGEMENT_STATE)
+        if (flags & GETADDR_UPDATE_MANAGEMENT_STATE)
         {
-          if (management)
-            management_set_state (management,
-                                  OPENVPN_STATE_RESOLVE,
-                                  NULL,
-                                  NULL,
-                                  NULL,
-                                  NULL,
-                                  NULL);
+            if (management)
+            {
+                management_set_state(management,
+                                     OPENVPN_STATE_RESOLVE,
+                                     NULL,
+                                     NULL,
+                                     NULL,
+                                     NULL,
+                                     NULL);
+            }
         }
 #endif
 
-      /*
-       * Resolve hostname
-       */
-      while (true)
+        /*
+         * Resolve hostname
+         */
+        while (true)
         {
-#ifndef WIN32
-         res_init ();
+#ifndef _WIN32
+            /* force resolv.conf reload */
+            res_init();
 #endif
-          /* try hostname lookup */
-          hints.ai_flags &= ~AI_NUMERICHOST;
-          dmsg (D_SOCKET_DEBUG, "GETADDRINFO flags=0x%04x ai_family=%d ai_socktype=%d",
-                flags, hints.ai_family, hints.ai_socktype);
-          status = getaddrinfo(hostname, servname, &hints, res);
-
-          if (signal_received)
+            /* try hostname lookup */
+            hints.ai_flags &= ~AI_NUMERICHOST;
+            dmsg(D_SOCKET_DEBUG,
+                 "GETADDRINFO flags=0x%04x ai_family=%d ai_socktype=%d",
+                 flags, hints.ai_family, hints.ai_socktype);
+            status = getaddrinfo(hostname, servname, &hints, res);
+
+            if (sig_info)
             {
-              get_signal (signal_received);
-              if (*signal_received) /* were we interrupted by a signal? */
+                get_signal(&sig_info->signal_received);
+                if (sig_info->signal_received) /* were we interrupted by a signal? */
                 {
-                  if (*signal_received == SIGUSR1) /* ignore SIGUSR1 */
+                    /* why are we overwriting SIGUSR1 ? */
+                    if (signal_reset(sig_info, SIGUSR1) == SIGUSR1) /* ignore SIGUSR1 */
                     {
-                      msg (level, "RESOLVE: Ignored SIGUSR1 signal received during DNS resolution attempt");
-                      *signal_received = 0;
+                        msg(level,
+                            "RESOLVE: Ignored SIGUSR1 signal received during "
+                            "DNS resolution attempt");
                     }
-                  else
+                    else
                     {
-                     /* turn success into failure (interrupted syscall) */
-                      if (0 == status) {
-                          ASSERT(res);
-                          freeaddrinfo(*res);
-                          *res = NULL;
-                          status = EAI_AGAIN;  /* = temporary failure */
-                          errno = EINTR;
-                      }
-                      goto done;
+                        /* turn success into failure (interrupted syscall) */
+                        if (0 == status)
+                        {
+                            ASSERT(res);
+                            freeaddrinfo(*res);
+                            *res = NULL;
+                            status = EAI_AGAIN; /* = temporary failure */
+                            errno = EINTR;
+                        }
+                        goto done;
                     }
                 }
             }
 
-          /* success? */
-          if (0 == status)
-            break;
+            /* success? */
+            if (0 == status)
+            {
+                break;
+            }
 
-          /* resolve lookup failed, should we
-             continue or fail? */
-          level = msglevel;
-          if (resolve_retries > 0)
-            level = D_RESOLVE_ERRORS;
+            /* resolve lookup failed, should we
+             * continue or fail? */
+            level = msglevel;
+            if (resolve_retries > 0)
+            {
+                level = D_RESOLVE_ERRORS;
+            }
 
-          msg (level,
-               fmt,
-               print_hostname,
-               print_servname,
-               gai_strerror(status));
+            msg(level,
+                fmt,
+                print_hostname,
+                print_servname,
+                gai_strerror(status));
 
-          if (--resolve_retries <= 0)
-            goto done;
+            if (--resolve_retries <= 0)
+            {
+                goto done;
+            }
 
-          openvpn_sleep (fail_wait_interval);
+            management_sleep(fail_wait_interval);
         }
 
-      ASSERT(res);
+        ASSERT(res);
 
-      /* hostname resolve succeeded */
+        /* hostname resolve succeeded */
 
-      /*
-       * Do not choose an IP Addresse by random or change the order *
-       * of IP addresses, doing so will break RFC 3484 address selection *
-       */
+        /*
+         * Do not choose an IP Addresse by random or change the order *
+         * of IP addresses, doing so will break RFC 3484 address selection *
+         */
     }
-  else
+    else
     {
-      /* IP address parse succeeded */
+        /* IP address parse succeeded */
+        if (flags & GETADDR_RANDOMIZE)
+        {
+            msg(M_WARN,
+                "WARNING: ignoring --remote-random-hostname because the "
+                "hostname is an IP address");
+        }
     }
 
- done:
-  if (signal_received && *signal_received)
+done:
+    if (sig_info && sig_info->signal_received)
     {
-      int level = 0;
-      if (flags & GETADDR_FATAL_ON_SIGNAL)
-        level = M_FATAL;
-      else if (flags & GETADDR_WARN_ON_SIGNAL)
-        level = M_WARN;
-      msg (level, "RESOLVE: signal received during DNS resolution attempt");
+        int level = 0;
+        if (flags & GETADDR_FATAL_ON_SIGNAL)
+        {
+            level = M_FATAL;
+        }
+        else if (flags & GETADDR_WARN_ON_SIGNAL)
+        {
+            level = M_WARN;
+        }
+        msg(level, "RESOLVE: signal received during DNS resolution attempt");
     }
 
-  gc_free (&gc);
-  return status;
+    gc_free(&gc);
+    return status;
 }
 
 /*
@@ -465,220 +659,260 @@ openvpn_getaddrinfo (unsigned int flags,
  * isn't very good about error checking.
  */
 int
-openvpn_inet_aton (const char *dotted_quad, struct in_addr *addr)
+openvpn_inet_aton(const char *dotted_quad, struct in_addr *addr)
 {
-  unsigned int a, b, c, d;
+    unsigned int a, b, c, d;
 
-  CLEAR (*addr);
-  if (sscanf (dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) == 4)
+    CLEAR(*addr);
+    if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) == 4)
+    {
+        if (a < 256 && b < 256 && c < 256 && d < 256)
+        {
+            addr->s_addr = htonl(a<<24 | b<<16 | c<<8 | d);
+            return OIA_IP; /* good dotted quad */
+        }
+    }
+    if (string_class(dotted_quad, CC_DIGIT|CC_DOT, 0))
     {
-      if (a < 256 && b < 256 && c < 256 && d < 256)
-       {
-         addr->s_addr = htonl (a<<24 | b<<16 | c<<8 | d);
-         return OIA_IP; /* good dotted quad */
-       }
+        return OIA_ERROR; /* probably a badly formatted dotted quad */
+    }
+    else
+    {
+        return OIA_HOSTNAME; /* probably a hostname */
     }
-  if (string_class (dotted_quad, CC_DIGIT|CC_DOT, 0))
-    return OIA_ERROR;    /* probably a badly formatted dotted quad */
-  else
-    return OIA_HOSTNAME; /* probably a hostname */
 }
 
 bool
-ip_addr_dotted_quad_safe (const char *dotted_quad)
+ip_addr_dotted_quad_safe(const char *dotted_quad)
 {
-  /* verify non-NULL */
-  if (!dotted_quad)
-    return false;
+    /* verify non-NULL */
+    if (!dotted_quad)
+    {
+        return false;
+    }
 
-  /* verify length is within limits */
-  if (strlen (dotted_quad) > 15)
-    return false;
+    /* verify length is within limits */
+    if (strlen(dotted_quad) > 15)
+    {
+        return false;
+    }
+
+    /* verify that all chars are either numeric or '.' and that no numeric
+     * substring is greater than 3 chars */
+    {
+        int nnum = 0;
+        const char *p = dotted_quad;
+        int c;
+
+        while ((c = *p++))
+        {
+            if (c >= '0' && c <= '9')
+            {
+                ++nnum;
+                if (nnum > 3)
+                {
+                    return false;
+                }
+            }
+            else if (c == '.')
+            {
+                nnum = 0;
+            }
+            else
+            {
+                return false;
+            }
+        }
+    }
 
-  /* verify that all chars are either numeric or '.' and that no numeric
-     substring is greater than 3 chars */
-  {
-    int nnum = 0;
-    const char *p = dotted_quad;
-    int c;
-
-    while ((c = *p++))
-      {
-       if (c >= '0' && c <= '9')
-         {
-           ++nnum;
-           if (nnum > 3)
-             return false;
-         }
-       else if (c == '.')
-         {
-           nnum = 0;
-         }
-       else
-         return false;
-      }
-  }
-
-  /* verify that string will convert to IP address */
-  {
-    struct in_addr a;
-    return openvpn_inet_aton (dotted_quad, &a) == OIA_IP;
-  }
+    /* verify that string will convert to IP address */
+    {
+        struct in_addr a;
+        return openvpn_inet_aton(dotted_quad, &a) == OIA_IP;
+    }
 }
 
 bool
-ipv6_addr_safe (const char *ipv6_text_addr)
+ipv6_addr_safe(const char *ipv6_text_addr)
 {
-  /* verify non-NULL */
-  if (!ipv6_text_addr)
-    return false;
+    /* verify non-NULL */
+    if (!ipv6_text_addr)
+    {
+        return false;
+    }
 
-  /* verify length is within limits */
-  if (strlen (ipv6_text_addr) > INET6_ADDRSTRLEN )
-    return false;
+    /* verify length is within limits */
+    if (strlen(ipv6_text_addr) > INET6_ADDRSTRLEN)
+    {
+        return false;
+    }
 
-  /* verify that string will convert to IPv6 address */
-  {
-    struct in6_addr a6;
-    return inet_pton( AF_INET6, ipv6_text_addr, &a6 ) == 1;
-  }
+    /* verify that string will convert to IPv6 address */
+    {
+        struct in6_addr a6;
+        return inet_pton( AF_INET6, ipv6_text_addr, &a6 ) == 1;
+    }
 }
 
 static bool
-dns_addr_safe (const char *addr)
+dns_addr_safe(const char *addr)
 {
-  if (addr)
+    if (addr)
     {
-      const size_t len = strlen (addr);
-      return len > 0 && len <= 255 && string_class (addr, CC_ALNUM|CC_DASH|CC_DOT, 0);
+        const size_t len = strlen(addr);
+        return len > 0 && len <= 255 && string_class(addr, CC_ALNUM|CC_DASH|CC_DOT, 0);
+    }
+    else
+    {
+        return false;
     }
-  else
-    return false;
 }
 
 bool
-ip_or_dns_addr_safe (const char *addr, const bool allow_fqdn)
+ip_or_dns_addr_safe(const char *addr, const bool allow_fqdn)
 {
-  if (ip_addr_dotted_quad_safe (addr))
-    return true;
-  else if (allow_fqdn)
-    return dns_addr_safe (addr);
-  else
-    return false;
+    if (ip_addr_dotted_quad_safe(addr))
+    {
+        return true;
+    }
+    else if (allow_fqdn)
+    {
+        return dns_addr_safe(addr);
+    }
+    else
+    {
+        return false;
+    }
 }
 
 bool
-mac_addr_safe (const char *mac_addr)
+mac_addr_safe(const char *mac_addr)
 {
-  /* verify non-NULL */
-  if (!mac_addr)
-    return false;
+    /* verify non-NULL */
+    if (!mac_addr)
+    {
+        return false;
+    }
 
-  /* verify length is within limits */
-  if (strlen (mac_addr) > 17)
-    return false;
+    /* verify length is within limits */
+    if (strlen(mac_addr) > 17)
+    {
+        return false;
+    }
+
+    /* verify that all chars are either alphanumeric or ':' and that no
+     * alphanumeric substring is greater than 2 chars */
+    {
+        int nnum = 0;
+        const char *p = mac_addr;
+        int c;
+
+        while ((c = *p++))
+        {
+            if ( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') )
+            {
+                ++nnum;
+                if (nnum > 2)
+                {
+                    return false;
+                }
+            }
+            else if (c == ':')
+            {
+                nnum = 0;
+            }
+            else
+            {
+                return false;
+            }
+        }
+    }
 
-  /* verify that all chars are either alphanumeric or ':' and that no
-     alphanumeric substring is greater than 2 chars */
-  {
-    int nnum = 0;
-    const char *p = mac_addr;
-    int c;
-
-    while ((c = *p++))
-      {
-       if ( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') )
-         {
-           ++nnum;
-           if (nnum > 2)
-             return false;
-         }
-       else if (c == ':')
-         {
-           nnum = 0;
-         }
-       else
-         return false;
-      }
-  }
-
-  /* error-checking is left to script invoked in lladdr.c */
-  return true;
+    /* error-checking is left to script invoked in lladdr.c */
+    return true;
 }
 
 static int
-socket_get_sndbuf (int sd)
+socket_get_sndbuf(socket_descriptor_t sd)
 {
-#if defined(HAVE_GETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_SNDBUF)
-  int val;
-  socklen_t len;
+#if defined(SOL_SOCKET) && defined(SO_SNDBUF)
+    int val;
+    socklen_t len;
 
-  len = sizeof (val);
-  if (getsockopt (sd, SOL_SOCKET, SO_SNDBUF, (void *) &val, &len) == 0
-      && len == sizeof (val))
-    return val;
+    len = sizeof(val);
+    if (getsockopt(sd, SOL_SOCKET, SO_SNDBUF, (void *) &val, &len) == 0
+        && len == sizeof(val))
+    {
+        return val;
+    }
 #endif
-  return 0;
+    return 0;
 }
 
 static void
-socket_set_sndbuf (int sd, int size)
+socket_set_sndbuf(socket_descriptor_t sd, int size)
 {
-#if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_SNDBUF)
-  if (setsockopt (sd, SOL_SOCKET, SO_SNDBUF, (void *) &size, sizeof (size)) != 0)
+#if defined(SOL_SOCKET) && defined(SO_SNDBUF)
+    if (setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (void *) &size, sizeof(size)) != 0)
     {
-      msg (M_WARN, "NOTE: setsockopt SO_SNDBUF=%d failed", size);
+        msg(M_WARN, "NOTE: setsockopt SO_SNDBUF=%d failed", size);
     }
 #endif
 }
 
 static int
-socket_get_rcvbuf (int sd)
+socket_get_rcvbuf(socket_descriptor_t sd)
 {
-#if defined(HAVE_GETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_RCVBUF)
-  int val;
-  socklen_t len;
+#if defined(SOL_SOCKET) && defined(SO_RCVBUF)
+    int val;
+    socklen_t len;
 
-  len = sizeof (val);
-  if (getsockopt (sd, SOL_SOCKET, SO_RCVBUF, (void *) &val, &len) == 0
-      && len == sizeof (val))
-    return val;
+    len = sizeof(val);
+    if (getsockopt(sd, SOL_SOCKET, SO_RCVBUF, (void *) &val, &len) == 0
+        && len == sizeof(val))
+    {
+        return val;
+    }
 #endif
-  return 0;
+    return 0;
 }
 
 static bool
-socket_set_rcvbuf (int sd, int size)
+socket_set_rcvbuf(socket_descriptor_t sd, int size)
 {
-#if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_RCVBUF)
-  if (setsockopt (sd, SOL_SOCKET, SO_RCVBUF, (void *) &size, sizeof (size)) != 0)
+#if defined(SOL_SOCKET) && defined(SO_RCVBUF)
+    if (setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (void *) &size, sizeof(size)) != 0)
     {
-      msg (M_WARN, "NOTE: setsockopt SO_RCVBUF=%d failed", size);
-      return false;
+        msg(M_WARN, "NOTE: setsockopt SO_RCVBUF=%d failed", size);
+        return false;
     }
-  return true;
+    return true;
 #endif
 }
 
 static void
-socket_set_buffers (int fd, const struct socket_buffer_size *sbs)
+socket_set_buffers(socket_descriptor_t fd, const struct socket_buffer_size *sbs)
 {
-  if (sbs)
+    if (sbs)
     {
-      const int sndbuf_old = socket_get_sndbuf (fd);
-      const int rcvbuf_old = socket_get_rcvbuf (fd);
+        const int sndbuf_old = socket_get_sndbuf(fd);
+        const int rcvbuf_old = socket_get_rcvbuf(fd);
 
-      if (sbs->sndbuf)
-       socket_set_sndbuf (fd, sbs->sndbuf);
+        if (sbs->sndbuf)
+        {
+            socket_set_sndbuf(fd, sbs->sndbuf);
+        }
 
-      if (sbs->rcvbuf)
-       socket_set_rcvbuf (fd, sbs->rcvbuf);
-       
-      msg (D_OSBUF, "Socket Buffers: R=[%d->%d] S=[%d->%d]",
-          rcvbuf_old,
-          socket_get_rcvbuf (fd),
-          sndbuf_old,
-          socket_get_sndbuf (fd));
+        if (sbs->rcvbuf)
+        {
+            socket_set_rcvbuf(fd, sbs->rcvbuf);
+        }
+
+        msg(D_OSBUF, "Socket Buffers: R=[%d->%d] S=[%d->%d]",
+            rcvbuf_old,
+            socket_get_rcvbuf(fd),
+            sndbuf_old,
+            socket_get_sndbuf(fd));
     }
 }
 
@@ -687,203 +921,262 @@ socket_set_buffers (int fd, const struct socket_buffer_size *sbs)
  */
 
 static bool
-socket_set_tcp_nodelay (int sd, int state)
+socket_set_tcp_nodelay(socket_descriptor_t sd, int state)
 {
-#if defined(WIN32) || (defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP) && defined(TCP_NODELAY))
-  if (setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (void *) &state, sizeof (state)) != 0)
+#if defined(_WIN32) || (defined(IPPROTO_TCP) && defined(TCP_NODELAY))
+    if (setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (void *) &state, sizeof(state)) != 0)
     {
-      msg (M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed", state);
-      return false;
+        msg(M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed", state);
+        return false;
     }
-  else
+    else
     {
-      dmsg (D_OSBUF, "Socket flags: TCP_NODELAY=%d succeeded", state);
-      return true;
+        dmsg(D_OSBUF, "Socket flags: TCP_NODELAY=%d succeeded", state);
+        return true;
     }
-#else
-  msg (M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed (No kernel support)", state);
-  return false;
+#else  /* if defined(_WIN32) || (defined(IPPROTO_TCP) && defined(TCP_NODELAY)) */
+    msg(M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed (No kernel support)", state);
+    return false;
 #endif
 }
 
 static inline void
-socket_set_mark (int sd, int mark)
+socket_set_mark(socket_descriptor_t sd, int mark)
 {
 #if defined(TARGET_LINUX) && HAVE_DECL_SO_MARK
-  if (mark && setsockopt (sd, SOL_SOCKET, SO_MARK, (void *) &mark, sizeof (mark)) != 0)
-    msg (M_WARN, "NOTE: setsockopt SO_MARK=%d failed", mark);
+    if (mark && setsockopt(sd, SOL_SOCKET, SO_MARK, (void *) &mark, sizeof(mark)) != 0)
+    {
+        msg(M_WARN, "NOTE: setsockopt SO_MARK=%d failed", mark);
+    }
 #endif
 }
 
 static bool
-socket_set_flags (int sd, unsigned int sockflags)
+socket_set_flags(socket_descriptor_t sd, unsigned int sockflags)
 {
-  if (sockflags & SF_TCP_NODELAY)
-    return socket_set_tcp_nodelay (sd, 1);
-  else
-    return true;
+    /* SF_TCP_NODELAY doesn't make sense for dco-win */
+    if ((sockflags & SF_TCP_NODELAY) && (!(sockflags & SF_DCO_WIN)))
+    {
+        return socket_set_tcp_nodelay(sd, 1);
+    }
+    else
+    {
+        return true;
+    }
 }
 
 bool
-link_socket_update_flags (struct link_socket *ls, unsigned int sockflags)
+link_socket_update_flags(struct link_socket *ls, unsigned int sockflags)
 {
-  if (ls && socket_defined (ls->sd))
-    return socket_set_flags (ls->sd, ls->sockflags = sockflags);
-  else
-    return false;
+    if (ls && socket_defined(ls->sd))
+    {
+        ls->sockflags |= sockflags;
+        return socket_set_flags(ls->sd, ls->sockflags);
+    }
+    else
+    {
+        return false;
+    }
 }
 
 void
-link_socket_update_buffer_sizes (struct link_socket *ls, int rcvbuf, int sndbuf)
+link_socket_update_buffer_sizes(struct link_socket *ls, int rcvbuf, int sndbuf)
 {
-  if (ls && socket_defined (ls->sd))
+    if (ls && socket_defined(ls->sd))
     {
-      ls->socket_buffer_sizes.sndbuf = sndbuf;
-      ls->socket_buffer_sizes.rcvbuf = rcvbuf;
-      socket_set_buffers (ls->sd, &ls->socket_buffer_sizes);
+        ls->socket_buffer_sizes.sndbuf = sndbuf;
+        ls->socket_buffer_sizes.rcvbuf = rcvbuf;
+        socket_set_buffers(ls->sd, &ls->socket_buffer_sizes);
     }
 }
 
 /*
- * SOCKET INITALIZATION CODE.
+ * SOCKET INITIALIZATION CODE.
  * Create a TCP/UDP socket
  */
 
 socket_descriptor_t
-create_socket_tcp (struct addrinfo* addrinfo)
+create_socket_tcp(struct addrinfo *addrinfo)
 {
-  socket_descriptor_t sd;
+    socket_descriptor_t sd;
 
-  ASSERT (addrinfo);
-  ASSERT (addrinfo->ai_socktype == SOCK_STREAM);
+    ASSERT(addrinfo);
+    ASSERT(addrinfo->ai_socktype == SOCK_STREAM);
 
-  if ((sd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0)
-    msg (M_ERR, "Cannot create TCP socket");
+    if ((sd = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0)
+    {
+        msg(M_ERR, "Cannot create TCP socket");
+    }
 
-#ifndef WIN32 /* using SO_REUSEADDR on Windows will cause bind to succeed on port conflicts! */
-  /* set SO_REUSEADDR on socket */
-  {
-    int on = 1;
-    if (setsockopt (sd, SOL_SOCKET, SO_REUSEADDR,
-                   (void *) &on, sizeof (on)) < 0)
-      msg (M_ERR, "TCP: Cannot setsockopt SO_REUSEADDR on TCP socket");
-  }
+#ifndef _WIN32 /* using SO_REUSEADDR on Windows will cause bind to succeed on port conflicts! */
+    /* set SO_REUSEADDR on socket */
+    {
+        int on = 1;
+        if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR,
+                       (void *) &on, sizeof(on)) < 0)
+        {
+            msg(M_ERR, "TCP: Cannot setsockopt SO_REUSEADDR on TCP socket");
+        }
+    }
 #endif
 
-  return sd;
+    /* set socket file descriptor to not pass across execs, so that
+     * scripts don't have access to it */
+    set_cloexec(sd);
+
+    return sd;
 }
 
 static socket_descriptor_t
-create_socket_udp (struct addrinfo* addrinfo, const unsigned int flags)
+create_socket_udp(struct addrinfo *addrinfo, const unsigned int flags)
 {
-  socket_descriptor_t sd;
+    socket_descriptor_t sd;
 
-  ASSERT (addrinfo);
-  ASSERT (addrinfo->ai_socktype == SOCK_DGRAM);
+    ASSERT(addrinfo);
+    ASSERT(addrinfo->ai_socktype == SOCK_DGRAM);
 
-  if ((sd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0)
-    msg (M_ERR, "UDP: Cannot create UDP/UDP6 socket");
+    if ((sd = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0)
+    {
+        msg(M_ERR, "UDP: Cannot create UDP/UDP6 socket");
+    }
 #if ENABLE_IP_PKTINFO
-  else if (flags & SF_USE_IP_PKTINFO)
+    else if (flags & SF_USE_IP_PKTINFO)
     {
-      int pad = 1;
-      if(addrinfo->ai_family == AF_INET)
+        int pad = 1;
+        if (addrinfo->ai_family == AF_INET)
         {
-#ifdef IP_PKTINFO
-          if (setsockopt (sd, SOL_IP, IP_PKTINFO,
-                          (void*)&pad, sizeof(pad)) < 0)
-            msg(M_ERR, "UDP: failed setsockopt for IP_PKTINFO");
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
+            if (setsockopt(sd, SOL_IP, IP_PKTINFO,
+                           (void *)&pad, sizeof(pad)) < 0)
+            {
+                msg(M_ERR, "UDP: failed setsockopt for IP_PKTINFO");
+            }
 #elif defined(IP_RECVDSTADDR)
-          if (setsockopt (sd, IPPROTO_IP, IP_RECVDSTADDR,
-                          (void*)&pad, sizeof(pad)) < 0)
-            msg(M_ERR, "UDP: failed setsockopt for IP_RECVDSTADDR");
-#else
+            if (setsockopt(sd, IPPROTO_IP, IP_RECVDSTADDR,
+                           (void *)&pad, sizeof(pad)) < 0)
+            {
+                msg(M_ERR, "UDP: failed setsockopt for IP_RECVDSTADDR");
+            }
+#else  /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */
 #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
 #endif
         }
-      else if (addrinfo->ai_family == AF_INET6 )
+        else if (addrinfo->ai_family == AF_INET6)
         {
 #ifndef IPV6_RECVPKTINFO /* Some older Darwin platforms require this */
-          if (setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO,
-                          (void*)&pad, sizeof(pad)) < 0)
+            if (setsockopt(sd, IPPROTO_IPV6, IPV6_PKTINFO,
+                           (void *)&pad, sizeof(pad)) < 0)
 #else
-          if (setsockopt (sd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
-                          (void*)&pad, sizeof(pad)) < 0)
+            if (setsockopt(sd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+                           (void *)&pad, sizeof(pad)) < 0)
 #endif
-            msg(M_ERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO");
+            { msg(M_ERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO");}
         }
     }
-#endif
-  return sd;
+#endif /* if ENABLE_IP_PKTINFO */
+
+    /* set socket file descriptor to not pass across execs, so that
+     * scripts don't have access to it */
+    set_cloexec(sd);
+
+    return sd;
 }
 
-static void bind_local (struct link_socket *sock, const sa_family_t ai_family)
+static void
+bind_local(struct link_socket *sock, const sa_family_t ai_family)
 {
     /* bind to local address/port */
     if (sock->bind_local)
-      {
+    {
         if (sock->socks_proxy && sock->info.proto == PROTO_UDP)
-            socket_bind (sock->ctrl_sd, sock->info.lsa->bind_local,
-                        ai_family, "SOCKS", false);
+        {
+            socket_bind(sock->ctrl_sd, sock->info.lsa->bind_local,
+                        ai_family, "SOCKS", false);
+        }
         else
-            socket_bind (sock->sd, sock->info.lsa->bind_local,
-                        ai_family,
-                         "TCP/UDP", sock->info.bind_ipv6_only);
-      }
+        {
+            socket_bind(sock->sd, sock->info.lsa->bind_local,
+                        ai_family,
+                        "TCP/UDP", sock->info.bind_ipv6_only);
+        }
+    }
 }
 
 static void
-create_socket (struct link_socket* sock, struct addrinfo* addr)
+create_socket(struct link_socket *sock, struct addrinfo *addr)
 {
-  if (addr->ai_protocol == IPPROTO_UDP || addr->ai_socktype == SOCK_DGRAM)
+    if (addr->ai_protocol == IPPROTO_UDP || addr->ai_socktype == SOCK_DGRAM)
     {
-      sock->sd = create_socket_udp (addr, sock->sockflags);
-      sock->sockflags |= SF_GETADDRINFO_DGRAM;
+        sock->sd = create_socket_udp(addr, sock->sockflags);
+        sock->sockflags |= SF_GETADDRINFO_DGRAM;
 
-      /* Assume that control socket and data socket to the socks proxy
-       * are using the same IP family */
-      if (sock->socks_proxy)
-       {
-         /* Construct a temporary addrinfo to create the socket,
-          * currently resolve two remote addresses is not supported,
-          * TODO: Rewrite the whole resolve_remote */
-         struct addrinfo addrinfo_tmp = *addr;
-         addrinfo_tmp.ai_socktype = SOCK_STREAM;
-         addrinfo_tmp.ai_protocol = IPPROTO_TCP;
-         sock->ctrl_sd = create_socket_tcp (&addrinfo_tmp);
-       }
+        /* Assume that control socket and data socket to the socks proxy
+         * are using the same IP family */
+        if (sock->socks_proxy)
+        {
+            /* Construct a temporary addrinfo to create the socket,
+             * currently resolve two remote addresses is not supported,
+             * TODO: Rewrite the whole resolve_remote */
+            struct addrinfo addrinfo_tmp = *addr;
+            addrinfo_tmp.ai_socktype = SOCK_STREAM;
+            addrinfo_tmp.ai_protocol = IPPROTO_TCP;
+            sock->ctrl_sd = create_socket_tcp(&addrinfo_tmp);
+        }
     }
-  else if (addr->ai_protocol == IPPROTO_TCP || addr->ai_socktype == SOCK_STREAM)
+    else if (addr->ai_protocol == IPPROTO_TCP || addr->ai_socktype == SOCK_STREAM)
     {
-      sock->sd = create_socket_tcp (addr);
+        sock->sd = create_socket_tcp(addr);
     }
-  else
+    else
     {
-      ASSERT (0);
+        ASSERT(0);
     }
+    /* Set af field of sock->info, so it always reflects the address family
+     * of the created socket */
+    sock->info.af = addr->ai_family;
+
     /* set socket buffers based on --sndbuf and --rcvbuf options */
-    socket_set_buffers (sock->sd, &sock->socket_buffer_sizes);
+    socket_set_buffers(sock->sd, &sock->socket_buffer_sizes);
 
     /* set socket to --mark packets with given value */
-    socket_set_mark (sock->sd, sock->mark);
+    socket_set_mark(sock->sd, sock->mark);
 
-    bind_local (sock, addr->ai_family);
+#if defined(TARGET_LINUX)
+    if (sock->bind_dev)
+    {
+        msg(M_INFO, "Using bind-dev %s", sock->bind_dev);
+        if (setsockopt(sock->sd, SOL_SOCKET, SO_BINDTODEVICE, sock->bind_dev, strlen(sock->bind_dev) + 1) != 0)
+        {
+            msg(M_WARN|M_ERRNO, "WARN: setsockopt SO_BINDTODEVICE=%s failed", sock->bind_dev);
+        }
+
+    }
+#endif
+
+    bind_local(sock, addr->ai_family);
 }
 
 #ifdef TARGET_ANDROID
-static void protect_fd_nonlocal (int fd, const struct sockaddr* addr)
+static void
+protect_fd_nonlocal(int fd, const struct sockaddr *addr)
 {
-  /* pass socket FD to management interface to pass on to VPNService API
-   * as "protected socket" (exempt from being routed into tunnel)
-   */
-  if (addr_local (addr)) {
-    msg(D_SOCKET_DEBUG, "Address is local, not protecting socket fd %d", fd);
-    return;
-  }
+    if (!management)
+    {
+        msg(M_FATAL, "Required management interface not available.");
+    }
 
-  msg(D_SOCKET_DEBUG, "Protecting socket fd %d", fd);
-  management->connection.fdtosend = fd;
-  management_android_control (management, "PROTECTFD", __func__);
+    /* pass socket FD to management interface to pass on to VPNService API
+     * as "protected socket" (exempt from being routed into tunnel)
+     */
+    if (addr_local(addr))
+    {
+        msg(D_SOCKET_DEBUG, "Address is local, not protecting socket fd %d", fd);
+        return;
+    }
+
+    msg(D_SOCKET_DEBUG, "Protecting socket fd %d", fd);
+    management->connection.fdtosend = fd;
+    management_android_control(management, "PROTECTFD", __func__);
 }
 #endif
 
@@ -891,1297 +1184,1370 @@ static void protect_fd_nonlocal (int fd, const struct sockaddr* addr)
  * Functions used for establishing a TCP stream connection.
  */
 static void
-socket_do_listen (socket_descriptor_t sd,
-                 const struct addrinfo *local,
-                 bool do_listen,
-                 bool do_set_nonblock)
-{
-  struct gc_arena gc = gc_new ();
-  if (do_listen)
-    {
-      ASSERT(local);
-      msg (M_INFO, "Listening for incoming TCP connection on %s", 
-          print_sockaddr (local->ai_addr, &gc));
-      if (listen (sd, 1))
-       msg (M_ERR, "TCP: listen() failed");
+socket_do_listen(socket_descriptor_t sd,
+                 const struct addrinfo *local,
+                 bool do_listen,
+                 bool do_set_nonblock)
+{
+    struct gc_arena gc = gc_new();
+    if (do_listen)
+    {
+        ASSERT(local);
+        msg(M_INFO, "Listening for incoming TCP connection on %s",
+            print_sockaddr(local->ai_addr, &gc));
+        if (listen(sd, 32))
+        {
+            msg(M_ERR, "TCP: listen() failed");
+        }
     }
 
-  /* set socket to non-blocking mode */
-  if (do_set_nonblock)
-    set_nonblock (sd);
+    /* set socket to non-blocking mode */
+    if (do_set_nonblock)
+    {
+        set_nonblock(sd);
+    }
 
-  gc_free (&gc);
+    gc_free(&gc);
 }
 
 socket_descriptor_t
-socket_do_accept (socket_descriptor_t sd,
-                 struct link_socket_actual *act,
-                 const bool nowait)
+socket_do_accept(socket_descriptor_t sd,
+                 struct link_socket_actual *act,
+                 const bool nowait)
 {
-  /* af_addr_size WILL return 0 in this case if AFs other than AF_INET
-   * are compiled because act is empty here.
-   * could use getsockname() to support later remote_len check
-   */
-  socklen_t remote_len_af = af_addr_size(act->dest.addr.sa.sa_family);
-  socklen_t remote_len = sizeof(act->dest.addr);
-  socket_descriptor_t new_sd = SOCKET_UNDEFINED;
+    /* af_addr_size WILL return 0 in this case if AFs other than AF_INET
+     * are compiled because act is empty here.
+     * could use getsockname() to support later remote_len check
+     */
+    socklen_t remote_len_af = af_addr_size(act->dest.addr.sa.sa_family);
+    socklen_t remote_len = sizeof(act->dest.addr);
+    socket_descriptor_t new_sd = SOCKET_UNDEFINED;
 
-  CLEAR (*act);
+    CLEAR(*act);
 
-#ifdef HAVE_GETPEERNAME
-  if (nowait)
+    if (nowait)
     {
-      new_sd = getpeername (sd, &act->dest.addr.sa, &remote_len);
+        new_sd = getpeername(sd, &act->dest.addr.sa, &remote_len);
 
-      if (!socket_defined (new_sd))
-       msg (D_LINK_ERRORS | M_ERRNO, "TCP: getpeername() failed");
-      else
-       new_sd = sd;
+        if (!socket_defined(new_sd))
+        {
+            msg(D_LINK_ERRORS | M_ERRNO, "TCP: getpeername() failed");
+        }
+        else
+        {
+            new_sd = sd;
+        }
     }
-#else
-  if (nowait)
-    msg (M_WARN, "TCP: this OS does not provide the getpeername() function");
-#endif
-  else
+    else
     {
-      new_sd = accept (sd, &act->dest.addr.sa, &remote_len);
+        new_sd = accept(sd, &act->dest.addr.sa, &remote_len);
     }
 
 #if 0 /* For debugging only, test the effect of accept() failures */
- {
-   static int foo = 0;
-   ++foo;
-   if (foo & 1)
-     new_sd = -1;
- }
+    {
+        static int foo = 0;
+        ++foo;
+        if (foo & 1)
+        {
+            new_sd = -1;
+        }
+    }
 #endif
 
-  if (!socket_defined (new_sd))
+    if (!socket_defined(new_sd))
     {
-      msg (D_LINK_ERRORS | M_ERRNO, "TCP: accept(%d) failed", sd);
+        msg(D_LINK_ERRORS | M_ERRNO, "TCP: accept(%d) failed", (int)sd);
     }
-  /* only valid if we have remote_len_af!=0 */
-  else if (remote_len_af && remote_len != remote_len_af)
+    /* only valid if we have remote_len_af!=0 */
+    else if (remote_len_af && remote_len != remote_len_af)
     {
-      msg (D_LINK_ERRORS, "TCP: Received strange incoming connection with unknown address length=%d", remote_len);
-      openvpn_close_socket (new_sd);
-      new_sd = SOCKET_UNDEFINED;
+        msg(D_LINK_ERRORS, "TCP: Received strange incoming connection with unknown address length=%d", remote_len);
+        openvpn_close_socket(new_sd);
+        new_sd = SOCKET_UNDEFINED;
     }
-  return new_sd;
+    else
+    {
+        /* set socket file descriptor to not pass across execs, so that
+         * scripts don't have access to it */
+        set_cloexec(sd);
+    }
+    return new_sd;
 }
 
 static void
-tcp_connection_established (const struct link_socket_actual *act)
+tcp_connection_established(const struct link_socket_actual *act)
 {
-  struct gc_arena gc = gc_new ();
-  msg (M_INFO, "TCP connection established with %s", 
-       print_link_socket_actual (act, &gc));
-  gc_free (&gc);
+    struct gc_arena gc = gc_new();
+    msg(M_INFO, "TCP connection established with %s",
+        print_link_socket_actual(act, &gc));
+    gc_free(&gc);
 }
 
-static int
-socket_listen_accept (socket_descriptor_t sd,
-                     struct link_socket_actual *act,
-                     const char *remote_dynamic,
-                     const struct addrinfo *local,
-                     bool do_listen,
-                     bool nowait,
-                     volatile int *signal_received)
-{
-  struct gc_arena gc = gc_new ();
-  /* struct openvpn_sockaddr *remote = &act->dest; */
-  struct openvpn_sockaddr remote_verify = act->dest;
-  int new_sd = SOCKET_UNDEFINED;
-
-  CLEAR (*act);
-  socket_do_listen (sd, local, do_listen, true);
-
-  while (true)
-    {
-      int status;
-      fd_set reads;
-      struct timeval tv;
-
-      FD_ZERO (&reads);
-      FD_SET (sd, &reads);
-      tv.tv_sec = 0;
-      tv.tv_usec = 0;
-
-      status = select (sd + 1, &reads, NULL, NULL, &tv);
-
-      get_signal (signal_received);
-      if (*signal_received)
-       {
-         gc_free (&gc);
-         return sd;
-       }
-
-      if (status < 0)
-       msg (D_LINK_ERRORS | M_ERRNO, "TCP: select() failed");
-
-      if (status <= 0)
-       {
-         openvpn_sleep (1);
-         continue;
-       }
-
-      new_sd = socket_do_accept (sd, act, nowait);
-
-      if (socket_defined (new_sd))
-       {
-          struct addrinfo* ai = NULL;
-          if(remote_dynamic)
-              openvpn_getaddrinfo(0, remote_dynamic, NULL, 1, NULL,
+static socket_descriptor_t
+socket_listen_accept(socket_descriptor_t sd,
+                     struct link_socket_actual *act,
+                     const char *remote_dynamic,
+                     const struct addrinfo *local,
+                     bool do_listen,
+                     bool nowait,
+                     volatile int *signal_received)
+{
+    struct gc_arena gc = gc_new();
+    /* struct openvpn_sockaddr *remote = &act->dest; */
+    struct openvpn_sockaddr remote_verify = act->dest;
+    socket_descriptor_t new_sd = SOCKET_UNDEFINED;
+
+    CLEAR(*act);
+    socket_do_listen(sd, local, do_listen, true);
+
+    while (true)
+    {
+        int status;
+        fd_set reads;
+        struct timeval tv;
+
+        FD_ZERO(&reads);
+        openvpn_fd_set(sd, &reads);
+        tv.tv_sec = 0;
+        tv.tv_usec = 0;
+
+        status = select(sd + 1, &reads, NULL, NULL, &tv);
+
+        get_signal(signal_received);
+        if (*signal_received)
+        {
+            gc_free(&gc);
+            return sd;
+        }
+
+        if (status < 0)
+        {
+            msg(D_LINK_ERRORS | M_ERRNO, "TCP: select() failed");
+        }
+
+        if (status <= 0)
+        {
+            management_sleep(1);
+            continue;
+        }
+
+        new_sd = socket_do_accept(sd, act, nowait);
+
+        if (socket_defined(new_sd))
+        {
+            struct addrinfo *ai = NULL;
+            if (remote_dynamic)
+            {
+                openvpn_getaddrinfo(0, remote_dynamic, NULL, 1, NULL,
                                     remote_verify.addr.sa.sa_family, &ai);
+            }
 
-          if(ai && !addrlist_match(&remote_verify, ai))
+            if (ai && !addrlist_match(&remote_verify, ai))
             {
-              msg (M_WARN,
-                   "TCP NOTE: Rejected connection attempt from %s due to --remote setting",
-                   print_link_socket_actual (act, &gc));
-              if (openvpn_close_socket (new_sd))
-                  msg (M_ERR, "TCP: close socket failed (new_sd)");
-              freeaddrinfo(ai);
+                msg(M_WARN,
+                    "TCP NOTE: Rejected connection attempt from %s due to --remote setting",
+                    print_link_socket_actual(act, &gc));
+                if (openvpn_close_socket(new_sd))
+                {
+                    msg(M_ERR, "TCP: close socket failed (new_sd)");
+                }
+                freeaddrinfo(ai);
             }
-         else
+            else
             {
-              if(ai)
-                  freeaddrinfo(ai);
-              break;
+                if (ai)
+                {
+                    freeaddrinfo(ai);
+                }
+                break;
             }
-       }
-      openvpn_sleep (1);
+        }
+        management_sleep(1);
     }
 
-  if (!nowait && openvpn_close_socket (sd))
-    msg (M_ERR, "TCP: close socket failed (sd)");
+    if (!nowait && openvpn_close_socket(sd))
+    {
+        msg(M_ERR, "TCP: close socket failed (sd)");
+    }
 
-  tcp_connection_established (act);
+    tcp_connection_established(act);
 
-  gc_free (&gc);
-  return new_sd;
+    gc_free(&gc);
+    return new_sd;
 }
 
-/* older mingw versions and WinXP do not have this define,
- * but Vista and up support the functionality - just define it here
- */
-#ifdef WIN32
-# ifndef IPV6_V6ONLY
-#  define IPV6_V6ONLY 27
-# endif
-#endif
 void
-socket_bind (socket_descriptor_t sd,
-             struct addrinfo *local,
-             int ai_family,
-            const char *prefix,
-             bool ipv6only)
+socket_bind(socket_descriptor_t sd,
+            struct addrinfo *local,
+            int ai_family,
+            const char *prefix,
+            bool ipv6only)
 {
-  struct gc_arena gc = gc_new ();
+    struct gc_arena gc = gc_new();
 
-  /* FIXME (schwabe)
-   * getaddrinfo for the bind address might return multiple AF_INET/AF_INET6
-   * entries for the requested protocol.
-   * For example if an address has multiple A records
-   * What is the correct way to deal with it?
-   */
+    /* FIXME (schwabe)
+     * getaddrinfo for the bind address might return multiple AF_INET/AF_INET6
+     * entries for the requested protocol.
+     * For example if an address has multiple A records
+     * What is the correct way to deal with it?
+     */
 
-  struct addrinfo* cur;
+    struct addrinfo *cur;
 
-  ASSERT(local);
+    ASSERT(local);
 
 
-  /* find the first addrinfo with correct ai_family */
-  for (cur = local; cur; cur=cur->ai_next)
+    /* find the first addrinfo with correct ai_family */
+    for (cur = local; cur; cur = cur->ai_next)
+    {
+        if (cur->ai_family == ai_family)
+        {
+            break;
+        }
+    }
+    if (!cur)
     {
-      if(cur->ai_family == ai_family)
-          break;
+        msg(M_FATAL, "%s: Socket bind failed: Addr to bind has no %s record",
+            prefix, addr_family_name(ai_family));
     }
-  if (!cur)
-      msg (M_FATAL, "%s: Socket bind failed: Addr to bind has no %s record",
-           prefix, addr_family_name(ai_family));
 
-  if (ai_family == AF_INET6)
+    if (ai_family == AF_INET6)
     {
-      int v6only = ipv6only ? 1: 0;    /* setsockopt must have an "int" */
+        int v6only = ipv6only ? 1 : 0;  /* setsockopt must have an "int" */
 
-      msg (M_INFO, "setsockopt(IPV6_V6ONLY=%d)", v6only);
-      if (setsockopt (sd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &v6only, sizeof(v6only)))
-       {
-         msg (M_NONFATAL|M_ERRNO, "Setting IPV6_V6ONLY=%d failed", v6only);
-       }
+        msg(M_INFO, "setsockopt(IPV6_V6ONLY=%d)", v6only);
+        if (setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &v6only, sizeof(v6only)))
+        {
+            msg(M_NONFATAL|M_ERRNO, "Setting IPV6_V6ONLY=%d failed", v6only);
+        }
     }
-  if (bind (sd, cur->ai_addr, cur->ai_addrlen))
+    if (bind(sd, cur->ai_addr, cur->ai_addrlen))
     {
-      const int errnum = openvpn_errno ();
-      msg (M_FATAL, "%s: Socket bind failed on local address %s: %s",
-          prefix,
-           print_sockaddr_ex (local->ai_addr, ":", PS_SHOW_PORT, &gc),
-           strerror_ts (errnum, &gc));
+        msg(M_FATAL | M_ERRNO, "%s: Socket bind failed on local address %s",
+            prefix,
+            print_sockaddr_ex(local->ai_addr, ":", PS_SHOW_PORT, &gc));
     }
-  gc_free (&gc);
+    gc_free(&gc);
 }
 
 int
-openvpn_connect (socket_descriptor_t sd,
-                const struct sockaddr *remote,
-                int connect_timeout,
-                volatile int *signal_received)
+openvpn_connect(socket_descriptor_t sd,
+                const struct sockaddr *remote,
+                int connect_timeout,
+                volatile int *signal_received)
 {
-  int status = 0;
+    int status = 0;
 
 #ifdef TARGET_ANDROID
-  protect_fd_nonlocal(sd, remote);
+    protect_fd_nonlocal(sd, remote);
 #endif
 
-#ifdef CONNECT_NONBLOCK
-  set_nonblock (sd);
-  status = connect (sd, remote, af_addr_size(remote->sa_family));
-  if (status)
-    status = openvpn_errno ();
-  if (
-#ifdef WIN32
-    status == WSAEWOULDBLOCK
+    set_nonblock(sd);
+    status = connect(sd, remote, af_addr_size(remote->sa_family));
+    if (status)
+    {
+        status = openvpn_errno();
+    }
+    if (
+#ifdef _WIN32
+        status == WSAEWOULDBLOCK
 #else
-    status == EINPROGRESS
+        status == EINPROGRESS
 #endif
-  )
-    {
-      while (true)
-       {
-         fd_set writes;
-         struct timeval tv;
-
-         FD_ZERO (&writes);
-         FD_SET (sd, &writes);
-         tv.tv_sec = 0;
-         tv.tv_usec = 0;
-
-         status = select (sd + 1, NULL, &writes, NULL, &tv);
-
-         if (signal_received)
-           {
-             get_signal (signal_received);
-             if (*signal_received)
-               {
-                 status = 0;
-                 break;
-               }
-           }
-         if (status < 0)
-           {
-             status = openvpn_errno ();
-             break;
-           }
-         if (status <= 0)
-           {
-             if (--connect_timeout < 0)
-               {
-                 status = ETIMEDOUT;
-                 break;
-               }
-             openvpn_sleep (1);
-             continue;
-           }
-
-         /* got it */
-         {
-           int val = 0;
-           socklen_t len;
-
-           len = sizeof (val);
-           if (getsockopt (sd, SOL_SOCKET, SO_ERROR, (void *) &val, &len) == 0
-               && len == sizeof (val))
-             status = val;
-           else
-             status = openvpn_errno ();
-           break;
-         }
-       }
-    }
+        )
+    {
+        while (true)
+        {
+#if POLL
+            struct pollfd fds[1];
+            fds[0].fd = sd;
+            fds[0].events = POLLOUT;
+            status = poll(fds, 1, (connect_timeout > 0) ? 1000 : 0);
 #else
-  status = connect (sd, remote, af_addr_size(remote->sa_family));
-  if (status)
-    status = openvpn_errno ();
+            fd_set writes;
+            struct timeval tv;
+
+            FD_ZERO(&writes);
+            openvpn_fd_set(sd, &writes);
+            tv.tv_sec = (connect_timeout > 0) ? 1 : 0;
+            tv.tv_usec = 0;
+
+            status = select(sd + 1, NULL, &writes, NULL, &tv);
 #endif
+            if (signal_received)
+            {
+                get_signal(signal_received);
+                if (*signal_received)
+                {
+                    status = 0;
+                    break;
+                }
+            }
+            if (status < 0)
+            {
+                status = openvpn_errno();
+                break;
+            }
+            if (status <= 0)
+            {
+                if (--connect_timeout < 0)
+                {
+#ifdef _WIN32
+                    status = WSAETIMEDOUT;
+#else
+                    status = ETIMEDOUT;
+#endif
+                    break;
+                }
+                management_sleep(0);
+                continue;
+            }
+
+            /* got it */
+            {
+                int val = 0;
+                socklen_t len;
+
+                len = sizeof(val);
+                if (getsockopt(sd, SOL_SOCKET, SO_ERROR, (void *) &val, &len) == 0
+                    && len == sizeof(val))
+                {
+                    status = val;
+                }
+                else
+                {
+                    status = openvpn_errno();
+                }
+                break;
+            }
+        }
+    }
 
-  return status;
+    return status;
 }
 
-void set_actual_address (struct link_socket_actual* actual, struct addrinfo* ai)
+void
+set_actual_address(struct link_socket_actual *actual, struct addrinfo *ai)
 {
-    CLEAR (*actual);
-    ASSERT (ai);
+    CLEAR(*actual);
+    ASSERT(ai);
 
     if (ai->ai_family == AF_INET)
+    {
         actual->dest.addr.in4 =
-        *((struct sockaddr_in*) ai->ai_addr);
+            *((struct sockaddr_in *) ai->ai_addr);
+    }
     else if (ai->ai_family == AF_INET6)
+    {
         actual->dest.addr.in6 =
-        *((struct sockaddr_in6*) ai->ai_addr);
+            *((struct sockaddr_in6 *) ai->ai_addr);
+    }
     else
+    {
         ASSERT(0);
+    }
 
 }
 
-void
-socket_connect (socket_descriptor_t* sd,
-                const struct sockaddr* dest,
-                const int connect_timeout,
-                struct signal_info* sig_info)
+static void
+socket_connect(socket_descriptor_t *sd,
+               const struct sockaddr *dest,
+               const int connect_timeout,
+               struct signal_info *sig_info)
 {
-  struct gc_arena gc = gc_new ();
-  int status;
+    struct gc_arena gc = gc_new();
+    int status;
 
-#ifdef CONNECT_NONBLOCK
-  msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]",
-       print_sockaddr (dest, &gc));
-#else
-  msg (M_INFO, "Attempting to establish TCP connection with %s",
-       print_sockaddr (dest, &gc));
-#endif
+    msg(M_INFO, "Attempting to establish TCP connection with %s",
+        print_sockaddr(dest, &gc));
 
 #ifdef ENABLE_MANAGEMENT
-  if (management)
-       management_set_state (management,
-                             OPENVPN_STATE_TCP_CONNECT,
-                             NULL,
-                              NULL,
-                              NULL,
-                              NULL,
-                              NULL);
+    if (management)
+    {
+        management_set_state(management,
+                             OPENVPN_STATE_TCP_CONNECT,
+                             NULL,
+                             NULL,
+                             NULL,
+                             NULL,
+                             NULL);
+    }
 #endif
 
-  /* Set the actual address */
-  status = openvpn_connect (*sd, dest, connect_timeout, &sig_info->signal_received);
+    /* Set the actual address */
+    status = openvpn_connect(*sd, dest, connect_timeout, &sig_info->signal_received);
 
-  get_signal (&sig_info->signal_received);
-  if (sig_info->signal_received)
-       goto done;
+    get_signal(&sig_info->signal_received);
+    if (sig_info->signal_received)
+    {
+        goto done;
+    }
 
-  if (status) {
+    if (status)
+    {
 
-    msg (D_LINK_ERRORS,
-         "TCP: connect to %s failed: %s",
-         print_sockaddr (dest, &gc),
-         strerror_ts (status, &gc));
+        msg(D_LINK_ERRORS, "TCP: connect to %s failed: %s",
+            print_sockaddr(dest, &gc), strerror(status));
 
-    openvpn_close_socket (*sd);
-    *sd = SOCKET_UNDEFINED;
-    sig_info->signal_received = SIGUSR1;
-    sig_info->source = SIG_SOURCE_CONNECTION_FAILED;
-  } else {
-      msg (M_INFO, "TCP connection established with %s",
-        print_sockaddr (dest, &gc));
-  }
+        openvpn_close_socket(*sd);
+        *sd = SOCKET_UNDEFINED;
+        register_signal(sig_info, SIGUSR1, "connection-failed");
+    }
+    else
+    {
+        msg(M_INFO, "TCP connection established with %s",
+            print_sockaddr(dest, &gc));
+    }
 
- done:
-  gc_free (&gc);
+done:
+    gc_free(&gc);
 }
 
+/*
+ * Stream buffer handling prototypes -- stream_buf is a helper class
+ * to assist in the packetization of stream transport protocols
+ * such as TCP.
+ */
+
+static void
+stream_buf_init(struct stream_buf *sb, struct buffer *buf,
+                const unsigned int sockflags, const int proto);
+
+static void
+stream_buf_close(struct stream_buf *sb);
+
+static bool
+stream_buf_added(struct stream_buf *sb, int length_added);
+
 /* For stream protocols, allocate a buffer to build up packet.
  Called after frame has been finalized. */
* Called after frame has been finalized. */
 
 static void
-socket_frame_init (const struct frame *frame, struct link_socket *sock)
+socket_frame_init(const struct frame *frame, struct link_socket *sock)
 {
-#ifdef WIN32
-  overlapped_io_init (&sock->reads, frame, FALSE, false);
-  overlapped_io_init (&sock->writes, frame, TRUE, false);
-  sock->rw_handle.read = sock->reads.overlapped.hEvent;
-  sock->rw_handle.write = sock->writes.overlapped.hEvent;
+#ifdef _WIN32
+    overlapped_io_init(&sock->reads, frame, FALSE);
+    overlapped_io_init(&sock->writes, frame, TRUE);
+    sock->rw_handle.read = sock->reads.overlapped.hEvent;
+    sock->rw_handle.write = sock->writes.overlapped.hEvent;
 #endif
 
-  if (link_socket_connection_oriented (sock))
+    if (link_socket_connection_oriented(sock))
     {
-#ifdef WIN32
-      stream_buf_init (&sock->stream_buf,
-                      &sock->reads.buf_init,
-                      sock->sockflags,
-                      sock->info.proto);
+#ifdef _WIN32
+        stream_buf_init(&sock->stream_buf,
+                        &sock->reads.buf_init,
+                        sock->sockflags,
+                        sock->info.proto);
 #else
-      alloc_buf_sock_tun (&sock->stream_buf_data,
-                         frame,
-                         false,
-                         FRAME_HEADROOM_MARKER_READ_STREAM);
-
-      stream_buf_init (&sock->stream_buf,
-                      &sock->stream_buf_data,
-                      sock->sockflags,
-                      sock->info.proto);
+        alloc_buf_sock_tun(&sock->stream_buf_data, frame);
+
+        stream_buf_init(&sock->stream_buf,
+                        &sock->stream_buf_data,
+                        sock->sockflags,
+                        sock->info.proto);
 #endif
     }
 }
 
-/*
- * Adjust frame structure based on a Path MTU value given
- * to us by the OS.
- */
-void
-frame_adjust_path_mtu (struct frame *frame, int pmtu, int proto)
+static void
+resolve_bind_local(struct link_socket *sock, const sa_family_t af)
 {
-  frame_set_mtu_dynamic (frame, pmtu - datagram_overhead (proto), SET_MTU_UPPER_BOUND);
+    struct gc_arena gc = gc_new();
+
+    /* resolve local address if undefined */
+    if (!sock->info.lsa->bind_local)
+    {
+        int flags = GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL
+                    |GETADDR_FATAL | GETADDR_PASSIVE;
+        int status;
+
+        if (proto_is_dgram(sock->info.proto))
+        {
+            flags |= GETADDR_DATAGRAM;
+        }
+
+        /* will return AF_{INET|INET6}from local_host */
+        status = get_cached_dns_entry(sock->dns_cache,
+                                      sock->local_host,
+                                      sock->local_port,
+                                      af,
+                                      flags,
+                                      &sock->info.lsa->bind_local);
+
+        if (status)
+        {
+            status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0,
+                                         NULL, af, &sock->info.lsa->bind_local);
+        }
+
+        if (status !=0)
+        {
+            msg(M_FATAL, "getaddrinfo() failed for local \"%s:%s\": %s",
+                sock->local_host, sock->local_port,
+                gai_strerror(status));
+        }
+    }
+
+    gc_free(&gc);
 }
 
 static void
-resolve_bind_local (struct link_socket *sock, const sa_family_t af)
+resolve_remote(struct link_socket *sock,
+               int phase,
+               const char **remote_dynamic,
+               struct signal_info *sig_info)
 {
-  struct gc_arena gc = gc_new ();
+    volatile int *signal_received = sig_info ? &sig_info->signal_received : NULL;
+    struct gc_arena gc = gc_new();
 
-  /* resolve local address if undefined */
-  if (!sock->info.lsa->bind_local)
+    /* resolve remote address if undefined */
+    if (!sock->info.lsa->remote_list)
     {
-      int flags = GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL |
-       GETADDR_FATAL | GETADDR_PASSIVE;
-      int status;
+        if (sock->remote_host)
+        {
+            unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags);
+            int retry = 0;
+            int status = -1;
+            struct addrinfo *ai;
+            if (proto_is_dgram(sock->info.proto))
+            {
+                flags |= GETADDR_DATAGRAM;
+            }
 
-      if(proto_is_dgram(sock->info.proto))
-       flags |= GETADDR_DATAGRAM;
+            if (sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE)
+            {
+                if (phase == 2)
+                {
+                    flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL);
+                }
+                retry = 0;
+            }
+            else if (phase == 1)
+            {
+                if (sock->resolve_retry_seconds)
+                {
+                    retry = 0;
+                }
+                else
+                {
+                    flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY);
+                    retry = 0;
+                }
+            }
+            else if (phase == 2)
+            {
+                if (sock->resolve_retry_seconds)
+                {
+                    flags |= GETADDR_FATAL;
+                    retry = sock->resolve_retry_seconds;
+                }
+                else
+                {
+                    ASSERT(0);
+                }
+            }
+            else
+            {
+                ASSERT(0);
+            }
 
-      /* will return AF_{INET|INET6}from local_host */
-      status = get_cached_dns_entry (sock->dns_cache,
-                                    sock->local_host,
-                                    sock->local_port,
-                                    af,
-                                    flags,
-                                    &sock->info.lsa->bind_local);
 
-      if (status)
-       status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0,
-                                  NULL, af, &sock->info.lsa->bind_local);
+            status = get_cached_dns_entry(sock->dns_cache,
+                                          sock->remote_host,
+                                          sock->remote_port,
+                                          sock->info.af,
+                                          flags, &ai);
+            if (status)
+            {
+                status = openvpn_getaddrinfo(flags, sock->remote_host, sock->remote_port,
+                                             retry, sig_info, sock->info.af, &ai);
+            }
 
-      if(status !=0) {
-       msg (M_FATAL, "getaddrinfo() failed for local \"%s:%s\": %s",
-            sock->local_host, sock->local_port,
-            gai_strerror(status));
-      }
+            if (status == 0)
+            {
+                sock->info.lsa->remote_list = ai;
+                sock->info.lsa->current_remote = ai;
+
+                dmsg(D_SOCKET_DEBUG,
+                     "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d",
+                     flags,
+                     phase,
+                     retry,
+                     signal_received ? *signal_received : -1,
+                     status);
+            }
+            if (signal_received && *signal_received)
+            {
+                goto done;
+            }
+            if (status!=0)
+            {
+                if (signal_received)
+                {
+                    /* potential overwrite of signal */
+                    register_signal(sig_info, SIGUSR1, "socks-resolve-failure");
+                }
+                goto done;
+            }
+        }
     }
 
-  gc_free (&gc);
-}
+    /* should we re-use previous active remote address? */
+    if (link_socket_actual_defined(&sock->info.lsa->actual))
+    {
+        msg(M_INFO, "TCP/UDP: Preserving recently used remote address: %s",
+            print_link_socket_actual(&sock->info.lsa->actual, &gc));
+        if (remote_dynamic)
+        {
+            *remote_dynamic = NULL;
+        }
+    }
+    else
+    {
+        CLEAR(sock->info.lsa->actual);
+        if (sock->info.lsa->current_remote)
+        {
+            set_actual_address(&sock->info.lsa->actual,
+                               sock->info.lsa->current_remote);
+        }
+    }
 
-static void
-resolve_remote (struct link_socket *sock,
-               int phase,
-               const char **remote_dynamic,
-               volatile int *signal_received)
-{
-  struct gc_arena gc = gc_new ();
-
-  /* resolve remote address if undefined */
-  if (!sock->info.lsa->remote_list)
-    {
-      if (sock->remote_host)
-       {
-         unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags);
-         int retry = 0;
-         int status = -1;
-         struct addrinfo* ai;
-         if (proto_is_dgram(sock->info.proto))
-           flags |= GETADDR_DATAGRAM;
-
-         if (sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE)
-           {
-             if (phase == 2)
-               flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL);
-             retry = 0;
-           }
-         else if (phase == 1)
-           {
-             if (sock->resolve_retry_seconds)
-               {
-                 retry = 0;
-               }
-             else
-               {
-                 flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY);
-                 retry = 0;
-               }
-           }
-         else if (phase == 2)
-           {
-             if (sock->resolve_retry_seconds)
-               {
-                 flags |= GETADDR_FATAL;
-                 retry = sock->resolve_retry_seconds;
-               }
-             else
-               {
-                 ASSERT (0);
-               }
-           }
-         else
-           {
-             ASSERT (0);
-           }
-
-
-         status = get_cached_dns_entry (sock->dns_cache,
-                                        sock->remote_host,
-                                        sock->remote_port,
-                                        sock->info.af,
-                                        flags, &ai);
-         if (status)
-           status = openvpn_getaddrinfo (flags, sock->remote_host, sock->remote_port,
-                                         retry, signal_received, sock->info.af, &ai);
-
-         if(status == 0) {
-           sock->info.lsa->remote_list = ai;
-           sock->info.lsa->current_remote = ai;
-
-           dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d",
-                 flags,
-                 phase,
-                 retry,
-                 signal_received ? *signal_received : -1,
-                 status);
-         }
-         if (signal_received)
-           {
-             if (*signal_received)
-               goto done;
-           }
-             if (status!=0)
-               {
-                 if (signal_received)
-                   *signal_received = SIGUSR1;
-                 goto done;
-               }
-       }
-    }
-  
-  /* should we re-use previous active remote address? */
-  if (link_socket_actual_defined (&sock->info.lsa->actual))
-    {
-      msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s",
-          print_link_socket_actual (&sock->info.lsa->actual, &gc));
-      if (remote_dynamic)
-       *remote_dynamic = NULL;
-    }
-  else
-    {
-      CLEAR (sock->info.lsa->actual);
-      if(sock->info.lsa->current_remote)
-       {
-         set_actual_address (&sock->info.lsa->actual,
-                             sock->info.lsa->current_remote);
-       }
-    }
-
- done:
-  gc_free (&gc);
+done:
+    gc_free(&gc);
 }
 
 
 
 struct link_socket *
-link_socket_new (void)
+link_socket_new(void)
 {
-  struct link_socket *sock;
+    struct link_socket *sock;
 
-  ALLOC_OBJ_CLEAR (sock, struct link_socket);
-  sock->sd = SOCKET_UNDEFINED;
-  sock->ctrl_sd = SOCKET_UNDEFINED;
-  return sock;
+    ALLOC_OBJ_CLEAR(sock, struct link_socket);
+    sock->sd = SOCKET_UNDEFINED;
+    sock->ctrl_sd = SOCKET_UNDEFINED;
+    return sock;
 }
 
 void
-link_socket_init_phase1 (struct link_socket *sock,
-                        const char *local_host,
-                        const char *local_port,
-                        const char *remote_host,
-                        const char *remote_port,
-                        struct cached_dns_entry *dns_cache,
-                        int proto,
-                        sa_family_t af,
-                        bool bind_ipv6_only,
-                        int mode,
-                        const struct link_socket *accept_from,
-                        struct http_proxy_info *http_proxy,
-                        struct socks_proxy_info *socks_proxy,
-#ifdef ENABLE_DEBUG
-                        int gremlin,
-#endif
-                        bool bind_local,
-                        bool remote_float,
-                        int inetd,
-                        struct link_socket_addr *lsa,
-                        const char *ipchange_command,
-                        const struct plugin_list *plugins,
-                        int resolve_retry_seconds,
-                        int connect_timeout,
-                        int mtu_discover_type,
-                        int rcvbuf,
-                        int sndbuf,
-                        int mark,
-                        unsigned int sockflags)
-{
-  ASSERT (sock);
-
-  sock->local_host = local_host;
-  sock->local_port = local_port;
-  sock->remote_host = remote_host;
-  sock->remote_port = remote_port;
-  sock->dns_cache = dns_cache;
-  sock->http_proxy = http_proxy;
-  sock->socks_proxy = socks_proxy;
-  sock->bind_local = bind_local;
-  sock->inetd = inetd;
-  sock->resolve_retry_seconds = resolve_retry_seconds;
-  sock->connect_timeout = connect_timeout;
-  sock->mtu_discover_type = mtu_discover_type;
+link_socket_init_phase1(struct context *c, int mode)
+{
+    struct link_socket *sock = c->c2.link_socket;
+    struct options *o = &c->options;
+    ASSERT(sock);
+
+    const char *remote_host = o->ce.remote;
+    const char *remote_port = o->ce.remote_port;
+
+    sock->local_host = o->ce.local;
+    sock->local_port = o->ce.local_port;
+    sock->remote_host = remote_host;
+    sock->remote_port = remote_port;
+    sock->dns_cache = c->c1.dns_cache;
+    sock->http_proxy = c->c1.http_proxy;
+    sock->socks_proxy = c->c1.socks_proxy;
+    sock->bind_local = o->ce.bind_local;
+    sock->resolve_retry_seconds = o->resolve_retry_seconds;
+    sock->mtu_discover_type = o->ce.mtu_discover_type;
 
 #ifdef ENABLE_DEBUG
-  sock->gremlin = gremlin;
+    sock->gremlin = o->gremlin;
 #endif
 
-  sock->socket_buffer_sizes.rcvbuf = rcvbuf;
-  sock->socket_buffer_sizes.sndbuf = sndbuf;
+    sock->socket_buffer_sizes.rcvbuf = o->rcvbuf;
+    sock->socket_buffer_sizes.sndbuf = o->sndbuf;
 
-  sock->sockflags = sockflags;
-  sock->mark = mark;
+    sock->sockflags = o->sockflags;
+#if PORT_SHARE
+    if (o->port_share_host && o->port_share_port)
+    {
+        sock->sockflags |= SF_PORT_SHARE;
+    }
+#endif
+    sock->mark = o->mark;
+    sock->bind_dev = o->bind_dev;
 
-  sock->info.proto = proto;
-  sock->info.af = af;
-  sock->info.remote_float = remote_float;
-  sock->info.lsa = lsa;
-  sock->info.bind_ipv6_only = bind_ipv6_only;
-  sock->info.ipchange_command = ipchange_command;
-  sock->info.plugins = plugins;
+    sock->info.proto = o->ce.proto;
+    sock->info.af = o->ce.af;
+    sock->info.remote_float = o->ce.remote_float;
+    sock->info.lsa = &c->c1.link_socket_addr;
+    sock->info.bind_ipv6_only = o->ce.bind_ipv6_only;
+    sock->info.ipchange_command = o->ipchange;
+    sock->info.plugins = c->plugins;
+    sock->server_poll_timeout = &c->c2.server_poll_interval;
 
-  sock->mode = mode;
-  if (mode == LS_MODE_TCP_ACCEPT_FROM)
+    sock->mode = mode;
+    if (mode == LS_MODE_TCP_ACCEPT_FROM)
     {
-      ASSERT (accept_from);
-      ASSERT (sock->info.proto == PROTO_TCP_SERVER);
-      ASSERT (!sock->inetd);
-      sock->sd = accept_from->sd;
+        ASSERT(c->c2.accept_from);
+        ASSERT(sock->info.proto == PROTO_TCP_SERVER);
+        sock->sd = c->c2.accept_from->sd;
+        /* inherit (possibly guessed) info AF from parent context */
+        sock->info.af = c->c2.accept_from->info.af;
     }
 
-  /* are we running in HTTP proxy mode? */
-  if (sock->http_proxy)
+    /* are we running in HTTP proxy mode? */
+    if (sock->http_proxy)
     {
-      ASSERT (sock->info.proto == PROTO_TCP_CLIENT);
-      ASSERT (!sock->inetd);
+        ASSERT(sock->info.proto == PROTO_TCP_CLIENT);
 
-      /* the proxy server */
-      sock->remote_host = http_proxy->options.server;
-      sock->remote_port = http_proxy->options.port;
+        /* the proxy server */
+        sock->remote_host = c->c1.http_proxy->options.server;
+        sock->remote_port = c->c1.http_proxy->options.port;
 
-      /* the OpenVPN server we will use the proxy to connect to */
-      sock->proxy_dest_host = remote_host;
-      sock->proxy_dest_port = remote_port;
+        /* the OpenVPN server we will use the proxy to connect to */
+        sock->proxy_dest_host = remote_host;
+        sock->proxy_dest_port = remote_port;
     }
-  /* or in Socks proxy mode? */
-  else if (sock->socks_proxy)
+    /* or in Socks proxy mode? */
+    else if (sock->socks_proxy)
     {
-      ASSERT (!sock->inetd);
-
-      /* the proxy server */
-      sock->remote_host = socks_proxy->server;
-      sock->remote_port = socks_proxy->port;
+        /* the proxy server */
+        sock->remote_host = c->c1.socks_proxy->server;
+        sock->remote_port = c->c1.socks_proxy->port;
 
-      /* the OpenVPN server we will use the proxy to connect to */
-      sock->proxy_dest_host = remote_host;
-      sock->proxy_dest_port = remote_port;
+        /* the OpenVPN server we will use the proxy to connect to */
+        sock->proxy_dest_host = remote_host;
+        sock->proxy_dest_port = remote_port;
     }
-  else
+    else
     {
-      sock->remote_host = remote_host;
-      sock->remote_port = remote_port;
+        sock->remote_host = remote_host;
+        sock->remote_port = remote_port;
     }
 
-  /* bind behavior for TCP server vs. client */
-  if (sock->info.proto == PROTO_TCP_SERVER)
+    /* bind behavior for TCP server vs. client */
+    if (sock->info.proto == PROTO_TCP_SERVER)
     {
-      if (sock->mode == LS_MODE_TCP_ACCEPT_FROM)
-       sock->bind_local = false;
-      else
-       sock->bind_local = true;
+        if (sock->mode == LS_MODE_TCP_ACCEPT_FROM)
+        {
+            sock->bind_local = false;
+        }
+        else
+        {
+            sock->bind_local = true;
+        }
     }
 
-  /* were we started by inetd or xinetd? */
-  if (sock->inetd)
+    if (mode != LS_MODE_TCP_ACCEPT_FROM)
+    {
+        if (sock->bind_local)
+        {
+            resolve_bind_local(sock, sock->info.af);
+        }
+        resolve_remote(sock, 1, NULL, NULL);
+    }
+}
+
+static void
+phase2_set_socket_flags(struct link_socket *sock)
+{
+    /* set misc socket parameters */
+    socket_set_flags(sock->sd, sock->sockflags);
+
+    /* set socket to non-blocking mode */
+    set_nonblock(sock->sd);
+
+    /* set Path MTU discovery options on the socket */
+    set_mtu_discover_type(sock->sd, sock->mtu_discover_type, sock->info.af);
+
+#if EXTENDED_SOCKET_ERROR_CAPABILITY
+    /* if the OS supports it, enable extended error passing on the socket */
+    set_sock_extended_error_passing(sock->sd, sock->info.af);
+#endif
+}
+
+
+static void
+linksock_print_addr(struct link_socket *sock)
+{
+    struct gc_arena gc = gc_new();
+    const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO;
+
+    /* print local address */
+    if (sock->bind_local)
     {
-      ASSERT (sock->info.proto != PROTO_TCP_CLIENT);
-      ASSERT (socket_defined (inetd_socket_descriptor));
-      sock->sd = inetd_socket_descriptor;
+        sa_family_t ai_family = sock->info.lsa->actual.dest.addr.sa.sa_family;
+        /* Socket is always bound on the first matching address,
+         * For bound sockets with no remote addr this is the element of
+         * the list */
+        struct addrinfo *cur;
+        for (cur = sock->info.lsa->bind_local; cur; cur = cur->ai_next)
+        {
+            if (!ai_family || ai_family == cur->ai_family)
+            {
+                break;
+            }
+        }
+        ASSERT(cur);
+        msg(msglevel, "%s link local (bound): %s",
+            proto2ascii(sock->info.proto, sock->info.af, true),
+            print_sockaddr(cur->ai_addr, &gc));
     }
-  else if (mode != LS_MODE_TCP_ACCEPT_FROM)
+    else
     {
-      if (sock->bind_local) {
-         resolve_bind_local (sock, sock->info.af);
-      }
-      resolve_remote (sock, 1, NULL, NULL);
+        msg(msglevel, "%s link local: (not bound)",
+            proto2ascii(sock->info.proto, sock->info.af, true));
+    }
+
+    /* print active remote address */
+    msg(msglevel, "%s link remote: %s",
+        proto2ascii(sock->info.proto, sock->info.af, true),
+        print_link_socket_actual_ex(&sock->info.lsa->actual,
+                                    ":",
+                                    PS_SHOW_PORT_IF_DEFINED,
+                                    &gc));
+    gc_free(&gc);
+}
+
+static void
+phase2_tcp_server(struct link_socket *sock, const char *remote_dynamic,
+                  struct signal_info *sig_info)
+{
+    volatile int *signal_received = sig_info ? &sig_info->signal_received : NULL;
+    switch (sock->mode)
+    {
+        case LS_MODE_DEFAULT:
+            sock->sd = socket_listen_accept(sock->sd,
+                                            &sock->info.lsa->actual,
+                                            remote_dynamic,
+                                            sock->info.lsa->bind_local,
+                                            true,
+                                            false,
+                                            signal_received);
+            break;
+
+        case LS_MODE_TCP_LISTEN:
+            socket_do_listen(sock->sd,
+                             sock->info.lsa->bind_local,
+                             true,
+                             false);
+            break;
+
+        case LS_MODE_TCP_ACCEPT_FROM:
+            sock->sd = socket_do_accept(sock->sd,
+                                        &sock->info.lsa->actual,
+                                        false);
+            if (!socket_defined(sock->sd))
+            {
+                register_signal(sig_info, SIGTERM, "socket-undefiled");
+                return;
+            }
+            tcp_connection_established(&sock->info.lsa->actual);
+            break;
+
+        default:
+            ASSERT(0);
     }
 }
 
-static
-void phase2_inetd (struct link_socket* sock, const struct frame *frame,
-                  const char *remote_dynamic, volatile int *signal_received)
+
+static void
+phase2_tcp_client(struct link_socket *sock, struct signal_info *sig_info)
+{
+    bool proxy_retry = false;
+    do
+    {
+        socket_connect(&sock->sd,
+                       sock->info.lsa->current_remote->ai_addr,
+                       get_server_poll_remaining_time(sock->server_poll_timeout),
+                       sig_info);
+
+        if (sig_info->signal_received)
+        {
+            return;
+        }
+
+        if (sock->http_proxy)
+        {
+            proxy_retry = establish_http_proxy_passthru(sock->http_proxy,
+                                                        sock->sd,
+                                                        sock->proxy_dest_host,
+                                                        sock->proxy_dest_port,
+                                                        sock->server_poll_timeout,
+                                                        &sock->stream_buf.residual,
+                                                        sig_info);
+        }
+        else if (sock->socks_proxy)
+        {
+            establish_socks_proxy_passthru(sock->socks_proxy,
+                                           sock->sd,
+                                           sock->proxy_dest_host,
+                                           sock->proxy_dest_port,
+                                           sig_info);
+        }
+        if (proxy_retry)
+        {
+            openvpn_close_socket(sock->sd);
+            sock->sd = create_socket_tcp(sock->info.lsa->current_remote);
+        }
+
+    } while (proxy_retry);
+
+}
+
+static void
+phase2_socks_client(struct link_socket *sock, struct signal_info *sig_info)
 {
-  bool remote_changed = false;
+    socket_connect(&sock->ctrl_sd,
+                   sock->info.lsa->current_remote->ai_addr,
+                   get_server_poll_remaining_time(sock->server_poll_timeout),
+                   sig_info);
 
-  if (sock->info.proto == PROTO_TCP_SERVER) {
-    /* AF_INET as default (and fallback) for inetd */
-    sock->info.lsa->actual.dest.addr.sa.sa_family = AF_INET;
-#ifdef HAVE_GETSOCKNAME
+    if (sig_info->signal_received)
     {
-      /* inetd: hint family type for dest = local's */
-      struct openvpn_sockaddr local_addr;
-      socklen_t addrlen = sizeof(local_addr);
-      if (getsockname (sock->sd, &local_addr.addr.sa, &addrlen) == 0) {
-       sock->info.lsa->actual.dest.addr.sa.sa_family = local_addr.addr.sa.sa_family;
-       dmsg (D_SOCKET_DEBUG, "inetd(%s): using sa_family=%d from getsockname(%d)",
-             proto2ascii(sock->info.proto, sock->info.af, false),
-             local_addr.addr.sa.sa_family, sock->sd);
-      } else
-       msg (M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET",
-            proto2ascii(sock->info.proto, sock->info.af, false), sock->sd);
+        return;
+    }
+
+    establish_socks_proxy_udpassoc(sock->socks_proxy,
+                                   sock->ctrl_sd,
+                                   sock->sd,
+                                   &sock->socks_relay.dest,
+                                   sig_info);
+
+    if (sig_info->signal_received)
+    {
+        return;
+    }
+
+    sock->remote_host = sock->proxy_dest_host;
+    sock->remote_port = sock->proxy_dest_port;
+
+    addr_zero_host(&sock->info.lsa->actual.dest);
+    if (sock->info.lsa->remote_list)
+    {
+        freeaddrinfo(sock->info.lsa->remote_list);
+        sock->info.lsa->current_remote = NULL;
+        sock->info.lsa->remote_list = NULL;
     }
-#else
-    msg (M_WARN, "inetd(%s): this OS does not provide the getsockname() "
-        "function, using AF_INET",
-        proto2ascii(sock->info.proto, false));
-#endif
-    sock->sd =
-      socket_listen_accept (sock->sd,
-                           &sock->info.lsa->actual,
-                           remote_dynamic,
-                           sock->info.lsa->bind_local,
-                           false,
-                           sock->inetd == INETD_NOWAIT,
-                           signal_received);
 
-  }
-  ASSERT (!remote_changed);
+    resolve_remote(sock, 1, NULL, sig_info);
 }
 
+#if defined(_WIN32)
 static void
-phase2_set_socket_flags (struct link_socket* sock)
+create_socket_dco_win(struct context *c, struct link_socket *sock,
+                      struct signal_info *sig_info)
 {
-  /* set misc socket parameters */
-  socket_set_flags (sock->sd, sock->sockflags);
+    if (!c->c1.tuntap)
+    {
+        struct tuntap *tt;
+        ALLOC_OBJ(tt, struct tuntap);
 
-  /* set socket to non-blocking mode */
-  set_nonblock (sock->sd);
+        *tt = create_dco_handle(c->options.dev_node, &c->gc);
 
-  /* set socket file descriptor to not pass across execs, so that
-     scripts don't have access to it */
-  set_cloexec (sock->sd);
+        /* Ensure we can "safely" cast the handle to a socket */
+        static_assert(sizeof(sock->sd) == sizeof(tt->hand), "HANDLE and SOCKET size differs");
 
-  if (socket_defined (sock->ctrl_sd))
-    set_cloexec (sock->ctrl_sd);
+        c->c1.tuntap = tt;
+    }
 
-  /* set Path MTU discovery options on the socket */
-  set_mtu_discover_type (sock->sd, sock->mtu_discover_type, sock->info.af);
+    dco_create_socket(c->c1.tuntap->hand,
+                      sock->info.lsa->current_remote,
+                      sock->bind_local, sock->info.lsa->bind_local,
+                      get_server_poll_remaining_time(sock->server_poll_timeout),
+                      sig_info);
 
-#if EXTENDED_SOCKET_ERROR_CAPABILITY
-  /* if the OS supports it, enable extended error passing on the socket */
-  set_sock_extended_error_passing (sock->sd);
-#endif
-}
+    sock->sockflags |= SF_DCO_WIN;
 
+    if (sig_info->signal_received)
+    {
+        return;
+    }
 
-static void
-linksock_print_addr (struct link_socket *sock)
-{
-  struct gc_arena gc = gc_new ();
-  const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO;
-
-  /* print local address */
- if (sock->inetd)
-    msg (msglevel, "%s link local: [inetd]", proto2ascii (sock->info.proto, sock->info.af, true));
-  else if (sock->bind_local)
-    {
-      sa_family_t ai_family = sock->info.lsa->actual.dest.addr.sa.sa_family;
-      /* Socket is always bound on the first matching address,
-       * For bound sockets with no remote addr this is the element of
-       * the list */
-      struct addrinfo *cur;
-      for (cur = sock->info.lsa->bind_local; cur; cur=cur->ai_next)
-       {
-         if(!ai_family || ai_family == cur->ai_family)
-           break;
-       }
-      ASSERT (cur);
-      msg (msglevel, "%s link local (bound): %s",
-          proto2ascii (sock->info.proto, sock->info.af, true),
-          print_sockaddr(cur->ai_addr,&gc));
-    }
-  else
-    msg (msglevel, "%s link local: (not bound)",
-        proto2ascii (sock->info.proto, sock->info.af, true));
-
-  /* print active remote address */
-  msg (msglevel, "%s link remote: %s",
-       proto2ascii (sock->info.proto, sock->info.af, true),
-       print_link_socket_actual_ex (&sock->info.lsa->actual,
-                                   ":",
-                                   PS_SHOW_PORT_IF_DEFINED,
-                                   &gc));
-  gc_free(&gc);
+    sock->sd = (SOCKET)c->c1.tuntap->hand;
+    linksock_print_addr(sock);
 }
+#endif /* if defined(_WIN32) */
 
-static void
-phase2_tcp_server (struct link_socket *sock, const char *remote_dynamic,
-                  volatile int *signal_received)
-{
-  switch (sock->mode)
-    {
-    case LS_MODE_DEFAULT:
-      sock->sd = socket_listen_accept (sock->sd,
-                                      &sock->info.lsa->actual,
-                                      remote_dynamic,
-                                      sock->info.lsa->bind_local,
-                                      true,
-                                      false,
-                                      signal_received);
-      break;
-    case LS_MODE_TCP_LISTEN:
-      socket_do_listen (sock->sd,
-                       sock->info.lsa->bind_local,
-                       true,
-                       false);
-      break;
-    case LS_MODE_TCP_ACCEPT_FROM:
-      sock->sd = socket_do_accept (sock->sd,
-                                  &sock->info.lsa->actual,
-                                  false);
-      if (!socket_defined (sock->sd))
-       {
-         *signal_received = SIGTERM;
-         return;
-       }
-      tcp_connection_established (&sock->info.lsa->actual);
-      break;
-    default:
-      ASSERT (0);
-    }
-}
+/* finalize socket initialization */
+void
+link_socket_init_phase2(struct context *c)
+{
+    struct link_socket *sock = c->c2.link_socket;
+    const struct frame *frame = &c->c2.frame;
+    struct signal_info *sig_info = c->sig;
 
+    const char *remote_dynamic = NULL;
+    struct signal_info sig_save = {0};
 
-static void
-phase2_tcp_client (struct link_socket *sock, struct signal_info *sig_info)
-{
-  bool proxy_retry = false;
-  do {
-    socket_connect (&sock->sd,
-                   sock->info.lsa->current_remote->ai_addr,
-                   sock->connect_timeout,
-                   sig_info);
+    ASSERT(sock);
+    ASSERT(sig_info);
 
     if (sig_info->signal_received)
-      return;
+    {
+        sig_save = *sig_info;
+        sig_save.signal_received = signal_reset(sig_info, 0);
+    }
 
-    if (sock->http_proxy)
-      {
-       proxy_retry = establish_http_proxy_passthru (sock->http_proxy,
-                                                    sock->sd,
-                                                    sock->proxy_dest_host,
-                                                    sock->proxy_dest_port,
-                                                    &sock->stream_buf.residual,
-                                                    &sig_info->signal_received);
-      }
-    else if (sock->socks_proxy)
-      {
-       establish_socks_proxy_passthru (sock->socks_proxy,
-                                       sock->sd,
-                                       sock->proxy_dest_host,
-                                       sock->proxy_dest_port,
-                                       &sig_info->signal_received);
-      }
-    if (proxy_retry)
-      {
-       openvpn_close_socket (sock->sd);
-       sock->sd = create_socket_tcp (sock->info.lsa->current_remote);
-      }
+    /* initialize buffers */
+    socket_frame_init(frame, sock);
 
-  } while (proxy_retry);
+    /*
+     * Pass a remote name to connect/accept so that
+     * they can test for dynamic IP address changes
+     * and throw a SIGUSR1 if appropriate.
+     */
+    if (sock->resolve_retry_seconds)
+    {
+        remote_dynamic = sock->remote_host;
+    }
 
-}
+    /* Second chance to resolv/create socket */
+    resolve_remote(sock, 2, &remote_dynamic,  sig_info);
 
-static void
-phase2_socks_client (struct link_socket *sock, struct signal_info *sig_info)
-{
-    socket_connect (&sock->ctrl_sd,
-                   sock->info.lsa->current_remote->ai_addr,
-                   sock->connect_timeout,
-                   sig_info);
+    /* If a valid remote has been found, create the socket with its addrinfo */
+    if (sock->info.lsa->current_remote)
+    {
+#if defined(_WIN32)
+        if (dco_enabled(&c->options))
+        {
+            create_socket_dco_win(c, sock, sig_info);
+            goto done;
+        }
+        else
+#endif
+        {
+            create_socket(sock, sock->info.lsa->current_remote);
+        }
 
-    if (sig_info->signal_received)
-       return;
+    }
 
-    establish_socks_proxy_udpassoc (sock->socks_proxy,
-                                   sock->ctrl_sd,
-                                   sock->sd,
-                                   &sock->socks_relay.dest,
-                                   &sig_info->signal_received);
+    /* If socket has not already been created create it now */
+    if (sock->sd == SOCKET_UNDEFINED)
+    {
+        /* If we have no --remote and have still not figured out the
+         * protocol family to use we will use the first of the bind */
 
-    if (sig_info->signal_received)
-       return;
+        if (sock->bind_local  && !sock->remote_host && sock->info.lsa->bind_local)
+        {
+            /* Warn if this is because neither v4 or v6 was specified
+             * and we should not connect a remote */
+            if (sock->info.af == AF_UNSPEC)
+            {
+                msg(M_WARN, "Could not determine IPv4/IPv6 protocol. Using %s",
+                    addr_family_name(sock->info.lsa->bind_local->ai_family));
+                sock->info.af = sock->info.lsa->bind_local->ai_family;
+            }
 
-    sock->remote_host = sock->proxy_dest_host;
-    sock->remote_port = sock->proxy_dest_port;
+            create_socket(sock, sock->info.lsa->bind_local);
+        }
+    }
 
-    addr_zero_host(&sock->info.lsa->actual.dest);
-    if (sock->info.lsa->remote_list)
-      {
-       freeaddrinfo(sock->info.lsa->remote_list);
-       sock->info.lsa->current_remote = NULL;
-       sock->info.lsa->remote_list = NULL;
-      }
+    /* Socket still undefined, give a warning and abort connection */
+    if (sock->sd == SOCKET_UNDEFINED)
+    {
+        msg(M_WARN, "Could not determine IPv4/IPv6 protocol");
+        register_signal(sig_info, SIGUSR1, "Could not determine IPv4/IPv6 protocol");
+        goto done;
+    }
 
-    resolve_remote (sock, 1, NULL, &sig_info->signal_received);
-}
+    if (sig_info->signal_received)
+    {
+        goto done;
+    }
 
-/* finalize socket initialization */
-void
-link_socket_init_phase2 (struct link_socket *sock,
-                        const struct frame *frame,
-                        struct signal_info *sig_info)
-{
-  const char *remote_dynamic = NULL;
-  int sig_save = 0;
-
-  ASSERT (sock);
-
-  if (sig_info && sig_info->signal_received)
-    {
-      sig_save = sig_info->signal_received;
-      sig_info->signal_received = 0;
-    }
-
-  /* initialize buffers */
-  socket_frame_init (frame, sock);
-
-  /*
-   * Pass a remote name to connect/accept so that
-   * they can test for dynamic IP address changes
-   * and throw a SIGUSR1 if appropriate.
-   */
-  if (sock->resolve_retry_seconds)
-    remote_dynamic = sock->remote_host;
-
-  /* were we started by inetd or xinetd? */
-  if (sock->inetd)
-    {
-      phase2_inetd (sock, frame, remote_dynamic,  &sig_info->signal_received);
-      if (sig_info && sig_info->signal_received)
-       goto done;
-
-    }
-  else
-    {
-      /* Second chance to resolv/create socket */
-      resolve_remote (sock, 2, &remote_dynamic,  &sig_info->signal_received);
-
-      /* If a valid remote has been found, create the socket with its addrinfo */
-      if (sock->info.lsa->current_remote)
-         create_socket (sock, sock->info.lsa->current_remote);
-
-      /* If socket has not already been created create it now */
-      if (sock->sd == SOCKET_UNDEFINED)
-       {
-         /* If we have no --remote and have still not figured out the
-          * protocol family to use we will use the first of the bind */
-
-         if (sock->bind_local  && !sock->remote_host && sock->info.lsa->bind_local)
-           {
-             /* Warn if this is because neither v4 or v6 was specified
-              * and we should not connect a remote */
-             if (sock->info.af == AF_UNSPEC)
-               {
-                 msg (M_WARN, "Could not determine IPv4/IPv6 protocol. Using %s",
-                    addr_family_name(sock->info.lsa->bind_local->ai_family));
-                 sock->info.af = sock->info.lsa->bind_local->ai_family;
-               }
-
-             create_socket (sock, sock->info.lsa->bind_local);
-           }
-       }
-
-      /* Socket still undefined, give a warning and abort connection */
-      if (sock->sd == SOCKET_UNDEFINED)
-       {
-         msg (M_WARN, "Could not determine IPv4/IPv6 protocol");
-         sig_info->signal_received = SIGUSR1;
-         goto done;
-       }
-
-      if (sig_info && sig_info->signal_received)
-       goto done;
-
-      if (sock->info.proto == PROTO_TCP_SERVER)
-       {
-         phase2_tcp_server (sock, remote_dynamic,
-                            &sig_info->signal_received);
-       }
-      else if (sock->info.proto == PROTO_TCP_CLIENT)
-       {
-         phase2_tcp_client (sock, sig_info);
-
-       }
-      else if (sock->info.proto == PROTO_UDP && sock->socks_proxy)
-       {
-         phase2_socks_client (sock, sig_info);
-       }
+    if (sock->info.proto == PROTO_TCP_SERVER)
+    {
+        phase2_tcp_server(sock, remote_dynamic, sig_info);
+    }
+    else if (sock->info.proto == PROTO_TCP_CLIENT)
+    {
+        phase2_tcp_client(sock, sig_info);
+
+    }
+    else if (sock->info.proto == PROTO_UDP && sock->socks_proxy)
+    {
+        phase2_socks_client(sock, sig_info);
+    }
 #ifdef TARGET_ANDROID
-      if (sock->sd != -1)
-       protect_fd_nonlocal (sock->sd, &sock->info.lsa->actual.dest.addr.sa);
+    if (sock->sd != -1)
+    {
+        protect_fd_nonlocal(sock->sd, &sock->info.lsa->actual.dest.addr.sa);
+    }
 #endif
-      if (sig_info && sig_info->signal_received)
-       goto done;
+    if (sig_info->signal_received)
+    {
+        goto done;
     }
 
-  phase2_set_socket_flags(sock);
-  linksock_print_addr(sock);
+    phase2_set_socket_flags(sock);
+    linksock_print_addr(sock);
 
- done:
-  if (sig_save && sig_info)
+done:
+    if (sig_save.signal_received)
     {
-      if (!sig_info->signal_received)
-       sig_info->signal_received = sig_save;
+        /* Always restore the saved signal -- register/throw_signal will handle priority */
+        if (sig_save.source == SIG_SOURCE_HARD && sig_info == &siginfo_static)
+        {
+            throw_signal(sig_save.signal_received);
+        }
+        else
+        {
+            register_signal(sig_info, sig_save.signal_received, sig_save.signal_text);
+        }
     }
 }
 
 void
-link_socket_close (struct link_socket *sock)
+link_socket_close(struct link_socket *sock)
 {
-  if (sock)
+    if (sock)
     {
 #ifdef ENABLE_DEBUG
-      const int gremlin = GREMLIN_CONNECTION_FLOOD_LEVEL (sock->gremlin);
+        const int gremlin = GREMLIN_CONNECTION_FLOOD_LEVEL(sock->gremlin);
 #else
-      const int gremlin = 0;
+        const int gremlin = 0;
 #endif
 
-      if (socket_defined (sock->sd))
-       {
-#ifdef WIN32
-         close_net_event_win32 (&sock->listen_handle, sock->sd, 0);
+        if (socket_defined(sock->sd))
+        {
+#ifdef _WIN32
+            close_net_event_win32(&sock->listen_handle, sock->sd, 0);
 #endif
-         if (!gremlin)
-           {
-             msg (D_LOW, "TCP/UDP: Closing socket");
-             if (openvpn_close_socket (sock->sd))
-               msg (M_WARN | M_ERRNO, "TCP/UDP: Close Socket failed");
-           }
-         sock->sd = SOCKET_UNDEFINED;
-#ifdef WIN32
-         if (!gremlin)
-           {
-             overlapped_io_close (&sock->reads);
-             overlapped_io_close (&sock->writes);
-           }
+            if (!gremlin)
+            {
+                msg(D_LOW, "TCP/UDP: Closing socket");
+                if (openvpn_close_socket(sock->sd))
+                {
+                    msg(M_WARN | M_ERRNO, "TCP/UDP: Close Socket failed");
+                }
+            }
+            sock->sd = SOCKET_UNDEFINED;
+#ifdef _WIN32
+            if (!gremlin)
+            {
+                overlapped_io_close(&sock->reads);
+                overlapped_io_close(&sock->writes);
+            }
 #endif
-       }
+        }
 
-      if (socket_defined (sock->ctrl_sd))
-       {
-         if (openvpn_close_socket (sock->ctrl_sd))
-           msg (M_WARN | M_ERRNO, "TCP/UDP: Close Socket (ctrl_sd) failed");
-         sock->ctrl_sd = SOCKET_UNDEFINED;
-       }
+        if (socket_defined(sock->ctrl_sd))
+        {
+            if (openvpn_close_socket(sock->ctrl_sd))
+            {
+                msg(M_WARN | M_ERRNO, "TCP/UDP: Close Socket (ctrl_sd) failed");
+            }
+            sock->ctrl_sd = SOCKET_UNDEFINED;
+        }
 
-      stream_buf_close (&sock->stream_buf);
-      free_buf (&sock->stream_buf_data);
-      if (!gremlin)
-       free (sock);
+        stream_buf_close(&sock->stream_buf);
+        free_buf(&sock->stream_buf_data);
+        if (!gremlin)
+        {
+            free(sock);
+        }
     }
 }
 
-/* for stream protocols, allow for packet length prefix */
-void
-socket_adjust_frame_parameters (struct frame *frame, int proto)
-{
-  if (link_socket_proto_connection_oriented (proto))
-    frame_add_to_extra_frame (frame, sizeof (packet_size_type));
-}
-
 void
-setenv_trusted (struct env_set *es, const struct link_socket_info *info)
+setenv_trusted(struct env_set *es, const struct link_socket_info *info)
 {
-  setenv_link_socket_actual (es, "trusted", &info->lsa->actual, SA_IP_PORT);
+    setenv_link_socket_actual(es, "trusted", &info->lsa->actual, SA_IP_PORT);
 }
 
 static void
-ipchange_fmt (const bool include_cmd, struct argv *argv, const struct link_socket_info *info, struct gc_arena *gc)
+ipchange_fmt(const bool include_cmd, struct argv *argv, const struct link_socket_info *info, struct gc_arena *gc)
 {
-  const char *host = print_sockaddr_ex (&info->lsa->actual.dest.addr.sa, " ", PS_SHOW_PORT , gc);
-  if (include_cmd)
-    argv_printf (argv, "%sc %s",
-                info->ipchange_command,
-                host);
-  else
-    argv_printf (argv, "%s", host);
+    const char *host = print_sockaddr_ex(&info->lsa->actual.dest.addr.sa, " ", PS_SHOW_PORT, gc);
+    if (include_cmd)
+    {
+        argv_parse_cmd(argv, info->ipchange_command);
+        argv_printf_cat(argv, "%s", host);
+    }
+    else
+    {
+        argv_printf(argv, "%s", host);
+    }
 
 }
 
 void
-link_socket_connection_initiated (const struct buffer *buf,
-                                 struct link_socket_info *info,
-                                 const struct link_socket_actual *act,
-                                 const char *common_name,
-                                 struct env_set *es)
+link_socket_connection_initiated(struct link_socket_info *info,
+                                 const struct link_socket_actual *act,
+                                 const char *common_name,
+                                 struct env_set *es)
 {
-  struct gc_arena gc = gc_new ();
-  
-  info->lsa->actual = *act; /* Note: skip this line for --force-dest */
-  setenv_trusted (es, info);
-  info->connection_established = true;
+    struct gc_arena gc = gc_new();
 
-  /* Print connection initiated message, with common name if available */
-  {
-    struct buffer out = alloc_buf_gc (256, &gc);
-    if (common_name)
-      buf_printf (&out, "[%s] ", common_name);
-    buf_printf (&out, "Peer Connection Initiated with %s", print_link_socket_actual (&info->lsa->actual, &gc));
-    msg (M_INFO, "%s", BSTR (&out));
-  }
+    info->lsa->actual = *act; /* Note: skip this line for --force-dest */
+    setenv_trusted(es, info);
+    info->connection_established = true;
 
-  /* set environmental vars */
-  setenv_str (es, "common_name", common_name);
+    /* Print connection initiated message, with common name if available */
+    {
+        struct buffer out = alloc_buf_gc(256, &gc);
+        if (common_name)
+        {
+            buf_printf(&out, "[%s] ", common_name);
+        }
+        buf_printf(&out, "Peer Connection Initiated with %s", print_link_socket_actual(&info->lsa->actual, &gc));
+        msg(M_INFO, "%s", BSTR(&out));
+    }
 
-  /* Process --ipchange plugin */
-  if (plugin_defined (info->plugins, OPENVPN_PLUGIN_IPCHANGE))
+    /* set environmental vars */
+    setenv_str(es, "common_name", common_name);
+
+    /* Process --ipchange plugin */
+    if (plugin_defined(info->plugins, OPENVPN_PLUGIN_IPCHANGE))
     {
-      struct argv argv = argv_new ();
-      ipchange_fmt (false, &argv, info, &gc);
-      if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
-       msg (M_WARN, "WARNING: ipchange plugin call failed");
-      argv_reset (&argv);
+        struct argv argv = argv_new();
+        ipchange_fmt(false, &argv, info, &gc);
+        if (plugin_call(info->plugins, OPENVPN_PLUGIN_IPCHANGE, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
+        {
+            msg(M_WARN, "WARNING: ipchange plugin call failed");
+        }
+        argv_free(&argv);
     }
 
-  /* Process --ipchange option */
-  if (info->ipchange_command)
+    /* Process --ipchange option */
+    if (info->ipchange_command)
     {
-      struct argv argv = argv_new ();
-      setenv_str (es, "script_type", "ipchange");
-      ipchange_fmt (true, &argv, info, &gc);
-      openvpn_run_script (&argv, es, 0, "--ipchange");
-      argv_reset (&argv);
+        struct argv argv = argv_new();
+        setenv_str(es, "script_type", "ipchange");
+        ipchange_fmt(true, &argv, info, &gc);
+        openvpn_run_script(&argv, es, 0, "--ipchange");
+        argv_free(&argv);
     }
 
-  gc_free (&gc);
+    gc_free(&gc);
 }
 
 void
-link_socket_bad_incoming_addr (struct buffer *buf,
-                              const struct link_socket_info *info,
-                              const struct link_socket_actual *from_addr)
-{
-  struct gc_arena gc = gc_new ();
-  struct addrinfo* ai;
-
-  switch(from_addr->dest.addr.sa.sa_family)
-    {
-    case AF_INET:
-    case AF_INET6:
-      msg (D_LINK_ERRORS,
-          "TCP/UDP: Incoming packet rejected from %s[%d], expected peer address: %s (allow this incoming source address/port by removing --remote or adding --float)",
-          print_link_socket_actual (from_addr, &gc),
-          (int)from_addr->dest.addr.sa.sa_family,
-          print_sockaddr_ex (info->lsa->remote_list->ai_addr,":" ,PS_SHOW_PORT, &gc));
-          /* print additional remote addresses */
-          for(ai=info->lsa->remote_list->ai_next;ai;ai=ai->ai_next) {
-             msg(D_LINK_ERRORS,"or from peer address: %s",
-                 print_sockaddr_ex(ai->ai_addr,":",PS_SHOW_PORT, &gc));
-          }
-      break;
+link_socket_bad_incoming_addr(struct buffer *buf,
+                              const struct link_socket_info *info,
+                              const struct link_socket_actual *from_addr)
+{
+    struct gc_arena gc = gc_new();
+    struct addrinfo *ai;
+
+    switch (from_addr->dest.addr.sa.sa_family)
+    {
+        case AF_INET:
+        case AF_INET6:
+            msg(D_LINK_ERRORS,
+                "TCP/UDP: Incoming packet rejected from %s[%d], expected peer address: %s (allow this incoming source address/port by removing --remote or adding --float)",
+                print_link_socket_actual(from_addr, &gc),
+                (int)from_addr->dest.addr.sa.sa_family,
+                print_sockaddr_ex(info->lsa->remote_list->ai_addr, ":", PS_SHOW_PORT, &gc));
+            /* print additional remote addresses */
+            for (ai = info->lsa->remote_list->ai_next; ai; ai = ai->ai_next)
+            {
+                msg(D_LINK_ERRORS, "or from peer address: %s",
+                    print_sockaddr_ex(ai->ai_addr, ":", PS_SHOW_PORT, &gc));
+            }
+            break;
     }
-  buf->len = 0;
-  gc_free (&gc);
+    buf->len = 0;
+    gc_free(&gc);
 }
 
 void
-link_socket_bad_outgoing_addr (void)
+link_socket_bad_outgoing_addr(void)
 {
-  dmsg (D_READ_WRITE, "TCP/UDP: No outgoing address to send packet");
+    dmsg(D_READ_WRITE, "TCP/UDP: No outgoing address to send packet");
 }
 
 in_addr_t
-link_socket_current_remote (const struct link_socket_info *info)
+link_socket_current_remote(const struct link_socket_info *info)
 {
-  const struct link_socket_addr *lsa = info->lsa;
+    const struct link_socket_addr *lsa = info->lsa;
 
-/* 
- * This logic supports "redirect-gateway" semantic, which 
+/*
+ * This logic supports "redirect-gateway" semantic, which
  * makes sense only for PF_INET routes over PF_INET endpoints
  *
  * Maybe in the future consider PF_INET6 endpoints also ...
  * by now just ignore it
  *
  * For --remote entries with multiple addresses this
- * only return the actual endpoint we have sucessfully connected to
+ * only return the actual endpoint we have successfully connected to
  */
-  if (lsa->actual.dest.addr.sa.sa_family != AF_INET)
-    return IPV4_INVALID_ADDR;
-
-  if (link_socket_actual_defined (&lsa->actual))
-    return ntohl (lsa->actual.dest.addr.in4.sin_addr.s_addr);
-  else if (lsa->current_remote)
-    return ntohl (((struct sockaddr_in*)lsa->current_remote->ai_addr)
-                    ->sin_addr.s_addr);
-  else
-    return 0;
+    if (lsa->actual.dest.addr.sa.sa_family != AF_INET)
+    {
+        return IPV4_INVALID_ADDR;
+    }
+
+    if (link_socket_actual_defined(&lsa->actual))
+    {
+        return ntohl(lsa->actual.dest.addr.in4.sin_addr.s_addr);
+    }
+    else if (lsa->current_remote)
+    {
+        return ntohl(((struct sockaddr_in *)lsa->current_remote->ai_addr)
+                     ->sin_addr.s_addr);
+    }
+    else
+    {
+        return 0;
+    }
 }
 
 const struct in6_addr *
-link_socket_current_remote_ipv6 (const struct link_socket_info *info)
+link_socket_current_remote_ipv6(const struct link_socket_info *info)
 {
-  const struct link_socket_addr *lsa = info->lsa;
+    const struct link_socket_addr *lsa = info->lsa;
 
 /* This logic supports "redirect-gateway" semantic,
  * for PF_INET6 routes over PF_INET6 endpoints
  *
  * For --remote entries with multiple addresses this
- * only return the actual endpoint we have sucessfully connected to
+ * only return the actual endpoint we have successfully connected to
  */
-  if (lsa->actual.dest.addr.sa.sa_family != AF_INET6)
-    return NULL;
+    if (lsa->actual.dest.addr.sa.sa_family != AF_INET6)
+    {
+        return NULL;
+    }
 
-  if (link_socket_actual_defined (&lsa->actual))
-    return &(lsa->actual.dest.addr.in6.sin6_addr);
-  else if (lsa->current_remote)
-    return &(((struct sockaddr_in6*)lsa->current_remote->ai_addr) ->sin6_addr);
-  else
-    return NULL;
+    if (link_socket_actual_defined(&lsa->actual))
+    {
+        return &(lsa->actual.dest.addr.in6.sin6_addr);
+    }
+    else if (lsa->current_remote)
+    {
+        return &(((struct sockaddr_in6 *)lsa->current_remote->ai_addr)->sin6_addr);
+    }
+    else
+    {
+        return NULL;
+    }
 }
 
 /*
  * Return a status string describing socket state.
  */
 const char *
-socket_stat (const struct link_socket *s, unsigned int rwflags, struct gc_arena *gc)
-{
-  struct buffer out = alloc_buf_gc (64, gc);
-  if (s)
-    {
-      if (rwflags & EVENT_READ)
-       {
-         buf_printf (&out, "S%s",
-                     (s->rwflags_debug & EVENT_READ) ? "R" : "r");
-#ifdef WIN32
-         buf_printf (&out, "%s",
-                     overlapped_io_state_ascii (&s->reads));
+socket_stat(const struct link_socket *s, unsigned int rwflags, struct gc_arena *gc)
+{
+    struct buffer out = alloc_buf_gc(64, gc);
+    if (s)
+    {
+        if (rwflags & EVENT_READ)
+        {
+            buf_printf(&out, "S%s",
+                       (s->rwflags_debug & EVENT_READ) ? "R" : "r");
+#ifdef _WIN32
+            buf_printf(&out, "%s",
+                       overlapped_io_state_ascii(&s->reads));
 #endif
-       }
-      if (rwflags & EVENT_WRITE)
-       {
-         buf_printf (&out, "S%s",
-                     (s->rwflags_debug & EVENT_WRITE) ? "W" : "w");
-#ifdef WIN32
-         buf_printf (&out, "%s",
-                     overlapped_io_state_ascii (&s->writes));
+        }
+        if (rwflags & EVENT_WRITE)
+        {
+            buf_printf(&out, "S%s",
+                       (s->rwflags_debug & EVENT_WRITE) ? "W" : "w");
+#ifdef _WIN32
+            buf_printf(&out, "%s",
+                       overlapped_io_state_ascii(&s->writes));
 #endif
-       }
+        }
     }
-  else
+    else
     {
-      buf_printf (&out, "S?");
+        buf_printf(&out, "S?");
     }
-  return BSTR (&out);
+    return BSTR(&out);
 }
 
 /*
@@ -2190,152 +2556,160 @@ socket_stat (const struct link_socket *s, unsigned int rwflags, struct gc_arena
  */
 
 static inline void
-stream_buf_reset (struct stream_buf *sb)
+stream_buf_reset(struct stream_buf *sb)
 {
-  dmsg (D_STREAM_DEBUG, "STREAM: RESET");
-  sb->residual_fully_formed = false;
-  sb->buf = sb->buf_init;
-  buf_reset (&sb->next);
-  sb->len = -1;
+    dmsg(D_STREAM_DEBUG, "STREAM: RESET");
+    sb->residual_fully_formed = false;
+    sb->buf = sb->buf_init;
+    buf_reset(&sb->next);
+    sb->len = -1;
 }
 
-void
-stream_buf_init (struct stream_buf *sb,
-                struct buffer *buf,
-                const unsigned int sockflags,
-                const int proto)
-{
-  sb->buf_init = *buf;
-  sb->maxlen = sb->buf_init.len;
-  sb->buf_init.len = 0;
-  sb->residual = alloc_buf (sb->maxlen);
-  sb->error = false;
+static void
+stream_buf_init(struct stream_buf *sb,
+                struct buffer *buf,
+                const unsigned int sockflags,
+                const int proto)
+{
+    sb->buf_init = *buf;
+    sb->maxlen = sb->buf_init.len;
+    sb->buf_init.len = 0;
+    sb->residual = alloc_buf(sb->maxlen);
+    sb->error = false;
 #if PORT_SHARE
-  sb->port_share_state = ((sockflags & SF_PORT_SHARE) && (proto == PROTO_TCP_SERVER))
-    ? PS_ENABLED
-    : PS_DISABLED;
+    sb->port_share_state = ((sockflags & SF_PORT_SHARE) && (proto == PROTO_TCP_SERVER))
+                           ? PS_ENABLED
+                           : PS_DISABLED;
 #endif
-  stream_buf_reset (sb);
+    stream_buf_reset(sb);
 
-  dmsg (D_STREAM_DEBUG, "STREAM: INIT maxlen=%d", sb->maxlen);
+    dmsg(D_STREAM_DEBUG, "STREAM: INIT maxlen=%d", sb->maxlen);
 }
 
 static inline void
-stream_buf_set_next (struct stream_buf *sb)
+stream_buf_set_next(struct stream_buf *sb)
 {
-  /* set up 'next' for next i/o read */
-  sb->next = sb->buf;
-  sb->next.offset = sb->buf.offset + sb->buf.len;
-  sb->next.len = (sb->len >= 0 ? sb->len : sb->maxlen) - sb->buf.len;
-  dmsg (D_STREAM_DEBUG, "STREAM: SET NEXT, buf=[%d,%d] next=[%d,%d] len=%d maxlen=%d",
-       sb->buf.offset, sb->buf.len,
-       sb->next.offset, sb->next.len,
-       sb->len, sb->maxlen);
-  ASSERT (sb->next.len > 0);
-  ASSERT (buf_safe (&sb->buf, sb->next.len));
+    /* set up 'next' for next i/o read */
+    sb->next = sb->buf;
+    sb->next.offset = sb->buf.offset + sb->buf.len;
+    sb->next.len = (sb->len >= 0 ? sb->len : sb->maxlen) - sb->buf.len;
+    dmsg(D_STREAM_DEBUG, "STREAM: SET NEXT, buf=[%d,%d] next=[%d,%d] len=%d maxlen=%d",
+         sb->buf.offset, sb->buf.len,
+         sb->next.offset, sb->next.len,
+         sb->len, sb->maxlen);
+    ASSERT(sb->next.len > 0);
+    ASSERT(buf_safe(&sb->buf, sb->next.len));
 }
 
 static inline void
-stream_buf_get_final (struct stream_buf *sb, struct buffer *buf)
+stream_buf_get_final(struct stream_buf *sb, struct buffer *buf)
 {
-  dmsg (D_STREAM_DEBUG, "STREAM: GET FINAL len=%d",
-       buf_defined (&sb->buf) ? sb->buf.len : -1);
-  ASSERT (buf_defined (&sb->buf));
-  *buf = sb->buf;
+    dmsg(D_STREAM_DEBUG, "STREAM: GET FINAL len=%d",
+         buf_defined(&sb->buf) ? sb->buf.len : -1);
+    ASSERT(buf_defined(&sb->buf));
+    *buf = sb->buf;
 }
 
 static inline void
-stream_buf_get_next (struct stream_buf *sb, struct buffer *buf)
+stream_buf_get_next(struct stream_buf *sb, struct buffer *buf)
 {
-  dmsg (D_STREAM_DEBUG, "STREAM: GET NEXT len=%d",
-       buf_defined (&sb->next) ? sb->next.len : -1);
-  ASSERT (buf_defined (&sb->next));
-  *buf = sb->next;
+    dmsg(D_STREAM_DEBUG, "STREAM: GET NEXT len=%d",
+         buf_defined(&sb->next) ? sb->next.len : -1);
+    ASSERT(buf_defined(&sb->next));
+    *buf = sb->next;
 }
 
 bool
-stream_buf_read_setup_dowork (struct link_socket* sock)
+stream_buf_read_setup_dowork(struct link_socket *sock)
 {
-  if (sock->stream_buf.residual.len && !sock->stream_buf.residual_fully_formed)
+    if (sock->stream_buf.residual.len && !sock->stream_buf.residual_fully_formed)
     {
-      ASSERT (buf_copy (&sock->stream_buf.buf, &sock->stream_buf.residual));
-      ASSERT (buf_init (&sock->stream_buf.residual, 0));
-      sock->stream_buf.residual_fully_formed = stream_buf_added (&sock->stream_buf, 0);
-      dmsg (D_STREAM_DEBUG, "STREAM: RESIDUAL FULLY FORMED [%s], len=%d",
-          sock->stream_buf.residual_fully_formed ? "YES" : "NO",
-          sock->stream_buf.residual.len);
+        ASSERT(buf_copy(&sock->stream_buf.buf, &sock->stream_buf.residual));
+        ASSERT(buf_init(&sock->stream_buf.residual, 0));
+        sock->stream_buf.residual_fully_formed = stream_buf_added(&sock->stream_buf, 0);
+        dmsg(D_STREAM_DEBUG, "STREAM: RESIDUAL FULLY FORMED [%s], len=%d",
+             sock->stream_buf.residual_fully_formed ? "YES" : "NO",
+             sock->stream_buf.residual.len);
     }
 
-  if (!sock->stream_buf.residual_fully_formed)
-    stream_buf_set_next (&sock->stream_buf);
-  return !sock->stream_buf.residual_fully_formed;
+    if (!sock->stream_buf.residual_fully_formed)
+    {
+        stream_buf_set_next(&sock->stream_buf);
+    }
+    return !sock->stream_buf.residual_fully_formed;
 }
 
-bool
-stream_buf_added (struct stream_buf *sb,
-                 int length_added)
+static bool
+stream_buf_added(struct stream_buf *sb,
+                 int length_added)
 {
-  dmsg (D_STREAM_DEBUG, "STREAM: ADD length_added=%d", length_added);
-  if (length_added > 0)
-    sb->buf.len += length_added;
+    dmsg(D_STREAM_DEBUG, "STREAM: ADD length_added=%d", length_added);
+    if (length_added > 0)
+    {
+        sb->buf.len += length_added;
+    }
 
-  /* if length unknown, see if we can get the length prefix from
-     the head of the buffer */
-  if (sb->len < 0 && sb->buf.len >= (int) sizeof (packet_size_type))
+    /* if length unknown, see if we can get the length prefix from
+     the head of the buffer */
+    if (sb->len < 0 && sb->buf.len >= (int) sizeof(packet_size_type))
     {
-      packet_size_type net_size;
+        packet_size_type net_size;
 
 #if PORT_SHARE
-      if (sb->port_share_state == PS_ENABLED)
-       {
-         if (!is_openvpn_protocol (&sb->buf))
-           {
-             msg (D_STREAM_ERRORS, "Non-OpenVPN client protocol detected");
-             sb->port_share_state = PS_FOREIGN;
-             sb->error = true;
-             return false;
-           }
-         else
-           sb->port_share_state = PS_DISABLED;
-       }
+        if (sb->port_share_state == PS_ENABLED)
+        {
+            if (!is_openvpn_protocol(&sb->buf))
+            {
+                msg(D_STREAM_ERRORS, "Non-OpenVPN client protocol detected");
+                sb->port_share_state = PS_FOREIGN;
+                sb->error = true;
+                return false;
+            }
+            else
+            {
+                sb->port_share_state = PS_DISABLED;
+            }
+        }
 #endif
 
-      ASSERT (buf_read (&sb->buf, &net_size, sizeof (net_size)));
-      sb->len = ntohps (net_size);
+        ASSERT(buf_read(&sb->buf, &net_size, sizeof(net_size)));
+        sb->len = ntohps(net_size);
 
-      if (sb->len < 1 || sb->len > sb->maxlen)
-       {
-         msg (M_WARN, "WARNING: Bad encapsulated packet length from peer (%d), which must be > 0 and <= %d -- please ensure that --tun-mtu or --link-mtu is equal on both peers -- this condition could also indicate a possible active attack on the TCP link -- [Attempting restart...]", sb->len, sb->maxlen);
-         stream_buf_reset (sb);
-         sb->error = true;
-         return false;
-       }
+        if (sb->len < 1 || sb->len > sb->maxlen)
+        {
+            msg(M_WARN, "WARNING: Bad encapsulated packet length from peer (%d), which must be > 0 and <= %d -- please ensure that --tun-mtu or --link-mtu is equal on both peers -- this condition could also indicate a possible active attack on the TCP link -- [Attempting restart...]", sb->len, sb->maxlen);
+            stream_buf_reset(sb);
+            sb->error = true;
+            return false;
+        }
     }
 
-  /* is our incoming packet fully read? */
-  if (sb->len > 0 && sb->buf.len >= sb->len)
+    /* is our incoming packet fully read? */
+    if (sb->len > 0 && sb->buf.len >= sb->len)
     {
-      /* save any residual data that's part of the next packet */
-      ASSERT (buf_init (&sb->residual, 0));
-      if (sb->buf.len > sb->len)
-         ASSERT (buf_copy_excess (&sb->residual, &sb->buf, sb->len));
-      dmsg (D_STREAM_DEBUG, "STREAM: ADD returned TRUE, buf_len=%d, residual_len=%d",
-          BLEN (&sb->buf),
-          BLEN (&sb->residual));
-      return true;
+        /* save any residual data that's part of the next packet */
+        ASSERT(buf_init(&sb->residual, 0));
+        if (sb->buf.len > sb->len)
+        {
+            ASSERT(buf_copy_excess(&sb->residual, &sb->buf, sb->len));
+        }
+        dmsg(D_STREAM_DEBUG, "STREAM: ADD returned TRUE, buf_len=%d, residual_len=%d",
+             BLEN(&sb->buf),
+             BLEN(&sb->residual));
+        return true;
     }
-  else
+    else
     {
-      dmsg (D_STREAM_DEBUG, "STREAM: ADD returned FALSE (have=%d need=%d)", sb->buf.len, sb->len);
-      stream_buf_set_next (sb);
-      return false;
+        dmsg(D_STREAM_DEBUG, "STREAM: ADD returned FALSE (have=%d need=%d)", sb->buf.len, sb->len);
+        stream_buf_set_next(sb);
+        return false;
     }
 }
 
-void
-stream_buf_close (struct stream_buf* sb)
+static void
+stream_buf_close(struct stream_buf *sb)
 {
-  free_buf (&sb->residual);
+    free_buf(&sb->residual);
 }
 
 /*
@@ -2344,14 +2718,16 @@ stream_buf_close (struct stream_buf* sb)
  * TCP socket, for use in server mode.
  */
 event_t
-socket_listen_event_handle (struct link_socket *s)
+socket_listen_event_handle(struct link_socket *s)
 {
-#ifdef WIN32
-  if (!defined_net_event_win32 (&s->listen_handle))
-    init_net_event_win32 (&s->listen_handle, FD_ACCEPT, s->sd, 0);
-  return &s->listen_handle;
-#else
-  return s->sd;
+#ifdef _WIN32
+    if (!defined_net_event_win32(&s->listen_handle))
+    {
+        init_net_event_win32(&s->listen_handle, FD_ACCEPT, s->sd, 0);
+    }
+    return &s->listen_handle;
+#else  /* ifdef _WIN32 */
+    return s->sd;
 #endif
 }
 
@@ -2360,72 +2736,90 @@ socket_listen_event_handle (struct link_socket *s)
  */
 
 const char *
-print_sockaddr_ex (const struct sockaddr *sa,
-                                  const char* separator,
-                                  const unsigned int flags,
-                                  struct gc_arena *gc)
-{
-  struct buffer out = alloc_buf_gc (128, gc);
-  bool addr_is_defined = false;
-  char hostaddr[NI_MAXHOST] = "";
-  char servname[NI_MAXSERV] = "";
-  int status;
+print_sockaddr_ex(const struct sockaddr *sa,
+                  const char *separator,
+                  const unsigned int flags,
+                  struct gc_arena *gc)
+{
+    struct buffer out = alloc_buf_gc(128, gc);
+    bool addr_is_defined = false;
+    char hostaddr[NI_MAXHOST] = "";
+    char servname[NI_MAXSERV] = "";
+    int status;
+
+    socklen_t salen = 0;
+    switch (sa->sa_family)
+    {
+        case AF_INET:
+            if (!(flags & PS_DONT_SHOW_FAMILY))
+            {
+                buf_puts(&out, "[AF_INET]");
+            }
+            salen = sizeof(struct sockaddr_in);
+            addr_is_defined = ((struct sockaddr_in *) sa)->sin_addr.s_addr != 0;
+            break;
 
-  socklen_t salen = 0;
-  switch(sa->sa_family)
-    {
-    case AF_INET:
-      if (!(flags & PS_DONT_SHOW_FAMILY))
-        buf_puts (&out, "[AF_INET]");
-      salen = sizeof (struct sockaddr_in);
-      addr_is_defined = ((struct sockaddr_in*) sa)->sin_addr.s_addr != 0;
-      break;
-    case AF_INET6:
-      if (!(flags & PS_DONT_SHOW_FAMILY))
-        buf_puts (&out, "[AF_INET6]");
-      salen = sizeof (struct sockaddr_in6);
-      addr_is_defined = !IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6*) sa)->sin6_addr);
-      break;
-    case AF_UNSPEC:
-      if (!(flags & PS_DONT_SHOW_FAMILY))
-        return "[AF_UNSPEC]";
-      else
-        return "";
-    default:
-      ASSERT(0);
+        case AF_INET6:
+            if (!(flags & PS_DONT_SHOW_FAMILY))
+            {
+                buf_puts(&out, "[AF_INET6]");
+            }
+            salen = sizeof(struct sockaddr_in6);
+            addr_is_defined = !IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) sa)->sin6_addr);
+            break;
+
+        case AF_UNSPEC:
+            if (!(flags & PS_DONT_SHOW_FAMILY))
+            {
+                return "[AF_UNSPEC]";
+            }
+            else
+            {
+                return "";
+            }
+
+        default:
+            ASSERT(0);
     }
 
-  status = getnameinfo(sa, salen, hostaddr, sizeof (hostaddr),
-              servname, sizeof(servname), NI_NUMERICHOST | NI_NUMERICSERV);
+    status = getnameinfo(sa, salen, hostaddr, sizeof(hostaddr),
+                         servname, sizeof(servname), NI_NUMERICHOST | NI_NUMERICSERV);
 
-  if(status!=0) {
-      buf_printf(&out,"[nameinfo() err: %s]",gai_strerror(status));
-      return BSTR(&out);
-  }
+    if (status!=0)
+    {
+        buf_printf(&out, "[nameinfo() err: %s]", gai_strerror(status));
+        return BSTR(&out);
+    }
 
-  if (!(flags & PS_DONT_SHOW_ADDR))
+    if (!(flags & PS_DONT_SHOW_ADDR))
     {
-      if (addr_is_defined)
-        buf_puts (&out, hostaddr);
-      else
-        buf_puts (&out, "[undef]");
+        if (addr_is_defined)
+        {
+            buf_puts(&out, hostaddr);
+        }
+        else
+        {
+            buf_puts(&out, "[undef]");
+        }
     }
 
-  if ((flags & PS_SHOW_PORT) || (flags & PS_SHOW_PORT_IF_DEFINED))
+    if ((flags & PS_SHOW_PORT) || (flags & PS_SHOW_PORT_IF_DEFINED))
     {
-      if (separator)
-        buf_puts (&out, separator);
+        if (separator)
+        {
+            buf_puts(&out, separator);
+        }
 
-      buf_puts (&out, servname);
+        buf_puts(&out, servname);
     }
 
-  return BSTR (&out);
+    return BSTR(&out);
 }
 
 const char *
-print_link_socket_actual (const struct link_socket_actual *act, struct gc_arena *gc)
+print_link_socket_actual(const struct link_socket_actual *act, struct gc_arena *gc)
 {
-  return print_link_socket_actual_ex (act, ":", PS_SHOW_PORT|PS_SHOW_PKTINFO, gc);
+    return print_link_socket_actual_ex(act, ":", PS_SHOW_PORT|PS_SHOW_PKTINFO, gc);
 }
 
 #ifndef IF_NAMESIZE
@@ -2433,62 +2827,70 @@ print_link_socket_actual (const struct link_socket_actual *act, struct gc_arena
 #endif
 
 const char *
-print_link_socket_actual_ex (const struct link_socket_actual *act,
-                            const char *separator,
-                            const unsigned int flags,
-                            struct gc_arena *gc)
+print_link_socket_actual_ex(const struct link_socket_actual *act,
+                            const char *separator,
+                            const unsigned int flags,
+                            struct gc_arena *gc)
 {
-  if (act)
+    if (act)
     {
-      char ifname[IF_NAMESIZE] = "[undef]";
-      struct buffer out = alloc_buf_gc (128, gc);
-      buf_printf (&out, "%s", print_sockaddr_ex (&act->dest.addr.sa, separator, flags, gc));
+        struct buffer out = alloc_buf_gc(128, gc);
+        buf_printf(&out, "%s", print_sockaddr_ex(&act->dest.addr.sa, separator, flags, gc));
 #if ENABLE_IP_PKTINFO
-      if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(act))
-       {
-         switch(act->dest.addr.sa.sa_family)
-           {
-           case AF_INET:
-               {
-                 struct openvpn_sockaddr sa;
-                 CLEAR (sa);
-                 sa.addr.in4.sin_family = AF_INET;
-#ifdef IP_PKTINFO
-                 sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst;
-                 if_indextoname(act->pi.in4.ipi_ifindex, ifname);
+        char ifname[IF_NAMESIZE] = "[undef]";
+
+        if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(act))
+        {
+            switch (act->dest.addr.sa.sa_family)
+            {
+                case AF_INET:
+                {
+                    struct openvpn_sockaddr sa;
+                    CLEAR(sa);
+                    sa.addr.in4.sin_family = AF_INET;
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
+                    sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst;
+                    if_indextoname(act->pi.in4.ipi_ifindex, ifname);
 #elif defined(IP_RECVDSTADDR)
-                 sa.addr.in4.sin_addr = act->pi.in4;
-                 ifname[0]=0;
-#else
+                    sa.addr.in4.sin_addr = act->pi.in4;
+                    ifname[0] = 0;
+#else  /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */
 #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
 #endif
-                 buf_printf (&out, " (via %s%%%s)",
-                             print_sockaddr_ex (&sa.addr.sa, separator, 0, gc),
-                             ifname);
-               }
-             break;
-           case AF_INET6:
-               {
-                 struct sockaddr_in6 sin6;
-                 char buf[INET6_ADDRSTRLEN] = "[undef]";
-                 CLEAR(sin6);
-                 sin6.sin6_family = AF_INET6;
-                 sin6.sin6_addr = act->pi.in6.ipi6_addr;
-                 if_indextoname(act->pi.in6.ipi6_ifindex, ifname);
-                 if (getnameinfo((struct sockaddr *)&sin6, sizeof (struct sockaddr_in6),
-                                 buf, sizeof (buf), NULL, 0, NI_NUMERICHOST) == 0)
-                   buf_printf (&out, " (via %s%%%s)", buf, ifname);
-                 else
-                   buf_printf (&out, " (via [getnameinfo() err]%%%s)", ifname);
-               }
-             break;
-           }
-       }
-#endif
-      return BSTR (&out);
+                    buf_printf(&out, " (via %s%%%s)",
+                               print_sockaddr_ex(&sa.addr.sa, separator, 0, gc),
+                               ifname);
+                }
+                break;
+
+                case AF_INET6:
+                {
+                    struct sockaddr_in6 sin6;
+                    char buf[INET6_ADDRSTRLEN] = "[undef]";
+                    CLEAR(sin6);
+                    sin6.sin6_family = AF_INET6;
+                    sin6.sin6_addr = act->pi.in6.ipi6_addr;
+                    if_indextoname(act->pi.in6.ipi6_ifindex, ifname);
+                    if (getnameinfo((struct sockaddr *)&sin6, sizeof(struct sockaddr_in6),
+                                    buf, sizeof(buf), NULL, 0, NI_NUMERICHOST) == 0)
+                    {
+                        buf_printf(&out, " (via %s%%%s)", buf, ifname);
+                    }
+                    else
+                    {
+                        buf_printf(&out, " (via [getnameinfo() err]%%%s)", ifname);
+                    }
+                }
+                break;
+            }
+        }
+#endif /* if ENABLE_IP_PKTINFO */
+        return BSTR(&out);
+    }
+    else
+    {
+        return "[NULL]";
     }
-  else
-    return "[NULL]";
 }
 
 /*
@@ -2496,19 +2898,19 @@ print_link_socket_actual_ex (const struct link_socket_actual *act,
  * to an ascii dotted quad.
  */
 const char *
-print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc)
+print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc)
 {
-  struct in_addr ia;
-  struct buffer out = alloc_buf_gc (64, gc);
+    struct in_addr ia;
+    char *out = gc_malloc(INET_ADDRSTRLEN, true, gc);
 
-  if (addr || !(flags & IA_EMPTY_IF_UNDEF))
+    if (addr || !(flags & IA_EMPTY_IF_UNDEF))
     {
-      CLEAR (ia);
-      ia.s_addr = (flags & IA_NET_ORDER) ? addr : htonl (addr);
+        CLEAR(ia);
+        ia.s_addr = (flags & IA_NET_ORDER) ? addr : htonl(addr);
 
-      buf_printf (&out, "%s", inet_ntoa (ia));
+        inet_ntop(AF_INET, &ia, out, INET_ADDRSTRLEN);
     }
-  return BSTR (&out);
+    return out;
 }
 
 /*
@@ -2516,116 +2918,148 @@ print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc)
  * to an ascii representation of an IPv6 address
  */
 const char *
-print_in6_addr (struct in6_addr a6, unsigned int flags, struct gc_arena *gc)
+print_in6_addr(struct in6_addr a6, unsigned int flags, struct gc_arena *gc)
 {
-  struct buffer out = alloc_buf_gc (64, gc);
-  char tmp_out_buf[64];                /* inet_ntop wants pointer to buffer */
+    char *out = gc_malloc(INET6_ADDRSTRLEN, true, gc);
 
-  if ( memcmp(&a6, &in6addr_any, sizeof(a6)) != 0 || 
-       !(flags & IA_EMPTY_IF_UNDEF))
+    if (memcmp(&a6, &in6addr_any, sizeof(a6)) != 0
+        || !(flags & IA_EMPTY_IF_UNDEF))
     {
-      inet_ntop (AF_INET6, &a6, tmp_out_buf, sizeof(tmp_out_buf)-1);
-      buf_printf (&out, "%s", tmp_out_buf );
+        inet_ntop(AF_INET6, &a6, out, INET6_ADDRSTRLEN);
     }
-  return BSTR (&out);
+    return out;
+}
+
+/*
+ * Convert an in_port_t in host byte order to a string
+ */
+const char *
+print_in_port_t(in_port_t port, struct gc_arena *gc)
+{
+    struct buffer buffer = alloc_buf_gc(8, gc);
+    buf_printf(&buffer, "%hu", port);
+    return BSTR(&buffer);
 }
 
 #ifndef UINT8_MAX
-# define UINT8_MAX 0xff
+#define UINT8_MAX 0xff
 #endif
 
 /* add some offset to an ipv6 address
  * (add in steps of 8 bits, taking overflow into next round)
  */
-struct in6_addr add_in6_addr( struct in6_addr base, uint32_t add )
+struct in6_addr
+add_in6_addr( struct in6_addr base, uint32_t add )
 {
     int i;
 
-    for( i=15; i>=0 && add > 0 ; i-- )
+    for (i = 15; i>=0 && add > 0; i--)
     {
-       register int carry;
-       register uint32_t h;
+        register int carry;
+        register uint32_t h;
 
-       h = (unsigned char) base.s6_addr[i];
-       base.s6_addr[i] = (h+add) & UINT8_MAX;
+        h = (unsigned char) base.s6_addr[i];
+        base.s6_addr[i] = (h+add) & UINT8_MAX;
 
-       /* using explicit carry for the 8-bit additions will catch
+        /* using explicit carry for the 8-bit additions will catch
          * 8-bit and(!) 32-bit overruns nicely
          */
-       carry = ((h & 0xff)  + (add & 0xff)) >> 8;
-       add = (add>>8) + carry;
+        carry = ((h & 0xff)  + (add & 0xff)) >> 8;
+        add = (add>>8) + carry;
     }
     return base;
 }
 
 /* set environmental variables for ip/port in *addr */
 void
-setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr, const unsigned int flags)
-{
-  char name_buf[256];
-
-  char buf[128];
-  switch(addr->addr.sa.sa_family)
-    {
-    case AF_INET:
-      if (flags & SA_IP_PORT)
-       openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip", name_prefix);
-      else
-       openvpn_snprintf (name_buf, sizeof (name_buf), "%s", name_prefix);
-
-      setenv_str (es, name_buf, inet_ntoa (addr->addr.in4.sin_addr));
-
-      if ((flags & SA_IP_PORT) && addr->addr.in4.sin_port)
-       {
-         openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix);
-         setenv_int (es, name_buf, ntohs (addr->addr.in4.sin_port));
-       }
-      break;
-    case AF_INET6:
-      if ( IN6_IS_ADDR_V4MAPPED( &addr->addr.in6.sin6_addr ))
-       {
-         struct in_addr ia;
-         ia.s_addr = *(in_addr_t *)&addr->addr.in6.sin6_addr.s6_addr[12] ;
-         openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip", name_prefix);
-         openvpn_snprintf (buf, sizeof(buf), "%s", inet_ntoa(ia) );
-       }
-      else
-        {
-         openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip6", name_prefix);
-         getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6),
-                     buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
-       }
-      setenv_str (es, name_buf, buf);
-
-      if ((flags & SA_IP_PORT) && addr->addr.in6.sin6_port)
-       {
-         openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix);
-         setenv_int (es, name_buf, ntohs (addr->addr.in6.sin6_port));
-       }
-      break;
+setenv_sockaddr(struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr, const unsigned int flags)
+{
+    char name_buf[256];
+
+    char buf[INET6_ADDRSTRLEN];
+    switch (addr->addr.sa.sa_family)
+    {
+        case AF_INET:
+            if (flags & SA_IP_PORT)
+            {
+                openvpn_snprintf(name_buf, sizeof(name_buf), "%s_ip", name_prefix);
+            }
+            else
+            {
+                openvpn_snprintf(name_buf, sizeof(name_buf), "%s", name_prefix);
+            }
+
+            inet_ntop(AF_INET, &addr->addr.in4.sin_addr, buf, sizeof(buf));
+            setenv_str(es, name_buf, buf);
+
+            if ((flags & SA_IP_PORT) && addr->addr.in4.sin_port)
+            {
+                openvpn_snprintf(name_buf, sizeof(name_buf), "%s_port", name_prefix);
+                setenv_int(es, name_buf, ntohs(addr->addr.in4.sin_port));
+            }
+            break;
+
+        case AF_INET6:
+            if (IN6_IS_ADDR_V4MAPPED( &addr->addr.in6.sin6_addr ))
+            {
+                struct in_addr ia;
+                memcpy(&ia.s_addr, &addr->addr.in6.sin6_addr.s6_addr[12],
+                       sizeof(ia.s_addr));
+                openvpn_snprintf(name_buf, sizeof(name_buf), "%s_ip", name_prefix);
+                inet_ntop(AF_INET, &ia, buf, sizeof(buf));
+            }
+            else
+            {
+                openvpn_snprintf(name_buf, sizeof(name_buf), "%s_ip6", name_prefix);
+                inet_ntop(AF_INET6, &addr->addr.in6.sin6_addr, buf, sizeof(buf));
+            }
+            setenv_str(es, name_buf, buf);
+
+            if ((flags & SA_IP_PORT) && addr->addr.in6.sin6_port)
+            {
+                openvpn_snprintf(name_buf, sizeof(name_buf), "%s_port", name_prefix);
+                setenv_int(es, name_buf, ntohs(addr->addr.in6.sin6_port));
+            }
+            break;
+    }
+}
+
+void
+setenv_in_addr_t(struct env_set *es, const char *name_prefix, in_addr_t addr, const unsigned int flags)
+{
+    if (addr || !(flags & SA_SET_IF_NONZERO))
+    {
+        struct openvpn_sockaddr si;
+        CLEAR(si);
+        si.addr.in4.sin_family = AF_INET;
+        si.addr.in4.sin_addr.s_addr = htonl(addr);
+        setenv_sockaddr(es, name_prefix, &si, flags);
     }
 }
 
 void
-setenv_in_addr_t (struct env_set *es, const char *name_prefix, in_addr_t addr, const unsigned int flags)
+setenv_in6_addr(struct env_set *es,
+                const char *name_prefix,
+                const struct in6_addr *addr,
+                const unsigned int flags)
 {
-  if (addr || !(flags & SA_SET_IF_NONZERO))
+    if (!IN6_IS_ADDR_UNSPECIFIED(addr) || !(flags & SA_SET_IF_NONZERO))
     {
-      struct openvpn_sockaddr si;
-      CLEAR (si);
-      si.addr.in4.sin_family = AF_INET;
-      si.addr.in4.sin_addr.s_addr = htonl (addr);
-      setenv_sockaddr (es, name_prefix, &si, flags);
+        struct openvpn_sockaddr si;
+        CLEAR(si);
+        si.addr.in6.sin6_family = AF_INET6;
+        si.addr.in6.sin6_addr = *addr;
+        setenv_sockaddr(es, name_prefix, &si, flags);
     }
 }
 
 void
-setenv_link_socket_actual (struct env_set *es,
-                          const char *name_prefix,
-                          const struct link_socket_actual *act,
-                          const unsigned int flags)
+setenv_link_socket_actual(struct env_set *es,
+                          const char *name_prefix,
+                          const struct link_socket_actual *act,
+                          const unsigned int flags)
 {
-  setenv_sockaddr (es, name_prefix, &act->dest, flags);
+    setenv_sockaddr(es, name_prefix, &act->dest, flags);
 }
 
 /*
@@ -2633,123 +3067,109 @@ setenv_link_socket_actual (struct env_set *es,
  */
 
 struct proto_names {
-  const char *short_form;
-  const char *display_form;
-  sa_family_t proto_af;
-  int proto;
+    const char *short_form;
+    const char *display_form;
+    sa_family_t proto_af;
+    int proto;
 };
 
 /* Indexed by PROTO_x */
 static const struct proto_names proto_names[] = {
-  {"proto-uninitialized",        "proto-NONE", AF_UNSPEC, PROTO_NONE},
-  /* try IPv4 and IPv6 (client), bind dual-stack (server) */
-  {"udp",        "UDP", AF_UNSPEC, PROTO_UDP},
-  {"tcp-server", "TCP_SERVER", AF_UNSPEC, PROTO_TCP_SERVER},
-  {"tcp-client", "TCP_CLIENT", AF_UNSPEC, PROTO_TCP_CLIENT},
-  {"tcp",        "TCP", AF_UNSPEC, PROTO_TCP},
-  /* force IPv4 */
-  {"udp4",       "UDPv4", AF_INET, PROTO_UDP},
-  {"tcp4-server","TCPv4_SERVER", AF_INET, PROTO_TCP_SERVER},
-  {"tcp4-client","TCPv4_CLIENT", AF_INET, PROTO_TCP_CLIENT},
-  {"tcp4",       "TCPv4", AF_INET, PROTO_TCP},
-  /* force IPv6 */
-  {"udp6"       ,"UDPv6", AF_INET6, PROTO_UDP},
-  {"tcp6-server","TCPv6_SERVER", AF_INET6, PROTO_TCP_SERVER},
-  {"tcp6-client","TCPv6_CLIENT", AF_INET6, PROTO_TCP_CLIENT},
-  {"tcp6"       ,"TCPv6", AF_INET6, PROTO_TCP},
-};
-
-bool
-proto_is_net(int proto)
-{
-  if (proto < 0 || proto >= PROTO_N)
-    ASSERT(0);
-    return proto != PROTO_NONE;
-}
-bool
-proto_is_dgram(int proto)
-{
-    return proto_is_udp(proto);
-}
-
-bool
-proto_is_udp(int proto)
-{
-  if (proto < 0 || proto >= PROTO_N)
-    ASSERT(0);
-  return proto == PROTO_UDP;
-}
-
-bool
-proto_is_tcp(int proto)
-{
-  if (proto < 0 || proto >= PROTO_N)
-    ASSERT(0);
-  return proto == PROTO_TCP_CLIENT || proto == PROTO_TCP_SERVER;
-}
+    {"proto-uninitialized", "proto-NONE", AF_UNSPEC, PROTO_NONE},
+    /* try IPv4 and IPv6 (client), bind dual-stack (server) */
+    {"udp",         "UDP", AF_UNSPEC, PROTO_UDP},
+    {"tcp-server",  "TCP_SERVER", AF_UNSPEC, PROTO_TCP_SERVER},
+    {"tcp-client",  "TCP_CLIENT", AF_UNSPEC, PROTO_TCP_CLIENT},
+    {"tcp",         "TCP", AF_UNSPEC, PROTO_TCP},
+    /* force IPv4 */
+    {"udp4",        "UDPv4", AF_INET, PROTO_UDP},
+    {"tcp4-server", "TCPv4_SERVER", AF_INET, PROTO_TCP_SERVER},
+    {"tcp4-client", "TCPv4_CLIENT", AF_INET, PROTO_TCP_CLIENT},
+    {"tcp4",        "TCPv4", AF_INET, PROTO_TCP},
+    /* force IPv6 */
+    {"udp6",        "UDPv6", AF_INET6, PROTO_UDP},
+    {"tcp6-server", "TCPv6_SERVER", AF_INET6, PROTO_TCP_SERVER},
+    {"tcp6-client", "TCPv6_CLIENT", AF_INET6, PROTO_TCP_CLIENT},
+    {"tcp6",        "TCPv6", AF_INET6, PROTO_TCP},
+};
 
 int
-ascii2proto (const char* proto_name)
+ascii2proto(const char *proto_name)
 {
-  int i;
-  for (i = 0; i < SIZE (proto_names); ++i)
-    if (!strcmp (proto_name, proto_names[i].short_form))
-      return proto_names[i].proto;
-  return -1;
+    int i;
+    for (i = 0; i < SIZE(proto_names); ++i)
+    {
+        if (!strcmp(proto_name, proto_names[i].short_form))
+        {
+            return proto_names[i].proto;
+        }
+    }
+    return -1;
 }
 
 sa_family_t
-ascii2af (const char* proto_name)
+ascii2af(const char *proto_name)
 {
     int i;
-    for (i = 0; i < SIZE (proto_names); ++i)
-        if (!strcmp (proto_name, proto_names[i].short_form))
+    for (i = 0; i < SIZE(proto_names); ++i)
+    {
+        if (!strcmp(proto_name, proto_names[i].short_form))
+        {
             return proto_names[i].proto_af;
+        }
+    }
     return 0;
 }
 
 const char *
-proto2ascii (int proto, sa_family_t af, bool display_form)
+proto2ascii(int proto, sa_family_t af, bool display_form)
 {
-  unsigned int i;
-  for (i = 0; i < SIZE (proto_names); ++i)
+    unsigned int i;
+    for (i = 0; i < SIZE(proto_names); ++i)
     {
-      if(proto_names[i].proto_af == af && proto_names[i].proto == proto)
+        if (proto_names[i].proto_af == af && proto_names[i].proto == proto)
         {
-          if(display_form)
-              return proto_names[i].display_form;
-          else
-              return proto_names[i].short_form;
+            if (display_form)
+            {
+                return proto_names[i].display_form;
+            }
+            else
+            {
+                return proto_names[i].short_form;
+            }
         }
     }
 
-  return "[unknown protocol]";
+    return "[unknown protocol]";
 }
 
 const char *
-proto2ascii_all (struct gc_arena *gc)
+proto2ascii_all(struct gc_arena *gc)
 {
-  struct buffer out = alloc_buf_gc (256, gc);
-  int i;
+    struct buffer out = alloc_buf_gc(256, gc);
+    int i;
 
-  for (i = 0; i < SIZE (proto_names); ++i)
+    for (i = 0; i < SIZE(proto_names); ++i)
     {
-      if (i)
-       buf_printf(&out, " ");
-      buf_printf(&out, "[%s]", proto_names[i].short_form);
+        if (i)
+        {
+            buf_printf(&out, " ");
+        }
+        buf_printf(&out, "[%s]", proto_names[i].short_form);
     }
-  return BSTR (&out);
+    return BSTR(&out);
 }
 
 const char *
-addr_family_name (int af) 
+addr_family_name(int af)
 {
-  switch (af)
+    switch (af)
     {
-    case AF_INET:  return "AF_INET";
-    case AF_INET6: return "AF_INET6";
+        case AF_INET:  return "AF_INET";
+
+        case AF_INET6: return "AF_INET6";
     }
-  return "AF_UNSPEC";
+    return "AF_UNSPEC";
 }
 
 /*
@@ -2762,24 +3182,30 @@ addr_family_name (int af)
  *
  * IPv6 and IPv4 protocols are comptabile but OpenVPN
  * has always sent UDPv4, TCPv4 over the wire. Keep these
- * strings for backward compatbility
+ * strings for backward compatibility
  */
-const char*
-proto_remote (int proto, bool remote)
+const char *
+proto_remote(int proto, bool remote)
 {
-  ASSERT (proto >= 0 && proto < PROTO_N);
-  if (proto == PROTO_UDP)
-       return "UDPv4";
+    ASSERT(proto >= 0 && proto < PROTO_N);
+    if (proto == PROTO_UDP)
+    {
+        return "UDPv4";
+    }
 
-  if ( (remote && proto == PROTO_TCP_CLIENT) ||
-       (!remote && proto == PROTO_TCP_SERVER))
-       return "TCPv4_SERVER";
-  if ( (remote && proto == PROTO_TCP_SERVER) ||
-       (!remote && proto == PROTO_TCP_CLIENT))
-       return "TCPv4_CLIENT";
+    if ( (remote && proto == PROTO_TCP_CLIENT)
+         || (!remote && proto == PROTO_TCP_SERVER))
+    {
+        return "TCPv4_SERVER";
+    }
+    if ( (remote && proto == PROTO_TCP_SERVER)
+         || (!remote && proto == PROTO_TCP_CLIENT))
+    {
+        return "TCPv4_CLIENT";
+    }
 
-  ASSERT (0);
-  return ""; /* Make the compiler happy */
+    ASSERT(0);
+    return ""; /* Make the compiler happy */
 }
 
 /*
@@ -2787,11 +3213,11 @@ proto_remote (int proto, bool remote)
  * we expect are considered to be fatal errors.
  */
 void
-bad_address_length (int actual, int expected)
+bad_address_length(int actual, int expected)
 {
-  msg (M_FATAL, "ERROR: received strange incoming packet with an address length of %d -- we only accept address lengths of %d.",
-       actual,
-       expected);
+    msg(M_FATAL, "ERROR: received strange incoming packet with an address length of %d -- we only accept address lengths of %d.",
+        actual,
+        expected);
 }
 
 /*
@@ -2799,637 +3225,696 @@ bad_address_length (int actual, int expected)
  */
 
 int
-link_socket_read_tcp (struct link_socket *sock,
-                     struct buffer *buf)
+link_socket_read_tcp(struct link_socket *sock,
+                     struct buffer *buf)
 {
-  int len = 0;
+    int len = 0;
 
-  if (!sock->stream_buf.residual_fully_formed)
+    if (!sock->stream_buf.residual_fully_formed)
     {
-#ifdef WIN32
-      len = socket_finalize (sock->sd, &sock->reads, buf, NULL);
+        /* with Linux-DCO, we sometimes try to access a socket that is
+         * already installed in the kernel and has no valid file descriptor
+         * anymore.  This is a bug.
+         * Handle by resetting client instance instead of crashing.
+         */
+        if (sock->sd == SOCKET_UNDEFINED)
+        {
+            msg(M_INFO, "BUG: link_socket_read_tcp(): sock->sd==-1, reset client instance" );
+            sock->stream_reset = true;              /* reset client instance */
+            return buf->len = 0;                    /* nothing to read */
+        }
+
+#ifdef _WIN32
+        sockethandle_t sh = { .s = sock->sd };
+        len = sockethandle_finalize(sh, &sock->reads, buf, NULL);
 #else
-      struct buffer frag;
-      stream_buf_get_next (&sock->stream_buf, &frag);
-      len = recv (sock->sd, BPTR (&frag), BLEN (&frag), MSG_NOSIGNAL);
+        struct buffer frag;
+        stream_buf_get_next(&sock->stream_buf, &frag);
+        len = recv(sock->sd, BPTR(&frag), BLEN(&frag), MSG_NOSIGNAL);
 #endif
 
-      if (!len)
-       sock->stream_reset = true;
-      if (len <= 0)
-       return buf->len = len;
+        if (!len)
+        {
+            sock->stream_reset = true;
+        }
+        if (len <= 0)
+        {
+            return buf->len = len;
+        }
     }
 
-  if (sock->stream_buf.residual_fully_formed
-      || stream_buf_added (&sock->stream_buf, len)) /* packet complete? */
+    if (sock->stream_buf.residual_fully_formed
+        || stream_buf_added(&sock->stream_buf, len)) /* packet complete? */
+    {
+        stream_buf_get_final(&sock->stream_buf, buf);
+        stream_buf_reset(&sock->stream_buf);
+        return buf->len;
+    }
+    else
     {
-      stream_buf_get_final (&sock->stream_buf, buf);
-      stream_buf_reset (&sock->stream_buf);
-      return buf->len;
+        return buf->len = 0; /* no error, but packet is still incomplete */
     }
-  else
-    return buf->len = 0; /* no error, but packet is still incomplete */
 }
 
-#ifndef WIN32
+#ifndef _WIN32
 
 #if ENABLE_IP_PKTINFO
 
-#pragma pack(1) /* needed to keep structure size consistent for 32 vs. 64-bit architectures */
-struct openvpn_in4_pktinfo
-{
-  struct cmsghdr cmsghdr;
-#ifdef HAVE_IN_PKTINFO
-  struct in_pktinfo pi4;
-#elif defined(IP_RECVDSTADDR)
-  struct in_addr pi4;
+/* make the buffer large enough to handle ancillary socket data for
+ * both IPv4 and IPv6 destination addresses, plus padding (see RFC 2292)
+ */
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
+#define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof(struct in6_pktinfo)), \
+                                  CMSG_SPACE(sizeof(struct in_pktinfo)) )
+#else
+#define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof(struct in6_pktinfo)), \
+                                  CMSG_SPACE(sizeof(struct in_addr)) )
 #endif
-};
-struct openvpn_in6_pktinfo
-{
-  struct cmsghdr cmsghdr;
-  struct in6_pktinfo pi6;
-};
-
-union openvpn_pktinfo {
-       struct openvpn_in4_pktinfo msgpi4;
-       struct openvpn_in6_pktinfo msgpi6;
-};
-#pragma pack()
 
 static socklen_t
-link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
-                                   struct buffer *buf,
-                                   int maxsize,
-                                   struct link_socket_actual *from)
-{
-  struct iovec iov;
-  union openvpn_pktinfo opi;
-  struct msghdr mesg;
-  socklen_t fromlen = sizeof (from->dest.addr);
-
-  iov.iov_base = BPTR (buf);
-  iov.iov_len = maxsize;
-  mesg.msg_iov = &iov;
-  mesg.msg_iovlen = 1;
-  mesg.msg_name = &from->dest.addr;
-  mesg.msg_namelen = fromlen;
-  mesg.msg_control = &opi;
-  mesg.msg_controllen = sizeof opi;
-  buf->len = recvmsg (sock->sd, &mesg, 0);
-  if (buf->len >= 0)
-    {
-      struct cmsghdr *cmsg;
-      fromlen = mesg.msg_namelen;
-      cmsg = CMSG_FIRSTHDR (&mesg);
-      if (cmsg != NULL
-         && CMSG_NXTHDR (&mesg, cmsg) == NULL
-#ifdef IP_PKTINFO
-         && cmsg->cmsg_level == SOL_IP 
-         && cmsg->cmsg_type == IP_PKTINFO
+link_socket_read_udp_posix_recvmsg(struct link_socket *sock,
+                                   struct buffer *buf,
+                                   struct link_socket_actual *from)
+{
+    struct iovec iov;
+    uint8_t pktinfo_buf[PKTINFO_BUF_SIZE];
+    struct msghdr mesg = {0};
+    socklen_t fromlen = sizeof(from->dest.addr);
+
+    ASSERT(sock->sd >= 0);                      /* can't happen */
+
+    iov.iov_base = BPTR(buf);
+    iov.iov_len = buf_forward_capacity_total(buf);
+    mesg.msg_iov = &iov;
+    mesg.msg_iovlen = 1;
+    mesg.msg_name = &from->dest.addr;
+    mesg.msg_namelen = fromlen;
+    mesg.msg_control = pktinfo_buf;
+    mesg.msg_controllen = sizeof pktinfo_buf;
+    buf->len = recvmsg(sock->sd, &mesg, 0);
+    if (buf->len >= 0)
+    {
+        struct cmsghdr *cmsg;
+        fromlen = mesg.msg_namelen;
+        cmsg = CMSG_FIRSTHDR(&mesg);
+        if (cmsg != NULL
+            && CMSG_NXTHDR(&mesg, cmsg) == NULL
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
+            && cmsg->cmsg_level == SOL_IP
+            && cmsg->cmsg_type == IP_PKTINFO
+            && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_pktinfo)) )
 #elif defined(IP_RECVDSTADDR)
-         && cmsg->cmsg_level == IPPROTO_IP
-         && cmsg->cmsg_type == IP_RECVDSTADDR
-#else
+            && cmsg->cmsg_level == IPPROTO_IP
+            && cmsg->cmsg_type == IP_RECVDSTADDR
+            && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_addr)) )
+#else  /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */
 #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
 #endif
-         && cmsg->cmsg_len >= sizeof (struct openvpn_in4_pktinfo))
-       {
-#ifdef IP_PKTINFO
-         struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
-         from->pi.in4.ipi_ifindex = pkti->ipi_ifindex;
-         from->pi.in4.ipi_spec_dst = pkti->ipi_spec_dst;
+        {
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
+            struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA(cmsg);
+            from->pi.in4.ipi_ifindex = pkti->ipi_ifindex;
+            from->pi.in4.ipi_spec_dst = pkti->ipi_spec_dst;
 #elif defined(IP_RECVDSTADDR)
-         from->pi.in4 = *(struct in_addr*) CMSG_DATA (cmsg);
-#else
+            from->pi.in4 = *(struct in_addr *) CMSG_DATA(cmsg);
+#else  /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */
 #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
 #endif
-       }
-      else if (cmsg != NULL
-         && CMSG_NXTHDR (&mesg, cmsg) == NULL
-         && cmsg->cmsg_level == IPPROTO_IPV6 
-         && cmsg->cmsg_type == IPV6_PKTINFO
-         && cmsg->cmsg_len >= sizeof (struct openvpn_in6_pktinfo))
-       {
-         struct in6_pktinfo *pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg);
-         from->pi.in6.ipi6_ifindex = pkti6->ipi6_ifindex;
-         from->pi.in6.ipi6_addr = pkti6->ipi6_addr;
-       }
-      else if (cmsg != NULL)
-       {
-         msg(M_WARN, "CMSG received that cannot be parsed (cmsg_level=%d, cmsg_type=%d, cmsg=len=%d)", (int)cmsg->cmsg_level, (int)cmsg->cmsg_type, (int)cmsg->cmsg_len );
-       }
-    }
-
-  return fromlen;
+        }
+        else if (cmsg != NULL
+                 && CMSG_NXTHDR(&mesg, cmsg) == NULL
+                 && cmsg->cmsg_level == IPPROTO_IPV6
+                 && cmsg->cmsg_type == IPV6_PKTINFO
+                 && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in6_pktinfo)) )
+        {
+            struct in6_pktinfo *pkti6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
+            from->pi.in6.ipi6_ifindex = pkti6->ipi6_ifindex;
+            from->pi.in6.ipi6_addr = pkti6->ipi6_addr;
+        }
+        else if (cmsg != NULL)
+        {
+            msg(M_WARN, "CMSG received that cannot be parsed (cmsg_level=%d, cmsg_type=%d, cmsg=len=%d)", (int)cmsg->cmsg_level, (int)cmsg->cmsg_type, (int)cmsg->cmsg_len );
+        }
+    }
+
+    return fromlen;
 }
-#endif
+#endif /* if ENABLE_IP_PKTINFO */
 
 int
-link_socket_read_udp_posix (struct link_socket *sock,
-                           struct buffer *buf,
-                           int maxsize,
-                           struct link_socket_actual *from)
-{
-  socklen_t fromlen = sizeof (from->dest.addr);
-  socklen_t expectedlen = af_addr_size(sock->info.af);
-  addr_zero_host(&from->dest);
-  ASSERT (buf_safe (buf, maxsize));
+link_socket_read_udp_posix(struct link_socket *sock,
+                           struct buffer *buf,
+                           struct link_socket_actual *from)
+{
+    socklen_t fromlen = sizeof(from->dest.addr);
+    socklen_t expectedlen = af_addr_size(sock->info.af);
+    addr_zero_host(&from->dest);
+
+    ASSERT(sock->sd >= 0);                      /* can't happen */
+
 #if ENABLE_IP_PKTINFO
-  /* Both PROTO_UDPv4 and PROTO_UDPv6 */
-  if (sock->info.proto == PROTO_UDP && sock->sockflags & SF_USE_IP_PKTINFO)
-    fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, maxsize, from);
-  else
+    /* Both PROTO_UDPv4 and PROTO_UDPv6 */
+    if (sock->info.proto == PROTO_UDP && sock->sockflags & SF_USE_IP_PKTINFO)
+    {
+        fromlen = link_socket_read_udp_posix_recvmsg(sock, buf, from);
+    }
+    else
 #endif
-    buf->len = recvfrom (sock->sd, BPTR (buf), maxsize, 0,
-                        &from->dest.addr.sa, &fromlen);
-  /* FIXME: won't do anything when sock->info.af == AF_UNSPEC */
-  if (buf->len >= 0 && expectedlen && fromlen != expectedlen)
-    bad_address_length (fromlen, expectedlen);
-  return buf->len;
+    buf->len = recvfrom(sock->sd, BPTR(buf), buf_forward_capacity(buf), 0,
+                        &from->dest.addr.sa, &fromlen);
+    /* FIXME: won't do anything when sock->info.af == AF_UNSPEC */
+    if (buf->len >= 0 && expectedlen && fromlen != expectedlen)
+    {
+        bad_address_length(fromlen, expectedlen);
+    }
+    return buf->len;
 }
 
-#endif
+#endif /* ifndef _WIN32 */
 
 /*
  * Socket Write Routines
  */
 
 int
-link_socket_write_tcp (struct link_socket *sock,
-                      struct buffer *buf,
-                      struct link_socket_actual *to)
-{
-  packet_size_type len = BLEN (buf);
-  dmsg (D_STREAM_DEBUG, "STREAM: WRITE %d offset=%d", (int)len, buf->offset);
-  ASSERT (len <= sock->stream_buf.maxlen);
-  len = htonps (len);
-  ASSERT (buf_write_prepend (buf, &len, sizeof (len)));
-#ifdef WIN32
-  return link_socket_write_win32 (sock, buf, to);
+link_socket_write_tcp(struct link_socket *sock,
+                      struct buffer *buf,
+                      struct link_socket_actual *to)
+{
+    packet_size_type len = BLEN(buf);
+    dmsg(D_STREAM_DEBUG, "STREAM: WRITE %d offset=%d", (int)len, buf->offset);
+    ASSERT(len <= sock->stream_buf.maxlen);
+    len = htonps(len);
+    ASSERT(buf_write_prepend(buf, &len, sizeof(len)));
+#ifdef _WIN32
+    return link_socket_write_win32(sock, buf, to);
 #else
-  return link_socket_write_tcp_posix (sock, buf, to);  
+    return link_socket_write_tcp_posix(sock, buf, to);
 #endif
 }
 
 #if ENABLE_IP_PKTINFO
 
 size_t
-link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
-                                    struct buffer *buf,
-                                    struct link_socket_actual *to)
-{
-  struct iovec iov;
-  struct msghdr mesg;
-  struct cmsghdr *cmsg;
-  union openvpn_pktinfo opi;
-
-  iov.iov_base = BPTR (buf);
-  iov.iov_len = BLEN (buf);
-  mesg.msg_iov = &iov;
-  mesg.msg_iovlen = 1;
-  switch (to->dest.addr.sa.sa_family)
-    {
-    case AF_INET:
-      {
-        mesg.msg_name = &to->dest.addr.sa;
-        mesg.msg_namelen = sizeof (struct sockaddr_in);
-        mesg.msg_control = &opi;
-        mesg.msg_flags = 0;
-#ifdef HAVE_IN_PKTINFO
-        mesg.msg_controllen = sizeof (struct openvpn_in4_pktinfo);
-        cmsg = CMSG_FIRSTHDR (&mesg);
-        cmsg->cmsg_len = sizeof (struct openvpn_in4_pktinfo);
-        cmsg->cmsg_level = SOL_IP;
-        cmsg->cmsg_type = IP_PKTINFO;
-       {
-        struct in_pktinfo *pkti;
-        pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
-        pkti->ipi_ifindex = to->pi.in4.ipi_ifindex;
-        pkti->ipi_spec_dst = to->pi.in4.ipi_spec_dst;
-        pkti->ipi_addr.s_addr = 0;
-       }
+link_socket_write_udp_posix_sendmsg(struct link_socket *sock,
+                                    struct buffer *buf,
+                                    struct link_socket_actual *to)
+{
+    struct iovec iov;
+    struct msghdr mesg;
+    struct cmsghdr *cmsg;
+    uint8_t pktinfo_buf[PKTINFO_BUF_SIZE];
+
+    iov.iov_base = BPTR(buf);
+    iov.iov_len = BLEN(buf);
+    mesg.msg_iov = &iov;
+    mesg.msg_iovlen = 1;
+    switch (to->dest.addr.sa.sa_family)
+    {
+        case AF_INET:
+        {
+            mesg.msg_name = &to->dest.addr.sa;
+            mesg.msg_namelen = sizeof(struct sockaddr_in);
+            mesg.msg_control = pktinfo_buf;
+            mesg.msg_flags = 0;
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
+            mesg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
+            cmsg = CMSG_FIRSTHDR(&mesg);
+            cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+            cmsg->cmsg_level = SOL_IP;
+            cmsg->cmsg_type = IP_PKTINFO;
+            {
+                struct in_pktinfo *pkti;
+                pkti = (struct in_pktinfo *) CMSG_DATA(cmsg);
+                pkti->ipi_ifindex = to->pi.in4.ipi_ifindex;
+                pkti->ipi_spec_dst = to->pi.in4.ipi_spec_dst;
+                pkti->ipi_addr.s_addr = 0;
+            }
 #elif defined(IP_RECVDSTADDR)
-       ASSERT( CMSG_SPACE(sizeof (struct in_addr)) <= sizeof(opi) );
-        mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_addr));
-        cmsg = CMSG_FIRSTHDR (&mesg);
-        cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
-        cmsg->cmsg_level = IPPROTO_IP;
-        cmsg->cmsg_type = IP_RECVDSTADDR;
-        *(struct in_addr *) CMSG_DATA (cmsg) = to->pi.in4;
-#else
+            ASSERT( CMSG_SPACE(sizeof(struct in_addr)) <= sizeof(pktinfo_buf) );
+            mesg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
+            cmsg = CMSG_FIRSTHDR(&mesg);
+            cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+            cmsg->cmsg_level = IPPROTO_IP;
+            cmsg->cmsg_type = IP_RECVDSTADDR;
+            *(struct in_addr *) CMSG_DATA(cmsg) = to->pi.in4;
+#else  /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */
 #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
-#endif
-        break;
-      }
-    case AF_INET6:
-      {
-        struct in6_pktinfo *pkti6;
-        mesg.msg_name = &to->dest.addr.sa;
-        mesg.msg_namelen = sizeof (struct sockaddr_in6);
-        mesg.msg_control = &opi;
-        mesg.msg_controllen = sizeof (struct openvpn_in6_pktinfo);
-        mesg.msg_flags = 0;
-        cmsg = CMSG_FIRSTHDR (&mesg);
-        cmsg->cmsg_len = sizeof (struct openvpn_in6_pktinfo);
-        cmsg->cmsg_level = IPPROTO_IPV6;
-        cmsg->cmsg_type = IPV6_PKTINFO;
-        pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg);
-        pkti6->ipi6_ifindex = to->pi.in6.ipi6_ifindex;
-        pkti6->ipi6_addr = to->pi.in6.ipi6_addr;
-        break;
-      }
-    default: ASSERT(0);
-    }
-  return sendmsg (sock->sd, &mesg, 0);
+#endif /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */
+            break;
+        }
+
+        case AF_INET6:
+        {
+            struct in6_pktinfo *pkti6;
+            mesg.msg_name = &to->dest.addr.sa;
+            mesg.msg_namelen = sizeof(struct sockaddr_in6);
+
+            ASSERT( CMSG_SPACE(sizeof(struct in6_pktinfo)) <= sizeof(pktinfo_buf) );
+            mesg.msg_control = pktinfo_buf;
+            mesg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
+            mesg.msg_flags = 0;
+            cmsg = CMSG_FIRSTHDR(&mesg);
+            cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+            cmsg->cmsg_level = IPPROTO_IPV6;
+            cmsg->cmsg_type = IPV6_PKTINFO;
+
+            pkti6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
+            pkti6->ipi6_ifindex = to->pi.in6.ipi6_ifindex;
+            pkti6->ipi6_addr = to->pi.in6.ipi6_addr;
+            break;
+        }
+
+        default: ASSERT(0);
+    }
+    return sendmsg(sock->sd, &mesg, 0);
 }
 
-#endif
+#endif /* if ENABLE_IP_PKTINFO */
 
 /*
  * Win32 overlapped socket I/O functions.
  */
 
-#ifdef WIN32
+#ifdef _WIN32
+
+static int
+socket_get_last_error(const struct link_socket *sock)
+{
+    if (socket_is_dco_win(sock))
+    {
+        return GetLastError();
+    }
+
+    return WSAGetLastError();
+}
 
 int
-socket_recv_queue (struct link_socket *sock, int maxsize)
-{
-  if (sock->reads.iostate == IOSTATE_INITIAL)
-    {
-      WSABUF wsabuf[1];
-      int status;
-
-      /* reset buf to its initial state */
-      if (proto_is_udp(sock->info.proto))
-       {
-         sock->reads.buf = sock->reads.buf_init;
-       }
-      else if (proto_is_tcp(sock->info.proto))
-       {
-         stream_buf_get_next (&sock->stream_buf, &sock->reads.buf);
-       }
-      else
-       {
-         ASSERT (0);
-       }
-
-      /* Win32 docs say it's okay to allocate the wsabuf on the stack */
-      wsabuf[0].buf = BPTR (&sock->reads.buf);
-      wsabuf[0].len = maxsize ? maxsize : BLEN (&sock->reads.buf);
-
-      /* check for buffer overflow */
-      ASSERT (wsabuf[0].len <= BLEN (&sock->reads.buf));
-
-      /* the overlapped read will signal this event on I/O completion */
-      ASSERT (ResetEvent (sock->reads.overlapped.hEvent));
-      sock->reads.flags = 0;
-
-      if (proto_is_udp(sock->info.proto))
-       {
-         sock->reads.addr_defined = true;
-         sock->reads.addrlen = sizeof (sock->reads.addr6);
-         status = WSARecvFrom(
-                              sock->sd,
-                              wsabuf,
-                              1,
-                              &sock->reads.size,
-                              &sock->reads.flags,
-                              (struct sockaddr *) &sock->reads.addr,
-                              &sock->reads.addrlen,
-                              &sock->reads.overlapped,
-                              NULL);
-       }
-      else if (proto_is_tcp(sock->info.proto))
-       {
-         sock->reads.addr_defined = false;
-         status = WSARecv(
-                          sock->sd,
-                          wsabuf,
-                          1,
-                          &sock->reads.size,
-                          &sock->reads.flags,
-                          &sock->reads.overlapped,
-                          NULL);
-       }
-      else
-       {
-         status = 0;
-         ASSERT (0);
-       }
-
-      if (!status) /* operation completed immediately? */
-       {
-         /* FIXME: won't do anything when sock->info.af == AF_UNSPEC */
-         int af_len = af_addr_size (sock->info.af);
-         if (sock->reads.addr_defined && af_len && sock->reads.addrlen != af_len)
-           bad_address_length (sock->reads.addrlen, af_len);
-         sock->reads.iostate = IOSTATE_IMMEDIATE_RETURN;
-
-         /* since we got an immediate return, we must signal the event object ourselves */
-         ASSERT (SetEvent (sock->reads.overlapped.hEvent));
-         sock->reads.status = 0;
-
-         dmsg (D_WIN32_IO, "WIN32 I/O: Socket Receive immediate return [%d,%d]",
-              (int) wsabuf[0].len,
-              (int) sock->reads.size);        
-       }
-      else
-       {
-         status = WSAGetLastError (); 
-         if (status == WSA_IO_PENDING) /* operation queued? */
-           {
-             sock->reads.iostate = IOSTATE_QUEUED;
-             sock->reads.status = status;
-             dmsg (D_WIN32_IO, "WIN32 I/O: Socket Receive queued [%d]",
-                  (int) wsabuf[0].len);
-           }
-         else /* error occurred */
-           {
-             struct gc_arena gc = gc_new ();
-             ASSERT (SetEvent (sock->reads.overlapped.hEvent));
-             sock->reads.iostate = IOSTATE_IMMEDIATE_RETURN;
-             sock->reads.status = status;
-             dmsg (D_WIN32_IO, "WIN32 I/O: Socket Receive error [%d]: %s",
-                  (int) wsabuf[0].len,
-                  strerror_win32 (status, &gc));
-             gc_free (&gc);
-           }
-       }
-    }
-  return sock->reads.iostate;
+socket_recv_queue(struct link_socket *sock, int maxsize)
+{
+    if (sock->reads.iostate == IOSTATE_INITIAL)
+    {
+        WSABUF wsabuf[1];
+        int status;
+
+        /* reset buf to its initial state */
+        if (proto_is_udp(sock->info.proto))
+        {
+            sock->reads.buf = sock->reads.buf_init;
+        }
+        else if (proto_is_tcp(sock->info.proto))
+        {
+            stream_buf_get_next(&sock->stream_buf, &sock->reads.buf);
+        }
+        else
+        {
+            ASSERT(0);
+        }
+
+        /* Win32 docs say it's okay to allocate the wsabuf on the stack */
+        wsabuf[0].buf = BSTR(&sock->reads.buf);
+        wsabuf[0].len = maxsize ? maxsize : BLEN(&sock->reads.buf);
+
+        /* check for buffer overflow */
+        ASSERT(wsabuf[0].len <= BLEN(&sock->reads.buf));
+
+        /* the overlapped read will signal this event on I/O completion */
+        ASSERT(ResetEvent(sock->reads.overlapped.hEvent));
+        sock->reads.flags = 0;
+
+        if (socket_is_dco_win(sock))
+        {
+            status = ReadFile((HANDLE)sock->sd, wsabuf[0].buf, wsabuf[0].len,
+                              &sock->reads.size, &sock->reads.overlapped);
+            /* Readfile status is inverted from WSARecv */
+            status = !status;
+        }
+        else if (proto_is_udp(sock->info.proto))
+        {
+            sock->reads.addr_defined = true;
+            sock->reads.addrlen = sizeof(sock->reads.addr6);
+            status = WSARecvFrom(
+                sock->sd,
+                wsabuf,
+                1,
+                &sock->reads.size,
+                &sock->reads.flags,
+                (struct sockaddr *) &sock->reads.addr,
+                &sock->reads.addrlen,
+                &sock->reads.overlapped,
+                NULL);
+        }
+        else if (proto_is_tcp(sock->info.proto))
+        {
+            sock->reads.addr_defined = false;
+            status = WSARecv(
+                sock->sd,
+                wsabuf,
+                1,
+                &sock->reads.size,
+                &sock->reads.flags,
+                &sock->reads.overlapped,
+                NULL);
+        }
+        else
+        {
+            status = 0;
+            ASSERT(0);
+        }
+
+        if (!status) /* operation completed immediately? */
+        {
+            /* FIXME: won't do anything when sock->info.af == AF_UNSPEC */
+            int af_len = af_addr_size(sock->info.af);
+            if (sock->reads.addr_defined && af_len && sock->reads.addrlen != af_len)
+            {
+                bad_address_length(sock->reads.addrlen, af_len);
+            }
+            sock->reads.iostate = IOSTATE_IMMEDIATE_RETURN;
+
+            /* since we got an immediate return, we must signal the event object ourselves */
+            ASSERT(SetEvent(sock->reads.overlapped.hEvent));
+            sock->reads.status = 0;
+
+            dmsg(D_WIN32_IO, "WIN32 I/O: Socket Receive immediate return [%d,%d]",
+                 (int) wsabuf[0].len,
+                 (int) sock->reads.size);
+        }
+        else
+        {
+            status = socket_get_last_error(sock);
+            if (status == WSA_IO_PENDING) /* operation queued? */
+            {
+                sock->reads.iostate = IOSTATE_QUEUED;
+                sock->reads.status = status;
+                dmsg(D_WIN32_IO, "WIN32 I/O: Socket Receive queued [%d]",
+                     (int) wsabuf[0].len);
+            }
+            else /* error occurred */
+            {
+                struct gc_arena gc = gc_new();
+                ASSERT(SetEvent(sock->reads.overlapped.hEvent));
+                sock->reads.iostate = IOSTATE_IMMEDIATE_RETURN;
+                sock->reads.status = status;
+                dmsg(D_WIN32_IO, "WIN32 I/O: Socket Receive error [%d]: %s",
+                     (int) wsabuf[0].len,
+                     strerror_win32(status, &gc));
+                gc_free(&gc);
+            }
+        }
+    }
+    return sock->reads.iostate;
 }
 
 int
-socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct link_socket_actual *to)
-{
-  if (sock->writes.iostate == IOSTATE_INITIAL)
-    {
-      WSABUF wsabuf[1];
-      int status;
-      /* make a private copy of buf */
-      sock->writes.buf = sock->writes.buf_init;
-      sock->writes.buf.len = 0;
-      ASSERT (buf_copy (&sock->writes.buf, buf));
-
-      /* Win32 docs say it's okay to allocate the wsabuf on the stack */
-      wsabuf[0].buf = BPTR (&sock->writes.buf);
-      wsabuf[0].len = BLEN (&sock->writes.buf);
-
-      /* the overlapped write will signal this event on I/O completion */
-      ASSERT (ResetEvent (sock->writes.overlapped.hEvent));
-      sock->writes.flags = 0;
-
-      if (proto_is_udp(sock->info.proto))
-       {
-         /* set destination address for UDP writes */
-         sock->writes.addr_defined = true;
-         if (to->dest.addr.sa.sa_family == AF_INET6)
-           {
-             sock->writes.addr6 = to->dest.addr.in6;
-             sock->writes.addrlen = sizeof (sock->writes.addr6);
-           }
-         else
-           {
-             sock->writes.addr = to->dest.addr.in4;
-             sock->writes.addrlen = sizeof (sock->writes.addr);
-           }
-
-         status = WSASendTo(
-                              sock->sd,
-                              wsabuf,
-                              1,
-                              &sock->writes.size,
-                              sock->writes.flags,
-                              (struct sockaddr *) &sock->writes.addr,
-                              sock->writes.addrlen,
-                              &sock->writes.overlapped,
-                              NULL);
-       }
-      else if (proto_is_tcp(sock->info.proto))
-       {
-         /* destination address for TCP writes was established on connection initiation */
-         sock->writes.addr_defined = false;
-
-         status = WSASend(
-                          sock->sd,
-                          wsabuf,
-                          1,
-                          &sock->writes.size,
-                          sock->writes.flags,
-                          &sock->writes.overlapped,
-                          NULL);
-       }
-      else 
-       {
-         status = 0;
-         ASSERT (0);
-       }
-
-      if (!status) /* operation completed immediately? */
-       {
-         sock->writes.iostate = IOSTATE_IMMEDIATE_RETURN;
-
-         /* since we got an immediate return, we must signal the event object ourselves */
-         ASSERT (SetEvent (sock->writes.overlapped.hEvent));
-
-         sock->writes.status = 0;
-
-         dmsg (D_WIN32_IO, "WIN32 I/O: Socket Send immediate return [%d,%d]",
-              (int) wsabuf[0].len,
-              (int) sock->writes.size);               
-       }
-      else
-       {
-         status = WSAGetLastError (); 
-         if (status == WSA_IO_PENDING) /* operation queued? */
-           {
-             sock->writes.iostate = IOSTATE_QUEUED;
-             sock->writes.status = status;
-             dmsg (D_WIN32_IO, "WIN32 I/O: Socket Send queued [%d]",
-                  (int) wsabuf[0].len);
-           }
-         else /* error occurred */
-           {
-             struct gc_arena gc = gc_new ();
-             ASSERT (SetEvent (sock->writes.overlapped.hEvent));
-             sock->writes.iostate = IOSTATE_IMMEDIATE_RETURN;
-             sock->writes.status = status;
-
-             dmsg (D_WIN32_IO, "WIN32 I/O: Socket Send error [%d]: %s",
-                  (int) wsabuf[0].len,
-                  strerror_win32 (status, &gc));
-
-             gc_free (&gc);
-           }
-       }
-    }
-  return sock->writes.iostate;
+socket_send_queue(struct link_socket *sock, struct buffer *buf, const struct link_socket_actual *to)
+{
+    if (sock->writes.iostate == IOSTATE_INITIAL)
+    {
+        WSABUF wsabuf[1];
+        int status;
+
+        /* make a private copy of buf */
+        sock->writes.buf = sock->writes.buf_init;
+        sock->writes.buf.len = 0;
+        ASSERT(buf_copy(&sock->writes.buf, buf));
+
+        /* Win32 docs say it's okay to allocate the wsabuf on the stack */
+        wsabuf[0].buf = BSTR(&sock->writes.buf);
+        wsabuf[0].len = BLEN(&sock->writes.buf);
+
+        /* the overlapped write will signal this event on I/O completion */
+        ASSERT(ResetEvent(sock->writes.overlapped.hEvent));
+        sock->writes.flags = 0;
+
+        if (socket_is_dco_win(sock))
+        {
+            status = WriteFile((HANDLE)sock->sd, wsabuf[0].buf, wsabuf[0].len,
+                               &sock->writes.size, &sock->writes.overlapped);
+
+            /* WriteFile status is inverted from WSASendTo */
+            status = !status;
+
+        }
+        else if (proto_is_udp(sock->info.proto))
+        {
+            /* set destination address for UDP writes */
+            sock->writes.addr_defined = true;
+            if (to->dest.addr.sa.sa_family == AF_INET6)
+            {
+                sock->writes.addr6 = to->dest.addr.in6;
+                sock->writes.addrlen = sizeof(sock->writes.addr6);
+            }
+            else
+            {
+                sock->writes.addr = to->dest.addr.in4;
+                sock->writes.addrlen = sizeof(sock->writes.addr);
+            }
+
+            status = WSASendTo(
+                sock->sd,
+                wsabuf,
+                1,
+                &sock->writes.size,
+                sock->writes.flags,
+                (struct sockaddr *) &sock->writes.addr,
+                sock->writes.addrlen,
+                &sock->writes.overlapped,
+                NULL);
+        }
+        else if (proto_is_tcp(sock->info.proto))
+        {
+            /* destination address for TCP writes was established on connection initiation */
+            sock->writes.addr_defined = false;
+
+            status = WSASend(
+                sock->sd,
+                wsabuf,
+                1,
+                &sock->writes.size,
+                sock->writes.flags,
+                &sock->writes.overlapped,
+                NULL);
+        }
+        else
+        {
+            status = 0;
+            ASSERT(0);
+        }
+
+        if (!status) /* operation completed immediately? */
+        {
+            sock->writes.iostate = IOSTATE_IMMEDIATE_RETURN;
+
+            /* since we got an immediate return, we must signal the event object ourselves */
+            ASSERT(SetEvent(sock->writes.overlapped.hEvent));
+
+            sock->writes.status = 0;
+
+            dmsg(D_WIN32_IO, "WIN32 I/O: Socket Send immediate return [%d,%d]",
+                 (int) wsabuf[0].len,
+                 (int) sock->writes.size);
+        }
+        else
+        {
+            status = socket_get_last_error(sock);
+            /* both status code have the identical value */
+            if (status == WSA_IO_PENDING || status == ERROR_IO_PENDING) /* operation queued? */
+            {
+                sock->writes.iostate = IOSTATE_QUEUED;
+                sock->writes.status = status;
+                dmsg(D_WIN32_IO, "WIN32 I/O: Socket Send queued [%d]",
+                     (int) wsabuf[0].len);
+            }
+            else /* error occurred */
+            {
+                struct gc_arena gc = gc_new();
+                ASSERT(SetEvent(sock->writes.overlapped.hEvent));
+                sock->writes.iostate = IOSTATE_IMMEDIATE_RETURN;
+                sock->writes.status = status;
+
+                dmsg(D_WIN32_IO, "WIN32 I/O: Socket Send error [%d]: %s",
+                     (int) wsabuf[0].len,
+                     strerror_win32(status, &gc));
+
+                gc_free(&gc);
+            }
+        }
+    }
+    return sock->writes.iostate;
 }
 
+/* Returns the number of bytes successfully read */
 int
-socket_finalize (SOCKET s,
-                struct overlapped_io *io,
-                struct buffer *buf,
-                struct link_socket_actual *from)
-{
-  int ret = -1;
-  BOOL status;
-
-  switch (io->iostate)
-    {
-    case IOSTATE_QUEUED:
-      status = WSAGetOverlappedResult(
-                                     s,
-                                     &io->overlapped,
-                                     &io->size,
-                                     FALSE,
-                                     &io->flags
-                                     );
-      if (status)
-       {
-         /* successful return for a queued operation */
-         if (buf)
-           *buf = io->buf;
-         ret = io->size;
-         io->iostate = IOSTATE_INITIAL;
-         ASSERT (ResetEvent (io->overlapped.hEvent));
-
-         dmsg (D_WIN32_IO, "WIN32 I/O: Socket Completion success [%d]", ret);
-       }
-      else
-       {
-         /* error during a queued operation */
-         ret = -1;
-         if (WSAGetLastError() != WSA_IO_INCOMPLETE)
-           {
-             /* if no error (i.e. just not finished yet), then DON'T execute this code */
-             io->iostate = IOSTATE_INITIAL;
-             ASSERT (ResetEvent (io->overlapped.hEvent));
-             msg (D_WIN32_IO | M_ERRNO, "WIN32 I/O: Socket Completion error");
-           }
-       }
-      break;
-
-    case IOSTATE_IMMEDIATE_RETURN:
-      io->iostate = IOSTATE_INITIAL;
-      ASSERT (ResetEvent (io->overlapped.hEvent));
-      if (io->status)
-       {
-         /* error return for a non-queued operation */
-         WSASetLastError (io->status);
-         ret = -1;
-         msg (D_WIN32_IO | M_ERRNO, "WIN32 I/O: Socket Completion non-queued error");
-       }
-      else
-       {
-         /* successful return for a non-queued operation */
-         if (buf)
-           *buf = io->buf;
-         ret = io->size;
-         dmsg (D_WIN32_IO, "WIN32 I/O: Socket Completion non-queued success [%d]", ret);
-       }
-      break;
-
-    case IOSTATE_INITIAL: /* were we called without proper queueing? */
-      WSASetLastError (WSAEINVAL);
-      ret = -1;
-      dmsg (D_WIN32_IO, "WIN32 I/O: Socket Completion BAD STATE");
-      break;
-
-    default:
-      ASSERT (0);
-    }
-  
-  /* return from address if requested */
-  if (from)
-    {
-      if (ret >= 0 && io->addr_defined)
-       {
-         /* TODO(jjo): streamline this mess */
-         /* in this func we dont have relevant info about the PF_ of this
-          * endpoint, as link_socket_actual will be zero for the 1st received packet
-          *
-          * Test for inets PF_ possible sizes
-          */
-         switch (io->addrlen)
-           {
-           case sizeof(struct sockaddr_in):
-           case sizeof(struct sockaddr_in6):
-           /* TODO(jjo): for some reason (?) I'm getting 24,28 for AF_INET6
-            * under WIN32*/
-           case sizeof(struct sockaddr_in6)-4:
-             break;
-           default:
-             bad_address_length (io->addrlen, af_addr_size(io->addr.sin_family));
-           }
-
-         switch (io->addr.sin_family)
-           {
-           case AF_INET:
-             from->dest.addr.in4 = io->addr;
-             break;
-           case AF_INET6:
-             from->dest.addr.in6 = io->addr6;
-             break;
-           }
-       }
-      else
-       CLEAR (from->dest.addr);
-    }
-  
-  if (buf)
-    buf->len = ret;
-  return ret;
-}
-
-#endif /* WIN32 */
+sockethandle_finalize(sockethandle_t sh,
+                      struct overlapped_io *io,
+                      struct buffer *buf,
+                      struct link_socket_actual *from)
+{
+    int ret = -1;
+    BOOL status;
+
+    switch (io->iostate)
+    {
+        case IOSTATE_QUEUED:
+            status = SocketHandleGetOverlappedResult(sh, io);
+            if (status)
+            {
+                /* successful return for a queued operation */
+                if (buf)
+                {
+                    *buf = io->buf;
+                }
+                ret = io->size;
+                io->iostate = IOSTATE_INITIAL;
+                ASSERT(ResetEvent(io->overlapped.hEvent));
+
+                dmsg(D_WIN32_IO, "WIN32 I/O: Completion success [%d]", ret);
+            }
+            else
+            {
+                /* error during a queued operation */
+                ret = -1;
+                if (SocketHandleGetLastError(sh) != ERROR_IO_INCOMPLETE)
+                {
+                    /* if no error (i.e. just not finished yet), then DON'T execute this code */
+                    io->iostate = IOSTATE_INITIAL;
+                    ASSERT(ResetEvent(io->overlapped.hEvent));
+                    msg(D_WIN32_IO | M_ERRNO, "WIN32 I/O: Completion error");
+                }
+            }
+            break;
+
+        case IOSTATE_IMMEDIATE_RETURN:
+            io->iostate = IOSTATE_INITIAL;
+            ASSERT(ResetEvent(io->overlapped.hEvent));
+            if (io->status)
+            {
+                /* error return for a non-queued operation */
+                SocketHandleSetLastError(sh, io->status);
+                ret = -1;
+                msg(D_WIN32_IO | M_ERRNO, "WIN32 I/O: Completion non-queued error");
+            }
+            else
+            {
+                /* successful return for a non-queued operation */
+                if (buf)
+                {
+                    *buf = io->buf;
+                }
+                ret = io->size;
+                dmsg(D_WIN32_IO, "WIN32 I/O: Completion non-queued success [%d]", ret);
+            }
+            break;
+
+        case IOSTATE_INITIAL: /* were we called without proper queueing? */
+            SocketHandleSetInvalError(sh);
+            ret = -1;
+            dmsg(D_WIN32_IO, "WIN32 I/O: Completion BAD STATE");
+            break;
+
+        default:
+            ASSERT(0);
+    }
+
+    /* return from address if requested */
+    if (!sh.is_handle && from)
+    {
+        if (ret >= 0 && io->addr_defined)
+        {
+            /* TODO(jjo): streamline this mess */
+            /* in this func we don't have relevant info about the PF_ of this
+             * endpoint, as link_socket_actual will be zero for the 1st received packet
+             *
+             * Test for inets PF_ possible sizes
+             */
+            switch (io->addrlen)
+            {
+                case sizeof(struct sockaddr_in):
+                case sizeof(struct sockaddr_in6):
+                /* TODO(jjo): for some reason (?) I'm getting 24,28 for AF_INET6
+                 * under _WIN32*/
+                case sizeof(struct sockaddr_in6)-4:
+                    break;
+
+                default:
+                    bad_address_length(io->addrlen, af_addr_size(io->addr.sin_family));
+            }
+
+            switch (io->addr.sin_family)
+            {
+                case AF_INET:
+                    from->dest.addr.in4 = io->addr;
+                    break;
+
+                case AF_INET6:
+                    from->dest.addr.in6 = io->addr6;
+                    break;
+            }
+        }
+        else
+        {
+            CLEAR(from->dest.addr);
+        }
+    }
+
+    if (buf)
+    {
+        buf->len = ret;
+    }
+    return ret;
+}
+
+#endif /* _WIN32 */
 
 /*
  * Socket event notification
  */
 
 unsigned int
-socket_set (struct link_socket *s,
-           struct event_set *es,
-           unsigned int rwflags,
-           void *arg,
-           unsigned int *persistent)
-{
-  if (s)
-    {
-      if ((rwflags & EVENT_READ) && !stream_buf_read_setup (s))
-       {
-         ASSERT (!persistent);
-         rwflags &= ~EVENT_READ;
-       }
-      
-#ifdef WIN32
-      if (rwflags & EVENT_READ)
-       socket_recv_queue (s, 0);
+socket_set(struct link_socket *s,
+           struct event_set *es,
+           unsigned int rwflags,
+           void *arg,
+           unsigned int *persistent)
+{
+    if (s)
+    {
+        if ((rwflags & EVENT_READ) && !stream_buf_read_setup(s))
+        {
+            ASSERT(!persistent);
+            rwflags &= ~EVENT_READ;
+        }
+
+#ifdef _WIN32
+        if (rwflags & EVENT_READ)
+        {
+            socket_recv_queue(s, 0);
+        }
 #endif
 
-      /* if persistent is defined, call event_ctl only if rwflags has changed since last call */
-      if (!persistent || *persistent != rwflags)
-       {
-         event_ctl (es, socket_event_handle (s), rwflags, arg);
-         if (persistent)
-           *persistent = rwflags;
-       }
+        /* if persistent is defined, call event_ctl only if rwflags has changed since last call */
+        if (!persistent || *persistent != rwflags)
+        {
+            event_ctl(es, socket_event_handle(s), rwflags, arg);
+            if (persistent)
+            {
+                *persistent = rwflags;
+            }
+        }
 
-      s->rwflags_debug = rwflags;
+        s->rwflags_debug = rwflags;
     }
-  return rwflags;
+    return rwflags;
 }
 
 void
-sd_close (socket_descriptor_t *sd)
+sd_close(socket_descriptor_t *sd)
 {
-  if (sd && socket_defined (*sd))
+    if (sd && socket_defined(*sd))
     {
-      openvpn_close_socket (*sd);
-      *sd = SOCKET_UNDEFINED;
+        openvpn_close_socket(*sd);
+        *sd = SOCKET_UNDEFINED;
     }
 }
 
@@ -3440,117 +3925,141 @@ sd_close (socket_descriptor_t *sd)
  */
 
 const char *
-sockaddr_unix_name (const struct sockaddr_un *local, const char *null)
+sockaddr_unix_name(const struct sockaddr_un *local, const char *null)
 {
-  if (local && local->sun_family == PF_UNIX)
-    return local->sun_path;
-  else
-    return null;
+    if (local && local->sun_family == PF_UNIX)
+    {
+        return local->sun_path;
+    }
+    else
+    {
+        return null;
+    }
 }
 
 socket_descriptor_t
-create_socket_unix (void)
+create_socket_unix(void)
 {
-  socket_descriptor_t sd;
+    socket_descriptor_t sd;
+
+    if ((sd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
+    {
+        msg(M_ERR, "Cannot create unix domain socket");
+    }
 
-  if ((sd = socket (PF_UNIX, SOCK_STREAM, 0)) < 0)
-    msg (M_ERR, "Cannot create unix domain socket");
-  return sd;
+    /* set socket file descriptor to not pass across execs, so that
+     * scripts don't have access to it */
+    set_cloexec(sd);
+
+    return sd;
 }
 
 void
-socket_bind_unix (socket_descriptor_t sd,
-                 struct sockaddr_un *local,
-                 const char *prefix)
+socket_bind_unix(socket_descriptor_t sd,
+                 struct sockaddr_un *local,
+                 const char *prefix)
 {
-  struct gc_arena gc = gc_new ();
-
-#ifdef HAVE_UMASK
-  const mode_t orig_umask = umask (0);
-#endif
+    struct gc_arena gc = gc_new();
+    const mode_t orig_umask = umask(0);
 
-  if (bind (sd, (struct sockaddr *) local, sizeof (struct sockaddr_un)))
+    if (bind(sd, (struct sockaddr *) local, sizeof(struct sockaddr_un)))
     {
-      const int errnum = openvpn_errno ();
-      msg (M_FATAL, "%s: Socket bind[%d] failed on unix domain socket %s: %s",
-          prefix,
-          (int)sd,
-           sockaddr_unix_name (local, "NULL"),
-           strerror_ts (errnum, &gc));
+        msg(M_FATAL | M_ERRNO,
+            "%s: Socket bind[%d] failed on unix domain socket %s",
+            prefix,
+            (int)sd,
+            sockaddr_unix_name(local, "NULL"));
     }
 
-#ifdef HAVE_UMASK
-  umask (orig_umask);
-#endif
-
-  gc_free (&gc);
+    umask(orig_umask);
+    gc_free(&gc);
 }
 
 socket_descriptor_t
-socket_accept_unix (socket_descriptor_t sd,
-                   struct sockaddr_un *remote)
+socket_accept_unix(socket_descriptor_t sd,
+                   struct sockaddr_un *remote)
 {
-  socklen_t remote_len = sizeof (struct sockaddr_un);
-  socket_descriptor_t ret;
+    socklen_t remote_len = sizeof(struct sockaddr_un);
+    socket_descriptor_t ret;
 
-  CLEAR (*remote);
-  ret = accept (sd, (struct sockaddr *) remote, &remote_len);
-  return ret;
+    CLEAR(*remote);
+    ret = accept(sd, (struct sockaddr *) remote, &remote_len);
+    if (ret >= 0)
+    {
+        /* set socket file descriptor to not pass across execs, so that
+         * scripts don't have access to it */
+        set_cloexec(ret);
+    }
+    return ret;
 }
 
 int
-socket_connect_unix (socket_descriptor_t sd,
-                    struct sockaddr_un *remote)
+socket_connect_unix(socket_descriptor_t sd,
+                    struct sockaddr_un *remote)
 {
-  int status = connect (sd, (struct sockaddr *) remote, sizeof (struct sockaddr_un));
-  if (status)
-    status = openvpn_errno ();
-  return status;
+    int status = connect(sd, (struct sockaddr *) remote, sizeof(struct sockaddr_un));
+    if (status)
+    {
+        status = openvpn_errno();
+    }
+    return status;
 }
 
 void
-sockaddr_unix_init (struct sockaddr_un *local, const char *path)
+sockaddr_unix_init(struct sockaddr_un *local, const char *path)
 {
-  local->sun_family = PF_UNIX;
-  strncpynt (local->sun_path, path, sizeof (local->sun_path));
+    local->sun_family = PF_UNIX;
+    strncpynt(local->sun_path, path, sizeof(local->sun_path));
 }
 
 void
-socket_delete_unix (const struct sockaddr_un *local)
+socket_delete_unix(const struct sockaddr_un *local)
 {
-  const char *name = sockaddr_unix_name (local, NULL);
-#ifdef HAVE_UNLINK
-  if (name && strlen (name))
-    unlink (name);
-#endif
+    const char *name = sockaddr_unix_name(local, NULL);
+    if (name && strlen(name))
+    {
+        unlink(name);
+    }
 }
 
 bool
-unix_socket_get_peer_uid_gid (const socket_descriptor_t sd, int *uid, int *gid)
+unix_socket_get_peer_uid_gid(const socket_descriptor_t sd, int *uid, int *gid)
 {
 #ifdef HAVE_GETPEEREID
-  uid_t u;
-  gid_t g;
-  if (getpeereid (sd, &u, &g) == -1) 
-    return false;
-  if (uid)
-    *uid = u;
-  if (gid)
-    *gid = g;
-  return true;
+    uid_t u;
+    gid_t g;
+    if (getpeereid(sd, &u, &g) == -1)
+    {
+        return false;
+    }
+    if (uid)
+    {
+        *uid = u;
+    }
+    if (gid)
+    {
+        *gid = g;
+    }
+    return true;
 #elif defined(SO_PEERCRED)
-  struct ucred peercred;
-  socklen_t so_len = sizeof(peercred);
-  if (getsockopt(sd, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) == -1) 
+    struct ucred peercred;
+    socklen_t so_len = sizeof(peercred);
+    if (getsockopt(sd, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) == -1)
+    {
+        return false;
+    }
+    if (uid)
+    {
+        *uid = peercred.uid;
+    }
+    if (gid)
+    {
+        *gid = peercred.gid;
+    }
+    return true;
+#else  /* ifdef HAVE_GETPEEREID */
     return false;
-  if (uid)
-    *uid = peercred.uid;
-  if (gid)
-    *gid = peercred.gid;
-  return true;
-#else
-  return false;
-#endif
+#endif /* ifdef HAVE_GETPEEREID */
 }
 
-#endif
+#endif /* if UNIX_SOCK_SUPPORT */