Index: ossp-pkg/l2/l2_ch_socket.c RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_ch_socket.c,v rcsdiff -q -kk '-r1.36' '-r1.37' -u '/v/ossp/cvs/ossp-pkg/l2/l2_ch_socket.c,v' 2>/dev/null --- l2_ch_socket.c 2002/07/30 19:08:25 1.36 +++ l2_ch_socket.c 2002/11/09 14:44:31 1.37 @@ -151,7 +151,7 @@ if (strcmp(cfg->szProto, "tcp") == 0) rc = sa_write(cfg->saRemote, buf, sizeRemain, &sizeWrite); else - rc = sa_send(cfg->saRemote, buf, sizeRemain, &sizeWrite, cfg->saaRemote); + rc = sa_send(cfg->saRemote, cfg->saaRemote, buf, sizeRemain, &sizeWrite); if (rc != SA_OK) return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_INT); sizeRemain = sizeRemain - sizeWrite; /* how much is left? */ Index: ossp-pkg/l2/l2_ch_syslog.c RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_ch_syslog.c,v rcsdiff -q -kk '-r1.31' '-r1.32' -u '/v/ossp/cvs/ossp-pkg/l2/l2_ch_syslog.c,v' 2>/dev/null --- l2_ch_syslog.c 2002/07/30 19:08:25 1.31 +++ l2_ch_syslog.c 2002/11/09 14:44:31 1.32 @@ -297,8 +297,8 @@ cfg->szIdent, buf); if ((n = strlen(caBuf)) > 1024) return L2_ERR_IO; - if ((rc = sa_send(cfg->saRemoteSock, caBuf, n, - NULL, cfg->saaRemoteAddr)) != SA_OK) + if ((rc = sa_send(cfg->saRemoteSock, cfg->saaRemoteAddr, + caBuf, n, NULL)) != SA_OK) return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_IO); } Index: ossp-pkg/l2/l2_ut_sa.ac RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_ut_sa.ac,v rcsdiff -q -kk '-r1.6' '-r1.7' -u '/v/ossp/cvs/ossp-pkg/l2/l2_ut_sa.ac,v' 2>/dev/null --- l2_ut_sa.ac 2002/10/11 16:00:48 1.6 +++ l2_ut_sa.ac 2002/11/09 14:44:31 1.7 @@ -42,8 +42,8 @@ changequote(<<,>>)dnl <<(^|[^a-zA-Z_0-9])$1[^a-zA-Z_0-9]>>dnl changequote([,]), [ -#include <$2>], - ac_cv_typedef_$1=yes, +#include <$2>], + ac_cv_typedef_$1=yes, ac_cv_typedef_$1=no ) ])dnl @@ -62,12 +62,12 @@ AC_CHECK_LIB(nsl, gethostname) if test ".`echo $LIBS | grep nsl`" = .; then AC_CHECK_LIB(nsl, gethostbyname) - fi + fi AC_CHECK_LIB(socket, accept) # make sure some platforms find their IPv6 library AC_CHECK_LIB(inet6, getaddrinfo) - + # check for system headers AC_CHECK_HEADERS(string.h sys/types.h sys/socket.h netdb.h netinet/in.h) Index: ossp-pkg/l2/l2_ut_sa.c RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_ut_sa.c,v rcsdiff -q -kk '-r1.19' '-r1.20' -u '/v/ossp/cvs/ossp-pkg/l2/l2_ut_sa.c,v' 2>/dev/null --- 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 /* for "struct timeval" */ #include /* for "struct sockaddr_un" */ #include /* for "struct sockaddr_in[6]" */ -#include /* for "PF_XXX", "AF_XXX" and "SOCK_XXX" */ +#include /* for "PF_XXX", "AF_XXX", "SOCK_XXX" and "SHUT_XX" */ #include /* 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: 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: - inet://:[#(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) { Index: ossp-pkg/l2/l2_ut_sa.h RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_ut_sa.h,v rcsdiff -q -kk '-r1.15' '-r1.16' -u '/v/ossp/cvs/ossp-pkg/l2/l2_ut_sa.h,v' 2>/dev/null --- l2_ut_sa.h 2002/10/21 15:14:04 1.15 +++ l2_ut_sa.h 2002/11/09 14:44:31 1.16 @@ -137,11 +137,11 @@ /* list of options */ typedef enum { - SA_OPTION_NAGLE, - SA_OPTION_LINGER, - SA_OPTION_REUSEADDR, - SA_OPTION_REUSEPORT, - SA_OPTION_NONBLOCK + SA_OPTION_NAGLE = 0, + SA_OPTION_LINGER = 1, + SA_OPTION_REUSEADDR = 2, + SA_OPTION_REUSEPORT = 3, + SA_OPTION_NONBLOCK = 4 } sa_option_t; /* list of system calls */ @@ -159,50 +159,51 @@ extern const char sa_id[]; /* address object operations */ -sa_rc_t sa_addr_create (sa_addr_t **saa); -sa_rc_t sa_addr_destroy (sa_addr_t *saa); +extern sa_rc_t sa_addr_create (sa_addr_t **__saa); +extern sa_rc_t sa_addr_destroy (sa_addr_t *__saa); /* address operations */ -sa_rc_t sa_addr_u2a (sa_addr_t *saa, const char *uri, ...); -sa_rc_t sa_addr_s2a (sa_addr_t *saa, const struct sockaddr *sabuf, socklen_t salen); -sa_rc_t sa_addr_a2u (sa_addr_t *saa, char **uri); -sa_rc_t sa_addr_a2s (sa_addr_t *saa, struct sockaddr **sabuf, socklen_t *salen); -sa_rc_t sa_addr_match (sa_addr_t *saa1, sa_addr_t *saa2, int prefixlen); +extern sa_rc_t sa_addr_u2a (sa_addr_t *__saa, const char *__uri, ...); +extern sa_rc_t sa_addr_s2a (sa_addr_t *__saa, const struct sockaddr *__sabuf, socklen_t __salen); +extern sa_rc_t sa_addr_a2u (sa_addr_t *__saa, char **__uri); +extern sa_rc_t sa_addr_a2s (sa_addr_t *__saa, struct sockaddr **__sabuf, socklen_t *__salen); +extern sa_rc_t sa_addr_match (sa_addr_t *__saa1, sa_addr_t *__saa2, int __prefixlen); /* socket object operations */ -sa_rc_t sa_create (sa_t **sa); -sa_rc_t sa_destroy (sa_t *sa); +extern sa_rc_t sa_create (sa_t **__sa); +extern sa_rc_t sa_destroy (sa_t *__sa); /* socket parameter operations */ -sa_rc_t sa_type (sa_t *sa, sa_type_t type); -sa_rc_t sa_timeout (sa_t *sa, sa_timeout_t id, long sec, long usec); -sa_rc_t sa_buffer (sa_t *sa, sa_buffer_t id, size_t size); -sa_rc_t sa_option (sa_t *sa, sa_option_t id, ...); -sa_rc_t sa_syscall (sa_t *sa, sa_syscall_t id, void (*fptr)(), void *fctx); +extern sa_rc_t sa_type (sa_t *__sa, sa_type_t __id); +extern sa_rc_t sa_timeout (sa_t *__sa, sa_timeout_t __id, long __sec, long __usec); +extern sa_rc_t sa_buffer (sa_t *__sa, sa_buffer_t __id, size_t __size); +extern sa_rc_t sa_option (sa_t *__sa, sa_option_t __id, ...); +extern sa_rc_t sa_syscall (sa_t *__sa, sa_syscall_t __id, void (*__fptr)(), void *__fctx); /* socket connection operations */ -sa_rc_t sa_bind (sa_t *sa, sa_addr_t *laddr); -sa_rc_t sa_connect (sa_t *sa, sa_addr_t *raddr); -sa_rc_t sa_listen (sa_t *sa, int backlog); -sa_rc_t sa_accept (sa_t *sa, sa_addr_t **caddr, sa_t **csa); -sa_rc_t sa_getremote (sa_t *sa, sa_addr_t **raddr); -sa_rc_t sa_getlocal (sa_t *sa, sa_addr_t **laddr); -sa_rc_t sa_getfd (sa_t *sa, int *fd); -sa_rc_t sa_shutdown (sa_t *sa, char *flags); +extern sa_rc_t sa_bind (sa_t *__sa, sa_addr_t *__laddr); +extern sa_rc_t sa_connect (sa_t *__sa, sa_addr_t *__raddr); +extern sa_rc_t sa_listen (sa_t *__sa, int __backlog); +extern sa_rc_t sa_accept (sa_t *__sa, sa_addr_t **__caddr, sa_t **__csa); +extern sa_rc_t sa_getremote (sa_t *__sa, sa_addr_t **__raddr); +extern sa_rc_t sa_getlocal (sa_t *__sa, sa_addr_t **__laddr); +extern sa_rc_t sa_getfd (sa_t *__sa, int *__fd); +extern sa_rc_t sa_shutdown (sa_t *__sa, char *__flags); /* socket input/output operations (stream communication) */ -sa_rc_t sa_read (sa_t *sa, char *buf, size_t buflen, size_t *bufdone); -sa_rc_t sa_readln (sa_t *sa, char *buf, size_t buflen, size_t *bufdone); -sa_rc_t sa_write (sa_t *sa, const char *buf, size_t buflen, size_t *bufdone); -sa_rc_t sa_writef (sa_t *sa, const char *fmt, ...); -sa_rc_t sa_flush (sa_t *sa); +extern sa_rc_t sa_read (sa_t *__sa, char *__buf, size_t __buflen, size_t *__bufdone); +extern sa_rc_t sa_readln (sa_t *__sa, char *__buf, size_t __buflen, size_t *__bufdone); +extern sa_rc_t sa_write (sa_t *__sa, const char *__buf, size_t __buflen, size_t *__bufdone); +extern sa_rc_t sa_writef (sa_t *__sa, const char *__fmt, ...); +extern sa_rc_t sa_flush (sa_t *__sa); /* socket input/output operations (datagram communication) */ -sa_rc_t sa_recv (sa_t *sa, char *buf, size_t buflen, size_t *bufdone, sa_addr_t **raddr); -sa_rc_t sa_send (sa_t *sa, const char *buf, size_t buflen, size_t *bufdone, sa_addr_t *raddr); +extern sa_rc_t sa_recv (sa_t *__sa, sa_addr_t **__raddr, char *__buf, size_t __buflen, size_t *__bufdone); +extern sa_rc_t sa_send (sa_t *__sa, sa_addr_t *__raddr, const char *__buf, size_t __buflen, size_t *__bufdone); +extern sa_rc_t sa_sendf (sa_t *__sa, sa_addr_t *__raddr, const char *__fmt, ...); /* error handling operations */ -char *sa_error (sa_rc_t rv); +extern char *sa_error (sa_rc_t __rv); /* cleanup */ #if defined(HAVE_CONFIG_H) && !defined(HAVE_SOCKLEN_T)