]> 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 82d0967d1a8cd7689d47f86b4caf11d6f539d5b9..480f4e51c7eea6062b45a92f80ccbbfa49a5902a 100644 (file)
@@ -5,7 +5,7 @@
  *             packet encryption, packet authentication, and
  *             packet compression.
  *
- *  Copyright (C) 2002-2017 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"
@@ -36,6 +33,7 @@
 #include "gremlin.h"
 #include "plugin.h"
 #include "ps.h"
+#include "run_command.h"
 #include "manage.h"
 #include "misc.h"
 #include "manage.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
  */
@@ -75,33 +62,140 @@ sf2gaf(const unsigned int 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;
+
+    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);
+    free(var_host);
+
+    return ret;
+}
 
-/*
- * 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 signal_info *sig_info)
 {
-    struct addrinfo *ai;
+    in_addr_t addr;
     int status;
-    status = openvpn_getaddrinfo(flags & ~GETADDR_HOST_ORDER, hostname, NULL,
-                                 resolve_retry_seconds, signal_received, AF_INET, &ai);
+
+    status = get_addr_generic(AF_INET, flags, hostname, &addr, NULL,
+                              resolve_retry_seconds, sig_info,
+                              M_WARN);
     if (status==0)
     {
-        struct in_addr ia;
         if (succeeded)
         {
             *succeeded = true;
         }
-        ia = ((struct sockaddr_in *)ai->ai_addr)->sin_addr;
-        freeaddrinfo(ai);
-        return (flags & GETADDR_HOST_ORDER) ? ntohl(ia.s_addr) : ia.s_addr;
+        return addr;
     }
     else
     {
@@ -113,6 +207,19 @@ getaddr(unsigned int flags,
     }
 }
 
+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)
 {
@@ -258,7 +365,8 @@ do_preresolve(struct context *c)
         /* 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);
+            status = do_preresolve_host(c, remote, ce->remote_port,
+                                        ce->af, flags);
             if (status != 0)
             {
                 goto err;
@@ -297,7 +405,8 @@ do_preresolve(struct context *c)
         {
             flags |= GETADDR_PASSIVE;
             flags &= ~GETADDR_RANDOMIZE;
-            status = do_preresolve_host(c, ce->local, ce->local_port, ce->af, flags);
+            status = do_preresolve_host(c, ce->local, ce->local_port,
+                                        ce->af, flags);
             if (status != 0)
             {
                 goto err;
@@ -321,13 +430,13 @@ openvpn_getaddrinfo(unsigned int flags,
                     const char *hostname,
                     const char *servname,
                     int resolve_retry_seconds,
-                    volatile int *signal_received,
+                    struct signal_info *sig_info,
                     int ai_family,
                     struct addrinfo **res)
 {
     struct addrinfo hints;
     int status;
-    int sigrec = 0;
+    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;
@@ -338,20 +447,6 @@ openvpn_getaddrinfo(unsigned int flags,
     ASSERT(hostname || servname);
     ASSERT(!(flags & GETADDR_HOST_ORDER));
 
-    if (hostname && (flags & GETADDR_RANDOMIZE))
-    {
-        hostname = hostname_randomize(hostname, &gc);
-    }
-
-    if (hostname)
-    {
-        print_hostname = hostname;
-    }
-    else
-    {
-        print_hostname = "undefined";
-    }
-
     if (servname)
     {
         print_servname = servname;
@@ -367,9 +462,9 @@ openvpn_getaddrinfo(unsigned int flags,
     }
 
     if ((flags & (GETADDR_FATAL_ON_SIGNAL|GETADDR_WARN_ON_SIGNAL))
-        && !signal_received)
+        && !sig_info)
     {
-        signal_received = &sigrec;
+        sig_info = &sigrec;
     }
 
     /* try numeric ipv6 addr first */
@@ -402,17 +497,33 @@ openvpn_getaddrinfo(unsigned int flags,
         const char *fmt;
         int level = 0;
 
+        if (hostname && (flags & GETADDR_RANDOMIZE))
+        {
+            hostname = hostname_randomize(hostname, &gc);
+        }
+
+        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) "
+                  "(I would have retried this name query if you had "
+                  "specified the --resolv-retry option.)";
         }
 
         if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL)
         {
             msg(msglevel, "RESOLVE: Cannot parse IP address: %s:%s (%s)",
-                print_hostname,print_servname, gai_strerror(status));
+                print_hostname, print_servname, gai_strerror(status));
             goto done;
         }
 
@@ -438,23 +549,27 @@ openvpn_getaddrinfo(unsigned int flags,
         while (true)
         {
 #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",
+            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)
+            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
                     {
@@ -497,7 +612,7 @@ openvpn_getaddrinfo(unsigned int flags,
                 goto done;
             }
 
-            openvpn_sleep(fail_wait_interval);
+            management_sleep(fail_wait_interval);
         }
 
         ASSERT(res);
@@ -512,10 +627,16 @@ openvpn_getaddrinfo(unsigned int flags,
     else
     {
         /* 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)
+    if (sig_info && sig_info->signal_received)
     {
         int level = 0;
         if (flags & GETADDR_FATAL_ON_SIGNAL)
@@ -712,9 +833,9 @@ mac_addr_safe(const char *mac_addr)
 }
 
 static int
-socket_get_sndbuf(int sd)
+socket_get_sndbuf(socket_descriptor_t sd)
 {
-#if defined(HAVE_GETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_SNDBUF)
+#if defined(SOL_SOCKET) && defined(SO_SNDBUF)
     int val;
     socklen_t len;
 
@@ -729,9 +850,9 @@ socket_get_sndbuf(int sd)
 }
 
 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 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);
@@ -740,9 +861,9 @@ socket_set_sndbuf(int sd, int size)
 }
 
 static int
-socket_get_rcvbuf(int sd)
+socket_get_rcvbuf(socket_descriptor_t sd)
 {
-#if defined(HAVE_GETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_RCVBUF)
+#if defined(SOL_SOCKET) && defined(SO_RCVBUF)
     int val;
     socklen_t len;
 
@@ -757,9 +878,9 @@ socket_get_rcvbuf(int sd)
 }
 
 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 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);
@@ -770,7 +891,7 @@ socket_set_rcvbuf(int sd, int size)
 }
 
 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)
     {
@@ -800,9 +921,9 @@ 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 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);
@@ -813,14 +934,14 @@ socket_set_tcp_nodelay(int sd, int state)
         dmsg(D_OSBUF, "Socket flags: TCP_NODELAY=%d succeeded", state);
         return true;
     }
-#else  /* if defined(_WIN32) || (defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP) && defined(TCP_NODELAY)) */
+#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)
@@ -831,9 +952,10 @@ socket_set_mark(int sd, int mark)
 }
 
 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)
+    /* 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);
     }
@@ -848,7 +970,8 @@ 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);
+        ls->sockflags |= sockflags;
+        return socket_set_flags(ls->sd, ls->sockflags);
     }
     else
     {
@@ -868,7 +991,7 @@ link_socket_update_buffer_sizes(struct link_socket *ls, int rcvbuf, int sndbuf)
 }
 
 /*
- * SOCKET INITALIZATION CODE.
+ * SOCKET INITIALIZATION CODE.
  * Create a TCP/UDP socket
  */
 
@@ -1008,12 +1131,28 @@ create_socket(struct link_socket *sock, struct addrinfo *addr)
     {
         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);
 
     /* set socket to --mark packets with given value */
     socket_set_mark(sock->sd, sock->mark);
 
+#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);
 }
 
@@ -1021,6 +1160,11 @@ create_socket(struct link_socket *sock, struct addrinfo *addr)
 static void
 protect_fd_nonlocal(int fd, const struct sockaddr *addr)
 {
+    if (!management)
+    {
+        msg(M_FATAL, "Required management interface not available.");
+    }
+
     /* pass socket FD to management interface to pass on to VPNService API
      * as "protected socket" (exempt from being routed into tunnel)
      */
@@ -1051,7 +1195,7 @@ socket_do_listen(socket_descriptor_t sd,
         ASSERT(local);
         msg(M_INFO, "Listening for incoming TCP connection on %s",
             print_sockaddr(local->ai_addr, &gc));
-        if (listen(sd, 1))
+        if (listen(sd, 32))
         {
             msg(M_ERR, "TCP: listen() failed");
         }
@@ -1081,7 +1225,6 @@ socket_do_accept(socket_descriptor_t sd,
 
     CLEAR(*act);
 
-#ifdef HAVE_GETPEERNAME
     if (nowait)
     {
         new_sd = getpeername(sd, &act->dest.addr.sa, &remote_len);
@@ -1095,12 +1238,6 @@ socket_do_accept(socket_descriptor_t sd,
             new_sd = sd;
         }
     }
-#else  /* ifdef HAVE_GETPEERNAME */
-    if (nowait)
-    {
-        msg(M_WARN, "TCP: this OS does not provide the getpeername() function");
-    }
-#endif
     else
     {
         new_sd = accept(sd, &act->dest.addr.sa, &remote_len);
@@ -1119,7 +1256,7 @@ socket_do_accept(socket_descriptor_t 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)
@@ -1146,7 +1283,7 @@ tcp_connection_established(const struct link_socket_actual *act)
     gc_free(&gc);
 }
 
-static int
+static socket_descriptor_t
 socket_listen_accept(socket_descriptor_t sd,
                      struct link_socket_actual *act,
                      const char *remote_dynamic,
@@ -1158,7 +1295,7 @@ socket_listen_accept(socket_descriptor_t sd,
     struct gc_arena gc = gc_new();
     /* struct openvpn_sockaddr *remote = &act->dest; */
     struct openvpn_sockaddr remote_verify = act->dest;
-    int new_sd = SOCKET_UNDEFINED;
+    socket_descriptor_t new_sd = SOCKET_UNDEFINED;
 
     CLEAR(*act);
     socket_do_listen(sd, local, do_listen, true);
@@ -1190,7 +1327,7 @@ socket_listen_accept(socket_descriptor_t sd,
 
         if (status <= 0)
         {
-            openvpn_sleep(1);
+            management_sleep(1);
             continue;
         }
 
@@ -1225,7 +1362,7 @@ socket_listen_accept(socket_descriptor_t sd,
                 break;
             }
         }
-        openvpn_sleep(1);
+        management_sleep(1);
     }
 
     if (!nowait && openvpn_close_socket(sd))
@@ -1239,14 +1376,6 @@ socket_listen_accept(socket_descriptor_t sd,
     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,
@@ -1294,11 +1423,9 @@ socket_bind(socket_descriptor_t sd,
     }
     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",
+        msg(M_FATAL | M_ERRNO, "%s: Socket bind failed on local address %s",
             prefix,
-            print_sockaddr_ex(local->ai_addr, ":", PS_SHOW_PORT, &gc),
-            strerror_ts(errnum, &gc));
+            print_sockaddr_ex(local->ai_addr, ":", PS_SHOW_PORT, &gc));
     }
     gc_free(&gc);
 }
@@ -1315,7 +1442,6 @@ openvpn_connect(socket_descriptor_t sd,
     protect_fd_nonlocal(sd, remote);
 #endif
 
-#ifdef CONNECT_NONBLOCK
     set_nonblock(sd);
     status = connect(sd, remote, af_addr_size(remote->sa_family));
     if (status)
@@ -1336,14 +1462,14 @@ openvpn_connect(socket_descriptor_t sd,
             struct pollfd fds[1];
             fds[0].fd = sd;
             fds[0].events = POLLOUT;
-            status = poll(fds, 1, 0);
+            status = poll(fds, 1, (connect_timeout > 0) ? 1000 : 0);
 #else
             fd_set writes;
             struct timeval tv;
 
             FD_ZERO(&writes);
             openvpn_fd_set(sd, &writes);
-            tv.tv_sec = 0;
+            tv.tv_sec = (connect_timeout > 0) ? 1 : 0;
             tv.tv_usec = 0;
 
             status = select(sd + 1, NULL, &writes, NULL, &tv);
@@ -1373,7 +1499,7 @@ openvpn_connect(socket_descriptor_t sd,
 #endif
                     break;
                 }
-                openvpn_sleep(1);
+                management_sleep(0);
                 continue;
             }
 
@@ -1396,13 +1522,6 @@ openvpn_connect(socket_descriptor_t sd,
             }
         }
     }
-#else  /* ifdef CONNECT_NONBLOCK */
-    status = connect(sd, remote, af_addr_size(remote->sa_family));
-    if (status)
-    {
-        status = openvpn_errno();
-    }
-#endif /* ifdef CONNECT_NONBLOCK */
 
     return status;
 }
@@ -1430,7 +1549,7 @@ set_actual_address(struct link_socket_actual *actual, struct addrinfo *ai)
 
 }
 
-void
+static void
 socket_connect(socket_descriptor_t *sd,
                const struct sockaddr *dest,
                const int connect_timeout,
@@ -1439,13 +1558,8 @@ socket_connect(socket_descriptor_t *sd,
     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
 
 #ifdef ENABLE_MANAGEMENT
     if (management)
@@ -1472,15 +1586,12 @@ socket_connect(socket_descriptor_t *sd,
     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;
+        register_signal(sig_info, SIGUSR1, "connection-failed");
     }
     else
     {
@@ -1492,6 +1603,22 @@ 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. */
 
@@ -1499,8 +1626,8 @@ static void
 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);
+    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
@@ -1513,10 +1640,7 @@ socket_frame_init(const struct frame *frame, struct link_socket *sock)
                         sock->sockflags,
                         sock->info.proto);
 #else
-        alloc_buf_sock_tun(&sock->stream_buf_data,
-                           frame,
-                           false,
-                           FRAME_HEADROOM_MARKER_READ_STREAM);
+        alloc_buf_sock_tun(&sock->stream_buf_data, frame);
 
         stream_buf_init(&sock->stream_buf,
                         &sock->stream_buf_data,
@@ -1526,16 +1650,6 @@ socket_frame_init(const struct frame *frame, struct link_socket *sock)
     }
 }
 
-/*
- * 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)
-{
-    frame_set_mtu_dynamic(frame, pmtu - datagram_overhead(proto), SET_MTU_UPPER_BOUND);
-}
-
 static void
 resolve_bind_local(struct link_socket *sock, const sa_family_t af)
 {
@@ -1582,8 +1696,9 @@ static void
 resolve_remote(struct link_socket *sock,
                int phase,
                const char **remote_dynamic,
-               volatile int *signal_received)
+               struct signal_info *sig_info)
 {
+    volatile int *signal_received = sig_info ? &sig_info->signal_received : NULL;
     struct gc_arena gc = gc_new();
 
     /* resolve remote address if undefined */
@@ -1646,7 +1761,7 @@ resolve_remote(struct link_socket *sock,
             if (status)
             {
                 status = openvpn_getaddrinfo(flags, sock->remote_host, sock->remote_port,
-                                             retry, signal_received, sock->info.af, &ai);
+                                             retry, sig_info, sock->info.af, &ai);
             }
 
             if (status == 0)
@@ -1654,25 +1769,24 @@ resolve_remote(struct link_socket *sock,
                 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",
+                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 && *signal_received)
             {
-                if (*signal_received)
-                {
-                    goto done;
-                }
+                goto done;
             }
             if (status!=0)
             {
                 if (signal_received)
                 {
-                    *signal_received = SIGUSR1;
+                    /* potential overwrite of signal */
+                    register_signal(sig_info, SIGUSR1, "socks-resolve-failure");
                 }
                 goto done;
             }
@@ -1717,87 +1831,70 @@ link_socket_new(void)
 }
 
 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 mtu_discover_type,
-                        int rcvbuf,
-                        int sndbuf,
-                        int mark,
-                        struct event_timeout *server_poll_timeout,
-                        unsigned int sockflags)
+link_socket_init_phase1(struct context *c, int mode)
 {
+    struct link_socket *sock = c->c2.link_socket;
+    struct options *o = &c->options;
     ASSERT(sock);
 
-    sock->local_host = local_host;
-    sock->local_port = local_port;
+    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 = 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->mtu_discover_type = mtu_discover_type;
+    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->sockflags = sockflags;
-    sock->mark = mark;
+    sock->socket_buffer_sizes.rcvbuf = o->rcvbuf;
+    sock->socket_buffer_sizes.sndbuf = o->sndbuf;
 
-    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->server_poll_timeout = server_poll_timeout;
+    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 = 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)
     {
-        ASSERT(accept_from);
+        ASSERT(c->c2.accept_from);
         ASSERT(sock->info.proto == PROTO_TCP_SERVER);
-        ASSERT(!sock->inetd);
-        sock->sd = accept_from->sd;
+        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)
     {
         ASSERT(sock->info.proto == PROTO_TCP_CLIENT);
-        ASSERT(!sock->inetd);
 
         /* the proxy server */
-        sock->remote_host = http_proxy->options.server;
-        sock->remote_port = http_proxy->options.port;
+        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;
@@ -1806,11 +1903,9 @@ link_socket_init_phase1(struct link_socket *sock,
     /* 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;
+        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;
@@ -1835,15 +1930,7 @@ link_socket_init_phase1(struct link_socket *sock,
         }
     }
 
-    /* were we started by inetd or xinetd? */
-    if (sock->inetd)
-    {
-        ASSERT(sock->info.proto != PROTO_TCP_CLIENT);
-        ASSERT(socket_defined(inetd_socket_descriptor));
-        sock->sd = inetd_socket_descriptor;
-        set_cloexec(sock->sd);          /* not created by create_socket*() */
-    }
-    else if (mode != LS_MODE_TCP_ACCEPT_FROM)
+    if (mode != LS_MODE_TCP_ACCEPT_FROM)
     {
         if (sock->bind_local)
         {
@@ -1853,53 +1940,6 @@ link_socket_init_phase1(struct link_socket *sock,
     }
 }
 
-static
-void
-phase2_inetd(struct link_socket *sock, const struct frame *frame,
-             const char *remote_dynamic, volatile int *signal_received)
-{
-    bool remote_changed = false;
-
-    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
-        {
-            /* 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);
-            }
-        }
-#else  /* ifdef HAVE_GETSOCKNAME */
-        msg(M_WARN, "inetd(%s): this OS does not provide the getsockname() "
-            "function, using AF_INET",
-            proto2ascii(sock->info.proto, false));
-#endif /* ifdef HAVE_GETSOCKNAME */
-        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);
-}
-
 static void
 phase2_set_socket_flags(struct link_socket *sock)
 {
@@ -1914,7 +1954,7 @@ phase2_set_socket_flags(struct link_socket *sock)
 
 #if EXTENDED_SOCKET_ERROR_CAPABILITY
     /* if the OS supports it, enable extended error passing on the socket */
-    set_sock_extended_error_passing(sock->sd);
+    set_sock_extended_error_passing(sock->sd, sock->info.af);
 #endif
 }
 
@@ -1926,11 +1966,7 @@ linksock_print_addr(struct link_socket *sock)
     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)
+    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,
@@ -1947,7 +1983,7 @@ linksock_print_addr(struct link_socket *sock)
         ASSERT(cur);
         msg(msglevel, "%s link local (bound): %s",
             proto2ascii(sock->info.proto, sock->info.af, true),
-            print_sockaddr(cur->ai_addr,&gc));
+            print_sockaddr(cur->ai_addr, &gc));
     }
     else
     {
@@ -1967,8 +2003,9 @@ linksock_print_addr(struct link_socket *sock)
 
 static void
 phase2_tcp_server(struct link_socket *sock, const char *remote_dynamic,
-                  volatile int *signal_received)
+                  struct signal_info *sig_info)
 {
+    volatile int *signal_received = sig_info ? &sig_info->signal_received : NULL;
     switch (sock->mode)
     {
         case LS_MODE_DEFAULT:
@@ -1994,7 +2031,7 @@ phase2_tcp_server(struct link_socket *sock, const char *remote_dynamic,
                                         false);
             if (!socket_defined(sock->sd))
             {
-                *signal_received = SIGTERM;
+                register_signal(sig_info, SIGTERM, "socket-undefiled");
                 return;
             }
             tcp_connection_established(&sock->info.lsa->actual);
@@ -2030,7 +2067,7 @@ phase2_tcp_client(struct link_socket *sock, struct signal_info *sig_info)
                                                         sock->proxy_dest_port,
                                                         sock->server_poll_timeout,
                                                         &sock->stream_buf.residual,
-                                                        &sig_info->signal_received);
+                                                        sig_info);
         }
         else if (sock->socks_proxy)
         {
@@ -2038,7 +2075,7 @@ phase2_tcp_client(struct link_socket *sock, struct signal_info *sig_info)
                                            sock->sd,
                                            sock->proxy_dest_host,
                                            sock->proxy_dest_port,
-                                           &sig_info->signal_received);
+                                           sig_info);
         }
         if (proxy_retry)
         {
@@ -2067,7 +2104,7 @@ phase2_socks_client(struct link_socket *sock, struct signal_info *sig_info)
                                    sock->ctrl_sd,
                                    sock->sd,
                                    &sock->socks_relay.dest,
-                                   &sig_info->signal_received);
+                                   sig_info);
 
     if (sig_info->signal_received)
     {
@@ -2085,25 +2122,63 @@ phase2_socks_client(struct link_socket *sock, struct signal_info *sig_info)
         sock->info.lsa->remote_list = NULL;
     }
 
-    resolve_remote(sock, 1, NULL, &sig_info->signal_received);
+    resolve_remote(sock, 1, NULL, sig_info);
 }
 
+#if defined(_WIN32)
+static void
+create_socket_dco_win(struct context *c, struct link_socket *sock,
+                      struct signal_info *sig_info)
+{
+    if (!c->c1.tuntap)
+    {
+        struct tuntap *tt;
+        ALLOC_OBJ(tt, struct tuntap);
+
+        *tt = create_dco_handle(c->options.dev_node, &c->gc);
+
+        /* Ensure we can "safely" cast the handle to a socket */
+        static_assert(sizeof(sock->sd) == sizeof(tt->hand), "HANDLE and SOCKET size differs");
+
+        c->c1.tuntap = tt;
+    }
+
+    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);
+
+    sock->sockflags |= SF_DCO_WIN;
+
+    if (sig_info->signal_received)
+    {
+        return;
+    }
+
+    sock->sd = (SOCKET)c->c1.tuntap->hand;
+    linksock_print_addr(sock);
+}
+#endif /* if defined(_WIN32) */
+
 /* finalize socket initialization */
 void
-link_socket_init_phase2(struct link_socket *sock,
-                        const struct frame *frame,
-                        struct signal_info *sig_info)
+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;
-    int sig_save = 0;
+    struct signal_info sig_save = {0};
 
     ASSERT(sock);
     ASSERT(sig_info);
 
     if (sig_info->signal_received)
     {
-        sig_save = sig_info->signal_received;
-        sig_info->signal_received = 0;
+        sig_save = *sig_info;
+        sig_save.signal_received = signal_reset(sig_info, 0);
     }
 
     /* initialize buffers */
@@ -2119,96 +2194,98 @@ link_socket_init_phase2(struct link_socket *sock,
         remote_dynamic = sock->remote_host;
     }
 
-    /* were we started by inetd or xinetd? */
-    if (sock->inetd)
+    /* Second chance to resolv/create socket */
+    resolve_remote(sock, 2, &remote_dynamic,  sig_info);
+
+    /* If a valid remote has been found, create the socket with its addrinfo */
+    if (sock->info.lsa->current_remote)
     {
-        phase2_inetd(sock, frame, remote_dynamic,  &sig_info->signal_received);
-        if (sig_info->signal_received)
+#if defined(_WIN32)
+        if (dco_enabled(&c->options))
         {
+            create_socket_dco_win(c, sock, sig_info);
             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)
+        else
+#endif
         {
             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;
-                }
+    /* 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 */
 
-                create_socket(sock, sock->info.lsa->bind_local);
+        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;
             }
-        }
 
-        /* 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;
+            create_socket(sock, sock->info.lsa->bind_local);
         }
+    }
 
-        if (sig_info->signal_received)
-        {
-            goto done;
-        }
+    /* 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;
+    }
 
-        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);
+    if (sig_info->signal_received)
+    {
+        goto done;
+    }
 
-        }
-        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->signal_received)
-        {
-            goto done;
-        }
+    if (sig_info->signal_received)
+    {
+        goto done;
     }
 
     phase2_set_socket_flags(sock);
     linksock_print_addr(sock);
 
 done:
-    if (sig_save)
+    if (sig_save.signal_received)
     {
-        if (!sig_info->signal_received)
+        /* 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
         {
-            sig_info->signal_received = sig_save;
+            register_signal(sig_info, sig_save.signal_received, sig_save.signal_text);
         }
     }
 }
@@ -2265,16 +2342,6 @@ link_socket_close(struct link_socket *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)
 {
@@ -2298,8 +2365,7 @@ ipchange_fmt(const bool include_cmd, struct argv *argv, const struct link_socket
 }
 
 void
-link_socket_connection_initiated(const struct buffer *buf,
-                                 struct link_socket_info *info,
+link_socket_connection_initiated(struct link_socket_info *info,
                                  const struct link_socket_actual *act,
                                  const char *common_name,
                                  struct env_set *es)
@@ -2333,7 +2399,7 @@ link_socket_connection_initiated(const struct buffer *buf,
         {
             msg(M_WARN, "WARNING: ipchange plugin call failed");
         }
-        argv_reset(&argv);
+        argv_free(&argv);
     }
 
     /* Process --ipchange option */
@@ -2343,7 +2409,7 @@ link_socket_connection_initiated(const struct buffer *buf,
         setenv_str(es, "script_type", "ipchange");
         ipchange_fmt(true, &argv, info, &gc);
         openvpn_run_script(&argv, es, 0, "--ipchange");
-        argv_reset(&argv);
+        argv_free(&argv);
     }
 
     gc_free(&gc);
@@ -2365,12 +2431,12 @@ link_socket_bad_incoming_addr(struct buffer *buf,
                 "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_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));
+                msg(D_LINK_ERRORS, "or from peer address: %s",
+                    print_sockaddr_ex(ai->ai_addr, ":", PS_SHOW_PORT, &gc));
             }
             break;
     }
@@ -2397,7 +2463,7 @@ link_socket_current_remote(const struct link_socket_info *info)
  * 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)
     {
@@ -2428,7 +2494,7 @@ link_socket_current_remote_ipv6(const struct link_socket_info *info)
  * 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)
     {
@@ -2499,7 +2565,7 @@ stream_buf_reset(struct stream_buf *sb)
     sb->len = -1;
 }
 
-void
+static void
 stream_buf_init(struct stream_buf *sb,
                 struct buffer *buf,
                 const unsigned int sockflags,
@@ -2573,7 +2639,7 @@ stream_buf_read_setup_dowork(struct link_socket *sock)
     return !sock->stream_buf.residual_fully_formed;
 }
 
-bool
+static bool
 stream_buf_added(struct stream_buf *sb,
                  int length_added)
 {
@@ -2640,7 +2706,7 @@ stream_buf_added(struct stream_buf *sb,
     }
 }
 
-void
+static void
 stream_buf_close(struct stream_buf *sb)
 {
     free_buf(&sb->residual);
@@ -2721,7 +2787,7 @@ print_sockaddr_ex(const struct sockaddr *sa,
 
     if (status!=0)
     {
-        buf_printf(&out,"[nameinfo() err: %s]",gai_strerror(status));
+        buf_printf(&out, "[nameinfo() err: %s]", gai_strerror(status));
         return BSTR(&out);
     }
 
@@ -2768,10 +2834,11 @@ print_link_socket_actual_ex(const struct link_socket_actual *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));
 #if ENABLE_IP_PKTINFO
+        char ifname[IF_NAMESIZE] = "[undef]";
+
         if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(act))
         {
             switch (act->dest.addr.sa.sa_family)
@@ -2834,16 +2901,16 @@ const char *
 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);
+    char *out = gc_malloc(INET_ADDRSTRLEN, true, gc);
 
     if (addr || !(flags & IA_EMPTY_IF_UNDEF))
     {
         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;
 }
 
 /*
@@ -2853,16 +2920,25 @@ print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc)
 const char *
 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))
     {
-        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
@@ -2900,7 +2976,7 @@ setenv_sockaddr(struct env_set *es, const char *name_prefix, const struct openvp
 {
     char name_buf[256];
 
-    char buf[128];
+    char buf[INET6_ADDRSTRLEN];
     switch (addr->addr.sa.sa_family)
     {
         case AF_INET:
@@ -2913,7 +2989,8 @@ setenv_sockaddr(struct env_set *es, const char *name_prefix, const struct openvp
                 openvpn_snprintf(name_buf, sizeof(name_buf), "%s", name_prefix);
             }
 
-            setenv_str(es, name_buf, inet_ntoa(addr->addr.in4.sin_addr));
+            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)
             {
@@ -2929,13 +3006,12 @@ setenv_sockaddr(struct env_set *es, const char *name_prefix, const struct openvp
                 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);
-                openvpn_snprintf(buf, sizeof(buf), "%s", inet_ntoa(ia) );
+                inet_ntop(AF_INET, &ia, buf, sizeof(buf));
             }
             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);
+                inet_ntop(AF_INET6, &addr->addr.in6.sin6_addr, buf, sizeof(buf));
             }
             setenv_str(es, name_buf, buf);
 
@@ -2999,59 +3075,24 @@ struct proto_names {
 
 /* Indexed by PROTO_x */
 static const struct proto_names proto_names[] = {
-    {"proto-uninitialized",        "proto-NONE", AF_UNSPEC, PROTO_NONE},
+    {"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},
+    {"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},
+    {"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},
+    {"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;
-}
-
 int
 ascii2proto(const char *proto_name)
 {
@@ -3141,7 +3182,7 @@ 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)
@@ -3191,8 +3232,21 @@ link_socket_read_tcp(struct link_socket *sock,
 
     if (!sock->stream_buf.residual_fully_formed)
     {
+        /* 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
-        len = socket_finalize(sock->sd, &sock->reads, buf, NULL);
+        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);
@@ -3226,7 +3280,7 @@ link_socket_read_tcp(struct link_socket *sock,
 
 #if ENABLE_IP_PKTINFO
 
-/* make the buffer large enough to handle ancilliary socket data for
+/* 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)
@@ -3244,9 +3298,11 @@ link_socket_read_udp_posix_recvmsg(struct link_socket *sock,
 {
     struct iovec iov;
     uint8_t pktinfo_buf[PKTINFO_BUF_SIZE];
-    struct msghdr mesg;
+    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;
@@ -3313,6 +3369,9 @@ link_socket_read_udp_posix(struct link_socket *sock,
     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)
@@ -3439,6 +3498,17 @@ link_socket_write_udp_posix_sendmsg(struct link_socket *sock,
 
 #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)
 {
@@ -3462,7 +3532,7 @@ socket_recv_queue(struct link_socket *sock, int maxsize)
         }
 
         /* Win32 docs say it's okay to allocate the wsabuf on the stack */
-        wsabuf[0].buf = BPTR(&sock->reads.buf);
+        wsabuf[0].buf = BSTR(&sock->reads.buf);
         wsabuf[0].len = maxsize ? maxsize : BLEN(&sock->reads.buf);
 
         /* check for buffer overflow */
@@ -3472,7 +3542,14 @@ socket_recv_queue(struct link_socket *sock, int maxsize)
         ASSERT(ResetEvent(sock->reads.overlapped.hEvent));
         sock->reads.flags = 0;
 
-        if (proto_is_udp(sock->info.proto))
+        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);
@@ -3525,7 +3602,7 @@ socket_recv_queue(struct link_socket *sock, int maxsize)
         }
         else
         {
-            status = WSAGetLastError();
+            status = socket_get_last_error(sock);
             if (status == WSA_IO_PENDING) /* operation queued? */
             {
                 sock->reads.iostate = IOSTATE_QUEUED;
@@ -3563,14 +3640,23 @@ socket_send_queue(struct link_socket *sock, struct buffer *buf, const struct lin
         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].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 (proto_is_udp(sock->info.proto))
+        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;
@@ -3631,8 +3717,9 @@ socket_send_queue(struct link_socket *sock, struct buffer *buf, const struct lin
         }
         else
         {
-            status = WSAGetLastError();
-            if (status == WSA_IO_PENDING) /* operation queued? */
+            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;
@@ -3657,11 +3744,12 @@ socket_send_queue(struct link_socket *sock, struct buffer *buf, const struct lin
     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)
+sockethandle_finalize(sockethandle_t sh,
+                      struct overlapped_io *io,
+                      struct buffer *buf,
+                      struct link_socket_actual *from)
 {
     int ret = -1;
     BOOL status;
@@ -3669,13 +3757,7 @@ socket_finalize(SOCKET s,
     switch (io->iostate)
     {
         case IOSTATE_QUEUED:
-            status = WSAGetOverlappedResult(
-                s,
-                &io->overlapped,
-                &io->size,
-                FALSE,
-                &io->flags
-                );
+            status = SocketHandleGetOverlappedResult(sh, io);
             if (status)
             {
                 /* successful return for a queued operation */
@@ -3687,18 +3769,18 @@ socket_finalize(SOCKET s,
                 io->iostate = IOSTATE_INITIAL;
                 ASSERT(ResetEvent(io->overlapped.hEvent));
 
-                dmsg(D_WIN32_IO, "WIN32 I/O: Socket Completion success [%d]", ret);
+                dmsg(D_WIN32_IO, "WIN32 I/O: Completion success [%d]", ret);
             }
             else
             {
                 /* error during a queued operation */
                 ret = -1;
-                if (WSAGetLastError() != WSA_IO_INCOMPLETE)
+                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: Socket Completion error");
+                    msg(D_WIN32_IO | M_ERRNO, "WIN32 I/O: Completion error");
                 }
             }
             break;
@@ -3709,9 +3791,9 @@ socket_finalize(SOCKET s,
             if (io->status)
             {
                 /* error return for a non-queued operation */
-                WSASetLastError(io->status);
+                SocketHandleSetLastError(sh, io->status);
                 ret = -1;
-                msg(D_WIN32_IO | M_ERRNO, "WIN32 I/O: Socket Completion non-queued error");
+                msg(D_WIN32_IO | M_ERRNO, "WIN32 I/O: Completion non-queued error");
             }
             else
             {
@@ -3721,14 +3803,14 @@ socket_finalize(SOCKET s,
                     *buf = io->buf;
                 }
                 ret = io->size;
-                dmsg(D_WIN32_IO, "WIN32 I/O: Socket Completion non-queued success [%d]", ret);
+                dmsg(D_WIN32_IO, "WIN32 I/O: Completion non-queued success [%d]", ret);
             }
             break;
 
         case IOSTATE_INITIAL: /* were we called without proper queueing? */
-            WSASetLastError(WSAEINVAL);
+            SocketHandleSetInvalError(sh);
             ret = -1;
-            dmsg(D_WIN32_IO, "WIN32 I/O: Socket Completion BAD STATE");
+            dmsg(D_WIN32_IO, "WIN32 I/O: Completion BAD STATE");
             break;
 
         default:
@@ -3736,12 +3818,12 @@ socket_finalize(SOCKET s,
     }
 
     /* return from address if requested */
-    if (from)
+    if (!sh.is_handle && 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
+            /* 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
@@ -3878,25 +3960,18 @@ socket_bind_unix(socket_descriptor_t sd,
                  const char *prefix)
 {
     struct gc_arena gc = gc_new();
-
-#ifdef HAVE_UMASK
     const mode_t orig_umask = umask(0);
-#endif
 
     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",
+        msg(M_FATAL | M_ERRNO,
+            "%s: Socket bind[%d] failed on unix domain socket %s",
             prefix,
             (int)sd,
-            sockaddr_unix_name(local, "NULL"),
-            strerror_ts(errnum, &gc));
+            sockaddr_unix_name(local, "NULL"));
     }
 
-#ifdef HAVE_UMASK
     umask(orig_umask);
-#endif
-
     gc_free(&gc);
 }
 
@@ -3941,12 +4016,10 @@ void
 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
 }
 
 bool