Bug 891551: Add implementation of socket option PR_SockOpt_Reuseport. NSPR_4_10_6_BETA1
authorPeter Tatrai <ptatrai@gmail.com>
Thu, 22 May 2014 14:14:20 -0700
changeset 4565 3db759f2844979b1edc03e2bf103fdd923cf21d7
parent 4564 8bd45bb4d68a16bc781ab7eadb42fffea169edd8
child 4566 e6e504e6844cdba64e9c27bfbf436a27ec03ac60
push id110
push userwtc@google.com
push dateThu, 22 May 2014 21:14:27 +0000
bugs891551
Bug 891551: Add implementation of socket option PR_SockOpt_Reuseport. r=wtc.
pr/include/prio.h
pr/src/io/prmapopt.c
pr/src/pthreads/ptio.c
pr/tests/sockopt.c
--- a/pr/include/prio.h
+++ b/pr/include/prio.h
@@ -206,16 +206,18 @@ typedef enum PRSockOption
     PR_SockOpt_DropMember,      /* drop an IP group membership */
     PR_SockOpt_McastInterface,  /* multicast interface address */
     PR_SockOpt_McastTimeToLive, /* multicast timetolive */
     PR_SockOpt_McastLoopback,   /* multicast loopback */
 
     PR_SockOpt_NoDelay,         /* don't delay send to coalesce packets */
     PR_SockOpt_MaxSegment,      /* maximum segment size */
     PR_SockOpt_Broadcast,       /* enable broadcast */
+    PR_SockOpt_Reuseport,       /* allow local address & port reuse on
+                                 * platforms that support it */
     PR_SockOpt_Last
 } PRSockOption;
 
 typedef struct PRLinger {
 	PRBool polarity;		    /* Polarity of the option's setting */
 	PRIntervalTime linger;	    /* Time to linger before closing */
 } PRLinger;
 
@@ -229,16 +231,18 @@ typedef struct PRSocketOptionData
     PRSockOption option;
     union
     {
         PRUintn ip_ttl;             /* IP time to live */
         PRUintn mcast_ttl;          /* IP multicast time to live */
         PRUintn tos;                /* IP type of service and precedence */
         PRBool non_blocking;        /* Non-blocking (network) I/O */
         PRBool reuse_addr;          /* Allow local address reuse */
+        PRBool reuse_port;          /* Allow local address & port reuse on
+                                     * platforms that support it */
         PRBool keep_alive;          /* Keep connections alive */
         PRBool mcast_loopback;      /* IP multicast loopback */
         PRBool no_delay;            /* Don't delay send to coalesce packets */
         PRBool broadcast;           /* Enable broadcast */
         PRSize max_segment;         /* Maximum segment size */
         PRSize recv_buffer_size;    /* Receive buffer size */
         PRSize send_buffer_size;    /* Send buffer size */
         PRLinger linger;            /* Time to linger on close if data present */
--- a/pr/src/io/prmapopt.c
+++ b/pr/src/io/prmapopt.c
@@ -80,16 +80,17 @@ PRStatus PR_CALLBACK _PR_SocketGetSocket
                 PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
                 return PR_FAILURE;
 #endif
             }
             case PR_SockOpt_Reuseaddr:
             case PR_SockOpt_Keepalive:
             case PR_SockOpt_NoDelay:
             case PR_SockOpt_Broadcast:
+            case PR_SockOpt_Reuseport:
             {
 #ifdef WIN32 /* Winsock */
                 BOOL value;
 #else
                 PRIntn value;
 #endif
                 length = sizeof(value);
                 rv = _PR_MD_GETSOCKOPT(
@@ -231,16 +232,17 @@ PRStatus PR_CALLBACK _PR_SocketSetSocket
                 PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
                 return PR_FAILURE;
 #endif
             }
             case PR_SockOpt_Reuseaddr:
             case PR_SockOpt_Keepalive:
             case PR_SockOpt_NoDelay:
             case PR_SockOpt_Broadcast:
+            case PR_SockOpt_Reuseport:
             {
 #ifdef WIN32 /* Winsock */
                 BOOL value;
 #else
                 PRIntn value;
 #endif
                 value = (data->value.reuse_addr) ? 1 : 0;
                 rv = _PR_MD_SETSOCKOPT(
@@ -407,36 +409,40 @@ PRStatus PR_CALLBACK _PR_SocketSetSocket
 #ifndef TCP_NODELAY                     /* don't delay to coalesce data     */
 #define TCP_NODELAY         _PR_NO_SUCH_SOCKOPT
 #endif
 
 #ifndef TCP_MAXSEG                      /* maxumum segment size for tcp     */
 #define TCP_MAXSEG          _PR_NO_SUCH_SOCKOPT
 #endif
 
-#ifndef SO_BROADCAST                 /* enable broadcast on udp sockets */
+#ifndef SO_BROADCAST                    /* enable broadcast on UDP sockets  */
 #define SO_BROADCAST        _PR_NO_SUCH_SOCKOPT
 #endif
 
+#ifndef SO_REUSEPORT                    /* allow local address & port reuse */
+#define SO_REUSEPORT        _PR_NO_SUCH_SOCKOPT
+#endif
+
 PRStatus _PR_MapOptionName(
     PRSockOption optname, PRInt32 *level, PRInt32 *name)
 {
     static PRInt32 socketOptions[PR_SockOpt_Last] =
     {
         0, SO_LINGER, SO_REUSEADDR, SO_KEEPALIVE, SO_RCVBUF, SO_SNDBUF,
         IP_TTL, IP_TOS, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP,
         IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_MULTICAST_LOOP,
-        TCP_NODELAY, TCP_MAXSEG, SO_BROADCAST
+        TCP_NODELAY, TCP_MAXSEG, SO_BROADCAST, SO_REUSEPORT
     };
     static PRInt32 socketLevels[PR_SockOpt_Last] =
     {
         0, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET,
         IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
         IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
-        IPPROTO_TCP, IPPROTO_TCP, SOL_SOCKET
+        IPPROTO_TCP, IPPROTO_TCP, SOL_SOCKET, SOL_SOCKET
     };
 
     if ((optname < PR_SockOpt_Linger)
     || (optname >= PR_SockOpt_Last))
     {
         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
         return PR_FAILURE;
     }
--- a/pr/src/pthreads/ptio.c
+++ b/pr/src/pthreads/ptio.c
@@ -2849,16 +2849,17 @@ static PRStatus pt_GetSocketOption(PRFil
                 data->value.linger.linger =
                     PR_SecondsToInterval(linger.l_linger);
                 break;
             }
             case PR_SockOpt_Reuseaddr:
             case PR_SockOpt_Keepalive:
             case PR_SockOpt_NoDelay:
             case PR_SockOpt_Broadcast:
+            case PR_SockOpt_Reuseport:
             {
                 PRIntn value;
                 length = sizeof(PRIntn);
                 rv = getsockopt(
                     fd->secret->md.osfd, level, name, (char*)&value, &length);
                 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
                 data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
                 break;
@@ -2968,16 +2969,17 @@ static PRStatus pt_SetSocketOption(PRFil
                 rv = setsockopt(
                     fd->secret->md.osfd, level, name, (char*)&linger, sizeof(linger));
                 break;
             }
             case PR_SockOpt_Reuseaddr:
             case PR_SockOpt_Keepalive:
             case PR_SockOpt_NoDelay:
             case PR_SockOpt_Broadcast:
+            case PR_SockOpt_Reuseport:
             {
                 PRIntn value = (data->value.reuse_addr) ? 1 : 0;
                 rv = setsockopt(
                     fd->secret->md.osfd, level, name,
                     (char*)&value, sizeof(PRIntn));
 #ifdef LINUX
                 /* for pt_LinuxSendFile */
                 if (name == TCP_NODELAY && rv == 0) {
--- a/pr/tests/sockopt.c
+++ b/pr/tests/sockopt.c
@@ -6,16 +6,20 @@
 #include "nspr.h"
 #include "prio.h"
 #include "prinit.h"
 #include "prprf.h"
 #include "obsolete/probslet.h"
 
 #include "plerror.h"
 
+#ifdef XP_UNIX
+#include <sys/socket.h>  /* SO_REUSEPORT */
+#endif
+
 static PRFileDesc *err = NULL;
 static PRBool failed = PR_FALSE;
 
 static void Failed(const char *msg1, const char *msg2)
 {
     if (NULL != msg1) PR_fprintf(err, "%s ", msg1);
     PL_FPrintError(err, msg2);
     failed = PR_TRUE;
@@ -49,16 +53,17 @@ int main(int argc, char **argv)
         "PR_SockOpt_DropMember",      /* drop an IP group membership */
         "PR_SockOpt_McastInterface",  /* multicast interface address */
         "PR_SockOpt_McastTimeToLive", /* multicast timetolive */
         "PR_SockOpt_McastLoopback",   /* multicast loopback */
 
         "PR_SockOpt_NoDelay",         /* don't delay send to coalesce packets */
         "PR_SockOpt_MaxSegment",      /* maximum segment size */
         "PR_SockOpt_Broadcast",       /* Enable broadcast */
+        "PR_SockOpt_Reuseport",       /* allow local address & port reuse */
         "PR_SockOpt_Last"
     };
 
     err = PR_GetSpecialFD(PR_StandardError);
     PR_STDIO_INIT();
 
     if (NULL == udp) Failed("PR_NewUDPSocket()", NULL);
     else if (NULL == tcp) Failed("PR_NewTCPSocket()", NULL);
@@ -125,16 +130,21 @@ int main(int argc, char **argv)
                     break;    
 #endif
 #ifndef SYMBIAN
                 case PR_SockOpt_Broadcast:
                     fd = udp; 
                     data.value.broadcast = PR_TRUE;         
                     break;    
 #endif
+#ifdef SO_REUSEPORT
+                case PR_SockOpt_Reuseport:
+                    data.value.reuse_port = PR_TRUE;
+                    break;
+#endif
                 default: continue;
             }
 
 			/*
 			 * TCP_MAXSEG can only be read, not set
 			 */
             if (option != PR_SockOpt_MaxSegment) {
 #ifdef WIN32