gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r34392 - in libmicrohttpd: . doc src/include src/microhttpd


From: gnunet
Subject: [GNUnet-SVN] r34392 - in libmicrohttpd: . doc src/include src/microhttpd
Date: Wed, 29 Oct 2014 20:50:58 +0100

Author: grothoff
Date: 2014-10-29 20:50:58 +0100 (Wed, 29 Oct 2014)
New Revision: 34392

Modified:
   libmicrohttpd/ChangeLog
   libmicrohttpd/doc/libmicrohttpd.texi
   libmicrohttpd/src/include/microhttpd.h
   libmicrohttpd/src/microhttpd/connection.c
   libmicrohttpd/src/microhttpd/connection_https.c
   libmicrohttpd/src/microhttpd/daemon.c
   libmicrohttpd/src/microhttpd/internal.c
   libmicrohttpd/src/microhttpd/internal.h
Log:
Hi Christian,

I attach the first attempt on SO_REUSEPORT. The patch is available
either at 
https://github.com/foxik/libmicrohttpd/commit/9ce9422742e10458f87275ea202a982e00c2b88c
or attached. (It is against the version with
MHD_DAEMON_OPTION_CURRENT_CONNECTIONS, but I can rebase it to current
SVN HEAD if you want.)

It seems that a reasonably multiplatform way of detecting SO_REUSEPORT is
  #ifdef SO_REPOSEPORT
which is used for example by Perl. For SO_EXCLUSIVEADDRUSE, the same
strategy seems to work too, according to Windows SDK headers and MinGW
WinAPI headers.

The current patch adds an option to allowing/disallowing address:port
reuse. One remark:
- currently both nonexisting SO_xxx and setsockopt failure are fatal and
  MHD_start_daemon fails. That may be too harsh -- maybe the
  MHD_OPTION_LISTENING_ADDRESS_REUSE should be only a hint.

  Nevertheless, as one can freely not use
  MHD_OPTION_LISTENING_ADDRESS_REUSE option, I chose the "fail on error"
  behaviour.

Thanks,
cheers,
Milan Straka

Original patch modified to get rid of some redundant USE_DEBUG
checks, fix indentation, and #ifndef SO_REUSEPORT on Linux,
we try be #defining it to 15 ourselves.



Modified: libmicrohttpd/ChangeLog
===================================================================
--- libmicrohttpd/ChangeLog     2014-10-29 15:53:17 UTC (rev 34391)
+++ libmicrohttpd/ChangeLog     2014-10-29 19:50:58 UTC (rev 34392)
@@ -1,3 +1,8 @@
+Wed Oct 29 20:45:21 CET 2014
+       Adding MHD_OPTION_LISTENING_ADDRESS_REUSE option allowing clients
+       to force allowing re-use of the address:port combination
+       (SO_REUSEPORT). -MS
+
 Wed Oct 29 16:27:05 CET 2014
        Adding MHD_DAEMON_INFO_CURRENT_CONNECTIONS to allow clients
        to query the number of active connections. -MS

Modified: libmicrohttpd/doc/libmicrohttpd.texi
===================================================================
--- libmicrohttpd/doc/libmicrohttpd.texi        2014-10-29 15:53:17 UTC (rev 
34391)
+++ libmicrohttpd/doc/libmicrohttpd.texi        2014-10-29 19:50:58 UTC (rev 
34392)
@@ -856,6 +856,20 @@
 a @code{const char *} argument.  The argument would be a zero-terminated
 string with a PEM encoded PKCS3 DH parameters structure suitable
 for passing to @code{gnutls_dh_parms_import_pkcs3}.
+
address@hidden MHD_OPTION_LISTENING_ADDRESS_REUSE
address@hidden bind, restricting bind
address@hidden reusing listening address
+This option must be followed by a @code{unsigned int} argument.
+If this option is present and true (nonzero) parameter is given, allow reusing
+the address:port of the listening socket (using @code{SO_REUSEPORT} on most
+platforms, and @code{SO_REUSEADDR} on Windows).  If a false (zero) parameter is
+given, disallow reusing the the address:port of the listening socket (this
+usually requires no special action, but @code{SO_EXCLUSIVEADDRUSE} is needed on
+Windows).  If this option is not present, default behaviour is undefined
+(currently, @code{SO_REUSEADDR} is used on all platforms, which disallows
+address:port reusing with the exception of Windows).
+
 @end table
 @end deftp
 

Modified: libmicrohttpd/src/include/microhttpd.h
===================================================================
--- libmicrohttpd/src/include/microhttpd.h      2014-10-29 15:53:17 UTC (rev 
34391)
+++ libmicrohttpd/src/include/microhttpd.h      2014-10-29 19:50:58 UTC (rev 
34392)
@@ -846,8 +846,16 @@
    * HTTPS daemon for key exchange.
    * This option must be followed by a `const char *` argument.
    */
-  MHD_OPTION_HTTPS_MEM_DHPARAMS = 24
+  MHD_OPTION_HTTPS_MEM_DHPARAMS = 24,
 
+  /**
+   * If present and set to true, allow reusing address:port socket
+   * (by using SO_REUSEPORT on most platform, or platform-specific ways).
+   * If present and set to false, disallow reusing address:port socket
+   * (does nothing on most plaform, but uses SO_EXCLUSIVEADDRUSE on Windows).
+   * This option must be followed by a `unsigned int` argument.
+   */
+  MHD_OPTION_LISTENING_ADDRESS_REUSE = 25,
 };
 
 

Modified: libmicrohttpd/src/microhttpd/connection.c
===================================================================
--- libmicrohttpd/src/microhttpd/connection.c   2014-10-29 15:53:17 UTC (rev 
34391)
+++ libmicrohttpd/src/microhttpd/connection.c   2014-10-29 19:50:58 UTC (rev 
34392)
@@ -1306,7 +1306,8 @@
   if (NULL == cpy)
     {
 #if HAVE_MESSAGES
-      MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n");
+      MHD_DLOG (connection->daemon,
+                "Not enough memory to parse cookies!\n");
 #endif
       transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
                                REQUEST_TOO_BIG);

Modified: libmicrohttpd/src/microhttpd/connection_https.c
===================================================================
--- libmicrohttpd/src/microhttpd/connection_https.c     2014-10-29 15:53:17 UTC 
(rev 34391)
+++ libmicrohttpd/src/microhttpd/connection_https.c     2014-10-29 19:50:58 UTC 
(rev 34392)
@@ -134,8 +134,10 @@
   unsigned int timeout;
 
 #if DEBUG_STATES
-  MHD_DLOG (connection->daemon, "%s: state: %s\n",
-            __FUNCTION__, MHD_state_to_string (connection->state));
+  MHD_DLOG (connection->daemon,
+            "%s: state: %s\n",
+            __FUNCTION__,
+            MHD_state_to_string (connection->state));
 #endif
   timeout = connection->connection_timeout;
   if ( (timeout != 0) && (timeout <= (MHD_monotonic_time() - 
connection->last_activity)))

Modified: libmicrohttpd/src/microhttpd/daemon.c
===================================================================
--- libmicrohttpd/src/microhttpd/daemon.c       2014-10-29 15:53:17 UTC (rev 
34391)
+++ libmicrohttpd/src/microhttpd/daemon.c       2014-10-29 19:50:58 UTC (rev 
34392)
@@ -552,7 +552,8 @@
     return 0;
 #endif
 #if HAVE_MESSAGES
-  MHD_DLOG (daemon, "You need to specify a certificate and key location\n");
+  MHD_DLOG (daemon,
+            "You need to specify a certificate and key location\n");
 #endif
   return -1;
 }
@@ -736,7 +737,9 @@
 #if DEBUG_CONNECT
 #if HAVE_MESSAGES
   if (NULL != max_fd)
-    MHD_DLOG (daemon, "Maximum socket in select set: %d\n", *max_fd);
+    MHD_DLOG (daemon,
+              "Maximum socket in select set: %d\n",
+              *max_fd);
 #endif
 #endif
   return MHD_YES;
@@ -826,7 +829,7 @@
               {
 #if HAVE_MESSAGES
                 MHD_DLOG (con->daemon,
-                        "Can't add FD to fd_set\n");
+                          "Can't add FD to fd_set\n");
 #endif
                 goto exit;
               }
@@ -1200,7 +1203,9 @@
 
 #if HAVE_MESSAGES
 #if DEBUG_CONNECT
-  MHD_DLOG (daemon, "Accepted connection on socket %d\n", client_socket);
+  MHD_DLOG (daemon,
+            "Accepted connection on socket %d\n",
+            client_socket);
 #endif
 #endif
   if ( (daemon->connections == daemon->connection_limit) ||
@@ -1226,7 +1231,8 @@
     {
 #if DEBUG_CLOSE
 #if HAVE_MESSAGES
-      MHD_DLOG (daemon, "Connection rejected, closing connection\n");
+      MHD_DLOG (daemon,
+                "Connection rejected, closing connection\n");
 #endif
 #endif
       if (0 != MHD_socket_close_ (client_socket))
@@ -1415,7 +1421,8 @@
         {
          eno = errno;
 #if HAVE_MESSAGES
-          MHD_DLOG (daemon, "Failed to create a thread: %s\n",
+          MHD_DLOG (daemon,
+                    "Failed to create a thread: %s\n",
                     MHD_strerror_ (res_thread_create));
 #endif
          goto cleanup;
@@ -1839,7 +1846,9 @@
 #endif
 #if HAVE_MESSAGES
 #if DEBUG_CONNECT
-  MHD_DLOG (daemon, "Accepted connection on socket %d\n", s);
+  MHD_DLOG (daemon,
+            "Accepted connection on socket %d\n",
+            s);
 #endif
 #endif
   (void) internal_add_connection (daemon, s,
@@ -1961,7 +1970,8 @@
   if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
     {
 #if HAVE_MESSAGES
-      MHD_DLOG (daemon, "Illegal call to MHD_get_timeout\n");
+      MHD_DLOG (daemon,
+                "Illegal call to MHD_get_timeout\n");
 #endif
       return MHD_NO;
     }
@@ -2196,7 +2206,9 @@
       if (EINTR == MHD_socket_errno_)
         return MHD_YES;
 #if HAVE_MESSAGES
-      MHD_DLOG (daemon, "select failed: %s\n", MHD_socket_last_strerr_ ());
+      MHD_DLOG (daemon,
+                "select failed: %s\n",
+                MHD_socket_last_strerr_ ());
 #endif
       return MHD_NO;
     }
@@ -2401,7 +2413,9 @@
       if (EINTR == MHD_socket_errno_)
        return MHD_YES;
 #if HAVE_MESSAGES
-      MHD_DLOG (daemon, "poll failed: %s\n", MHD_socket_last_strerr_ ());
+      MHD_DLOG (daemon,
+                "poll failed: %s\n",
+                MHD_socket_last_strerr_ ());
 #endif
       return MHD_NO;
     }
@@ -2492,10 +2506,9 @@
                          &event))
        {
 #if HAVE_MESSAGES
-         if (0 != (daemon->options & MHD_USE_DEBUG))
-           MHD_DLOG (daemon,
-                     "Call to epoll_ctl failed: %s\n",
-                     MHD_socket_last_strerr_ ());
+          MHD_DLOG (daemon,
+                    "Call to epoll_ctl failed: %s\n",
+                    MHD_socket_last_strerr_ ());
 #endif
          return MHD_NO;
        }
@@ -2544,10 +2557,9 @@
          if (EINTR == MHD_socket_errno_)
            return MHD_YES;
 #if HAVE_MESSAGES
-         if (0 != (daemon->options & MHD_USE_DEBUG))
-           MHD_DLOG (daemon,
-                     "Call to epoll_wait failed: %s\n",
-                     MHD_socket_last_strerr_ ());
+          MHD_DLOG (daemon,
+                    "Call to epoll_wait failed: %s\n",
+                    MHD_socket_last_strerr_ ());
 #endif
          return MHD_NO;
        }
@@ -2994,7 +3006,8 @@
               if (gnutls_dh_params_init (&daemon->https_mem_dhparams) < 0)
                 {
 #if HAVE_MESSAGES
-                  MHD_DLOG(daemon, "Error initializing DH parameters\n");
+                  MHD_DLOG(daemon,
+                           "Error initializing DH parameters\n");
 #endif
                   return MHD_NO;
                 }
@@ -3004,7 +3017,8 @@
                                                  GNUTLS_X509_FMT_PEM) < 0)
                 {
 #if HAVE_MESSAGES
-                  MHD_DLOG(daemon, "Bad Diffie-Hellman parameters format\n");
+                  MHD_DLOG(daemon,
+                           "Bad Diffie-Hellman parameters format\n");
 #endif
                   gnutls_dh_params_deinit (daemon->https_mem_dhparams);
                   return MHD_NO;
@@ -3028,7 +3042,7 @@
              ret = gnutls_priority_init (&daemon->priority_cache,
                                          pstr = va_arg (ap, const char*),
                                          NULL);
-             if (ret != GNUTLS_E_SUCCESS)
+             if (GNUTLS_E_SUCCESS != ret)
              {
 #if HAVE_MESSAGES
                MHD_DLOG (daemon,
@@ -3084,6 +3098,9 @@
           daemon->fastopen_queue_size = va_arg (ap, unsigned int);
           break;
 #endif
+       case MHD_OPTION_LISTENING_ADDRESS_REUSE:
+         daemon->listening_address_reuse = va_arg (ap, unsigned int) ? 1 : -1;
+         break;
        case MHD_OPTION_ARRAY:
          oa = va_arg (ap, struct MHD_OptionItem*);
          i = 0;
@@ -3109,6 +3126,7 @@
                case MHD_OPTION_PER_IP_CONNECTION_LIMIT:
                case MHD_OPTION_THREAD_POOL_SIZE:
                 case MHD_OPTION_TCP_FASTOPEN_QUEUE_SIZE:
+               case MHD_OPTION_LISTENING_ADDRESS_REUSE:
                  if (MHD_YES != parse_options (daemon,
                                                servaddr,
                                                opt,
@@ -3254,10 +3272,9 @@
   if (-1 == daemon->epoll_fd)
     {
 #if HAVE_MESSAGES
-      if (0 != (daemon->options & MHD_USE_DEBUG))
-       MHD_DLOG (daemon,
-                 "Call to epoll_create1 failed: %s\n",
-                 MHD_socket_last_strerr_ ());
+      MHD_DLOG (daemon,
+                "Call to epoll_create1 failed: %s\n",
+                MHD_socket_last_strerr_ ());
 #endif
       return MHD_NO;
     }
@@ -3274,10 +3291,9 @@
                      &event))
     {
 #if HAVE_MESSAGES
-      if (0 != (daemon->options & MHD_USE_DEBUG))
-       MHD_DLOG (daemon,
-                 "Call to epoll_ctl failed: %s\n",
-                 MHD_socket_last_strerr_ ());
+      MHD_DLOG (daemon,
+                "Call to epoll_ctl failed: %s\n",
+                MHD_socket_last_strerr_ ());
 #endif
       return MHD_NO;
     }
@@ -3293,10 +3309,9 @@
                           &event))
         {
 #if HAVE_MESSAGES
-          if (0 != (daemon->options & MHD_USE_DEBUG))
-            MHD_DLOG (daemon,
-                      "Call to epoll_ctl failed: %s\n",
-                      MHD_socket_last_strerr_ ());
+          MHD_DLOG (daemon,
+                    "Call to epoll_ctl failed: %s\n",
+                    MHD_socket_last_strerr_ ());
 #endif
           return MHD_NO;
         }
@@ -3379,6 +3394,7 @@
     }
 #endif
   daemon->socket_fd = MHD_INVALID_SOCKET;
+  daemon->listening_address_reuse = 0;
   daemon->options = (enum MHD_OPTION) flags;
 #if WINDOWS
   /* Winsock is broken with respect to 'shutdown';
@@ -3553,25 +3569,111 @@
       if (MHD_INVALID_SOCKET == socket_fd)
        {
 #if HAVE_MESSAGES
-         if (0 != (flags & MHD_USE_DEBUG))
-           MHD_DLOG (daemon,
-                     "Call to socket failed: %s\n",
-                     MHD_socket_last_strerr_ ());
+          MHD_DLOG (daemon,
+                    "Call to socket failed: %s\n",
+                    MHD_socket_last_strerr_ ());
 #endif
          goto free_and_fail;
        }
-      if ( (0 > setsockopt (socket_fd,
-                           SOL_SOCKET,
-                           SO_REUSEADDR,
-                           (void*)&on, sizeof (on))) &&
-          (0 != (flags & MHD_USE_DEBUG)) )
-       {
+
+      /* Apply the socket options according to listening_address_reuse. */
+      if (0 == daemon->listening_address_reuse)
+        {
+          /* No user requirement, use "traditional" default SO_REUSEADDR,
+           and do not fail if it doesn't work */
+          if (0 > setsockopt (socket_fd,
+                              SOL_SOCKET,
+                              SO_REUSEADDR,
+                              (void*)&on, sizeof (on)))
 #if HAVE_MESSAGES
-         MHD_DLOG (daemon,
-                   "setsockopt failed: %s\n",
-                   MHD_socket_last_strerr_ ());
+            MHD_DLOG (daemon,
+                      "setsockopt failed: %s\n",
+                      MHD_socket_last_strerr_ ());
 #endif
-       }
+        }
+      else if (daemon->listening_address_reuse > 0)
+        {
+          /* User requested to allow reusing listening address:port.
+           * Use SO_REUSEADDR on Windows and SO_REUSEPORT on most platforms.
+           * Fail if SO_REUSEPORT does not exist or setsockopt fails.
+           */
+#ifdef _WIN32
+          /* SO_REUSEADDR on W32 has the same semantics
+             as SO_REUSEPORT on BSD/Linux */
+          if (0 > setsockopt (socket_fd,
+                              SOL_SOCKET,
+                              SO_REUSEADDR,
+                              (void*)&on, sizeof (on)))
+            {
+#if HAVE_MESSAGES
+              MHD_DLOG (daemon,
+                        "setsockopt failed: %s\n",
+                        MHD_socket_last_strerr_ ());
+#endif
+              goto free_and_fail;
+            }
+#else
+#ifndef SO_REUSEPORT
+#ifdef LINUX
+/* Supported since Linux 3.9, but often not present (or commented out)
+   in the headers at this time; but 15 is reserved for this and
+   thus should be safe to use. */
+#define SO_REUSEPORT 15
+#endif
+#endif
+#ifdef SO_REUSEPORT
+          if (0 > setsockopt (socket_fd,
+                              SOL_SOCKET,
+                              SO_REUSEPORT,
+                              (void*)&on, sizeof (on)))
+            {
+#if HAVE_MESSAGES
+              MHD_DLOG (daemon,
+                        "setsockopt failed: %s\n",
+                        MHD_socket_last_strerr_ ());
+#endif
+              goto free_and_fail;
+            }
+#else
+          /* we're supposed to allow address:port re-use, but
+             on this platform we cannot; fail hard */
+#if HAVE_MESSAGES
+          MHD_DLOG (daemon,
+                    "Cannot allow listening address reuse: SO_REUSEPORT not 
defined\n");
+#endif
+          goto free_and_fail;
+#endif
+#endif
+        }
+      else /* if (daemon->listening_address_reuse < 0) */
+        {
+          /* User requested to disallow reusing listening address:port.
+           * Do nothing except for Windows where SO_EXCLUSIVEADDRUSE
+           * is used. Fail if it does not exist or setsockopt fails.
+           */
+#ifdef _WIN32
+#ifdef SO_EXCLUSIVEADDRUSE
+          if (0 > setsockopt (socket_fd,
+                              SOL_SOCKET,
+                              SO_EXCLUSIVEADDRUSE,
+                              (void*)&on, sizeof (on)))
+            {
+#if HAVE_MESSAGES
+              MHD_DLOG (daemon,
+                        "setsockopt failed: %s\n",
+                        MHD_socket_last_strerr_ ());
+#endif
+              goto free_and_fail;
+            }
+#else /* SO_EXCLUSIVEADDRUSE not defined on W32? */
+#if HAVE_MESSAGES
+          MHD_DLOG (daemon,
+                    "Cannot disallow listening address reuse: 
SO_EXCLUSIVEADDRUSE not defined\n");
+#endif
+          goto free_and_fail;
+#endif
+#endif /* _WIN32 */
+        }
 
       /* check for user supplied sockaddr */
 #if HAVE_INET6
@@ -3621,28 +3723,24 @@
          const char
 #endif
             on = (MHD_USE_DUAL_STACK != (flags & MHD_USE_DUAL_STACK));
-         if ( (0 > setsockopt (socket_fd,
-                               IPPROTO_IPV6, IPV6_V6ONLY,
-                               &on, sizeof (on))) &&
-              (0 != (flags & MHD_USE_DEBUG)) )
-           {
+         if (0 > setsockopt (socket_fd,
+                              IPPROTO_IPV6, IPV6_V6ONLY,
+                              &on, sizeof (on)))
 #if HAVE_MESSAGES
-             MHD_DLOG (daemon,
-                       "setsockopt failed: %s\n",
-                       MHD_socket_last_strerr_ ());
+            MHD_DLOG (daemon,
+                      "setsockopt failed: %s\n",
+                      MHD_socket_last_strerr_ ());
 #endif
-           }
 #endif
 #endif
        }
       if (-1 == bind (socket_fd, servaddr, addrlen))
        {
 #if HAVE_MESSAGES
-         if (0 != (flags & MHD_USE_DEBUG))
-           MHD_DLOG (daemon,
-                     "Failed to bind to port %u: %s\n",
-                     (unsigned int) port,
-                     MHD_socket_last_strerr_ ());
+          MHD_DLOG (daemon,
+                    "Failed to bind to port %u: %s\n",
+                    (unsigned int) port,
+                    MHD_socket_last_strerr_ ());
 #endif
          if (0 != MHD_socket_close_ (socket_fd))
            MHD_PANIC ("close failed\n");
@@ -3686,10 +3784,9 @@
       if (listen (socket_fd, 32) < 0)
        {
 #if HAVE_MESSAGES
-         if (0 != (flags & MHD_USE_DEBUG))
-           MHD_DLOG (daemon,
-                     "Failed to listen for connections: %s\n",
-                     MHD_socket_last_strerr_ ());
+          MHD_DLOG (daemon,
+                    "Failed to listen for connections: %s\n",
+                    MHD_socket_last_strerr_ ());
 #endif
          if (0 != MHD_socket_close_ (socket_fd))
            MHD_PANIC ("close failed\n");
@@ -3705,11 +3802,10 @@
        (0 == (flags & (MHD_USE_POLL | MHD_USE_EPOLL_LINUX_ONLY)) ) )
     {
 #if HAVE_MESSAGES
-      if ((flags & MHD_USE_DEBUG) != 0)
-        MHD_DLOG (daemon,
-                 "Socket descriptor larger than FD_SETSIZE: %d > %d\n",
-                 socket_fd,
-                 FD_SETSIZE);
+      MHD_DLOG (daemon,
+                "Socket descriptor larger than FD_SETSIZE: %d > %d\n",
+                socket_fd,
+                FD_SETSIZE);
 #endif
       if (0 != MHD_socket_close_ (socket_fd))
        MHD_PANIC ("close failed\n");
@@ -4123,7 +4219,8 @@
 
 #if DEBUG_CLOSE
 #if HAVE_MESSAGES
-  MHD_DLOG (daemon, "MHD listen socket shutdown\n");
+  MHD_DLOG (daemon,
+            "MHD listen socket shutdown\n");
 #endif
 #endif
 

Modified: libmicrohttpd/src/microhttpd/internal.c
===================================================================
--- libmicrohttpd/src/microhttpd/internal.c     2014-10-29 15:53:17 UTC (rev 
34391)
+++ libmicrohttpd/src/microhttpd/internal.c     2014-10-29 19:50:58 UTC (rev 
34392)
@@ -95,7 +95,7 @@
 {
   va_list va;
 
-  if ((daemon->options & MHD_USE_DEBUG) == 0)
+  if (0 == (daemon->options & MHD_USE_DEBUG))
     return;
   va_start (va, format);
   daemon->custom_error_log (daemon->custom_error_log_cls, format, va);

Modified: libmicrohttpd/src/microhttpd/internal.h
===================================================================
--- libmicrohttpd/src/microhttpd/internal.h     2014-10-29 15:53:17 UTC (rev 
34391)
+++ libmicrohttpd/src/microhttpd/internal.h     2014-10-29 19:50:58 UTC (rev 
34392)
@@ -1099,6 +1099,15 @@
    */
   MHD_socket socket_fd;
 
+  /**
+   * Whether to allow/disallow/ignore reuse of listening address.
+   * The semantics is the following:
+   * 0: ignore (user did not ask for neither allow/disallow, use SO_REUSEADDR)
+   * >0: allow (use SO_REUSEPORT on most platforms, SO_REUSEADDR on Windows)
+   * <0: disallow (mostly no action, SO_EXCLUSIVEADDRUSE on Windows)
+   */
+  int listening_address_reuse;
+
 #if EPOLL_SUPPORT
   /**
    * File descriptor associated with our epoll loop.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]