OSSP CVS Repository

ossp - Difference in ossp-pkg/l2/l2_ut_sa.c versions 1.17 and 1.18
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [History

ossp-pkg/l2/l2_ut_sa.c 1.17 -> 1.18

--- l2_ut_sa.c   2001/10/31 21:26:11     1.17
+++ l2_ut_sa.c   2002/10/11 16:00:48     1.18
@@ -1,11 +1,11 @@
 /*
-**  SA - OSSP Socket Abstraction Library
-**  Copyright (c) 2001 Ralf S. Engelschall <rse@engelschall.com>
-**  Copyright (c) 2001 The OSSP Project <http://www.ossp.org/>
-**  Copyright (c) 2001 Cable & Wireless Deutschland <http://www.cw.com/de/>
+**  OSSP sa - Socket Abstraction
+**  Copyright (c) 2001-2002 Ralf S. Engelschall <rse@engelschall.com>
+**  Copyright (c) 2001-2002 The OSSP Project <http://www.ossp.org/>
+**  Copyright (c) 2001-2002 Cable & Wireless Deutschland <http://www.cw.com/de/>
 **
-**  This file is part of OSSP SA, a socket abstraction library which
-**  can be found at http://www.ossp.org/pkg/sa/.
+**  This file is part of OSSP sa, a socket abstraction library which
+**  can be found at http://www.ossp.org/pkg/lib/sa/.
 **
 **  Permission to use, copy, modify, and distribute this software for
 **  any purpose with or without fee is hereby granted, provided that
@@ -45,12 +45,25 @@
 #include <sys/time.h>    /* for "struct timeval" */
 #include <sys/un.h>      /* for "struct sockaddr_un" */
 #include <netinet/in.h>  /* for "struct sockaddr_in[6]" */
-#include <sys/socket.h>  /* for "AF_XXX" and "SOCK_XXX" */
+#include <sys/socket.h>  /* for "PF_XXX", "AF_XXX" and "SOCK_XXX" */
 #include <arpa/inet.h>   /* for "inet_XtoX" */
 
 /* include own API header */
 #include "l2_ut_sa.h"
 
+/* unique library identifier */
+const char sa_id[] = "OSSP sa";
+
+/* support for OSSP ex based exception throwing */
+#ifdef WITH_EX
+#include "ex.h"
+#define SA_RC(rv) \
+    (  (rv) != SA_OK && (ex_catching && !ex_shielding) \
+     ? (ex_throw(sa_id, NULL, (rv)), (rv)) : (rv) )
+#else
+#define SA_RC(rv) (rv)
+#endif /* WITH_EX */
+
 /* boolean values */
 #ifndef FALSE
 #define FALSE (0)
@@ -64,6 +77,17 @@
 #define AF_LOCAL AF_UNIX
 #endif
 
+/* backward compatibility for PF_XXX (still unused) */
+#if !defined(PF_LOCAL) && defined(AF_LOCAL)
+#define PF_LOCAL AF_LOCAL
+#endif
+#if !defined(PF_INET) && defined(AF_INET)
+#define PF_INET AF_INET
+#endif
+#if !defined(PF_INET6) && defined(AF_INET6)
+#define PF_INET6 AF_INET6
+#endif
+
 /* backward compatibility for ssize_t */
 #if defined(HAVE_CONFIG_H) && !defined(HAVE_SSIZE_T)
 #define ssize_t long
@@ -130,14 +154,14 @@
     do { \
         (sa)->scSysCall.sc_##fn.fptr.any = (void (*)())(ptr); \
         (sa)->scSysCall.sc_##fn.fctx = (ctx); \
-    } while(0)
+    } while (0)
 
 /* system call structure assignment macro */
 #define SA_SC_COPY(sa1, sa2, fn) \
     do { \
         (sa1)->scSysCall.sc_##fn.fptr.any = (sa2)->scSysCall.sc_##fn.fptr.any; \
         (sa1)->scSysCall.sc_##fn.fctx     = (sa2)->scSysCall.sc_##fn.fctx; \
-    } while(0)
+    } while (0)
 
 /* system call function call macros */
 #define SA_SC_CALL_0(sa, fn) \
@@ -214,10 +238,17 @@
     struct in_addr in_val;
 
     if (family == AF_INET) {
+#if defined(HAVE_INET_ATON)
         /* at least for IPv4 we can rely on the old inet_aton(3)
            and for IPv6 inet_pton(3) would exist anyway */
         if (inet_aton(strptr, &in_val) == 0)
             return 0;
+#elif defined(HAVE_INET_ADDR)
+        /* at least for IPv4 try to rely on the even older inet_addr(3) */
+        memset(&in_val, '\0', sizeof(in_val));
+        if ((in_val.s_addr = inet_addr(strptr)) == ((in_addr_t)-1))
+            return 0;
+#endif
         memcpy(addrptr, &in_val, sizeof(struct in_addr));
         return 1;
     }
@@ -232,14 +263,14 @@
 #ifdef HAVE_INET_NTOP
     return inet_ntop(family, src, dst, size);
 #else
-    struct in_addr in_val;
     char *cp;
     int n;
 
     if (family == AF_INET) {
+#ifdef HAVE_INET_NTOA
         /* at least for IPv4 we can rely on the old inet_ntoa(3)
            and for IPv6 inet_ntop(3) would exist anyway */
-        if ((cp = inet_ntoa(src)) == NULL) 
+        if ((cp = inet_ntoa(*((struct in_addr *)src))) == NULL) 
             return NULL;
         n = strlen(cp);
         if (n > size-1)
@@ -247,6 +278,7 @@
         memcpy(dst, cp, n);
         dst[n] = '\0';
         return dst;
+#endif
     }
     errno = EAFNOSUPPORT;
     return NULL;
@@ -356,13 +388,13 @@
     else {
         /* perform real output */
         ctx.bufptr = buffer;
-        ctx.buflen = bufsize - 1;
+        ctx.buflen = bufsize;
         n = sa_mvxprintf(sa_mvsnprintf_cb, &ctx, format, ap);
+        if (n != -1 && ctx.buflen == 0)
+            n = -1;
+        if (n != -1)
+            *(ctx.bufptr) = '\0';
     }
-    if (n != -1 && ctx.buflen == 0)
-        n = -1;
-    if (n != -1)
-        *(ctx.bufptr) = '\0';
     return n;
 }
 
@@ -387,11 +419,11 @@
 
     /* argument sanity check(s) */
     if (saap == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* allocate and initialize new address object */
     if ((saa = (sa_addr_t *)malloc(sizeof(sa_addr_t))) == NULL)
-        return SA_ERR_MEM;
+        return SA_RC(SA_ERR_MEM);
     saa->nFamily = 0;
     saa->saBuf   = NULL;
     saa->slBuf   = 0;
@@ -407,7 +439,7 @@
 {
     /* argument sanity check(s) */
     if (saa == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* free address objects and sub-object(s) */
     if (saa->saBuf != NULL)
@@ -436,7 +468,7 @@
     char *cpHost;
     char *cpPort;
     char *cpProto;
-    int nPort;
+    unsigned int nPort;
     const char *cpPath;
     char uribuf[1024];
     char *cp;
@@ -445,7 +477,7 @@
 
     /* argument sanity check(s) */
     if (saa == NULL || uri == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* on-the-fly create or just take over URI */
     va_start(ap, uri);
@@ -472,12 +504,12 @@
         /* fill-in socket address structure */
         n = strlen(cpPath);
         if (n == 0)
-            return SA_ERR_ARG;
+            return SA_RC(SA_ERR_ARG);
         if ((n+1) > sizeof(un.sun_path))
-            return SA_ERR_MEM;
+            return SA_RC(SA_ERR_MEM);
         if (cpPath[0] != '/') {
             if (getcwd(un.sun_path, sizeof(un.sun_path)-(n+1)) == NULL)
-                return SA_ERR_MEM;
+                return SA_RC(SA_ERR_MEM);
             cp = un.sun_path + strlen(un.sun_path);
         }
         else
@@ -497,22 +529,22 @@
         if (cpHost[0] == '[') {
             /* IPv6 address (see RFC2732) */
 #ifndef AF_INET6
-            return SA_ERR_IMP;
+            return SA_RC(SA_ERR_IMP);
 #else
             bIPv6 = TRUE;
             cpHost++;
             if ((cp = strchr(cpHost, ']')) == NULL)
-                return SA_ERR_ARG;
+                return SA_RC(SA_ERR_ARG);
             *cp++ = '\0';
             if (*cp != ':')
-                return SA_ERR_ARG;
+                return SA_RC(SA_ERR_ARG);
             cp++;
 #endif
         }
         else {
             /* IPv4 address or hostname */
             if ((cp = strrchr(cpHost, ':')) == NULL)
-                return SA_ERR_ARG;
+                return SA_RC(SA_ERR_ARG);
             *cp++ = '\0';
         }
         cpPort = cp;
@@ -532,10 +564,10 @@
             }
         }
         if (bNumeric)
-            nPort = atoi(cpPort);
+            nPort = (unsigned int)atoi(cpPort);
         else {
             if ((se = getservbyname(cpPort, cpProto)) == NULL)
-                return SA_ERR_SYS;
+                return SA_RC(SA_ERR_SYS);
             nPort = ntohs(se->s_port);
         }
 
@@ -585,19 +617,19 @@
             }
 #endif
             else
-                return SA_ERR_ARG;
+                return SA_RC(SA_ERR_ARG);
         }
         else
-            return SA_ERR_ARG;
+            return SA_RC(SA_ERR_ARG);
     }
     else
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* fill-in result address structure */
     if (saa->saBuf != NULL)
         free(saa->saBuf);
     if ((saa->saBuf = (struct sockaddr *)malloc(sl)) == NULL)
-        return SA_ERR_MEM;
+        return SA_RC(SA_ERR_MEM);
     memcpy(saa->saBuf, sa, sl);
     saa->slBuf = sl;
     saa->nFamily = sf;
@@ -610,7 +642,7 @@
 {
     /* argument sanity check(s) */
     if (saa == NULL || sabuf == NULL || salen == 0)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* make sure we import only supported addresses */
     if (!(   sabuf->sa_family == AF_LOCAL
@@ -619,13 +651,13 @@
           || sabuf->sa_family == AF_INET6
 #endif
          ))
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* create result address structure */
     if (saa->saBuf != NULL)
         free(saa->saBuf);
     if ((saa->saBuf = (struct sockaddr *)malloc(salen)) == NULL)
-        return SA_ERR_MEM;
+        return SA_RC(SA_ERR_MEM);
     memcpy(saa->saBuf, sabuf, salen);
     saa->slBuf = salen;
 
@@ -645,11 +677,11 @@
     struct sockaddr_in6 *sa6;
 #endif
     char caHost[512];
-    int nPort;
+    unsigned int nPort;
 
     /* argument sanity check(s) */
     if (saa == NULL || uri == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* export object contents */
     if (saa->nFamily == AF_LOCAL) {
@@ -680,7 +712,7 @@
     }
 #endif
     else
-        return SA_ERR_INT;
+        return SA_RC(SA_ERR_INT);
 
     /* pass result to caller */
     *uri = strdup(uribuf);
@@ -693,11 +725,11 @@
 {
     /* argument sanity check(s) */
     if (saa == NULL || sabuf == NULL || salen == 0)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* export underlying address structure */
     if ((*sabuf = (struct sockaddr *)malloc(saa->slBuf)) == NULL)
-        return SA_ERR_MEM;
+        return SA_RC(SA_ERR_MEM);
     memmove(*sabuf, saa->saBuf, saa->slBuf);
     *salen = saa->slBuf;
 
@@ -715,10 +747,12 @@
     int i;
     const unsigned char *ucp0;
 #endif
+    unsigned int np1, np2;
+    int bMatchPort;
 
     /* argument sanity check(s) */
-    if (saa1 == NULL || saa2 == NULL || prefixlen < -1)
-        return SA_ERR_ARG;
+    if (saa1 == NULL || saa2 == NULL)
+        return SA_RC(SA_ERR_ARG);
 
     /* short circuiting for wildcard matching */
     if (prefixlen == 0)
@@ -726,18 +760,20 @@
 
     /* determine address representation pointer and size */
     if (saa1->nFamily == AF_LOCAL) {
+        np1  = 0;
+        np2  = 0;
         ucp1 = (const unsigned char *)(((struct sockaddr_un *)saa1->saBuf)->sun_path);
         ucp2 = (const unsigned char *)(((struct sockaddr_un *)saa2->saBuf)->sun_path);
         l1 = strlen(((struct sockaddr_un *)saa1->saBuf)->sun_path) * 8;
         l2 = strlen(((struct sockaddr_un *)saa2->saBuf)->sun_path) * 8;
-        if (prefixlen == -1) {
+        if (prefixlen < 0) {
             if (l1 != l2)
-                return SA_ERR_MTC;
+                return SA_RC(SA_ERR_MTC);
             nBits = l1;
         }
         else {
             if (l1 < prefixlen || l2 < prefixlen)
-                return SA_ERR_MTC;
+                return SA_RC(SA_ERR_MTC);
             nBits = prefixlen;
         }
     }
@@ -747,12 +783,16 @@
         /* special case of comparing a regular IPv4 address (1.2.3.4) with an 
            "IPv4-mapped IPv6 address" (::ffff:1.2.3.4). For details see RFC 2373. */
         if (saa1->nFamily == AF_INET6) {
+            np1  = (unsigned int)(((struct sockaddr_in6 *)saa1->saBuf)->sin6_port);
+            np2  = (unsigned int)(((struct sockaddr_in  *)saa2->saBuf)->sin_port);
             ucp1 = (const unsigned char *)&(((struct sockaddr_in6 *)saa1->saBuf)->sin6_addr);
             ucp2 = (const unsigned char *)&(((struct sockaddr_in  *)saa2->saBuf)->sin_addr);
             ucp0 = ucp1;
             ucp1 += 12;
         }
         else {
+            np1  = (unsigned int)(((struct sockaddr_in  *)saa1->saBuf)->sin_port);
+            np2  = (unsigned int)(((struct sockaddr_in6 *)saa2->saBuf)->sin6_port);
             ucp1 = (const unsigned char *)&(((struct sockaddr_in  *)saa1->saBuf)->sin_addr);
             ucp2 = (const unsigned char *)&(((struct sockaddr_in6 *)saa2->saBuf)->sin6_addr);
             ucp0 = ucp2;
@@ -760,34 +800,42 @@
         }
         for (i = 0; i < 10; i++)
             if (ucp0[i] != 0x00)
-                return SA_ERR_MTC;
+                return SA_RC(SA_ERR_MTC);
         if (!(ucp0[10] == 0xFF && ucp0[11] == 0xFF))
-            return SA_ERR_MTC;
+            return SA_RC(SA_ERR_MTC);
         nBits = 32;
     }
 #endif
     else if (saa1->nFamily == AF_INET) {
+        np1  = (unsigned int)(((struct sockaddr_in *)saa1->saBuf)->sin_port);
+        np2  = (unsigned int)(((struct sockaddr_in *)saa2->saBuf)->sin_port);
         ucp1 = (const unsigned char *)&(((struct sockaddr_in *)saa1->saBuf)->sin_addr);
         ucp2 = (const unsigned char *)&(((struct sockaddr_in *)saa2->saBuf)->sin_addr);
         nBits = 32;
     }
 #ifdef AF_INET6
     else if (saa1->nFamily == AF_INET6) {
+        np1  = (unsigned int)(((struct sockaddr_in6 *)saa1->saBuf)->sin6_port);
+        np2  = (unsigned int)(((struct sockaddr_in6 *)saa2->saBuf)->sin6_port);
         ucp1 = (const unsigned char *)&(((struct sockaddr_in6 *)saa1->saBuf)->sin6_addr);
         ucp2 = (const unsigned char *)&(((struct sockaddr_in6 *)saa2->saBuf)->sin6_addr);
         nBits = 128;
-#endif
     }
+#endif
     else
-        return SA_ERR_INT;
+        return SA_RC(SA_ERR_INT);
 
     /* make sure we do not compare than possible */
-    if (prefixlen > nBits)
-        return SA_ERR_ARG;
+    if (prefixlen > (nBits+1))
+        return SA_RC(SA_ERR_ARG);
 
-    /* support equal matching (= all bits) */
-    if (prefixlen == -1)
+    /* support equal matching (= all bits plus optionally port) */
+    bMatchPort = FALSE;
+    if (prefixlen < 0) {
+        if (prefixlen < -1)
+            bMatchPort = TRUE;
         prefixlen = nBits;
+    }
 
     /* perform address representation comparison 
        (assumption guaranteed by API: network byte order is used) */
@@ -795,15 +843,21 @@
     nBits  = (prefixlen % 8);
     if (nBytes > 0) {
         if (memcmp(ucp1, ucp2, nBytes) != 0)
-            return SA_ERR_MTC;
+            return SA_RC(SA_ERR_MTC);
     }
     if (nBits > 0) {
         uc1 = ucp1[nBytes];
         uc2 = ucp2[nBytes];
         mask = (0xFF << (8-nBits)) & 0xFF;
         if ((uc1 & mask) != (uc2 & mask))
-            return SA_ERR_MTC;
+            return SA_RC(SA_ERR_MTC);
     }
+
+    /* optionally perform additional port matching */
+    if (bMatchPort)
+        if (np1 != np2)
+            return SA_RC(SA_ERR_MTC);
+
     return SA_OK;
 }
 
@@ -814,15 +868,15 @@
     if (sa->fdSocket != -1) {
         if (SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_READ])) {
             if (setsockopt(sa->fdSocket, SOL_SOCKET, SO_RCVTIMEO,
-                           &sa->tvTimeout[SA_TIMEOUT_READ],
-                           sizeof(sa->tvTimeout[SA_TIMEOUT_READ])) < 0)
-                return SA_ERR_SYS;
+                           (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,
-                           &sa->tvTimeout[SA_TIMEOUT_WRITE],
-                           sizeof(sa->tvTimeout[SA_TIMEOUT_WRITE])) < 0)
-                return SA_ERR_SYS;
+                           (const void *)(&sa->tvTimeout[SA_TIMEOUT_WRITE]),
+                           (socklen_t)(sizeof(sa->tvTimeout[SA_TIMEOUT_WRITE]))) < 0)
+                return SA_RC(SA_ERR_SYS);
         }
     }
 #endif
@@ -834,16 +888,17 @@
 {
     int nType;
     int nProto;
+#if !(defined(IPPROTO_TCP) && defined(IPPROTO_UDP))
     struct protoent *pe;
-    char *cpProto;
+#endif
 
     /* argument sanity check(s) */
     if (sa == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* only perform operation if socket still does not exist */
     if (sa->fdSocket != -1)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* determine socket type */
     if (sa->eType == SA_TYPE_STREAM)
@@ -851,7 +906,7 @@
     else if (sa->eType == SA_TYPE_DATAGRAM)
         nType = SOCK_DGRAM;
     else
-        return SA_ERR_INT;
+        return SA_RC(SA_ERR_INT);
 
     /* determine socket protocol */
     if (nFamily == AF_LOCAL) 
@@ -861,22 +916,31 @@
 #else
     else if (nFamily == AF_INET) {
 #endif
+#if defined(IPPROTO_TCP) && defined(IPPROTO_UDP)
+        if (nType == SOCK_STREAM)
+            nProto = IPPROTO_TCP;
+        else if (nType == SOCK_DGRAM)
+            nProto = IPPROTO_UDP;
+        else
+            return SA_RC(SA_ERR_INT);
+#else
         if (nType == SOCK_STREAM)
-            cpProto = "tcp";
+            pe = getprotobyname("tcp");
         else if (nType == SOCK_DGRAM)
-            cpProto = "udp";
+            pe = getprotobyname("udp");
         else
-            return SA_ERR_INT;
-        if ((pe = getprotobyname(cpProto)) == NULL)
-            return SA_ERR_SYS;
+            return SA_RC(SA_ERR_INT);
+        if (pe == NULL)
+            return SA_RC(SA_ERR_SYS);
         nProto = pe->p_proto;
+#endif
     }
     else
-        return SA_ERR_INT;
+        return SA_RC(SA_ERR_INT);
 
     /* create the underlying socket */
     if ((sa->fdSocket = socket(nFamily, nType, nProto)) == -1)
-        return SA_ERR_SYS;
+        return SA_RC(SA_ERR_SYS);
 
     /* optionally set kernel timeouts */
     sa_socket_settimeouts(sa);
@@ -889,11 +953,11 @@
 {
     /* argument sanity check(s) */
     if (sa == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* check context */
     if (sa->fdSocket == -1)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* close socket */
     close(sa->fdSocket);
@@ -910,11 +974,11 @@
 
     /* argument sanity check(s) */
     if (sap == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* allocate and initialize socket object */
     if ((sa = (sa_t *)malloc(sizeof(sa_t))) == NULL)
-        return SA_ERR_MEM;
+        return SA_RC(SA_ERR_MEM);
 
     /* init object attributes */
     sa->eType          = SA_TYPE_STREAM;
@@ -952,7 +1016,7 @@
 {
     /* argument sanity check(s) */
     if (sa == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* kill underlying socket */
     sa_socket_kill(sa);
@@ -972,9 +1036,9 @@
 {
     /* argument sanity check(s) */
     if (sa == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
     if (!(type == SA_TYPE_STREAM || type == SA_TYPE_DATAGRAM))
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* kill underlying socket if type changes */
     if (sa->eType != type)
@@ -993,7 +1057,7 @@
 
     /* argument sanity check(s) */
     if (sa == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     if (id == SA_TIMEOUT_ALL) {
         for (i = 0; i < (sizeof(sa->tvTimeout)/sizeof(sa->tvTimeout[0])); i++) {
@@ -1019,19 +1083,19 @@
 
     /* argument sanity check(s) */
     if (sa == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     if (id == SA_BUFFER_READ) {
         /* configure read/incoming buffer */
         if (sa->nReadLen > size)
-            return SA_ERR_USE;
+            return SA_RC(SA_ERR_USE);
         if (size > 0) {
             if (sa->cpReadBuf == NULL)
                 cp = (char *)malloc(size);
             else
                 cp = (char *)realloc(sa->cpReadBuf, size);
             if (cp == NULL)
-                return SA_ERR_SYS;
+                return SA_RC(SA_ERR_SYS);
             sa->cpReadBuf = cp;
             sa->nReadSize = size;
         }
@@ -1045,14 +1109,14 @@
     else if (id == SA_BUFFER_WRITE) {
         /* configure write/outgoing buffer */
         if (sa->nWriteLen > size)
-            return SA_ERR_USE;
+            return SA_RC(SA_ERR_USE);
         if (size > 0) {
             if (sa->cpWriteBuf == NULL)
                 cp = (char *)malloc(size);
             else
                 cp = (char *)realloc(sa->cpWriteBuf, size);
             if (cp == NULL)
-                return SA_ERR_SYS;
+                return SA_RC(SA_ERR_SYS);
             sa->cpWriteBuf = cp;
             sa->nWriteSize = size;
         }
@@ -1063,7 +1127,8 @@
             sa->nWriteSize = 0;
         }
     }
-        return SA_ERR_ARG;
+    else
+        return SA_RC(SA_ERR_ARG);
 
     return SA_OK;
 }
@@ -1076,7 +1141,7 @@
 
     /* argument sanity check(s) */
     if (sa == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* process option */
     rv = SA_OK;
@@ -1091,17 +1156,60 @@
                 break;
             }
             if (setsockopt(sa->fdSocket, IPPROTO_TCP, TCP_NODELAY, 
-                           (void *)&mode, sizeof(mode)) < 0)
+                           (const void *)&mode, (socklen_t)sizeof(mode)) < 0)
                 rv = SA_ERR_SYS;
 #else
             rv = SA_ERR_IMP;
 #endif
             break;
         }
+        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;
+#else
+            rv = SA_ERR_IMP;
+#endif
+            break;
+        }
+        case SA_OPTION_REUSEADDR:
+#ifdef SA_OPTION_REUSEPORT
+        case SA_OPTION_REUSEPORT: 
+#endif
+        {
+            /* enable/disable reusability of binding to address or port */
+            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;
+#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;
@@ -1120,31 +1228,32 @@
     }
     va_end(ap);
 
-    return rv;
+    return SA_RC(rv);
 }
 
 /* override system call */
 sa_rc_t sa_syscall(sa_t *sa, sa_syscall_t id, void (*fptr)(), void *fctx)
 {
+    sa_rc_t rv;
+
+    /* argument sanity check(s) */
     if (sa == NULL || fptr == NULL)
-        return SA_ERR_ARG;
-    if (id == SA_SYSCALL_CONNECT)
-        SA_SC_ASSIGN(sa, connect, fptr, fctx); 
-    else if (id == SA_SYSCALL_ACCEPT)
-        SA_SC_ASSIGN(sa, accept, fptr, fctx); 
-    else if (id == SA_SYSCALL_SELECT)
-        SA_SC_ASSIGN(sa, select, fptr, fctx); 
-    else if (id == SA_SYSCALL_READ)
-        SA_SC_ASSIGN(sa, read, fptr, fctx); 
-    else if (id == SA_SYSCALL_WRITE)
-        SA_SC_ASSIGN(sa, write, fptr, fctx); 
-    else if (id == SA_SYSCALL_RECVFROM)
-        SA_SC_ASSIGN(sa, recvfrom, fptr, fctx); 
-    else if (id == SA_SYSCALL_SENDTO)
-        SA_SC_ASSIGN(sa, sendto, fptr, fctx); 
-    else
-        return SA_ERR_ARG;
-    return SA_OK;
+        return SA_RC(SA_ERR_ARG);
+
+    /* assign system call */
+    rv = SA_OK;
+    switch (id) {
+        case SA_SYSCALL_CONNECT:  SA_SC_ASSIGN(sa, connect,  fptr, fctx); break;
+        case SA_SYSCALL_ACCEPT:   SA_SC_ASSIGN(sa, accept,   fptr, fctx); break;
+        case SA_SYSCALL_SELECT:   SA_SC_ASSIGN(sa, select,   fptr, fctx); break;
+        case SA_SYSCALL_READ:     SA_SC_ASSIGN(sa, read,     fptr, fctx); break;
+        case SA_SYSCALL_WRITE:    SA_SC_ASSIGN(sa, write,    fptr, fctx); break;
+        case SA_SYSCALL_RECVFROM: SA_SC_ASSIGN(sa, recvfrom, fptr, fctx); break;
+        case SA_SYSCALL_SENDTO:   SA_SC_ASSIGN(sa, sendto,   fptr, fctx); break;
+        default: rv = SA_ERR_ARG; 
+    }
+
+    return SA_RC(rv);
 }
 
 /* bind socket to a local address */
@@ -1155,12 +1264,12 @@
 
     /* argument sanity check(s) */
     if (sa == NULL || laddr == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* lazy creation of underlying socket */
     if (sa->fdSocket == -1)
         if ((rv = sa_socket_init(sa, laddr->nFamily)) != SA_OK)
-            return rv;
+            return SA_RC(rv);
 
     /* remove a possibly existing old Unix Domain socket on filesystem */
     if (laddr->nFamily == AF_LOCAL) {
@@ -1170,7 +1279,7 @@
 
     /* perform bind operation on underlying socket */
     if (bind(sa->fdSocket, laddr->saBuf, laddr->slBuf) == -1)
-        return SA_ERR_SYS;
+        return SA_RC(SA_ERR_SYS);
 
     return SA_OK;
 }
@@ -1185,16 +1294,16 @@
 
     /* argument sanity check(s) */
     if (sa == NULL || raddr == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* connecting is only possible for stream communication */ 
     if (sa->eType != SA_TYPE_STREAM)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* lazy creation of underlying socket */
     if (sa->fdSocket == -1)
         if ((rv = sa_socket_init(sa, raddr->nFamily)) != SA_OK)
-            return rv;
+            return SA_RC(rv);
 
     rv = SA_OK;
     if (SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_CONNECT])) {
@@ -1246,7 +1355,7 @@
 
         /* fetch pending error */
         len = sizeof(error);
-        if (getsockopt(sa->fdSocket, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
+        if (getsockopt(sa->fdSocket, SOL_SOCKET, SO_ERROR, (void *)&error, &len) < 0)
             error = errno;
 
         done:
@@ -1262,7 +1371,7 @@
             rv = SA_ERR_SYS;
         }
     }
-    return rv;
+    return SA_RC(rv);
 }
 
 /* listen on socket for connections */
@@ -1270,19 +1379,19 @@
 {
     /* argument sanity check(s) */
     if (sa == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* listening is only possible for stream communication */ 
     if (sa->eType != SA_TYPE_STREAM)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* at least sa_bind() has to be already performed */
     if (sa->fdSocket == -1)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* perform listen operation on underlying socket */
     if (listen(sa->fdSocket, backlog) == -1)
-        return SA_ERR_SYS;
+        return SA_RC(SA_ERR_SYS);
 
     return SA_OK;
 }
@@ -1306,15 +1415,15 @@
 
     /* argument sanity check(s) */
     if (sa == NULL || caddr == NULL || csa == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* accepting connections is only possible for stream communication */ 
     if (sa->eType != SA_TYPE_STREAM)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* at least sa_listen() has to be already performed */
     if (sa->fdSocket == -1)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* if timeout is enabled, perform a smart-blocking wait */
     if (!SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_ACCEPT])) {
@@ -1325,28 +1434,28 @@
                              &sa->tvTimeout[SA_TIMEOUT_ACCEPT]);
         } while (n == -1 && errno == EINTR);
         if (n == 0) 
-            return SA_ERR_TMT;
+            return SA_RC(SA_ERR_TMT);
         if (n <= 0)
-            return SA_ERR_SYS;
+            return SA_RC(SA_ERR_SYS);
     }
 
     /* perform accept operation on underlying socket */
     sa_len = sizeof(sa_buf);
     if ((s = SA_SC_CALL_3(sa, accept, sa->fdSocket, (struct sockaddr *)&sa_buf, &sa_len)) == -1)
-        return SA_ERR_SYS;
+        return SA_RC(SA_ERR_SYS);
 
     /* create result address object */
     if ((rv = sa_addr_create(caddr)) != SA_OK)
-        return rv;
+        return SA_RC(rv);
     if ((rv = sa_addr_s2a(*caddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) {
         sa_addr_destroy(*caddr);
-        return rv;
+        return SA_RC(rv);
     }
 
     /* create result socket object */
     if ((rv = sa_create(csa)) != SA_OK) {
         sa_addr_destroy(*caddr);
-        return rv;
+        return SA_RC(rv);
     }
 
     /* fill-in child socket */
@@ -1384,27 +1493,27 @@
 
     /* argument sanity check(s) */
     if (sa == NULL || raddr == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* peers exist only for stream communication */ 
     if (sa->eType != SA_TYPE_STREAM)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* at least sa_connect() or sa_accept() has to be already performed */
     if (sa->fdSocket == -1)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* determine remote address of underlying socket */
     sa_len = sizeof(sa_buf);
     if (getpeername(sa->fdSocket, (struct sockaddr *)&sa_buf, &sa_len) < 0)
-        return SA_ERR_SYS;
+        return SA_RC(SA_ERR_SYS);
 
     /* create result address object */
     if ((rv = sa_addr_create(raddr)) != SA_OK)
-        return rv;
+        return SA_RC(rv);
     if ((rv = sa_addr_s2a(*raddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) {
         sa_addr_destroy(*raddr);
-        return rv;
+        return SA_RC(rv);
     }
 
     return SA_OK;
@@ -1424,23 +1533,23 @@
 
     /* argument sanity check(s) */
     if (sa == NULL || laddr == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* at least sa_bind() has to be already performed */
     if (sa->fdSocket == -1)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* determine local address of underlying socket */
     sa_len = sizeof(sa_buf);
     if (getsockname(sa->fdSocket, (struct sockaddr *)&sa_buf, &sa_len) < 0)
-        return SA_ERR_SYS;
+        return SA_RC(SA_ERR_SYS);
 
     /* create result address object */
     if ((rv = sa_addr_create(laddr)) != SA_OK)
-        return rv;
+        return SA_RC(rv);
     if ((rv = sa_addr_s2a(*laddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) {
         sa_addr_destroy(*laddr);
-        return rv;
+        return SA_RC(rv);
     }
 
     return SA_OK;
@@ -1451,11 +1560,11 @@
 {
     /* argument sanity check(s) */
     if (sa == NULL || fd == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* if still no socket exists, say this explicitly */
     if (sa->fdSocket == -1)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* pass socket to caller */
     *fd = sa->fdSocket;
@@ -1506,19 +1615,19 @@
 {
     int n;
     sa_rc_t rv;
-    size_t res;
+    int res;
 
     /* argument sanity check(s) */
     if (sa == NULL || cpBuf == NULL || nBufReq == 0)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* reading is only possible for stream communication */ 
     if (sa->eType != SA_TYPE_STREAM)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* at least a connection has to exist */
     if (sa->fdSocket == -1)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* perform read operation */
     rv = SA_OK;
@@ -1537,7 +1646,7 @@
     else {
         /* user-space buffered I/O */
         res = 0;
-        while (1) {
+        for (;;) {
             if (nBufReq <= sa->nReadLen) {
                 /* buffer holds enough data, so just use this */
                 memmove(cpBuf, sa->cpReadBuf, nBufReq);
@@ -1592,9 +1701,9 @@
 
     /* pass number of actually read bytes to caller */ 
     if (nBufRes != NULL)
-        *nBufRes = res;
+        *nBufRes = (size_t)res;
 
-    return rv;
+    return SA_RC(rv);
 }
 
 /* read data from socket until [CR]LF (convinience function) */
@@ -1607,15 +1716,15 @@
 
     /* argument sanity check(s) */
     if (sa == NULL || cpBuf == NULL || nBufReq == 0)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* reading is only possible for stream communication */ 
     if (sa->eType != SA_TYPE_STREAM)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* at least a connection has to exist */
     if (sa->fdSocket == -1)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* we just perform a plain sa_read() per character, because if
        buffers are enabled, this is not as stupid as it looks at the first
@@ -1639,7 +1748,7 @@
     if (nBufRes != NULL)
         *nBufRes = res;
 
-    return rv;
+    return SA_RC(rv);
 }
 
 /* internal raw write operation */
@@ -1683,21 +1792,21 @@
 /* write data to socket */
 sa_rc_t sa_write(sa_t *sa, const char *cpBuf, size_t nBufReq, size_t *nBufRes)
 {
-    size_t n;
-    size_t res;
+    int n;
+    int res;
     sa_rc_t rv;
 
     /* argument sanity check(s) */
     if (sa == NULL || cpBuf == NULL || nBufReq == 0)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* writing is only possible for stream communication */ 
     if (sa->eType != SA_TYPE_STREAM)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* at least a connection has to exist */
     if (sa->fdSocket == -1)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     rv = SA_OK;
     if (sa->nWriteSize == 0) {
@@ -1740,9 +1849,9 @@
 
     /* pass number of actually written bytes to caller */
     if (nBufRes != NULL)
-        *nBufRes = res;
+        *nBufRes = (size_t)res;
 
-    return rv;
+    return SA_RC(rv);
 }
 
 /* output callback function context for sa_writef() */
@@ -1771,15 +1880,15 @@
 
     /* argument sanity check(s) */
     if (sa == NULL || cpFmt == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* writing is only possible for stream communication */ 
     if (sa->eType != SA_TYPE_STREAM)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* at least a connection has to exist */
     if (sa->fdSocket == -1)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* format string into temporary buffer */
     va_start(ap, cpFmt);
@@ -1794,20 +1903,20 @@
 /* flush write/outgoing I/O buffer */
 sa_rc_t sa_flush(sa_t *sa)
 {
-    size_t n;
+    int n;
     sa_rc_t rv;
 
     /* argument sanity check(s) */
     if (sa == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* flushing is only possible for stream communication */ 
     if (sa->eType != SA_TYPE_STREAM)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* at least a connection has to exist */
     if (sa->fdSocket == -1)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* try to flush buffer */
     rv = SA_OK;
@@ -1825,7 +1934,7 @@
         }
         sa->nWriteLen = 0;
     }
-    return rv;
+    return SA_RC(rv);
 }
 
 /* shutdown a socket connection */
@@ -1835,15 +1944,15 @@
 
     /* argument sanity check(s) */
     if (sa == NULL || flags == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* shutdown is only possible for stream communication */ 
     if (sa->eType != SA_TYPE_STREAM)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* at least a connection has to exist */
     if (sa->fdSocket == -1)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* determine flags for shutdown(2) */
     how = 0;
@@ -1854,11 +1963,11 @@
     else if (strcmp(flags, "rw") == 0)
         how = SHUT_RDWR;
     else
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* perform shutdown operation on underlying socket */
     if (shutdown(sa->fdSocket, how) == -1)
-        return SA_ERR_SYS;
+        return SA_RC(SA_ERR_SYS);
 
     return SA_OK;
 }
@@ -1879,15 +1988,15 @@
 
     /* argument sanity check(s) */
     if (sa == NULL || buf == NULL || buflen == 0 || raddr == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* receiving is only possible for datagram communication */ 
     if (sa->eType != SA_TYPE_DATAGRAM)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* at least a sa_bind() has to be performed */
     if (sa->fdSocket == -1)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* if timeout is enabled, perform explicit/smart blocking instead 
        of implicitly/hard blocking in the recvfrom(2) system call */
@@ -1901,14 +2010,14 @@
         if (n == 0) 
             errno = ETIMEDOUT;
         if (n <= 0)
-            return SA_ERR_SYS;
+            return SA_RC(SA_ERR_SYS);
     }
 
     /* perform receive operation on underlying socket */
     sa_len = sizeof(sa_buf);
     if ((n = SA_SC_CALL_6(sa, recvfrom, sa->fdSocket, buf, buflen, 0, 
                           (struct sockaddr *)&sa_buf, &sa_len)) == -1)
-        return SA_ERR_SYS;
+        return SA_RC(SA_ERR_SYS);
 
     /* create result address object */
     if ((rv = sa_addr_create(raddr)) != SA_OK)
@@ -1934,11 +2043,11 @@
 
     /* argument sanity check(s) */
     if (sa == NULL || buf == NULL || buflen == 0 || raddr == NULL)
-        return SA_ERR_ARG;
+        return SA_RC(SA_ERR_ARG);
 
     /* sending is only possible for datagram communication */ 
     if (sa->eType != SA_TYPE_DATAGRAM)
-        return SA_ERR_USE;
+        return SA_RC(SA_ERR_USE);
 
     /* lazy creation of underlying socket */
     if (sa->fdSocket == -1)
@@ -1957,12 +2066,12 @@
         if (n == 0) 
             errno = ETIMEDOUT;
         if (n <= 0)
-            return SA_ERR_SYS;
+            return SA_RC(SA_ERR_SYS);
     }
 
     /* perform send operation on underlying socket */
     if ((n = SA_SC_CALL_6(sa, sendto, sa->fdSocket, buf, buflen, 0, raddr->saBuf, raddr->slBuf)) == -1)
-        return SA_ERR_SYS;
+        return SA_RC(SA_ERR_SYS);
 
     /* pass actual number of sent bytes to caller */
     if (bufdone != NULL)

CVSTrac 2.0.1