--- 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)
|