--- l2_ut_sa.c 2002/10/21 15:14:04 1.19
+++ l2_ut_sa.c 2002/11/09 14:44:31 1.20
@@ -45,7 +45,7 @@
#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 "PF_XXX", "AF_XXX" and "SOCK_XXX" */
+#include <sys/socket.h> /* for "PF_XXX", "AF_XXX", "SOCK_XXX" and "SHUT_XX" */
#include <arpa/inet.h> /* for "inet_XtoX" */
/* include own API header */
@@ -88,6 +88,19 @@
#define PF_INET6 AF_INET6
#endif
+/* backward compatibility for SHUT_XX. Some platforms (like brain-dead
+ OpenUNIX) define those only if _XOPEN_SOURCE is defined, but unfortunately
+ then fail in their other vendor includes due to internal inconsistencies. */
+#if !defined(SHUT_RD)
+#define SHUT_RD 0
+#endif
+#if !defined(SHUT_WR)
+#define SHUT_WR 1
+#endif
+#if !defined(SHUT_RDWR)
+#define SHUT_RDWR 2
+#endif
+
/* backward compatibility for ssize_t */
#if !defined(HAVE_SSIZE_T)
#define ssize_t long
@@ -203,7 +216,13 @@
SA_SC_DECLARE_6(ssize_t, recvfrom, int, void *, size_t, int, struct sockaddr *, socklen_t *)
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) */
@@ -216,6 +235,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 */
@@ -270,7 +290,7 @@
#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(*((struct in_addr *)src))) == NULL)
+ if ((cp = inet_ntoa(*((struct in_addr *)src))) == NULL)
return NULL;
n = strlen(cp);
if (n > size-1)
@@ -289,14 +309,14 @@
static int sa_mvxprintf(int (*output)(void *ctx, const char *buffer, size_t bufsize), void *ctx, const char *format, va_list ap)
{
/* sufficient integer buffer: <available-bits> x log_10(2) + safety */
- char ibuf[((sizeof(int)*8)/3)+10];
+ char ibuf[((sizeof(int)*8)/3)+10];
char *cp;
char c;
int d;
int n;
int bytes;
- if (format == NULL || ap == NULL)
+ if (format == NULL)
return -1;
bytes = 0;
while (*format != '\0') {
@@ -378,11 +398,11 @@
int n;
sa_mvsnprintf_cb_t ctx;
- if (format == NULL || ap == NULL)
+ if (format == NULL)
return -1;
if (buffer != NULL && bufsize == 0)
return -1;
- if (buffer == NULL)
+ if (buffer == NULL)
/* just determine output length */
n = sa_mvxprintf(NULL, NULL, format, ap);
else {
@@ -489,7 +509,7 @@
sl = 0;
sf = 0;
- /* parse URI and resolve contents.
+ /* parse URI and resolve contents.
The following syntax is recognized:
- unix:<path>
- inet://<host>:<port>[#(tcp|udp)] */
@@ -609,7 +629,7 @@
else if (he->h_addrtype == AF_INET6) {
sa6.sin6_family = AF_INET6;
sa6.sin6_port = htons(nPort);
- memcpy(&sa6.sin6_addr.s6_addr, he->h_addr_list[0],
+ memcpy(&sa6.sin6_addr.s6_addr, he->h_addr_list[0],
sizeof(sa6.sin6_addr.s6_addr));
sa = (struct sockaddr *)&sa6;
sl = sizeof(sa6);
@@ -691,7 +711,7 @@
|| saa->slBuf < sizeof(struct sockaddr_un))
/* in case the remote side of a Unix Domain socket was not
bound, a "struct sockaddr_un" can occur with a length less
- than the expected one. Then there is actually no path at all.
+ than the expected one. Then there is actually no path at all.
This has been verified under FreeBSD, Linux and Solaris. */
sa_msnprintf(uribuf, sizeof(uribuf), "unix:/NOT-BOUND");
else
@@ -780,7 +800,7 @@
#ifdef AF_INET6
else if ( (saa1->nFamily == AF_INET && saa2->nFamily == AF_INET6)
|| (saa1->nFamily == AF_INET6 && saa2->nFamily == AF_INET )) {
- /* special case of comparing a regular IPv4 address (1.2.3.4) with an
+ /* 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);
@@ -837,7 +857,7 @@
prefixlen = nBits;
}
- /* perform address representation comparison
+ /* perform address representation comparison
(assumption guaranteed by API: network byte order is used) */
nBytes = (prefixlen / 8);
nBits = (prefixlen % 8);
@@ -864,25 +884,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)
{
@@ -891,6 +1006,7 @@
#if !(defined(IPPROTO_TCP) && defined(IPPROTO_UDP))
struct protoent *pe;
#endif
+ sa_rc_t rv;
/* argument sanity check(s) */
if (sa == NULL)
@@ -909,7 +1025,7 @@
return SA_RC(SA_ERR_INT);
/* determine socket protocol */
- if (nFamily == AF_LOCAL)
+ if (nFamily == AF_LOCAL)
nProto = 0;
#ifdef AF_INET6
else if (nFamily == AF_INET || nFamily == AF_INET6) {
@@ -943,7 +1059,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;
}
@@ -996,6 +1117,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);
@@ -1054,6 +1181,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)
@@ -1070,8 +1198,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;
}
@@ -1095,7 +1224,7 @@
else
cp = (char *)realloc(sa->cpReadBuf, size);
if (cp == NULL)
- return SA_RC(SA_ERR_SYS);
+ return SA_RC(SA_ERR_MEM);
sa->cpReadBuf = cp;
sa->nReadSize = size;
}
@@ -1116,7 +1245,7 @@
else
cp = (char *)realloc(sa->cpWriteBuf, size);
if (cp == NULL)
- return SA_RC(SA_ERR_SYS);
+ return SA_RC(SA_ERR_MEM);
sa->cpWriteBuf = cp;
sa->nWriteSize = size;
}
@@ -1148,16 +1277,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
@@ -1165,61 +1288,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: {
@@ -1228,7 +1330,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 */
@@ -1250,7 +1360,7 @@
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;
+ default: rv = SA_ERR_ARG;
}
return SA_RC(rv);
@@ -1296,7 +1406,7 @@
if (sa == NULL || raddr == NULL)
return SA_RC(SA_ERR_ARG);
- /* connecting is only possible for stream communication */
+ /* connecting is only possible for stream communication */
if (sa->eType != SA_TYPE_STREAM)
return SA_RC(SA_ERR_USE);
@@ -1329,7 +1439,7 @@
/* ok if connect completed immediately */
if (n == 0)
- goto done;
+ goto done;
/* wait for read or write possibility */
FD_ZERO(&rset);
@@ -1381,7 +1491,7 @@
if (sa == NULL)
return SA_RC(SA_ERR_ARG);
- /* listening is only possible for stream communication */
+ /* listening is only possible for stream communication */
if (sa->eType != SA_TYPE_STREAM)
return SA_RC(SA_ERR_USE);
@@ -1409,7 +1519,7 @@
struct sockaddr_in6 sa6;
#endif
} sa_buf;
- socklen_t sa_len;
+ socklen_t sa_size;
int s;
int i;
@@ -1417,7 +1527,7 @@
if (sa == NULL || caddr == NULL || csa == NULL)
return SA_RC(SA_ERR_ARG);
- /* accepting connections is only possible for stream communication */
+ /* accepting connections is only possible for stream communication */
if (sa->eType != SA_TYPE_STREAM)
return SA_RC(SA_ERR_USE);
@@ -1433,21 +1543,21 @@
n = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &fds, NULL, NULL,
&sa->tvTimeout[SA_TIMEOUT_ACCEPT]);
} while (n == -1 && errno == EINTR);
- if (n == 0)
+ if (n == 0)
return SA_RC(SA_ERR_TMT);
if (n <= 0)
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)
+ sa_size = sizeof(sa_buf);
+ if ((s = SA_SC_CALL_3(sa, accept, sa->fdSocket, (struct sockaddr *)&sa_buf, &sa_size)) == -1)
return SA_RC(SA_ERR_SYS);
/* create result address object */
if ((rv = sa_addr_create(caddr)) != SA_OK)
return SA_RC(rv);
- if ((rv = sa_addr_s2a(*caddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) {
+ if ((rv = sa_addr_s2a(*caddr, (struct sockaddr *)&sa_buf, sa_size)) != SA_OK) {
sa_addr_destroy(*caddr);
return SA_RC(rv);
}
@@ -1489,13 +1599,13 @@
struct sockaddr_in6 sa6;
#endif
} sa_buf;
- socklen_t sa_len;
+ socklen_t sa_size;
/* argument sanity check(s) */
if (sa == NULL || raddr == NULL)
return SA_RC(SA_ERR_ARG);
- /* peers exist only for stream communication */
+ /* peers exist only for stream communication */
if (sa->eType != SA_TYPE_STREAM)
return SA_RC(SA_ERR_USE);
@@ -1504,14 +1614,14 @@
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)
+ sa_size = sizeof(sa_buf);
+ if (getpeername(sa->fdSocket, (struct sockaddr *)&sa_buf, &sa_size) < 0)
return SA_RC(SA_ERR_SYS);
/* create result address object */
if ((rv = sa_addr_create(raddr)) != SA_OK)
return SA_RC(rv);
- if ((rv = sa_addr_s2a(*raddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) {
+ if ((rv = sa_addr_s2a(*raddr, (struct sockaddr *)&sa_buf, sa_size)) != SA_OK) {
sa_addr_destroy(*raddr);
return SA_RC(rv);
}
@@ -1529,7 +1639,7 @@
struct sockaddr_in6 sa6;
#endif
} sa_buf;
- socklen_t sa_len;
+ socklen_t sa_size;
/* argument sanity check(s) */
if (sa == NULL || laddr == NULL)
@@ -1540,14 +1650,14 @@
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)
+ sa_size = sizeof(sa_buf);
+ if (getsockname(sa->fdSocket, (struct sockaddr *)&sa_buf, &sa_size) < 0)
return SA_RC(SA_ERR_SYS);
/* create result address object */
if ((rv = sa_addr_create(laddr)) != SA_OK)
return SA_RC(rv);
- if ((rv = sa_addr_s2a(*laddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) {
+ if ((rv = sa_addr_s2a(*laddr, (struct sockaddr *)&sa_buf, sa_size)) != SA_OK) {
sa_addr_destroy(*laddr);
return SA_RC(rv);
}
@@ -1580,14 +1690,14 @@
fd_set fds;
#endif
- /* if timeout is enabled, perform explicit/smart blocking instead
+ /* if timeout is enabled, perform explicit/smart blocking instead
of implicitly/hard blocking in the read(2) system call */
#if !(defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO))
if (!SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_READ])) {
FD_ZERO(&fds);
FD_SET(sa->fdSocket, &fds);
do {
- rv = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &fds, NULL, NULL,
+ rv = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &fds, NULL, NULL,
&sa->tvTimeout[SA_TIMEOUT_READ]);
} while (rv == -1 && errno == EINTR);
if (rv == 0) {
@@ -1621,7 +1731,7 @@
if (sa == NULL || cpBuf == NULL || nBufReq == 0)
return SA_RC(SA_ERR_ARG);
- /* reading is only possible for stream communication */
+ /* reading is only possible for stream communication */
if (sa->eType != SA_TYPE_STREAM)
return SA_RC(SA_ERR_USE);
@@ -1686,7 +1796,7 @@
else if (n < 0)
/* error on this read, but perhaps ok as a whole */
rv = (res == 0 ? SA_ERR_SYS : SA_OK);
- if (n == 0)
+ else if (n == 0)
/* EOF on this read, but perhaps ok as a whole */
rv = (res == 0 ? SA_ERR_EOF : SA_OK);
else {
@@ -1699,7 +1809,7 @@
}
}
- /* pass number of actually read bytes to caller */
+ /* pass number of actually read bytes to caller */
if (nBufRes != NULL)
*nBufRes = (size_t)res;
@@ -1718,7 +1828,7 @@
if (sa == NULL || cpBuf == NULL || nBufReq == 0)
return SA_RC(SA_ERR_ARG);
- /* reading is only possible for stream communication */
+ /* reading is only possible for stream communication */
if (sa->eType != SA_TYPE_STREAM)
return SA_RC(SA_ERR_USE);
@@ -1759,14 +1869,14 @@
fd_set fds;
#endif
- /* if timeout is enabled, perform explicit/smart blocking instead
+ /* if timeout is enabled, perform explicit/smart blocking instead
of implicitly/hard blocking in the write(2) system call */
#if !(defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO))
if (!SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_WRITE])) {
FD_ZERO(&fds);
FD_SET(sa->fdSocket, &fds);
do {
- rv = SA_SC_CALL_5(sa, select, sa->fdSocket+1, NULL, &fds, NULL,
+ rv = SA_SC_CALL_5(sa, select, sa->fdSocket+1, NULL, &fds, NULL,
&sa->tvTimeout[SA_TIMEOUT_WRITE]);
} while (rv == -1 && errno == EINTR);
if (rv == 0) {
@@ -1800,7 +1910,7 @@
if (sa == NULL || cpBuf == NULL || nBufReq == 0)
return SA_RC(SA_ERR_ARG);
- /* writing is only possible for stream communication */
+ /* writing is only possible for stream communication */
if (sa->eType != SA_TYPE_STREAM)
return SA_RC(SA_ERR_USE);
@@ -1867,8 +1977,8 @@
sa_writef_cb_t *ctx = (sa_writef_cb_t *)_ctx;
if ((ctx->rv = sa_write(ctx->sa, buffer, bufsize, &n)) != SA_OK)
- n = -1;
- return n;
+ return -1;
+ return (int)n;
}
/* write formatted string to socket (convinience function) */
@@ -1882,7 +1992,7 @@
if (sa == NULL || cpFmt == NULL)
return SA_RC(SA_ERR_ARG);
- /* writing is only possible for stream communication */
+ /* writing is only possible for stream communication */
if (sa->eType != SA_TYPE_STREAM)
return SA_RC(SA_ERR_USE);
@@ -1910,7 +2020,7 @@
if (sa == NULL)
return SA_RC(SA_ERR_ARG);
- /* flushing is only possible for stream communication */
+ /* flushing is only possible for stream communication */
if (sa->eType != SA_TYPE_STREAM)
return SA_RC(SA_ERR_USE);
@@ -1946,7 +2056,7 @@
if (sa == NULL || flags == NULL)
return SA_RC(SA_ERR_ARG);
- /* shutdown is only possible for stream communication */
+ /* shutdown is only possible for stream communication */
if (sa->eType != SA_TYPE_STREAM)
return SA_RC(SA_ERR_USE);
@@ -1960,11 +2070,15 @@
how = SHUT_RD;
else if (strcmp(flags, "w") == 0)
how = SHUT_WR;
- else if (strcmp(flags, "rw") == 0)
+ else if (strcmp(flags, "rw") == 0 || strcmp(flags, "wr") == 0)
how = SHUT_RDWR;
else
return SA_RC(SA_ERR_ARG);
+ /* flush write buffers */
+ if ((how & SHUT_WR) || (how & SHUT_RDWR))
+ sa_flush(sa);
+
/* perform shutdown operation on underlying socket */
if (shutdown(sa->fdSocket, how) == -1)
return SA_RC(SA_ERR_SYS);
@@ -1973,7 +2087,7 @@
}
/* receive data via socket */
-sa_rc_t sa_recv(sa_t *sa, char *buf, size_t buflen, size_t *bufdone, sa_addr_t **raddr)
+sa_rc_t sa_recv(sa_t *sa, sa_addr_t **raddr, char *buf, size_t buflen, size_t *bufdone)
{
sa_rc_t rv;
union {
@@ -1982,7 +2096,7 @@
struct sockaddr_in6 sa6;
#endif
} sa_buf;
- socklen_t sa_len;
+ socklen_t sa_size;
size_t n;
fd_set fds;
@@ -1990,7 +2104,7 @@
if (sa == NULL || buf == NULL || buflen == 0 || raddr == NULL)
return SA_RC(SA_ERR_ARG);
- /* receiving is only possible for datagram communication */
+ /* receiving is only possible for datagram communication */
if (sa->eType != SA_TYPE_DATAGRAM)
return SA_RC(SA_ERR_USE);
@@ -1998,31 +2112,31 @@
if (sa->fdSocket == -1)
return SA_RC(SA_ERR_USE);
- /* if timeout is enabled, perform explicit/smart blocking instead
+ /* if timeout is enabled, perform explicit/smart blocking instead
of implicitly/hard blocking in the recvfrom(2) system call */
if (!SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_READ])) {
FD_ZERO(&fds);
FD_SET(sa->fdSocket, &fds);
do {
- n = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &fds, NULL, NULL,
+ n = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &fds, NULL, NULL,
&sa->tvTimeout[SA_TIMEOUT_READ]);
} while (n == -1 && errno == EINTR);
- if (n == 0)
+ if (n == 0)
errno = ETIMEDOUT;
if (n <= 0)
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)
+ sa_size = sizeof(sa_buf);
+ if ((n = SA_SC_CALL_6(sa, recvfrom, sa->fdSocket, buf, buflen, 0,
+ (struct sockaddr *)&sa_buf, &sa_size)) == -1)
return SA_RC(SA_ERR_SYS);
/* create result address object */
if ((rv = sa_addr_create(raddr)) != SA_OK)
return rv;
- if ((rv = sa_addr_s2a(*raddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) {
+ if ((rv = sa_addr_s2a(*raddr, (struct sockaddr *)&sa_buf, sa_size)) != SA_OK) {
sa_addr_destroy(*raddr);
return rv;
}
@@ -2035,7 +2149,7 @@
}
/* send data via socket */
-sa_rc_t sa_send(sa_t *sa, const char *buf, size_t buflen, size_t *bufdone, sa_addr_t *raddr)
+sa_rc_t sa_send(sa_t *sa, sa_addr_t *raddr, const char *buf, size_t buflen, size_t *bufdone)
{
size_t n;
fd_set fds;
@@ -2045,7 +2159,7 @@
if (sa == NULL || buf == NULL || buflen == 0 || raddr == NULL)
return SA_RC(SA_ERR_ARG);
- /* sending is only possible for datagram communication */
+ /* sending is only possible for datagram communication */
if (sa->eType != SA_TYPE_DATAGRAM)
return SA_RC(SA_ERR_USE);
@@ -2054,16 +2168,16 @@
if ((rv = sa_socket_init(sa, raddr->nFamily)) != SA_OK)
return rv;
- /* if timeout is enabled, perform explicit/smart blocking instead
+ /* if timeout is enabled, perform explicit/smart blocking instead
of implicitly/hard blocking in the sendto(2) system call */
if (!SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_WRITE])) {
FD_ZERO(&fds);
FD_SET(sa->fdSocket, &fds);
do {
- n = SA_SC_CALL_5(sa, select, sa->fdSocket+1, NULL, &fds, NULL,
+ n = SA_SC_CALL_5(sa, select, sa->fdSocket+1, NULL, &fds, NULL,
&sa->tvTimeout[SA_TIMEOUT_WRITE]);
} while (n == -1 && errno == EINTR);
- if (n == 0)
+ if (n == 0)
errno = ETIMEDOUT;
if (n <= 0)
return SA_RC(SA_ERR_SYS);
@@ -2080,6 +2194,46 @@
return SA_OK;
}
+/* send formatted string to socket (convinience function) */
+sa_rc_t sa_sendf(sa_t *sa, sa_addr_t *raddr, const char *cpFmt, ...)
+{
+ va_list ap;
+ size_t nBuf;
+ char *cpBuf;
+ sa_rc_t rv;
+ char caBuf[1024];
+
+ /* argument sanity check(s) */
+ if (sa == NULL || raddr == NULL || cpFmt == NULL)
+ return SA_RC(SA_ERR_ARG);
+
+ /* format string into temporary buffer */
+ va_start(ap, cpFmt);
+ nBuf = sa_mvsnprintf(NULL, 0, cpFmt, ap);
+ va_end(ap);
+ if ((nBuf+1) > sizeof(caBuf)) {
+ /* requires a larger buffer, so allocate dynamically */
+ if ((cpBuf = (char *)malloc(nBuf+1)) == NULL)
+ return SA_RC(SA_ERR_MEM);
+ }
+ else {
+ /* fits into small buffer, so allocate statically */
+ cpBuf = caBuf;
+ }
+ va_start(ap, cpFmt);
+ sa_mvsnprintf(cpBuf, nBuf+1, cpFmt, ap);
+ va_end(ap);
+
+ /* pass-through to sa_send() */
+ rv = sa_send(sa, raddr, cpBuf, nBuf, NULL);
+
+ /* cleanup dynamically allocated buffer */
+ if ((nBuf+1) > sizeof(caBuf))
+ free(cpBuf);
+
+ return rv;
+}
+
/* return error string */
char *sa_error(sa_rc_t rv)
{
|