OSSP CVS Repository

ossp - Check-in [2686]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 2686
Date: 2002-Oct-30 09:42:16 (local)
2002-Oct-30 08:42:16 (UTC)
User:rse
Branch:
Comment: Rewrote the implementation of sa_option(3) in order to make options configurable before the underlying socket is implicitly allocated. This fixes especially sa_option(sa, SA_OPTION_REUSEADDR, 1) before sa_bind().
Tickets:
Inspections:
Files:
ossp-pkg/sa/ChangeLog      1.1 -> 1.2     6 inserted, 0 deleted
ossp-pkg/sa/sa.c      1.62 -> 1.63     163 inserted, 66 deleted
ossp-pkg/sa/sa.h      1.31 -> 1.32     5 inserted, 5 deleted
ossp-pkg/sa/sa.pod      1.33 -> 1.34     3 inserted, 5 deleted

ossp-pkg/sa/ChangeLog 1.1 -> 1.2

--- ChangeLog    2002/10/26 17:59:29     1.1
+++ ChangeLog    2002/10/30 08:42:16     1.2
@@ -13,6 +13,12 @@
 
   Changes between 0.9.2 and 0.9.3 (11-Oct-2002 to xx-Oct-2002)
 
+   o Rewrote the implementation of sa_option(3) in order to make options
+     configurable _before_ the underlying socket is implicitly
+     allocated. This fixes especially sa_option(sa, SA_OPTION_REUSEADDR, 1) 
+     before sa_bind().
+     [Ralf S. Engelschall, Michael van Elst <mlelstv@dev.de.cw.net>]
+
    o Finished writing the documentation (manual page sa.pod).
      [Ralf S. Engelschall]
 


ossp-pkg/sa/sa.c 1.62 -> 1.63

--- sa.c 2002/10/26 15:45:32     1.62
+++ sa.c 2002/10/30 08:42:16     1.63
@@ -206,6 +206,12 @@
     SA_SC_DECLARE_6(ssize_t, sendto,   int, const void *, size_t, int, const struct sockaddr *, socklen_t)
 } sa_syscall_tab_t;
 
+/* socket option information */
+typedef struct {
+    int todo;
+    int value;
+} sa_optinfo_t;
+
 /* socket abstraction object */
 struct sa_st {
     sa_type_t        eType;            /* socket type (stream or datagram) */
@@ -218,6 +224,7 @@
     int              nWriteSize;       /* write buffer current size */
     char            *cpWriteBuf;       /* write buffer memory chunk */
     sa_syscall_tab_t scSysCall;        /* table of system calls */
+    sa_optinfo_t     optInfo[5];       /* option storage */
 };
 
 /* socket address abstraction object */
@@ -866,25 +873,120 @@
 /* set timeouts if timeouts or done in kernel */
 static sa_rc_t sa_socket_settimeouts(sa_t *sa)
 {
+    /* stop processing if socket is still not allocated */
+    if (sa->fdSocket == -1)
+        return SA_OK;
+
 #if defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO)
-    if (sa->fdSocket != -1) {
-        if (SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_READ])) {
-            if (setsockopt(sa->fdSocket, SOL_SOCKET, SO_RCVTIMEO,
-                           (const void *)(&sa->tvTimeout[SA_TIMEOUT_READ]),
-                           (socklen_t)(sizeof(sa->tvTimeout[SA_TIMEOUT_READ]))) < 0)
-                return SA_RC(SA_ERR_SYS);
-        }
-        if (SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_WRITE])) {
-            if (setsockopt(sa->fdSocket, SOL_SOCKET, SO_SNDTIMEO,
-                           (const void *)(&sa->tvTimeout[SA_TIMEOUT_WRITE]),
-                           (socklen_t)(sizeof(sa->tvTimeout[SA_TIMEOUT_WRITE]))) < 0)
-                return SA_RC(SA_ERR_SYS);
-        }
+    if (SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_READ])) {
+        if (setsockopt(sa->fdSocket, SOL_SOCKET, SO_RCVTIMEO,
+                       (const void *)(&sa->tvTimeout[SA_TIMEOUT_READ]),
+                       (socklen_t)(sizeof(sa->tvTimeout[SA_TIMEOUT_READ]))) < 0)
+            return SA_RC(SA_ERR_SYS);
+    }
+    if (SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_WRITE])) {
+        if (setsockopt(sa->fdSocket, SOL_SOCKET, SO_SNDTIMEO,
+                       (const void *)(&sa->tvTimeout[SA_TIMEOUT_WRITE]),
+                       (socklen_t)(sizeof(sa->tvTimeout[SA_TIMEOUT_WRITE]))) < 0)
+            return SA_RC(SA_ERR_SYS);
     }
 #endif
     return SA_OK;
 }
 
+/* set socket options */
+static sa_rc_t sa_socket_setoptions(sa_t *sa)
+{
+    int i;
+    sa_rc_t rv;
+
+    /* stop processing if socket is still not allocated */
+    if (sa->fdSocket == -1)
+        return SA_OK;
+
+    /* check for pending options */
+    rv = SA_OK;
+    for (i = 0; i < (sizeof(sa->optInfo)/sizeof(sa->optInfo[0])); i++) {
+        if (sa->optInfo[i].todo) {
+            switch (i) {
+                /* enable/disable Nagle's Algorithm (see RFC898) */
+                case SA_OPTION_NAGLE: {
+#if defined(IPPROTO_TCP) && defined(TCP_NODELAY)
+                    int mode = sa->optInfo[i].value;
+                    if (setsockopt(sa->fdSocket, IPPROTO_TCP, TCP_NODELAY,
+                                   (const void *)&mode,
+                                   (socklen_t)sizeof(mode)) < 0)
+                        rv = SA_ERR_SYS;
+                    else
+                        sa->optInfo[i].todo = FALSE;
+#endif
+                    break;
+                }
+                /* enable/disable linger close semantics */
+                case SA_OPTION_LINGER: {
+#if defined(SO_LINGER)
+                    struct linger linger;
+                    linger.l_onoff  = (sa->optInfo[i].value == 0 ? 0 : 1);
+                    linger.l_linger = sa->optInfo[i].value;
+                    if (setsockopt(sa->fdSocket, SOL_SOCKET, SO_LINGER,
+                                   (const void *)&linger,
+                                   (socklen_t)sizeof(struct linger)) < 0)
+                        rv = SA_ERR_SYS;
+                    else
+                        sa->optInfo[i].todo = FALSE;
+#endif
+                    break;
+                }
+                /* enable/disable reusability of binding to address */
+                case SA_OPTION_REUSEADDR: {
+#if defined(SO_REUSEADDR)
+                    int mode = sa->optInfo[i].value;
+                    if (setsockopt(sa->fdSocket, SOL_SOCKET, SO_REUSEADDR,
+                                   (const void *)&mode, (socklen_t)sizeof(mode)) < 0)
+                        rv = SA_ERR_SYS;
+                    else
+                        sa->optInfo[i].todo = FALSE;
+#endif
+                    break;
+                }
+                /* enable/disable reusability of binding to port */
+                case SA_OPTION_REUSEPORT: {
+#if defined(SO_REUSEPORT)
+                    int mode = sa->optInfo[i].value;
+                    if (setsockopt(sa->fdSocket, SOL_SOCKET, SO_REUSEPORT,
+                                   (const void *)&mode, (socklen_t)sizeof(mode)) < 0)
+                        rv = SA_ERR_SYS;
+                    else
+                        sa->optInfo[i].todo = FALSE;
+#endif
+                    break;
+                }
+                /* enable/disable non-blocking I/O mode */
+                case SA_OPTION_NONBLOCK: {
+                    int mode = sa->optInfo[i].value;
+                    int flags;
+                    if ((flags = fcntl(sa->fdSocket, F_GETFL, 0)) < 0) {
+                        rv = SA_ERR_SYS;
+                        break;
+                    }
+                    if (mode == 0)
+                        flags &= ~(O_NONBLOCK);
+                    else
+                        flags |= O_NONBLOCK;
+                    if (fcntl(sa->fdSocket, F_SETFL, flags) < 0)
+                        rv = SA_ERR_SYS;
+                    else
+                        sa->optInfo[i].todo = FALSE;
+                    break;
+                }
+                default: /* NOTREACHED */ break;
+            }
+        }
+    }
+
+    return SA_RC(rv);
+}
+
 /* internal lazy/delayed initialization of underlying socket */
 static sa_rc_t sa_socket_init(sa_t *sa, int nFamily)
 {
@@ -893,6 +995,7 @@
 #if !(defined(IPPROTO_TCP) && defined(IPPROTO_UDP))
     struct protoent *pe;
 #endif
+    sa_rc_t rv;
 
     /* argument sanity check(s) */
     if (sa == NULL)
@@ -945,7 +1048,12 @@
         return SA_RC(SA_ERR_SYS);
 
     /* optionally set kernel timeouts */
-    sa_socket_settimeouts(sa);
+    if ((rv = sa_socket_settimeouts(sa)) != SA_OK)
+        return SA_RC(rv);
+
+    /* optionally configure changed options */
+    if ((rv = sa_socket_setoptions(sa)) != SA_OK)
+        return SA_RC(rv);
 
     return SA_OK;
 }
@@ -998,6 +1106,12 @@
         sa->tvTimeout[i].tv_usec = 0;
     }
 
+    /* init options object attributes */
+    for (i = 0; i < (sizeof(sa->optInfo)/sizeof(sa->optInfo[0])); i++) {
+        sa->optInfo[i].todo  = FALSE;
+        sa->optInfo[i].value = 0;
+    }
+
     /* init syscall object attributes */
     SA_SC_ASSIGN(sa, connect,  connect,  NULL);
     SA_SC_ASSIGN(sa, accept,   accept,   NULL);
@@ -1056,6 +1170,7 @@
 sa_rc_t sa_timeout(sa_t *sa, sa_timeout_t id, long sec, long usec)
 {
     int i;
+    sa_rc_t rv;
 
     /* argument sanity check(s) */
     if (sa == NULL)
@@ -1072,8 +1187,9 @@
         sa->tvTimeout[id].tv_usec = usec;
     }
 
-    /* optionally set kernel timeouts */
-    sa_socket_settimeouts(sa);
+    /* try to already set timeouts */
+    if ((rv = sa_socket_settimeouts(sa)) != SA_OK)
+        return SA_RC(rv);
 
     return SA_OK;
 }
@@ -1150,16 +1266,10 @@
     va_start(ap, id);
     switch (id) {
         case SA_OPTION_NAGLE: {
-            /* enable/disable Nagle's Algorithm (see RFC898) */
 #if defined(IPPROTO_TCP) && defined(TCP_NODELAY)
             int mode = ((int)va_arg(ap, int) ? 1 : 0);
-            if (sa->fdSocket == -1) {
-                rv = SA_ERR_USE;
-                break;
-            }
-            if (setsockopt(sa->fdSocket, IPPROTO_TCP, TCP_NODELAY,
-                           (const void *)&mode, (socklen_t)sizeof(mode)) < 0)
-                rv = SA_ERR_SYS;
+            sa->optInfo[SA_OPTION_NAGLE].value = mode;
+            sa->optInfo[SA_OPTION_NAGLE].todo = TRUE;
 #else
             rv = SA_ERR_IMP;
 #endif
@@ -1167,61 +1277,40 @@
         }
         case SA_OPTION_LINGER: {
 #if defined(SO_LINGER)
-            struct linger *linger = (struct linger *)va_arg(ap, void *);
-            if (sa->fdSocket == -1) {
-                rv = SA_ERR_USE;
-                break;
-            }
-            if (setsockopt(sa->fdSocket, SOL_SOCKET, SO_LINGER,
-                           (const void *)linger, (socklen_t)sizeof(struct linger)) < 0)
-                rv = SA_ERR_SYS;
+            int amount = ((int)va_arg(ap, int) ? 1 : 0);
+            sa->optInfo[SA_OPTION_LINGER].value = amount;
+            sa->optInfo[SA_OPTION_LINGER].todo = TRUE;
 #else
             rv = SA_ERR_IMP;
 #endif
             break;
         }
         case SA_OPTION_REUSEADDR:
-#ifdef SA_OPTION_REUSEPORT
-        case SA_OPTION_REUSEPORT:
+        {
+#if defined(SO_REUSEADDR)
+            int mode = ((int)va_arg(ap, int) ? 1 : 0);
+            sa->optInfo[SA_OPTION_REUSEADDR].value = mode;
+            sa->optInfo[SA_OPTION_REUSEADDR].todo = TRUE;
+#else
+            rv = SA_ERR_IMP;
 #endif
+            break;
+        }
+        case SA_OPTION_REUSEPORT:
         {
-            /* enable/disable reusability of binding to address or port */
+#if defined(SO_REUSEPORT)
             int mode = ((int)va_arg(ap, int) ? 1 : 0);
-            int flag;
-            if (sa->fdSocket == -1) {
-                rv = SA_ERR_USE;
-                break;
-            }
-            switch (id) {
-                case SA_OPTION_REUSEADDR: flag = SO_REUSEADDR; break;
-#ifdef SA_OPTION_REUSEPORT
-                case SA_OPTION_REUSEPORT: flag = SO_REUSEPORT; break;
+            sa->optInfo[SA_OPTION_REUSEPORT].value = mode;
+            sa->optInfo[SA_OPTION_REUSEPORT].todo = TRUE;
+#else
+            rv = SA_ERR_IMP;
 #endif
-                default: flag = 0; break;
-            }
-            if (setsockopt(sa->fdSocket, SOL_SOCKET, flag,
-                           (const void *)&mode, (socklen_t)sizeof(mode)) < 0)
-                rv = SA_ERR_SYS;
             break;
         }
         case SA_OPTION_NONBLOCK: {
-            /* enable/disable non-blocking I/O mode */
-            int flags;
             int mode = (int)va_arg(ap, int);
-            if (sa->fdSocket == -1) {
-                rv = SA_ERR_USE;
-                break;
-            }
-            if ((flags = fcntl(sa->fdSocket, F_GETFL, 0)) < 0) {
-                rv = SA_ERR_SYS;
-                break;
-            }
-            if (mode == 0)
-                flags &= ~(O_NONBLOCK);
-            else
-                flags |= O_NONBLOCK;
-            if (fcntl(sa->fdSocket, F_SETFL, flags) < 0)
-                rv = SA_ERR_SYS;
+            sa->optInfo[SA_OPTION_NONBLOCK].value = mode;
+            sa->optInfo[SA_OPTION_NONBLOCK].todo = TRUE;
             break;
         }
         default: {
@@ -1230,7 +1319,15 @@
     }
     va_end(ap);
 
-    return SA_RC(rv);
+    /* if an error already occured, stop here */
+    if (rv != SA_OK)
+        return SA_RC(rv);
+
+    /* else already (re)set) options (if possible) */
+    if ((rv = sa_socket_setoptions(sa)) != SA_OK)
+        return SA_RC(rv);
+
+    return SA_OK;
 }
 
 /* override system call */


ossp-pkg/sa/sa.h 1.31 -> 1.32

--- sa.h 2002/10/11 15:27:39     1.31
+++ sa.h 2002/10/30 08:42:16     1.32
@@ -137,11 +137,11 @@
 
 /* list of options */
 typedef enum {
-    SA_OPTION_NAGLE,
-    SA_OPTION_LINGER,
-    SA_OPTION_REUSEADDR,
-    SA_OPTION_REUSEPORT,
-    SA_OPTION_NONBLOCK
+    SA_OPTION_NAGLE     = 0,
+    SA_OPTION_LINGER    = 1,
+    SA_OPTION_REUSEADDR = 2,
+    SA_OPTION_REUSEPORT = 3,
+    SA_OPTION_NONBLOCK  = 4
 } sa_option_t;
 
 /* list of system calls */


ossp-pkg/sa/sa.pod 1.33 -> 1.34

--- sa.pod       2002/10/26 18:28:16     1.33
+++ sa.pod       2002/10/30 08:42:16     1.34
@@ -458,11 +458,9 @@
 C<SA_OPTION_NAGLE> (C<int> I<yesno>) for enabling (I<yesno>=C<1>) or
 disabling (I<yesno> == C<0>) Nagle's Algorithm (see RFC898).
 
-C<SA_OPTION_LINGER> (C<struct linger *>I<linger>) for enabling
-(C<linger-E<gt>l_onoff> == C<1> and C<linger-E<gt>l_linger> ==
-I<seconds>) or disabling (C<linger-E<gt>l_onoff> == C<0>) lingering
-on close (see C<SO_LINGER> of setsockopt(2) and C<struct linger> in
-F<sys/socket.h>).
+C<SA_OPTION_LINGER> (C<int> I<amount>) for enabling (I<amount> ==
+I<seconds> E<gt> C<0>) or disabling (I<amount> == C<0>) lingering on
+close (see C<SO_LINGER> of setsockopt(2)).
 
 C<SA_OPTION_REUSEADDR> (C<int> I<yesno>) for enabling (I<yesno> ==
 C<1>) or disabling (I<yesno> == C<0>) the reusability of the address on

CVSTrac 2.0.1