changeset 6596:e778fe9a4463

Stream: set SO_REUSEADDR for UDP upstream sockets. The option is only set if the socket is bound to a specific port to allow several such sockets coexist at the same time. This is required, for example, when nginx acts as a transparent proxy and receives two datagrams from the same client in a short time. The feature is only implemented for Linux.
author Roman Arutyunyan <arut@nginx.com>
date Mon, 20 Jun 2016 12:48:47 +0300
parents 0c98c4092440
children 0a820872dd4c
files src/event/ngx_event_connect.c
diffstat 1 files changed, 25 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -21,6 +21,9 @@ ngx_int_t
 ngx_event_connect_peer(ngx_peer_connection_t *pc)
 {
     int                rc, type;
+#if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX)
+    in_port_t          port;
+#endif
     ngx_int_t          event;
     ngx_err_t          err;
     ngx_uint_t         level;
@@ -87,9 +90,13 @@ ngx_event_connect_peer(ngx_peer_connecti
         }
 #endif
 
+#if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX)
+        port = ngx_inet_get_port(pc->sockaddr);
+#endif
+
 #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT)
 
-        if (pc->sockaddr->sa_family != AF_UNIX) {
+        if (pc->sockaddr->sa_family != AF_UNIX && port == 0) {
             static int  bind_address_no_port = 1;
 
             if (bind_address_no_port) {
@@ -113,6 +120,23 @@ ngx_event_connect_peer(ngx_peer_connecti
 
 #endif
 
+#if (NGX_LINUX)
+
+        if (pc->type == SOCK_DGRAM && port != 0) {
+            int  reuse_addr = 1;
+
+            if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+                           (const void *) &reuse_addr, sizeof(int))
+                 == -1)
+            {
+                ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
+                              "setsockopt(SO_REUSEADDR) failed");
+                goto failed;
+            }
+        }
+
+#endif
+
         if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) {
             ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno,
                           "bind(%V) failed", &pc->local->name);