Index: ossp-pkg/l2/configure.ac RCS File: /v/ossp/cvs/ossp-pkg/l2/configure.ac,v rcsdiff -q -kk '-r1.10' '-r1.11' -u '/v/ossp/cvs/ossp-pkg/l2/configure.ac,v' 2>/dev/null --- configure.ac 2001/09/14 19:06:40 1.10 +++ configure.ac 2001/10/06 14:33:09 1.11 @@ -84,6 +84,7 @@ AC_CHECK_FUNCS(inet_aton inet_pton inet_ntoa inet_ntop snprintf vsnprintf) sinclude(l2_ut_sa.ac) +AC_CHECK_SA AC_CHECK_EXTLIB([Dmalloc], dmalloc, dmalloc_debug, dmalloc.h, AC_DEFINE(WITH_DMALLOC)) Index: ossp-pkg/l2/l2_ch_smtp.c RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_ch_smtp.c,v rcsdiff -q -kk '-r1.3' '-r1.4' -u '/v/ossp/cvs/ossp-pkg/l2/l2_ch_smtp.c,v' 2>/dev/null --- l2_ch_smtp.c 2001/09/14 12:55:20 1.3 +++ l2_ch_smtp.c 2001/10/06 14:33:09 1.4 @@ -121,7 +121,10 @@ return L2_ERR_USE; /* create socket address */ - if ((rc = sa_u2a(&cfg->saaServer, "tcp://%s:%s", cfg->cpHost, cfg->cpPort)) != SA_OK) + if ((rc = sa_addr_create(&cfg->saaServer)) != SA_OK) + return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_INT); + if ((rc = sa_addr_u2a(cfg->saaServer, "inet://%s:%s", + cfg->cpHost, cfg->cpPort)) != SA_OK) return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_INT); /* create socket */ @@ -190,31 +193,31 @@ cu(sa_rv == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_INT); /* | 220 en1.engelschall.com ESMTP SMTP Sendmail 8.11.0+ ready */ - sa_rv = sa_readline(sa, caLine, sizeof(caLine), &n); + sa_rv = sa_readln(sa, caLine, sizeof(caLine), &n); cu_on(!(sa_rv == SA_OK && n > 3 && atoi(caLine) == 220), L2_ERR_IO); /* | HELO l2 * | 250 en1.engelschall.com Hello en1.engelschall.com [141.1.129.1], pleased to meet you */ - sa_printf(sa, "HELO %s\r\n", cfg->cpLocalHost); - sa_rv = sa_readline(sa, caLine, sizeof(caLine), &n); + sa_writef(sa, "HELO %s\r\n", cfg->cpLocalHost); + sa_rv = sa_readln(sa, caLine, sizeof(caLine), &n); cu_on(!(sa_rv == SA_OK && n > 3 && atoi(caLine) == 250), L2_ERR_IO); /* | MAIL From: * | 250 2.1.0 ... Sender ok */ - sa_printf(sa, "MAIL FROM:<%s>\r\n", cfg->cpFrom); - sa_rv = sa_readline(sa, caLine, sizeof(caLine), &n); + sa_writef(sa, "MAIL FROM:<%s>\r\n", cfg->cpFrom); + sa_rv = sa_readln(sa, caLine, sizeof(caLine), &n); cu_on(!(sa_rv == SA_OK && n > 3 && atoi(caLine) == 250), L2_ERR_IO); /* | RCPT To: * | 250 2.1.5 ... Recipient ok */ - sa_printf(sa, "RCPT TO:<%s>\r\n", cfg->cpRcpt); - sa_rv = sa_readline(sa, caLine, sizeof(caLine), &n); + sa_writef(sa, "RCPT TO:<%s>\r\n", cfg->cpRcpt); + sa_rv = sa_readln(sa, caLine, sizeof(caLine), &n); cu_on(!(sa_rv == SA_OK && n > 3 && atoi(caLine) == 250), L2_ERR_IO); /* | DATA * | 354 Enter mail, end with "." on a line by itself */ - sa_printf(sa, "DATA\r\n"); - sa_rv = sa_readline(sa, caLine, sizeof(caLine), &n); + sa_writef(sa, "DATA\r\n"); + sa_rv = sa_readln(sa, caLine, sizeof(caLine), &n); cu_on(!(sa_rv == SA_OK && n > 3 && atoi(caLine) == 354), L2_ERR_IO); /* | Date: Fri, 14 Sep 2001 14:50:51 CEST @@ -226,24 +229,24 @@ t = time(NULL); tm = localtime(&t); strftime(caDate, sizeof(caDate), "%a, %d %b %Y %H:%M:%S %Z", tm); - sa_printf(sa, "Date: %s\r\n", caDate); - sa_printf(sa, "From: %s\r\n", cfg->cpFrom); - sa_printf(sa, "To: %s\r\n", cfg->cpRcpt); - sa_printf(sa, "Subject: %s\r\n", cfg->cpSubject); + sa_writef(sa, "Date: %s\r\n", caDate); + sa_writef(sa, "From: %s\r\n", cfg->cpFrom); + sa_writef(sa, "To: %s\r\n", cfg->cpRcpt); + sa_writef(sa, "Subject: %s\r\n", cfg->cpSubject); if (cfg->cpLocalProg != NULL) - sa_printf(sa, "User-Agent: %s (%s)\r\n", + sa_writef(sa, "User-Agent: %s (%s)\r\n", l2_version.v_web, cfg->cpLocalProg); else - sa_printf(sa, "User-Agent: %s\r\n", l2_version.v_web); + sa_writef(sa, "User-Agent: %s\r\n", l2_version.v_web); sa_write(sa, "\r\n", 2, NULL); /* | A program of user rse on host en1.engelschall.com logged: * | [2001-09-10/01:02:03] sample logging message */ if (cfg->cpLocalProg != NULL) - sa_printf(sa, "Program %s of user %s on host %s logged:\r\n", + sa_writef(sa, "Program %s of user %s on host %s logged:\r\n", cfg->cpLocalProg, cfg->cpLocalUser, cfg->cpLocalHost); else - sa_printf(sa, "A program of user %s on host %s logged:\r\n", + sa_writef(sa, "A program of user %s on host %s logged:\r\n", cfg->cpLocalUser, cfg->cpLocalHost); cpB = buf; cpE = buf; @@ -263,13 +266,13 @@ /* | . * | 250 2.0.0 f88Aev847031 Message accepted for delivery */ sa_write(sa, ".\r\n", 3, NULL); - sa_readline(sa, caLine, sizeof(caLine), &n); + sa_readln(sa, caLine, sizeof(caLine), &n); cu_on(!(sa_rv == SA_OK && n > 3 && atoi(caLine) == 250), L2_ERR_IO); /* | QUIT * | 221 2.0.0 en1.engelschall.com closing connection */ - sa_printf(sa, "QUIT\r\n"); - sa_readline(sa, caLine, sizeof(caLine), &n); + sa_writef(sa, "QUIT\r\n"); + sa_readln(sa, caLine, sizeof(caLine), &n); cus: @@ -290,7 +293,7 @@ cfg->saServer = NULL; } if (cfg->saaServer != NULL) { - free(cfg->saaServer); + sa_addr_destroy(cfg->saaServer); cfg->saaServer = NULL; } 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.21' '-r1.22' -u '/v/ossp/cvs/ossp-pkg/l2/l2_ch_syslog.c,v' 2>/dev/null --- l2_ch_syslog.c 2001/09/14 19:11:00 1.21 +++ l2_ch_syslog.c 2001/10/06 14:33:09 1.22 @@ -220,17 +220,23 @@ /* open remote syslog connection via UDP socket */ if (cfg->szRemoteHost == NULL) return L2_ERR_USE; - if ((rc = sa_u2a(&cfg->saaRemoteAddr, "udp://%s:%d", - cfg->szRemoteHost, cfg->nRemotePort)) != SA_OK) + if ((rc = sa_addr_create(&cfg->saaRemoteAddr)) != SA_OK) + return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_INT); + if ((rc = sa_addr_u2a(cfg->saaRemoteAddr, "inet://%s:%d", + cfg->szRemoteHost, cfg->nRemotePort)) != SA_OK) return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_INT); if ((rc = sa_create(&cfg->saRemoteSock)) != SA_OK) return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_INT); + sa_type(cfg->saRemoteSock, SA_TYPE_DATAGRAM); sa_timeout(cfg->saRemoteSock, 10, 0); + if ((rc = sa_addr_create(&la)) != SA_OK) + return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_INT); /* FIXME: if uid == 0 -> use port 514 */ - if ((rc = sa_u2a(&la, "udp://0.0.0.0:0")) != SA_OK) + if ((rc = sa_addr_u2a(la, "inet://0.0.0.0:0")) != SA_OK) return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_INT); if ((rc = sa_bind(cfg->saRemoteSock, la)) != SA_OK) return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_INT); + sa_addr_destroy(la); } return L2_OK; } @@ -286,8 +292,8 @@ cfg->szIdent, buf); if ((n = strlen(caBuf)) > 1024) return L2_ERR_IO; - if ((rc = sa_writeto(cfg->saRemoteSock, caBuf, n, - NULL, cfg->saaRemoteAddr)) != SA_OK) + if ((rc = sa_send(cfg->saRemoteSock, caBuf, n, + NULL, cfg->saaRemoteAddr)) != SA_OK) return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_IO); } @@ -308,7 +314,7 @@ cfg->saRemoteSock = NULL; } if (cfg->saaRemoteAddr != NULL) { - free(cfg->saaRemoteAddr); + sa_addr_destroy(cfg->saaRemoteAddr); cfg->saaRemoteAddr = NULL; } } @@ -334,7 +340,7 @@ if (cfg->saRemoteSock != NULL) sa_destroy(cfg->saRemoteSock); if (cfg->saaRemoteAddr != NULL) - free(cfg->saaRemoteAddr); + sa_addr_destroy(cfg->saaRemoteAddr); free(cfg); return L2_OK; Index: ossp-pkg/l2/l2_p.h RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_p.h,v rcsdiff -q -kk '-r1.23' '-r1.24' -u '/v/ossp/cvs/ossp-pkg/l2/l2_p.h,v' 2>/dev/null --- l2_p.h 2001/10/02 14:11:51 1.23 +++ l2_p.h 2001/10/06 14:33:09 1.24 @@ -41,7 +41,6 @@ #include "l2.h" #include "l2_config.h" #include "l2_ut_pcre.h" -#define SA_PREFIX l2_ut_ #include "l2_ut_sa.h" #if defined(HAVE_DMALLOC_H) && defined(WITH_DMALLOC) 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.1' '-r1.2' -u '/v/ossp/cvs/ossp-pkg/l2/l2_ut_sa.ac,v' 2>/dev/null --- l2_ut_sa.ac 2001/09/14 19:06:40 1.1 +++ l2_ut_sa.ac 2001/10/06 14:33:09 1.2 @@ -27,15 +27,18 @@ ## sa.ac: socket abstraction Autoconf checks ## -AC_CHECK_HEADERS(sys/types.h sys/socket.h netdb.h netinet/in.h) +AC_DEFUN(AC_CHECK_SA,[ + # make sure libnsl and libsocket are linked in if they exist + AC_CHECK_LIB(nsl, gethostname) + if test ".`echo $LIBS | grep nsl`" = .; then + AC_CHECK_LIB(nsl, gethostbyname) + fi + AC_CHECK_LIB(socket, accept) + + # check for system headers + AC_CHECK_HEADERS(string.h sys/types.h sys/socket.h netdb.h netinet/in.h) -AC_CHECK_LIB(nsl, gethostname) -if test ".`echo $LIBS | grep nsl`" = .; then - AC_CHECK_LIB(nsl, gethostbyname) -fi -AC_CHECK_LIB(socket, accept) - -AC_CHECK_FUNCS(inet_aton inet_pton) -AC_CHECK_FUNCS(inet_ntoa inet_ntop) -AC_CHECK_FUNCS(snprintf vsnprintf) + # check for system functions + AC_CHECK_FUNCS(inet_aton inet_pton inet_ntoa inet_ntop snprintf) +]) 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.13' '-r1.14' -u '/v/ossp/cvs/ossp-pkg/l2/l2_ut_sa.c,v' 2>/dev/null --- l2_ut_sa.c 2001/10/02 14:11:51 1.13 +++ l2_ut_sa.c 2001/10/06 14:33:09 1.14 @@ -31,318 +31,432 @@ #include "l2_config.h" /* include system API headers */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include /* for "s[n]printf()" */ +#include /* for "malloc()" & friends */ +#include /* for "va_xxx()" and "va_list" */ +#include /* for "strxxx()" and "size_t" */ +#include /* for general prerequisites */ +#include /* for isxxx() */ +#include /* for "EXXX" */ +#include /* for "F_XXX" and "O_XXX" */ +#include /* for standard Unix stuff */ +#include /* for "struct prototent" */ +#include /* for "struct timeval" */ +#include /* for "struct sockaddr_un" */ +#include /* for "struct sockaddr_in[6]" */ +#include /* for "AF_XXX" and "SOCK_XXX" */ +#include /* for "inet_xtoy" */ /* include own API header */ -#define SA_PREFIX l2_ut_ #include "l2_ut_sa.h" /* socket address abstraction object */ struct sa_addr_st { - struct sockaddr *saBuf; - socklen_t slBuf; - int nFamily; - int nProto; + int nFamily; /* the socket family (AF_XXX) */ + struct sockaddr *saBuf; /* the "struct sockaddr_xx" actually */ + socklen_t slBuf; /* the length of "struct sockaddr_xx" */ }; /* socket abstraction object */ struct sa_st { - int sSocket; - int bTimeout; - struct timeval tvTimeout; - int nReadLen; - int nReadSize; - char *cpReadBuf; - int nWriteLen; - int nWriteSize; - char *cpWriteBuf; + sa_type_t eType; /* socket type (stream or datagram) */ + int fdSocket; /* socket file descriptor */ + int bTimeout; /* timeout enabling flag */ + struct timeval tvTimeout; /* timeout value (sec, usec) */ + int nReadLen; /* read buffer current length */ + int nReadSize; /* read buffer current size */ + char *cpReadBuf; /* read buffer memory chunk */ + int nWriteLen; /* write buffer current length */ + int nWriteSize; /* write buffer current size */ + char *cpWriteBuf; /* write buffer memory chunk */ }; -/* make sure AF_LOCAL define exists */ +/* boolean values */ +#ifndef FALSE +#define FALSE (0) +#endif +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +/* backward compatibility for AF_LOCAL */ #if !defined(AF_LOCAL) && defined(AF_UNIX) #define AF_LOCAL AF_UNIX #endif -/* make sure inet_pton() exists */ -#if defined(HAVE_INET_PTON) -#define sa_inet_pton inet_pton -#elif defined(HAVE_INET_ATON) -static int inet_pton(int family, const char *strptr, void *addrptr) +/* convert Internet address from presentation to network format */ +static int sa_inet_pton(int family, const char *strptr, void *addrptr) { +#ifdef HAVE_INET_PTON + return inet_pton(family, strptr, addrptr); +#else struct in_addr in_val; if (family == AF_INET) { - if (inet_aton(strptr, &in_val)) { - memcpy(addrptr, &in_val, sizeof(struct in_addr)); - return 1; - } - return 0; + /* 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; + memcpy(addrptr, &in_val, sizeof(struct in_addr)); + return 1; } errno = EAFNOSUPPORT; - return -1; -} -#else -#error "neither inet_pton nor inet_aton available" + return 0; #endif +} -/* make sure inet_ntop() exists */ -#if defined(HAVE_INET_NTOP) -#define sa_inet_ntop inet_ntop -#elif defined(HAVE_INET_NTOA) -static char *inet_ntop(int family, const void *src, char *dst, size_t size) +/* convert Internet address from network to presentation format */ +static const char *sa_inet_ntop(int family, const void *src, char *dst, size_t size) { +#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) { - if ((cp = inet_ntoa(src)) != NULL) { - n = strlen(cp); - if (n > size-1) - n = size-1; - memcpy(dst, cp, n); - dst[n] = '\0'; - return 1; - } - return 0; + /* 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) + return NULL; + n = strlen(cp); + if (n > size-1) + n = size-1; + memcpy(dst, cp, n); + dst[n] = '\0'; + return dst; } errno = EAFNOSUPPORT; - return -1; -} -#else -#error "neither inet_ntop nor inet_ntoa available" + return NULL; #endif +} -/* make sure vsnprintf() exists */ -#if defined(HAVE_VSNPRINTF) -#define sa_vsnprintf vsnprintf -#elif defined(HAVE_VSPRINTF) -static int sa_vsnprintf(char *str, size_t size, const char *fmt, va_list ap) +/* minimal vsnprintf(3) variant which supports %{c,s,d} only */ +static int sa_mvsnprintf(char *buffer, size_t bufsize, const char *format, va_list ap) { - int rv; - - rv = vsprintf(str, fmt, ap); - if (rv > size) { - fprintf(stderr, "ERROR: vsprintf(3) buffer overflow!\n"); - abort(); - } -} + char *bufptr; + char *bufend; + /* sufficient integer buffer: x log_10(2) + safety */ + char ibuf[((sizeof(int)*8)/3)+10]; + char *cp; + char c; + int d; + int n; + + bufptr = buffer; + bufend = buffer + bufsize - 1; + while ((c = *format++) != '\0' && bufptr < bufend) { + if (c == '%') { + c = *format++; + if (c == '%') + /* implement "%%" */ + *bufptr++ = c; + else if (c == 'c') + /* implement "%c" */ + *bufptr++ = (char)va_arg(ap, int); + else if (c == 's') { + /* implement "%s" */ + if ((cp = (char *)va_arg(ap, char *)) == NULL) + cp = "(null)"; + n = strlen(cp); + if ((bufptr + n) > bufend) + n = bufend - bufptr; + memcpy(bufptr, cp, n); + bufptr += n; + } + else if (c == 'd') { + /* implement "%d" */ + d = (int)va_arg(ap, int); +#ifdef HAVE_SNPRINTF + snprintf(ibuf, sizeof(ibuf), "%d", d); /* explicitly secure */ #else -#error "neither vsnprintf nor vsprintf available" + sprintf(ibuf, "%d", d); /* implicitly secure */ #endif + n = strlen(ibuf); + memcpy(bufptr, ibuf, n); + bufptr += n; + } + else { + *bufptr++ = '%'; + if (bufptr < bufend) + *bufptr++ = c; + } + } + else + *bufptr++ = c; + } + *bufptr = '\0'; + return (bufptr - buffer); +} -/* make sure snprintf() exists */ -#if defined(HAVE_SNPRINTF) -#define sa_snprintf snprintf -#else -static int sa_snprintf(char *str, size_t size, const char *fmt, ...) +/* minimal snprintf(3) variant which supports %{c,s,d} only */ +static int sa_msnprintf(char *buffer, size_t bufsize, const char *format, ...) { + int chars; va_list ap; - int rv; - va_start(ap, fmt); - rv = sa_vsnprintf(str, size, fmt, ap); + /* argument sanity check(s) */ + if (buffer == NULL || bufsize == 0 || format == NULL) + return 0; + + /* pass through to va_list based variant */ + va_start(ap, format); + chars = sa_mvsnprintf(buffer, bufsize, format, ap); va_end(ap); - return rv; + + return chars; } -#endif -sa_rc_t sa_u2a(sa_addr_t **saa, const char *uri, ...) +/* create address object */ +sa_rc_t sa_addr_create(sa_addr_t **saap) +{ + sa_addr_t *saa; + + /* argument sanity check(s) */ + if (saap == NULL) + return SA_ERR_ARG; + + /* allocate and initialize new address object */ + if ((saa = (sa_addr_t *)malloc(sizeof(sa_addr_t))) == NULL) + return SA_ERR_MEM; + saa->nFamily = 0; + saa->saBuf = NULL; + saa->slBuf = 0; + + /* pass object to caller */ + *saap = saa; + + return SA_OK; +} + +/* destroy address object */ +sa_rc_t sa_addr_destroy(sa_addr_t *saa) +{ + /* argument sanity check(s) */ + if (saa == NULL) + return SA_ERR_ARG; + + /* free address objects and sub-object(s) */ + if (saa->saBuf != NULL) + free(saa->saBuf); + free(saa); + + return SA_OK; +} + +/* import URI into address object */ +sa_rc_t sa_addr_u2a(sa_addr_t *saa, const char *uri, ...) { va_list ap; - int nPort; + int sf; socklen_t sl; struct sockaddr *sa; + struct sockaddr_un un; struct sockaddr_in sa4; #ifdef AF_INET6 struct sockaddr_in6 sa6; #endif struct hostent *he; struct servent *se; - struct protoent *pe; int bNumeric; - int i; - char *cpProto; - int nProto; char *cpHost; char *cpPort; + char *cpProto; + int nPort; + const char *cpPath; char uribuf[1024]; char *cp; - int sf; + int i; + int n; - /* argument sanity check */ + /* argument sanity check(s) */ if (saa == NULL || uri == NULL) return SA_ERR_ARG; /* on-the-fly create or just take over URI */ va_start(ap, uri); - sa_vsnprintf(uribuf, sizeof(uribuf), uri, ap); + sa_mvsnprintf(uribuf, sizeof(uribuf), uri, ap); va_end(ap); - /* parse URI into protocol, host and port parts */ - uri = uribuf; - cpProto = "tcp"; - if ((cp = strstr(uri, "://")) != NULL) { - cpProto = (char *)uri; - *cp = '\0'; - uri = cp+3; - } - cpHost = (char *)uri; - if ((cp = strchr(uri, ':')) == NULL) - return SA_ERR_ARG; - *cp++ = '\0'; - cpPort = cp; - - /* resolve protocol */ - if ((pe = getprotobyname(cpProto)) == NULL) - return SA_ERR_SYS; - nProto = pe->p_proto; + /* initialize result variables */ + sa = NULL; + sl = 0; + sf = 0; - /* resolve port */ - bNumeric = 1; - for (i = 0; cpPort[i] != '\0'; i++) { - if (!isdigit((int)cpPort[i])) { - bNumeric = 0; - break; + /* parse URI and resolve contents. + The following syntax is recognized: + - unix: + - inet://:[#(tcp|udp)] */ + uri = uribuf; + if (strncmp(uri, "unix:", 5) == 0) { + /* parse URI */ + cpPath = uri+5; + if (cpPath[0] != '/') + return SA_ERR_ARG; + + /* mandatory(!) socket address structure initialization */ + memset(&un, 0, sizeof(un)); + + /* fill-in socket address structure */ + n = strlen(cpPath); + if ((n+1) > sizeof(un.sun_path)) + return SA_ERR_MEM; + memcpy(un.sun_path, cpPath, n+1); + un.sun_family = AF_LOCAL; + + /* provide results */ + sa = (struct sockaddr *)&un; + sl = sizeof(un); + sf = AF_LOCAL; + } + else if (strncmp(uri, "inet://", 7) == 0) { + /* parse URI */ + cpHost = (char *)(uri+7); + if ((cp = strchr(cpHost, ':')) == NULL) + return SA_ERR_ARG; + *cp++ = '\0'; + cpPort = cp; + + /* resolve port */ + nPort = 0; + bNumeric = 1; + for (i = 0; cpPort[i] != '\0'; i++) { + if (!isdigit((int)cpPort[i])) { + bNumeric = 0; + break; + } + } + if (bNumeric) + nPort = atoi(cpPort); + else { + cpProto = "tcp"; + if ((cp = strchr(cpPort, '#')) != NULL) { + *cp++ = '\0'; + cpProto = cp; + } + if ((se = getservbyname(cpPort, cpProto)) == NULL) + return SA_ERR_SYS; + nPort = ntohs(se->s_port); } - } - if (bNumeric) - nPort = atoi(cpPort); - else { - if ((se = getservbyname(cpPort, cpProto)) == NULL) - return SA_ERR_SYS; - nPort = ntohs(se->s_port); - } - /* mandatory(!) socket address structure initialization */ - memset(&sa4, 0, sizeof(sa4)); + /* mandatory(!) socket address structure initialization */ + memset(&sa4, 0, sizeof(sa4)); #ifdef AF_INET6 - memset(&sa6, 0, sizeof(sa6)); + memset(&sa6, 0, sizeof(sa6)); #endif - /* resolve host by trying to parse it as either directly a IPv4 or - IPv6 address or by resolving it to either a IPv4 or IPv6 address */ - sa = NULL; - sl = 0; - sf = 0; - if (inet_pton(AF_INET, cpHost, &sa4.sin_addr.s_addr) == 1) { - sa4.sin_family = AF_INET; - sa4.sin_port = htons(nPort); - sa = (struct sockaddr *)&sa4; - sl = sizeof(sa4); - sf = AF_INET; - } -#ifdef AF_INET6 - else if (inet_pton(AF_INET6, cpHost, &sa6.sin6_addr.s6_addr) == 1) { - sa6.sin6_family = AF_INET6; - sa6.sin6_port = htons(nPort); - sa = (struct sockaddr *)&sa6; - sl = sizeof(sa6); - sf = AF_INET6; - } -#endif - else if ((he = gethostbyname(cpHost)) != NULL) { - if (he->h_addrtype == AF_INET) { + /* resolve host by trying to parse it as either directly a IPv4 or + IPv6 address or by resolving it to either a IPv4 or IPv6 address */ + if (sa_inet_pton(AF_INET, cpHost, &sa4.sin_addr.s_addr) == 1) { sa4.sin_family = AF_INET; sa4.sin_port = htons(nPort); - memcpy(&sa4.sin_addr.s_addr, he->h_addr_list[0], sizeof(sa4.sin_addr.s_addr)); sa = (struct sockaddr *)&sa4; sl = sizeof(sa4); sf = AF_INET; } #ifdef AF_INET6 - else if (he->h_addrtype == AF_INET6) { + else if (sa_inet_pton(AF_INET6, cpHost, &sa6.sin6_addr.s6_addr) == 1) { sa6.sin6_family = AF_INET6; sa6.sin6_port = htons(nPort); - memcpy(&sa6.sin6_addr.s6_addr, he->h_addr_list[0], sizeof(sa6.sin6_addr.s6_addr)); sa = (struct sockaddr *)&sa6; sl = sizeof(sa6); sf = AF_INET6; } #endif + else if ((he = gethostbyname(cpHost)) != NULL) { + if (he->h_addrtype == AF_INET) { + sa4.sin_family = AF_INET; + sa4.sin_port = htons(nPort); + memcpy(&sa4.sin_addr.s_addr, he->h_addr_list[0], + sizeof(sa4.sin_addr.s_addr)); + sa = (struct sockaddr *)&sa4; + sl = sizeof(sa4); + sf = AF_INET; + } +#ifdef AF_INET6 + 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], + sizeof(sa6.sin6_addr.s6_addr)); + sa = (struct sockaddr *)&sa6; + sl = sizeof(sa6); + sf = AF_INET6; + } +#endif + } } - if (sa == NULL) - return SA_ERR_ARG; - - /* create result address structure */ - if ((*saa = (sa_addr_t *)malloc(sizeof(sa_addr_t))) == NULL) - return SA_ERR_MEM; - if (((*saa)->saBuf = (struct sockaddr *)malloc(sl)) == NULL) { - free(*saa); + + /* make sure result variables are set */ + if (sa == NULL || sl == 0 || sf == 0) + return SA_ERR_INT; + + /* fill-in result address structure */ + if (saa->saBuf != NULL) + free(saa->saBuf); + if ((saa->saBuf = (struct sockaddr *)malloc(sl)) == NULL) return SA_ERR_MEM; - } - memcpy((*saa)->saBuf, sa, sl); - (*saa)->slBuf = sl; - (*saa)->nFamily = sf; - (*saa)->nProto = nProto; + memcpy(saa->saBuf, sa, sl); + saa->slBuf = sl; + saa->nFamily = sf; + return SA_OK; } -sa_rc_t sa_s2a(sa_addr_t **saa, const struct sockaddr *sabuf, socklen_t salen) +/* import "struct sockaddr" into address object */ +sa_rc_t sa_addr_s2a(sa_addr_t *saa, const struct sockaddr *sabuf, socklen_t salen) { + struct sockaddr_un *un; struct sockaddr_in *sa4; #ifdef AF_INET6 struct sockaddr_in6 *sa6; #endif - struct protoent *pe; int sf; + /* argument sanity check(s) */ if (saa == NULL || sabuf == NULL || salen == 0) return SA_ERR_ARG; /* create result address structure */ - if ((*saa = (sa_addr_t *)malloc(sizeof(sa_addr_t))) == NULL) - return SA_ERR_MEM; - if (((*saa)->saBuf = (struct sockaddr *)malloc(salen)) == NULL) { - free(*saa); + if (saa->saBuf != NULL) + free(saa->saBuf); + if ((saa->saBuf = (struct sockaddr *)malloc(salen)) == NULL) return SA_ERR_MEM; - } - memcpy((*saa)->saBuf, sabuf, salen); - (*saa)->slBuf = salen; + memcpy(saa->saBuf, sabuf, salen); + saa->slBuf = salen; - /* fill in family */ + /* resolve family */ sf = 0; - if (sizeof(struct sockaddr_in) == salen) { + if (sizeof(struct sockaddr_un) == salen) { + un = (struct sockaddr_un *)((void *)sabuf); + if (un->sun_family == AF_LOCAL) + sf = AF_LOCAL; + } + if (sf == 0 && sizeof(struct sockaddr_in) == salen) { sa4 = (struct sockaddr_in *)((void *)sabuf); if (sa4->sin_family == AF_INET) sf = AF_INET; } #ifdef AF_INET6 - else if (sizeof(struct sockaddr_in6) == salen) { + if (sf == 0 && sizeof(struct sockaddr_in6) == salen) { sa6 = (struct sockaddr_in6 *)((void *)sabuf); if (sa6->sin6_family == AF_INET6) sf = AF_INET6; } #endif - (*saa)->nFamily = sf; + if (sf == 0) + return SA_ERR_ARG; + saa->nFamily = sf; - /* fill in protocol */ - if ((pe = getprotobyname("tcp")) != NULL) - (*saa)->nProto = pe->p_proto; - else - (*saa)->nProto = 0; return SA_OK; } -sa_rc_t sa_a2u(const sa_addr_t *saa, char **uri) +/* export address object into URI */ +sa_rc_t sa_addr_a2u(sa_addr_t *saa, char **uri) { char uribuf[1024]; - struct protoent *pe; + struct sockaddr_un *un; struct sockaddr_in *sa4; #ifdef AF_INET6 struct sockaddr_in6 *sa6; @@ -350,159 +464,297 @@ char caHost[512]; int nPort; + /* argument sanity check(s) */ if (saa == NULL || uri == NULL) return SA_ERR_ARG; - if ((pe = getprotobynumber(saa->nProto)) == NULL) - return SA_ERR_SYS; - if (saa->nFamily == AF_INET) { - sa4 = (struct sockaddr_in *)((void *)saa->saBuf); - inet_ntop(AF_INET, &sa4->sin_addr.s_addr, caHost, sizeof(caHost)); - nPort = ntohs(sa4->sin_port); + + /* export object contents */ + if (saa->nFamily == AF_LOCAL) { + un = (struct sockaddr_un *)((void *)saa->saBuf); + sa_msnprintf(uribuf, sizeof(uribuf), "unix:%s", un->sun_path); } #ifdef AF_INET6 - else if (saa->nFamily == AF_INET6) { - sa6 = (struct sockaddr_in6 *)((void *)saa->saBuf); - inet_ntop(AF_INET6, &sa6->sin6_addr.s6_addr, caHost, sizeof(caHost)); - nPort = ntohs(sa6->sin6_port); - } + else if (saa->nFamily == AF_INET || saa->nFamily == AF_INET6) { +#else + else if (saa->nFamily == AF_INET) { #endif + if (saa->nFamily == AF_INET) { + sa4 = (struct sockaddr_in *)((void *)saa->saBuf); + sa_inet_ntop(AF_INET, &sa4->sin_addr.s_addr, caHost, sizeof(caHost)); + nPort = ntohs(sa4->sin_port); + } +#ifdef AF_INET6 + else { + sa6 = (struct sockaddr_in6 *)((void *)saa->saBuf); + sa_inet_ntop(AF_INET6, &sa6->sin6_addr.s6_addr, caHost, sizeof(caHost)); + nPort = ntohs(sa6->sin6_port); + } +#endif + sa_msnprintf(uribuf, sizeof(uribuf), "inet://%s:%d", caHost, nPort); + } else - return SA_ERR_ARG; - sa_snprintf(uribuf, sizeof(uribuf), "%s://%s:%d", pe->p_name, caHost, nPort); + return SA_ERR_INT; + + /* pass result to caller */ *uri = strdup(uribuf); + return SA_OK; } -sa_rc_t sa_a2s(const sa_addr_t *saa, struct sockaddr **sabuf, socklen_t *salen) +/* export address object into "struct sockaddr" */ +sa_rc_t sa_addr_a2s(sa_addr_t *saa, struct sockaddr **sabuf, socklen_t *salen) { + /* argument sanity check(s) */ if (saa == NULL || sabuf == NULL || salen == 0) return SA_ERR_ARG; + /* export underlying address structure */ if ((*sabuf = (struct sockaddr *)malloc(saa->slBuf)) == NULL) return SA_ERR_MEM; memmove(*sabuf, saa->saBuf, saa->slBuf); *salen = saa->slBuf; + return SA_OK; } -static sa_rc_t sa_socket_init(sa_t *sa, int family, int proto) +/* internal lazy/delayed initialization of underlying socket */ +static sa_rc_t sa_socket_init(sa_t *sa, int nFamily) { - int type; + int nType; + int nProto; + struct protoent *pe; + char *cpProto; + /* argument sanity check(s) */ if (sa == NULL) return SA_ERR_ARG; - if (proto == IPPROTO_TCP) - type = SOCK_STREAM; - else if (proto == IPPROTO_UDP) - type = SOCK_DGRAM; - else - return SA_ERR_ARG; - if (sa->sSocket != -1) + + /* only perform operation if socket still does not exist */ + if (sa->fdSocket != -1) return SA_ERR_USE; - if ((sa->sSocket = socket(family, type, proto)) == -1) + + /* determine socket type */ + if (sa->eType == SA_TYPE_STREAM) + nType = SOCK_STREAM; + else if (sa->eType == SA_TYPE_DATAGRAM) + nType = SOCK_DGRAM; + else + return SA_ERR_INT; + + /* determine socket protocol */ + if (nFamily == AF_LOCAL) + nProto = 0; +#ifdef AF_INET6 + else if (nFamily == AF_INET || nFamily == AF_INET6) { +#else + else if (nFamily == AF_INET) { +#endif + if (nType == SOCK_STREAM) + cpProto = "tcp"; + else if (nType == SOCK_DGRAM) + cpProto = "udp"; + else + return SA_ERR_INT; + if ((pe = getprotobyname(cpProto)) == NULL) + return SA_ERR_SYS; + nProto = pe->p_proto; + } + else + return SA_ERR_INT; + + /* create the underlying socket */ + if ((sa->fdSocket = socket(nFamily, nType, nProto)) == -1) return SA_ERR_SYS; + return SA_OK; } +/* internal destruction of underlying socket */ static sa_rc_t sa_socket_kill(sa_t *sa) { + /* argument sanity check(s) */ if (sa == NULL) return SA_ERR_ARG; - if (sa->sSocket != -1) { - close(sa->sSocket); - sa->sSocket = -1; - } + + /* check context */ + if (sa->fdSocket == -1) + return SA_ERR_USE; + + /* close socket */ + close(sa->fdSocket); + sa->fdSocket = -1; + return SA_OK; } +/* create abstract socket object */ sa_rc_t sa_create(sa_t **sap) { sa_t *sa; + /* argument sanity check(s) */ + if (sap == NULL) + return SA_ERR_ARG; + + /* allocate and initialize socket object */ if ((sa = (sa_t *)malloc(sizeof(sa_t))) == NULL) return SA_ERR_MEM; - sa->sSocket = -1; - sa->bTimeout = 0; - sa->nReadLen = 0; - sa->nReadSize = 1024; - if ((sa->cpReadBuf = (char *)malloc(sa->nReadSize)) == NULL) { - free(sa); - return SA_ERR_MEM; - } - sa->nWriteLen = 0; - sa->nWriteSize = 1024; - if ((sa->cpWriteBuf = (char *)malloc(sa->nWriteSize)) == NULL) { - free(sa->cpReadBuf); - free(sa); - return SA_ERR_MEM; - } + sa->eType = SA_TYPE_STREAM; + sa->fdSocket = -1; + sa->bTimeout = FALSE; + sa->tvTimeout.tv_sec = 0; + sa->tvTimeout.tv_usec = 0; + sa->nReadLen = 0; + sa->nReadSize = 0; + sa->cpReadBuf = NULL; + sa->nWriteLen = 0; + sa->nWriteSize = 0; + sa->cpWriteBuf = NULL; + + /* pass object to caller */ *sap = sa; + return SA_OK; } +/* destroy abstract socket object */ sa_rc_t sa_destroy(sa_t *sa) { + /* argument sanity check(s) */ if (sa == NULL) return SA_ERR_ARG; + + /* kill underlying socket */ sa_socket_kill(sa); + + /* free object and sub-objects */ if (sa->cpReadBuf != NULL) free(sa->cpReadBuf); if (sa->cpWriteBuf != NULL) free(sa->cpWriteBuf); free(sa); + return SA_OK; } +/* switch communication type of socket */ +sa_rc_t sa_type(sa_t *sa, sa_type_t type) +{ + /* argument sanity check(s) */ + if (sa == NULL) + return SA_ERR_ARG; + if (!(type == SA_TYPE_STREAM || type == SA_TYPE_DATAGRAM)) + return SA_ERR_ARG; + + /* kill underlying socket if type changes */ + if (sa->eType != type) + sa_socket_kill(sa); + + /* set new type */ + sa->eType = type; + + return SA_OK; +} + +/* configure I/O timeout */ sa_rc_t sa_timeout(sa_t *sa, long sec, long usec) { + /* argument sanity check(s) */ if (sa == NULL) return SA_ERR_ARG; - if (sec == 0 && usec == 0) { - sa->bTimeout = 0; - sa->tvTimeout.tv_sec = 0; - sa->tvTimeout.tv_usec = 0; - } - else { - sa->bTimeout = 1; - sa->tvTimeout.tv_sec = sec; - sa->tvTimeout.tv_usec = usec; - } + + /* configure timeout */ + if (sec == 0 && usec == 0) + sa->bTimeout = FALSE; /* deactivate timeout */ + else + sa->bTimeout = TRUE; /* activate timeout */ + sa->tvTimeout.tv_sec = sec; + sa->tvTimeout.tv_usec = usec; + return SA_OK; } +/* configure I/O buffers */ sa_rc_t sa_buffers(sa_t *sa, size_t rsize, size_t wsize) { char *cp; + /* argument sanity check(s) */ if (sa == NULL) return SA_ERR_ARG; + + /* make sure buffered were already flushed sufficiently */ if (sa->nReadLen > rsize || sa->nWriteLen > wsize) - return SA_ERR_ARG; - if ((cp = (char *)realloc(sa->cpReadBuf, rsize)) == NULL) - return SA_ERR_SYS; - sa->cpReadBuf = cp; - sa->nReadSize = rsize; - if ((cp = (char *)realloc(sa->cpWriteBuf, wsize)) == NULL) - return SA_ERR_SYS; - sa->cpWriteBuf = cp; - sa->nWriteSize = wsize; + return SA_ERR_USE; + + /* configure read/incoming buffer */ + if (rsize > 0) { + if (sa->cpReadBuf == NULL) + cp = (char *)malloc(rsize); + else + cp = (char *)realloc(sa->cpReadBuf, rsize); + if (cp == NULL) + return SA_ERR_SYS; + sa->cpReadBuf = cp; + sa->nReadSize = rsize; + } + else { + if (sa->cpReadBuf != NULL) + free(sa->cpReadBuf); + sa->cpReadBuf = NULL; + sa->nReadSize = 0; + } + + /* configure write/outgoing buffer */ + if (wsize > 0) { + if (sa->cpWriteBuf == NULL) + cp = (char *)malloc(wsize); + else + cp = (char *)realloc(sa->cpWriteBuf, wsize); + if (cp == NULL) + return SA_ERR_SYS; + sa->cpWriteBuf = cp; + sa->nWriteSize = wsize; + } + else { + if (sa->cpWriteBuf != NULL) + free(sa->cpWriteBuf); + sa->cpWriteBuf = NULL; + sa->nWriteSize = 0; + } + return SA_OK; } +/* bind socket to a local address */ sa_rc_t sa_bind(sa_t *sa, sa_addr_t *laddr) { sa_rc_t rv; + struct sockaddr_un *un; + /* argument sanity check(s) */ if (sa == NULL || laddr == NULL) return SA_ERR_ARG; - if (sa->sSocket == -1) - if ((rv = sa_socket_init(sa, laddr->nFamily, laddr->nProto)) != SA_OK) + + /* lazy creation of underlying socket */ + if (sa->fdSocket == -1) + if ((rv = sa_socket_init(sa, laddr->nFamily)) != SA_OK) return rv; - if (bind(sa->sSocket, laddr->saBuf, laddr->slBuf) == -1) + + /* remove a possibly existing old Unix Domain socket on filesystem */ + if (laddr->nFamily == AF_LOCAL) { + un = (struct sockaddr_un *)((void *)laddr->saBuf); + unlink(un->sun_path); + } + + /* perform bind operation on underlying socket */ + if (bind(sa->fdSocket, laddr->saBuf, laddr->slBuf) == -1) return SA_ERR_SYS; + return SA_OK; } +/* connect socket to a remote address */ sa_rc_t sa_connect(sa_t *sa, sa_addr_t *raddr) { int flags, n, error; @@ -510,87 +762,106 @@ socklen_t len; sa_rc_t rv; - if (sa == NULL) + /* argument sanity check(s) */ + if (sa == NULL || raddr == NULL) return SA_ERR_ARG; - if (sa->sSocket == -1) - if ((rv = sa_socket_init(sa, raddr->nFamily, raddr->nProto)) != SA_OK) - return rv; + /* connecting is only possible for stream communication */ + if (sa->eType != SA_TYPE_STREAM) + return SA_ERR_USE; - if (!sa->bTimeout) - return connect(sa->sSocket, raddr->saBuf, raddr->slBuf); + /* lazy creation of underlying socket */ + if (sa->fdSocket == -1) + if ((rv = sa_socket_init(sa, raddr->nFamily)) != SA_OK) + return rv; - error = 0; rv = SA_OK; + if (!sa->bTimeout) { + /* standard/non-timeout-aware connect operation */ + if (connect(sa->fdSocket, raddr->saBuf, raddr->slBuf) < 0) + rv = SA_ERR_SYS; + } + else { + /* emulated/timeout-aware connect operation */ + error = 0; - /* remember socket flags */ - flags = fcntl(sa->sSocket, F_GETFL, 0); + /* temporarily switch underlying socket to non-blocking mode */ + flags = fcntl(sa->fdSocket, F_GETFL, 0); + fcntl(sa->fdSocket, F_SETFL, flags|O_NONBLOCK); + + /* perform the connect operation */ + if ((n = connect(sa->fdSocket, raddr->saBuf, raddr->slBuf)) < 0) { + if (errno != EINPROGRESS) { + error = errno; + goto done; + } + } - /* switch to non-blocking mode */ - fcntl(sa->sSocket, F_SETFL, flags|O_NONBLOCK); + /* ok if connect completed immediately */ + if (n == 0) + goto done; + + /* wait for read or write possibility */ + FD_ZERO(&rset); + FD_ZERO(&wset); + FD_SET(sa->fdSocket, &rset); + FD_SET(sa->fdSocket, &wset); + do { + n = select(sa->fdSocket+1, &rset, &wset, NULL, &sa->tvTimeout); + } while (n == -1 && errno == EINTR); - /* perform the connect */ - if ((n = connect(sa->sSocket, raddr->saBuf, raddr->slBuf)) < 0) { - if (errno != EINPROGRESS) { + /* decide on return semantic */ + if (n < 0) { error = errno; goto done; } - } - - /* if connect completed immediately */ - if (n == 0) - goto done; - - /* wait for read or write possibility */ - FD_ZERO(&rset); - FD_ZERO(&wset); - FD_SET(sa->sSocket, &rset); - FD_SET(sa->sSocket, &wset); - do { - n = select(sa->sSocket+1, &rset, &wset, NULL, &sa->tvTimeout); - } while (n == -1 && errno == EINTR); - - /* decide on return semantic */ - if (n < 0) { - error = errno; - goto done; - } - else if (n == 0) { - error = ETIMEDOUT; - goto done; - } + else if (n == 0) { + error = ETIMEDOUT; + goto done; + } - /* fetch pending error */ - len = sizeof(error); - if (getsockopt(sa->sSocket, SOL_SOCKET, SO_ERROR, &error, &len) < 0) - error = errno; + /* fetch pending error */ + len = sizeof(error); + if (getsockopt(sa->fdSocket, SOL_SOCKET, SO_ERROR, &error, &len) < 0) + error = errno; - done: + done: - /* reset socket flags */ - fcntl(sa->sSocket, F_SETFL, flags); + /* reset socket flags */ + fcntl(sa->fdSocket, F_SETFL, flags); - /* optionally set errno */ - if (error != 0) { - errno = error; - rv = SA_ERR_SYS; + /* optionally set errno */ + if (error != 0) { + errno = error; + rv = SA_ERR_SYS; + } } - return rv; } +/* listen on socket for connections */ sa_rc_t sa_listen(sa_t *sa, int backlog) { + /* argument sanity check(s) */ if (sa == NULL) return SA_ERR_ARG; - if (sa->sSocket == -1) - /* at least sa_bind() has to be already performed */ + + /* listening is only possible for stream communication */ + if (sa->eType != SA_TYPE_STREAM) + return SA_ERR_USE; + + /* at least sa_bind() has to be already performed */ + if (sa->fdSocket == -1) return SA_ERR_USE; - if (listen(sa->sSocket, backlog) == -1) + + /* perform listen operation on underlying socket */ + if (listen(sa->fdSocket, backlog) == -1) return SA_ERR_SYS; + return SA_OK; } +/* accept a connection on socket */ sa_rc_t sa_accept(sa_t *sa, sa_addr_t **caddr, sa_t **csa) { sa_rc_t rv; @@ -605,35 +876,55 @@ socklen_t sa_len; int s; - if (sa == NULL) + /* argument sanity check(s) */ + if (sa == NULL || caddr == NULL || csa == NULL) return SA_ERR_ARG; - if (sa->sSocket == -1) - /* at least sa_listen() has to be already performed */ + + /* accepting connections is only possible for stream communication */ + if (sa->eType != SA_TYPE_STREAM) return SA_ERR_USE; + + /* at least sa_listen() has to be already performed */ + if (sa->fdSocket == -1) + return SA_ERR_USE; + + /* if timeout is enabled, perform a smart-blocking wait */ if (sa->bTimeout) { FD_ZERO(&fds); - FD_SET(sa->sSocket, &fds); + FD_SET(sa->fdSocket, &fds); do { - n = select(sa->sSocket+1, &fds, NULL, NULL, &sa->tvTimeout); + n = select(sa->fdSocket+1, &fds, NULL, NULL, &sa->tvTimeout); } while (n == -1 && errno == EINTR); if (n == 0) errno = ETIMEDOUT; if (n <= 0) return SA_ERR_SYS; } + + /* perform accept operation on underlying socket */ sa_len = sizeof(sa_buf); - if ((s = accept(sa->sSocket, (struct sockaddr *)&sa_buf, &sa_len)) == -1) + if ((s = accept(sa->fdSocket, (struct sockaddr *)&sa_buf, &sa_len)) == -1) return SA_ERR_SYS; - if ((rv = sa_s2a(caddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) + + /* create result address object */ + if ((rv = sa_addr_create(caddr)) != SA_OK) + return rv; + if ((rv = sa_addr_s2a(*caddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) { + sa_addr_destroy(*caddr); return rv; + } + + /* create result socket object */ if ((rv = sa_create(csa)) != SA_OK) { - free(*caddr); + sa_addr_destroy(*caddr); return rv; } - (*csa)->sSocket = s; + (*csa)->fdSocket = s; + return SA_OK; } +/* determine remote address */ sa_rc_t sa_getremote(sa_t *sa, sa_addr_t **raddr) { sa_rc_t rv; @@ -645,16 +936,35 @@ } sa_buf; socklen_t sa_len; - if (sa == NULL) + /* argument sanity check(s) */ + if (sa == NULL || raddr == NULL) return SA_ERR_ARG; + + /* peers exist only for stream communication */ + if (sa->eType != SA_TYPE_STREAM) + return SA_ERR_USE; + + /* at least sa_connect() or sa_accept() has to be already performed */ + if (sa->fdSocket == -1) + return SA_ERR_USE; + + /* determine remote address of underlying socket */ sa_len = sizeof(sa_buf); - if (getpeername(sa->sSocket, (struct sockaddr *)&sa_buf, &sa_len) < 0) + if (getpeername(sa->fdSocket, (struct sockaddr *)&sa_buf, &sa_len) < 0) return SA_ERR_SYS; - if ((rv = sa_s2a(raddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) + + /* 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) { + sa_addr_destroy(*raddr); + return rv; + } + return SA_OK; } +/* determine local address */ sa_rc_t sa_getlocal(sa_t *sa, sa_addr_t **laddr) { sa_rc_t rv; @@ -666,147 +976,187 @@ } sa_buf; socklen_t sa_len; - if (sa == NULL) + /* argument sanity check(s) */ + if (sa == NULL || laddr == NULL) return SA_ERR_ARG; + + /* at least sa_bind() has to be already performed */ + if (sa->fdSocket == -1) + return SA_ERR_USE; + + /* determine local address of underlying socket */ sa_len = sizeof(sa_buf); - if (getsockname(sa->sSocket, (struct sockaddr *)&sa_buf, &sa_len) < 0) + if (getsockname(sa->fdSocket, (struct sockaddr *)&sa_buf, &sa_len) < 0) return SA_ERR_SYS; - if ((rv = sa_s2a(laddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) + + /* create result address object */ + if ((rv = sa_addr_create(laddr)) != SA_OK) + return rv; + if ((rv = sa_addr_s2a(*laddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) { + sa_addr_destroy(*laddr); return rv; + } + return SA_OK; } +/* peek at underlying socket */ sa_rc_t sa_getfd(sa_t *sa, int *fd) { + /* argument sanity check(s) */ if (sa == NULL || fd == NULL) return SA_ERR_ARG; - *fd = sa->sSocket; + + /* if still no socket exists, say this explicitly */ + if (sa->fdSocket == -1) + return SA_ERR_USE; + + /* pass socket to caller */ + *fd = sa->fdSocket; + return SA_OK; } +/* internal raw read operation */ static int sa_read_raw(sa_t *sa, char *cpBuf, int nBufLen) { int rv; fd_set fds; + /* if timeout is enabled, perform explicit/smart blocking instead + of implicitly/hard blocking in the read(2) system call */ if (sa->bTimeout) { FD_ZERO(&fds); - FD_SET(sa->sSocket, &fds); + FD_SET(sa->fdSocket, &fds); do { - rv = select(sa->sSocket+1, &fds, NULL, NULL, &sa->tvTimeout); + rv = select(sa->fdSocket+1, &fds, NULL, NULL, &sa->tvTimeout); } while (rv == -1 && errno == EINTR); if (rv == 0) { errno = ETIMEDOUT; return -1; } } + + /* perform read operation on underlying socket */ do { - rv = read(sa->sSocket, cpBuf, nBufLen); + rv = read(sa->fdSocket, cpBuf, nBufLen); } while (rv == -1 && errno == EINTR); + return rv; } +/* read data from socket */ sa_rc_t sa_read(sa_t *sa, char *cpBuf, size_t nBufReq, size_t *nBufRes) { int n; - int rv; + sa_rc_t rv; size_t res; + /* argument sanity check(s) */ if (sa == NULL || cpBuf == NULL || nBufReq == 0) - return 0; - - /* flush write buffer */ + return SA_ERR_ARG; + + /* reading is only possible for stream communication */ + if (sa->eType != SA_TYPE_STREAM) + return SA_ERR_USE; + + /* at least a connection has to exist */ + if (sa->fdSocket == -1) + return SA_ERR_USE; + + /* trigger a write buffer flush */ if (sa->nWriteLen > 0) sa_flush(sa); + + /* perform read operation */ rv = SA_OK; - res = 0; - while (1) { - if (nBufReq <= sa->nReadLen) { - /* buffer holds enough data, so use this */ - memmove(cpBuf, sa->cpReadBuf, nBufReq); - memmove(sa->cpReadBuf, sa->cpReadBuf+nBufReq, sa->nReadLen-nBufReq); - sa->nReadLen -= nBufReq; - res += nBufReq; - } - else { - if (sa->nReadLen > 0) { - /* fetch already existing buffer contents as a start */ - memmove(cpBuf, sa->cpReadBuf, sa->nReadLen); - nBufReq -= sa->nReadLen; - cpBuf += sa->nReadLen; - res += sa->nReadLen; - sa->nReadLen = 0; - } - if (nBufReq >= sa->nReadSize) { - /* buffer is too small at all, so read directly */ - n = sa_read_raw(sa, cpBuf, nBufReq); - if (n > 0) - res += n; - else if (n <= 0) - rv = SA_ERR_SYS; + if (sa->nReadSize == 0) { + /* user-space unbuffered I/O */ + res = sa_read_raw(sa, cpBuf, nBufReq); + if (res == 0) + rv = SA_ERR_EOF; + else if (res < 0) + rv = SA_ERR_SYS; + } + else { + /* user-space buffered I/O */ + res = 0; + while (1) { + if (nBufReq <= sa->nReadLen) { + /* buffer holds enough data, so just use this */ + memmove(cpBuf, sa->cpReadBuf, nBufReq); + memmove(sa->cpReadBuf, sa->cpReadBuf+nBufReq, sa->nReadLen-nBufReq); + sa->nReadLen -= nBufReq; + res += nBufReq; } else { - /* fill buffer with new data */ - n = sa_read_raw(sa, sa->cpReadBuf, sa->nReadSize); - if (n <= 0) - rv = SA_ERR_SYS; + if (sa->nReadLen > 0) { + /* fetch already existing buffer contents as a start */ + memmove(cpBuf, sa->cpReadBuf, sa->nReadLen); + nBufReq -= sa->nReadLen; + cpBuf += sa->nReadLen; + res += sa->nReadLen; + sa->nReadLen = 0; + } + if (nBufReq >= sa->nReadSize) { + /* buffer is too small at all, so read directly */ + n = sa_read_raw(sa, cpBuf, nBufReq); + if (n > 0) + res += n; + else if (n == 0) + rv = (res == 0 ? SA_ERR_EOF : SA_OK); + else if (n < 0) + rv = (res == 0 ? SA_ERR_SYS : SA_OK); + } else { - sa->nReadLen = n; - continue; + /* fill buffer with new data */ + n = sa_read_raw(sa, sa->cpReadBuf, sa->nReadSize); + if (n < 0) + /* error on this read, but perhaps ok as a whole */ + rv = (res == 0 ? SA_ERR_SYS : SA_OK); + if (n == 0) + /* EOF on this read, but perhaps ok as a whole */ + rv = (res == 0 ? SA_ERR_EOF : SA_OK); + else { + sa->nReadLen = n; + continue; /* REPEAT OPERATION! */ + } } } + break; } - break; } + + /* pass number of actually read bytes to caller */ if (nBufRes != NULL) *nBufRes = res; - return rv; -} -sa_rc_t sa_readfrom(sa_t *sa, char *buf, size_t buflen, size_t *bufdone, sa_addr_t **raddr) -{ - sa_rc_t rv; - union { - struct sockaddr_in sa4; -#ifdef AF_INET6 - struct sockaddr_in6 sa6; -#endif - } sa_buf; - socklen_t sa_len; - size_t n; - fd_set fds; - - if (sa == NULL || buf == NULL || buflen == 0 || raddr == NULL) - return SA_ERR_ARG; - if (sa->bTimeout) { - FD_ZERO(&fds); - FD_SET(sa->sSocket, &fds); - do { - n = select(sa->sSocket+1, &fds, NULL, NULL, &sa->tvTimeout); - } while (n == -1 && errno == EINTR); - if (n == 0) - errno = ETIMEDOUT; - if (n <= 0) - return SA_ERR_SYS; - } - sa_len = sizeof(sa_buf); - if ((n = recvfrom(sa->sSocket, buf, buflen, 0, (struct sockaddr *)&sa_buf, &sa_len)) == -1) - return SA_ERR_SYS; - if ((rv = sa_s2a(raddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) - return rv; - if (bufdone != NULL) - *bufdone = n; - return SA_OK; + return rv; } -sa_rc_t sa_readline(sa_t *sa, char *cpBuf, size_t nBufReq, size_t *nBufRes) +/* read data from socket until [CR]LF (convinience function) */ +sa_rc_t sa_readln(sa_t *sa, char *cpBuf, size_t nBufReq, size_t *nBufRes) { char c; size_t n; size_t res; - if (sa == NULL) + /* argument sanity check(s) */ + if (sa == NULL || cpBuf == NULL || nBufReq == 0) return SA_ERR_ARG; + + /* reading is only possible for stream communication */ + if (sa->eType != SA_TYPE_STREAM) + return SA_ERR_USE; + + /* at least a connection has to exist */ + if (sa->fdSocket == -1) + return 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 + hand and if buffers are disabled, there is no better solution + anyway. */ res = 0; while (res < (nBufReq-1)) { sa_read(sa, &c, 1, &n); @@ -817,131 +1167,187 @@ break; } cpBuf[res] = '\0'; + + /* pass number of actually read characters to caller */ if (nBufRes != NULL) *nBufRes = res; + return SA_OK; } +/* internal raw write operation */ static int sa_write_raw(sa_t *sa, const char *cpBuf, int nBufLen) { int rv; fd_set fds; + /* if timeout is enabled, perform explicit/smart blocking instead + of implicitly/hard blocking in the write(2) system call */ if (sa->bTimeout) { FD_ZERO(&fds); - FD_SET(sa->sSocket, &fds); + FD_SET(sa->fdSocket, &fds); do { - rv = select(sa->sSocket+1, NULL, &fds, NULL, &sa->tvTimeout); + rv = select(sa->fdSocket+1, NULL, &fds, NULL, &sa->tvTimeout); } while (rv == -1 && errno == EINTR); if (rv == 0) { errno = ETIMEDOUT; return -1; } } + + /* perform write operation on underlying socket */ do { - rv = write(sa->sSocket, cpBuf, nBufLen); + rv = write(sa->fdSocket, cpBuf, nBufLen); } while (rv == -1 && errno == EINTR); + return rv; } +/* 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; + sa_rc_t rv; - if (sa == NULL) + /* argument sanity check(s) */ + if (sa == NULL || cpBuf == NULL || nBufReq == 0) return SA_ERR_ARG; - if (nBufReq > (sa->nWriteSize - sa->nWriteLen)) { - /* not enough space in buffer, so flush buffer */ - sa_flush(sa); - } - res = 0; - if (nBufReq >= sa->nWriteSize) { - /* buffer too small at all, so write immediately */ - while (nBufReq > 0) { - n = sa_write_raw(sa, cpBuf, nBufReq); - if (n <= 0) - break; - nBufReq -= n; - cpBuf += n; - res += n; - } + /* writing is only possible for stream communication */ + if (sa->eType != SA_TYPE_STREAM) + return SA_ERR_USE; + + /* at least a connection has to exist */ + if (sa->fdSocket == -1) + return SA_ERR_USE; + + rv = SA_OK; + if (sa->nWriteSize == 0) { + /* user-space unbuffered I/O */ + res = sa_write_raw(sa, cpBuf, nBufReq); + if (res < 0) + rv = SA_ERR_SYS; } else { - /* (again) enough sprace in buffer, so store data */ - memmove(sa->cpWriteBuf+sa->nWriteLen, cpBuf, nBufReq); - sa->nWriteLen += nBufReq; - res = nBufReq; + /* user-space buffered I/O */ + if (nBufReq > (sa->nWriteSize - sa->nWriteLen)) { + /* not enough space in buffer, so flush buffer first */ + sa_flush(sa); + } + res = 0; + if (nBufReq >= sa->nWriteSize) { + /* buffer too small at all, so write immediately */ + while (nBufReq > 0) { + n = sa_write_raw(sa, cpBuf, nBufReq); + if (n < 0) + rv = (res == 0 ? SA_ERR_SYS : SA_OK); + if (n <= 0) + break; + nBufReq -= n; + cpBuf += n; + res += n; + } + } + else { + /* (again) enough sprace in buffer, so store data */ + memmove(sa->cpWriteBuf+sa->nWriteLen, cpBuf, nBufReq); + sa->nWriteLen += nBufReq; + res = nBufReq; + } } + + /* pass number of actually written bytes to caller */ if (nBufRes != NULL) *nBufRes = res; - return SA_OK; -} - -sa_rc_t sa_writeto(sa_t *sa, const char *buf, size_t buflen, size_t *bufdone, sa_addr_t *raddr) -{ - size_t n; - fd_set fds; - if (sa == NULL || buf == NULL || buflen == 0 || raddr == NULL) - return SA_ERR_ARG; - if (sa->bTimeout) { - FD_ZERO(&fds); - FD_SET(sa->sSocket, &fds); - do { - n = select(sa->sSocket+1, NULL, &fds, NULL, &sa->tvTimeout); - } while (n == -1 && errno == EINTR); - if (n == 0) - errno = ETIMEDOUT; - if (n <= 0) - return SA_ERR_SYS; - } - if ((n = sendto(sa->sSocket, buf, buflen, 0, raddr->saBuf, raddr->slBuf)) == -1) - return SA_ERR_SYS; - if (bufdone != NULL) - *bufdone = n; - return SA_OK; + return rv; } -sa_rc_t sa_printf(sa_t *sa, const char *cpFmt, ...) +/* write formatted string to socket (convinience function) */ +sa_rc_t sa_writef(sa_t *sa, const char *cpFmt, ...) { va_list ap; size_t n; char caBuf[1024]; + sa_rc_t rv; - if (sa == NULL) + /* argument sanity check(s) */ + if (sa == NULL || cpFmt == NULL) return SA_ERR_ARG; + + /* writing is only possible for stream communication */ + if (sa->eType != SA_TYPE_STREAM) + return SA_ERR_USE; + + /* at least a connection has to exist */ + if (sa->fdSocket == -1) + return SA_ERR_USE; + + /* format string into temporary buffer */ va_start(ap, cpFmt); - n = sa_vsnprintf(caBuf, sizeof(caBuf), cpFmt, ap); - sa_write(sa, caBuf, n, &n); + n = sa_mvsnprintf(caBuf, sizeof(caBuf), cpFmt, ap); va_end(ap); - return SA_OK; + + /* write result buffer to socket */ + rv = sa_write(sa, caBuf, n, &n); + + return rv; } +/* flush write/outgoing I/O buffer */ sa_rc_t sa_flush(sa_t *sa) { size_t n; + sa_rc_t rv; + /* argument sanity check(s) */ if (sa == NULL) return SA_ERR_ARG; - while (sa->nWriteLen > 0) { - n = sa_write_raw(sa, sa->cpWriteBuf, sa->nWriteLen); - if (n <= 0) - break; - memmove(sa->cpWriteBuf, sa->cpWriteBuf+n, sa->nWriteLen-n); - sa->nWriteLen -= n; + + /* flushing is only possible for stream communication */ + if (sa->eType != SA_TYPE_STREAM) + return SA_ERR_USE; + + /* at least a connection has to exist */ + if (sa->fdSocket == -1) + return SA_ERR_USE; + + /* try to flush buffer */ + rv = SA_OK; + if (sa->nWriteSize > 0) { + while (sa->nWriteLen > 0) { + n = sa_write_raw(sa, sa->cpWriteBuf, sa->nWriteLen); + if (n < 0) + rv = SA_ERR_SYS; + if (n <= 0) + break; + memmove(sa->cpWriteBuf, sa->cpWriteBuf+n, sa->nWriteLen-n); + sa->nWriteLen -= n; + } + sa->nWriteLen = 0; } - sa->nWriteLen = 0; - return SA_OK; + return rv; } +/* shutdown a socket connection */ sa_rc_t sa_shutdown(sa_t *sa, char *flags) { int how; + /* argument sanity check(s) */ if (sa == NULL || flags == NULL) return SA_ERR_ARG; + + /* shutdown is only possible for stream communication */ + if (sa->eType != SA_TYPE_STREAM) + return SA_ERR_USE; + + /* at least a connection has to exist */ + if (sa->fdSocket == -1) + return SA_ERR_USE; + + /* determine flags for shutdown(2) */ how = 0; if (strcmp(flags, "r") == 0) how = SHUT_RD; @@ -949,8 +1355,119 @@ how = SHUT_WR; else if (strcmp(flags, "rw") == 0) how = SHUT_RDWR; - if (shutdown(sa->sSocket, how) == -1) + else + return SA_ERR_ARG; + + /* perform shutdown operation on underlying socket */ + if (shutdown(sa->fdSocket, how) == -1) + return SA_ERR_SYS; + + return SA_OK; +} + +/* 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 rv; + union { + struct sockaddr_in sa4; +#ifdef AF_INET6 + struct sockaddr_in6 sa6; +#endif + } sa_buf; + socklen_t sa_len; + size_t n; + fd_set fds; + + /* argument sanity check(s) */ + if (sa == NULL || buf == NULL || buflen == 0 || raddr == NULL) + return SA_ERR_ARG; + + /* receiving is only possible for datagram communication */ + if (sa->eType != SA_TYPE_DATAGRAM) + return SA_ERR_USE; + + /* at least a sa_bind() has to be performed */ + if (sa->fdSocket == -1) + return SA_ERR_USE; + + /* if timeout is enabled, perform explicit/smart blocking instead + of implicitly/hard blocking in the recvfrom(2) system call */ + if (sa->bTimeout) { + FD_ZERO(&fds); + FD_SET(sa->fdSocket, &fds); + do { + n = select(sa->fdSocket+1, &fds, NULL, NULL, &sa->tvTimeout); + } while (n == -1 && errno == EINTR); + if (n == 0) + errno = ETIMEDOUT; + if (n <= 0) + return SA_ERR_SYS; + } + + /* perform receive operation on underlying socket */ + sa_len = sizeof(sa_buf); + if ((n = recvfrom(sa->fdSocket, buf, buflen, 0, + (struct sockaddr *)&sa_buf, &sa_len)) == -1) + return 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) { + sa_addr_destroy(*raddr); + return rv; + } + + /* pass actual number of received bytes to caller */ + if (bufdone != NULL) + *bufdone = n; + + return SA_OK; +} + +/* 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) +{ + size_t n; + fd_set fds; + sa_rc_t rv; + + /* argument sanity check(s) */ + if (sa == NULL || buf == NULL || buflen == 0 || raddr == NULL) + return SA_ERR_ARG; + + /* sending is only possible for datagram communication */ + if (sa->eType != SA_TYPE_DATAGRAM) + return SA_ERR_USE; + + /* lazy creation of underlying socket */ + if (sa->fdSocket == -1) + if ((rv = sa_socket_init(sa, raddr->nFamily)) != SA_OK) + return rv; + + /* if timeout is enabled, perform explicit/smart blocking instead + of implicitly/hard blocking in the sendto(2) system call */ + if (sa->bTimeout) { + FD_ZERO(&fds); + FD_SET(sa->fdSocket, &fds); + do { + n = select(sa->fdSocket+1, NULL, &fds, NULL, &sa->tvTimeout); + } while (n == -1 && errno == EINTR); + if (n == 0) + errno = ETIMEDOUT; + if (n <= 0) + return SA_ERR_SYS; + } + + /* perform send operation on underlying socket */ + if ((n = sendto(sa->fdSocket, buf, buflen, 0, raddr->saBuf, raddr->slBuf)) == -1) return SA_ERR_SYS; + + /* pass actual number of sent bytes to caller */ + if (bufdone != NULL) + *bufdone = n; + return SA_OK; } 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.8' '-r1.9' -u '/v/ossp/cvs/ossp-pkg/l2/l2_ut_sa.h,v' 2>/dev/null --- l2_ut_sa.h 2001/10/02 14:11:51 1.8 +++ l2_ut_sa.h 2001/10/06 14:33:09 1.9 @@ -30,7 +30,9 @@ #ifndef __SA_H__ #define __SA_H__ -/* system definitions of "size_t", "socklen_t", "struct sockaddr" */ +#define SA_PREFIX l2_util_ + +/* system definitions of "size_t", "socklen_t", "struct sockaddr *" */ #include #include #include @@ -44,34 +46,37 @@ #define __SA_CONCAT(x) x #define SA_CONCAT(x,y) __SA_CONCAT(x)y #endif -#define sa_addr_st SA_CONCAT(SA_PREFIX,sa_addr_st) -#define sa_addr_t SA_CONCAT(SA_PREFIX,sa_addr_t) -#define sa_rc_t SA_CONCAT(SA_PREFIX,sa_rc_t) -#define sa_st SA_CONCAT(SA_PREFIX,sa_st) -#define sa_t SA_CONCAT(SA_PREFIX,sa_t) -#define sa_u2a SA_CONCAT(SA_PREFIX,sa_u2a) -#define sa_s2a SA_CONCAT(SA_PREFIX,sa_s2a) -#define sa_a2u SA_CONCAT(SA_PREFIX,sa_a2u) -#define sa_a2s SA_CONCAT(SA_PREFIX,sa_a2s) -#define sa_create SA_CONCAT(SA_PREFIX,sa_create) -#define sa_destroy SA_CONCAT(SA_PREFIX,sa_destroy) -#define sa_timeout SA_CONCAT(SA_PREFIX,sa_timeout) -#define sa_buffers SA_CONCAT(SA_PREFIX,sa_buffers) -#define sa_bind SA_CONCAT(SA_PREFIX,sa_bind) -#define sa_connect SA_CONCAT(SA_PREFIX,sa_connect) -#define sa_listen SA_CONCAT(SA_PREFIX,sa_listen) -#define sa_accept SA_CONCAT(SA_PREFIX,sa_accept) -#define sa_getremote SA_CONCAT(SA_PREFIX,sa_getremote) -#define sa_getlocal SA_CONCAT(SA_PREFIX,sa_getlocal) -#define sa_getfd SA_CONCAT(SA_PREFIX,sa_getfd) -#define sa_shutdown SA_CONCAT(SA_PREFIX,sa_shutdown) -#define sa_read SA_CONCAT(SA_PREFIX,sa_read) -#define sa_readfrom SA_CONCAT(SA_PREFIX,sa_readfrom) -#define sa_readline SA_CONCAT(SA_PREFIX,sa_readline) -#define sa_write SA_CONCAT(SA_PREFIX,sa_write) -#define sa_writeto SA_CONCAT(SA_PREFIX,sa_writeto) -#define sa_printf SA_CONCAT(SA_PREFIX,sa_printf) -#define sa_flush SA_CONCAT(SA_PREFIX,sa_flush) +#define sa_addr_st SA_CONCAT(SA_PREFIX,sa_addr_st) +#define sa_addr_t SA_CONCAT(SA_PREFIX,sa_addr_t) +#define sa_rc_t SA_CONCAT(SA_PREFIX,sa_rc_t) +#define sa_st SA_CONCAT(SA_PREFIX,sa_st) +#define sa_t SA_CONCAT(SA_PREFIX,sa_t) +#define sa_addr_create SA_CONCAT(SA_PREFIX,sa_addr_create) +#define sa_addr_destroy SA_CONCAT(SA_PREFIX,sa_addr_destroy) +#define sa_addr_u2a SA_CONCAT(SA_PREFIX,sa_addr_u2a) +#define sa_addr_s2a SA_CONCAT(SA_PREFIX,sa_addr_s2a) +#define sa_addr_a2u SA_CONCAT(SA_PREFIX,sa_addr_a2u) +#define sa_addr_a2s SA_CONCAT(SA_PREFIX,sa_addr_a2s) +#define sa_create SA_CONCAT(SA_PREFIX,sa_create) +#define sa_destroy SA_CONCAT(SA_PREFIX,sa_destroy) +#define sa_type SA_CONCAT(SA_PREFIX,sa_type) +#define sa_timeout SA_CONCAT(SA_PREFIX,sa_timeout) +#define sa_buffers SA_CONCAT(SA_PREFIX,sa_buffers) +#define sa_bind SA_CONCAT(SA_PREFIX,sa_bind) +#define sa_connect SA_CONCAT(SA_PREFIX,sa_connect) +#define sa_listen SA_CONCAT(SA_PREFIX,sa_listen) +#define sa_accept SA_CONCAT(SA_PREFIX,sa_accept) +#define sa_getremote SA_CONCAT(SA_PREFIX,sa_getremote) +#define sa_getlocal SA_CONCAT(SA_PREFIX,sa_getlocal) +#define sa_getfd SA_CONCAT(SA_PREFIX,sa_getfd) +#define sa_shutdown SA_CONCAT(SA_PREFIX,sa_shutdown) +#define sa_read SA_CONCAT(SA_PREFIX,sa_read) +#define sa_readln SA_CONCAT(SA_PREFIX,sa_readln) +#define sa_write SA_CONCAT(SA_PREFIX,sa_write) +#define sa_writef SA_CONCAT(SA_PREFIX,sa_writef) +#define sa_flush SA_CONCAT(SA_PREFIX,sa_flush) +#define sa_recv SA_CONCAT(SA_PREFIX,sa_recv) +#define sa_send SA_CONCAT(SA_PREFIX,sa_send) #endif /* socket address abstraction object type */ @@ -82,48 +87,62 @@ struct sa_st; typedef struct sa_st sa_t; +/* socket connection types */ +typedef enum { + SA_TYPE_STREAM, + SA_TYPE_DATAGRAM +} sa_type_t; + /* return codes */ typedef enum { - SA_OK, - SA_ERR_ARG, - SA_ERR_USE, - SA_ERR_MEM, - SA_ERR_SYS, - SA_ERR_INT + SA_OK, /* everything ok */ + SA_ERR_ARG, /* invalid argument (wrong parameter) */ + SA_ERR_USE, /* invalid use (wrong context) */ + SA_ERR_MEM, /* out of memory */ + SA_ERR_SYS, /* system error (see errno) */ + SA_ERR_EOF, /* end of file/socket communication */ + SA_ERR_INT /* internal error */ } sa_rc_t; +/* address object operations */ +sa_rc_t sa_addr_create (sa_addr_t **saa); +sa_rc_t sa_addr_destroy (sa_addr_t *saa); + /* address operations */ -sa_rc_t sa_u2a (sa_addr_t **saa, const char *uri, ...); -sa_rc_t sa_s2a (sa_addr_t **saa, const struct sockaddr *sabuf, socklen_t salen); -sa_rc_t sa_a2u (const sa_addr_t *saa, char **uri); -sa_rc_t sa_a2s (const sa_addr_t *saa, struct sockaddr **sabuf, socklen_t *salen); - -/* object operations */ -sa_rc_t sa_create (sa_t **sa); -sa_rc_t sa_destroy (sa_t *sa); - -/* parameter operations */ -sa_rc_t sa_timeout (sa_t *sa, long sec, long usec); -sa_rc_t sa_buffers (sa_t *sa, size_t rsize, size_t wsize); - -/* 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); - -/* input/output operations */ -sa_rc_t sa_read (sa_t *sa, char *buf, size_t buflen, size_t *bufdone); -sa_rc_t sa_readfrom (sa_t *sa, char *buf, size_t buflen, size_t *bufdone, sa_addr_t **raddr); -sa_rc_t sa_readline (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_writeto (sa_t *sa, const char *buf, size_t buflen, size_t *bufdone, sa_addr_t *raddr); -sa_rc_t sa_printf (sa_t *sa, const char *fmt, ...); -sa_rc_t sa_flush (sa_t *sa); +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); + +/* socket object operations */ +sa_rc_t sa_create (sa_t **sa); +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, long sec, long usec); +sa_rc_t sa_buffers (sa_t *sa, size_t rsize, size_t wsize); + +/* 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); + +/* 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); + +/* 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); #endif /* __SA_H__ */