head 1.29; access; symbols L2_0_9_13:1.29 FSL_1_7_0:1.29 L2_0_9_12:1.29 LMTP2NNTP_1_4_1:1.29 LMTP2NNTP_1_4_0:1.29 FSL_1_6_1:1.29 L2_0_9_11:1.29 FSL_1_6_0:1.27 FSL_1_6b2:1.27 L2_0_9_10:1.27 FSL_1_6b1:1.27 L2_0_9_9:1.27 LMTP2NNTP_1_3_0:1.25 LMTP2NNTP_1_3b2:1.25 LMTP2NNTP_1_3b1:1.25 LMTP2NNTP_1_3a3:1.25 FSL_1_5_0:1.25 LMTP2NNTP_1_3a2:1.25 FSL_1_5a3:1.25 LMTP2NNTP_1_3a1:1.25 FSL_1_5a2:1.25 L2_0_9_8:1.25 FSL_1_5a1:1.25 L2_0_9_7:1.25 L2_0_9_6:1.25 FSL_1_4_0:1.21 FSL_1_4b1:1.21 L2_0_9_5:1.21 FSL_1_4a1:1.21 FSL_1_3_0:1.21 FSL_1_3b1:1.21 L2_0_9_4:1.21 FSL_1_2_1:1.21 L2_0_9_3:1.21 FSL_1_2_0:1.21 L2_0_9_2:1.21 FSL_1_1_0:1.21 FSL_1_1b1:1.21 WORKOFF:1.21.0.2 WORKOFF_BP:1.21 FSL_1_0_8:1.21 LMTP2NNTP_1_2_0:1.21 LMTP2NNTP_1_2b4:1.21 LMTP2NNTP_1_2b3:1.21 LMTP2NNTP_1_2b2:1.21 LMTP2NNTP_1_2b1:1.20 LMTP2NNTP_1_2a8:1.20 LMTP2NNTP_1_2a7:1.20 FSL_1_0_7:1.20 FSL_1_0_6:1.20 FSL_1_0_5:1.19 FSL_1_0_4:1.18 L2_0_9_1:1.18 FSL_1_0_3:1.17 LMTP2NNTP_1_2a6:1.17 FSL_1_0_2:1.17 FSL_1_0_1:1.17 FSL_1_0_0:1.17 FSL_0_9_0:1.17 L2_0_9_0:1.17 FSL_0_1_12:1.17 FSL_0_1_11:1.17 FSL_0_1_10:1.17 FSL_0_1_9:1.17 FSL_0_1_8:1.17 FSL_0_1_7:1.17 FSL_0_1_6:1.17 FSL_0_1_5:1.17 FSL_0_1_1:1.17 LMTP2NNTP_1_2a5:1.17 LMTP2NNTP_1_2a4:1.17 LMTP2NNTP_1_2a3:1.17 LMTP2NNTP_1_2a1:1.17 LMTP2NNTP_1_1_1:1.15 LMTP2NNTP_1_1_0:1.15 LMTP2NNTP_1_1b4:1.15 LMTP2NNTP_1_1b3:1.15 L2_CHANNEL_ONLY_REVAMPING_BEFORE:1.17 LMTP2NNTP_1_1b2:1.15 LMTP2NNTP_1_1b1:1.15 L2_0_1_0:1.7; locks; strict; comment @ * @; 1.29 date 2005.10.03.08.20.18; author rse; state Exp; branches; next 1.28; 1.28 date 2005.10.03.08.00.16; author rse; state Exp; branches; next 1.27; 1.27 date 2005.02.02.12.26.44; author thl; state Exp; branches; next 1.26; 1.26 date 2005.01.24.15.03.18; author rse; state Exp; branches; next 1.25; 1.25 date 2004.04.21.12.02.12; author thl; state Exp; branches; next 1.24; 1.24 date 2004.04.02.12.27.32; author thl; state Exp; branches; next 1.23; 1.23 date 2004.03.26.17.14.48; author thl; state Exp; branches; next 1.22; 1.22 date 2004.02.17.09.21.04; author thl; state Exp; branches; next 1.21; 1.21 date 2003.02.10.10.13.23; author thl; state Exp; branches 1.21.2.1; next 1.20; 1.20 date 2002.11.09.14.44.31; author rse; state Exp; branches; next 1.19; 1.19 date 2002.10.21.15.14.04; author rse; state Exp; branches; next 1.18; 1.18 date 2002.10.11.16.00.48; author rse; state Exp; branches; next 1.17; 1.17 date 2001.10.31.21.26.11; author rse; state Exp; branches; next 1.16; 1.16 date 2001.10.26.10.59.47; author rse; state Exp; branches; next 1.15; 1.15 date 2001.10.10.15.58.27; author rse; state Exp; branches; next 1.14; 1.14 date 2001.10.06.14.33.09; author rse; state Exp; branches; next 1.13; 1.13 date 2001.10.02.14.11.51; author thl; state Exp; branches; next 1.12; 1.12 date 2001.09.14.19.06.40; author rse; state Exp; branches; next 1.11; 1.11 date 2001.09.14.10.22.37; author rse; state Exp; branches; next 1.10; 1.10 date 2001.09.13.20.27.56; author rse; state Exp; branches; next 1.9; 1.9 date 2001.09.13.20.13.08; author rse; state Exp; branches; next 1.8; 1.8 date 2001.09.13.20.07.17; author rse; state Exp; branches; next 1.7; 1.7 date 2001.09.13.12.19.45; author thl; state Exp; branches; next 1.6; 1.6 date 2001.09.11.10.37.04; author thl; state Exp; branches; next 1.5; 1.5 date 2001.09.09.15.54.31; author rse; state Exp; branches; next 1.4; 1.4 date 2001.09.08.22.05.46; author rse; state Exp; branches; next 1.3; 1.3 date 2001.09.07.10.25.56; author thl; state Exp; branches; next 1.2; 1.2 date 2001.09.06.17.17.41; author rse; state Exp; branches; next 1.1; 1.1 date 2001.09.06.16.28.38; author rse; state Exp; branches; next ; 1.21.2.1 date 2004.02.17.09.22.00; author thl; state Exp; branches; next ; desc @@ 1.29 log @import OSSP sa 1.2.6 @ text @/* ** OSSP sa - Socket Abstraction ** Copyright (c) 2001-2005 Ralf S. Engelschall ** Copyright (c) 2001-2005 The OSSP Project ** Copyright (c) 2001-2005 Cable & Wireless ** ** This file is part of OSSP sa, a socket abstraction library which ** can be found at http://www.ossp.org/pkg/lib/sa/. ** ** Permission to use, copy, modify, and distribute this software for ** any purpose with or without fee is hereby granted, provided that ** the above copyright notice and this permission notice appear in all ** copies. ** ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. ** ** sa.c: socket abstraction library */ /* include optional Autoconf header */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* include system API headers */ #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 "PF_XXX", "AF_XXX", "SOCK_XXX" and "SHUT_XX" */ #include /* for "inet_XtoX" */ /* include own API header */ #include "l2_ut_sa.h" /* unique library identifier */ const char sa_id[] = "OSSP sa"; /* support for OSSP ex based exception throwing */ #ifdef WITH_EX #include "ex.h" #define SA_RC(rv) \ ( (rv) != SA_OK && (ex_catching && !ex_shielding) \ ? (ex_throw(sa_id, NULL, (rv)), (rv)) : (rv) ) #else #define SA_RC(rv) (rv) #endif /* WITH_EX */ /* boolean values */ #ifndef FALSE #define FALSE (0) #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 /* backward compatibility for PF_XXX (still unused) */ #if !defined(PF_LOCAL) && defined(AF_LOCAL) #define PF_LOCAL AF_LOCAL #endif #if !defined(PF_INET) && defined(AF_INET) #define PF_INET AF_INET #endif #if !defined(PF_INET6) && defined(AF_INET6) #define PF_INET6 AF_INET6 #endif /* backward compatibility for 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_CONFIG_H) && !defined(HAVE_SSIZE_T) #define ssize_t long #endif /* backward compatibility for O_NONBLOCK */ #if !defined(O_NONBLOCK) && defined(O_NDELAY) #define O_NONBLOCK O_NDELAY #endif /* system call structure declaration macros */ #define SA_SC_DECLARE_0(rc_t, fn) \ struct { \ union { void (*any)(void); \ rc_t (*std)(void); \ rc_t (*ctx)(void *); } fptr; \ void *fctx; \ } sc_##fn; #define SA_SC_DECLARE_1(rc_t, fn, a1_t) \ struct { \ union { void (*any)(void); \ rc_t (*std)(a1_t); \ rc_t (*ctx)(void *, a1_t); } fptr; \ void *fctx; \ } sc_##fn; #define SA_SC_DECLARE_2(rc_t, fn, a1_t, a2_t) \ struct { \ union { void (*any)(void); \ rc_t (*std)(a1_t, a2_t); \ rc_t (*ctx)(void *, a1_t, a2_t); } fptr; \ void *fctx; \ } sc_##fn; #define SA_SC_DECLARE_3(rc_t, fn, a1_t, a2_t, a3_t) \ struct { \ union { void (*any)(void); \ rc_t (*std)(a1_t, a2_t, a3_t); \ rc_t (*ctx)(void *, a1_t, a2_t, a3_t); } fptr; \ void *fctx; \ } sc_##fn; #define SA_SC_DECLARE_4(rc_t, fn, a1_t, a2_t, a3_t, a4_t) \ struct { \ union { void (*any)(void); \ rc_t (*std)(a1_t, a2_t, a3_t, a4_t); \ rc_t (*ctx)(void *, a1_t, a2_t, a3_t, a4_t); } fptr; \ void *fctx; \ } sc_##fn; #define SA_SC_DECLARE_5(rc_t, fn, a1_t, a2_t, a3_t, a4_t, a5_t) \ struct { \ union { void (*any)(void); \ rc_t (*std)(a1_t, a2_t, a3_t, a4_t, a5_t); \ rc_t (*ctx)(void *, a1_t, a2_t, a3_t, a4_t, a5_t); } fptr; \ void *fctx; \ } sc_##fn; #define SA_SC_DECLARE_6(rc_t, fn, a1_t, a2_t, a3_t, a4_t, a5_t, a6_t) \ struct { \ union { void (*any)(void); \ rc_t (*std)(a1_t, a2_t, a3_t, a4_t, a5_t, a6_t); \ rc_t (*ctx)(void *, a1_t, a2_t, a3_t, a4_t, a5_t, a6_t); } fptr; \ void *fctx; \ } sc_##fn; /* system call structure assignment macro */ #define SA_SC_ASSIGN(sa, fn, ptr, ctx) \ do { \ (sa)->scSysCall.sc_##fn.fptr.any = (void (*)(void))(ptr); \ (sa)->scSysCall.sc_##fn.fctx = (ctx); \ } while (0) /* system call structure assignment macro */ #define SA_SC_COPY(sa1, sa2, fn) \ do { \ (sa1)->scSysCall.sc_##fn.fptr.any = (sa2)->scSysCall.sc_##fn.fptr.any; \ (sa1)->scSysCall.sc_##fn.fctx = (sa2)->scSysCall.sc_##fn.fctx; \ } while (0) /* system call function call macros */ #define SA_SC_CALL_0(sa, fn) \ ( (sa)->scSysCall.sc_##fn.fctx != NULL \ ? ((sa)->scSysCall.sc_##fn.fptr.ctx)((sa)->scSysCall.sc_##fn.fctx) \ : ((sa)->scSysCall.sc_##fn.fptr.std)(void) ) #define SA_SC_CALL_1(sa, fn, a1) \ ( (sa)->scSysCall.sc_##fn.fctx != NULL \ ? ((sa)->scSysCall.sc_##fn.fptr.ctx)((sa)->scSysCall.sc_##fn.fctx, a1) \ : ((sa)->scSysCall.sc_##fn.fptr.std)(a1) ) #define SA_SC_CALL_2(sa, fn, a1, a2) \ ( (sa)->scSysCall.sc_##fn.fctx != NULL \ ? ((sa)->scSysCall.sc_##fn.fptr.ctx)((sa)->scSysCall.sc_##fn.fctx, a1, a2) \ : ((sa)->scSysCall.sc_##fn.fptr.std)(a1, a2) ) #define SA_SC_CALL_3(sa, fn, a1, a2, a3) \ ( (sa)->scSysCall.sc_##fn.fctx != NULL \ ? ((sa)->scSysCall.sc_##fn.fptr.ctx)((sa)->scSysCall.sc_##fn.fctx, a1, a2, a3) \ : ((sa)->scSysCall.sc_##fn.fptr.std)(a1, a2, a3) ) #define SA_SC_CALL_4(sa, fn, a1, a2, a3, a4) \ ( (sa)->scSysCall.sc_##fn.fctx != NULL \ ? ((sa)->scSysCall.sc_##fn.fptr.ctx)((sa)->scSysCall.sc_##fn.fctx, a1, a2, a3, a4) \ : ((sa)->scSysCall.sc_##fn.fptr.std)(a1, a2, a3, a4) ) #define SA_SC_CALL_5(sa, fn, a1, a2, a3, a4, a5) \ ( (sa)->scSysCall.sc_##fn.fctx != NULL \ ? ((sa)->scSysCall.sc_##fn.fptr.ctx)((sa)->scSysCall.sc_##fn.fctx, a1, a2, a3, a4, a5) \ : ((sa)->scSysCall.sc_##fn.fptr.std)(a1, a2, a3, a4, a5) ) #define SA_SC_CALL_6(sa, fn, a1, a2, a3, a4, a5, a6) \ ( (sa)->scSysCall.sc_##fn.fctx != NULL \ ? ((sa)->scSysCall.sc_##fn.fptr.ctx)((sa)->scSysCall.sc_##fn.fctx, a1, a2, a3, a4, a5, a6) \ : ((sa)->scSysCall.sc_##fn.fptr.std)(a1, a2, a3, a4, a5, a6) ) /* system call table */ typedef struct { SA_SC_DECLARE_3(int, connect, int, const struct sockaddr *, socklen_t) SA_SC_DECLARE_3(int, accept, int, struct sockaddr *, socklen_t *) SA_SC_DECLARE_5(int, select, int, fd_set *, fd_set *, fd_set *, struct timeval *) SA_SC_DECLARE_3(ssize_t, read, int, void *, size_t) SA_SC_DECLARE_3(ssize_t, write, int, const void *, size_t) 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) */ int fdSocket; /* socket file descriptor */ struct timeval tvTimeout[4]; /* timeout values (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 */ sa_syscall_tab_t scSysCall; /* table of system calls */ sa_optinfo_t optInfo[5]; /* option storage */ }; /* socket address abstraction object */ struct sa_addr_st { int nFamily; /* the socket family (AF_XXX) */ struct sockaddr *saBuf; /* the "struct sockaddr_xx" actually */ socklen_t slBuf; /* the length of "struct sockaddr_xx" */ }; /* handy struct timeval check */ #define SA_TVISZERO(tv) \ ((tv).tv_sec == 0 && (tv).tv_usec == 0) /* convert Internet address from presentation to network format */ #ifndef HAVE_GETADDRINFO 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 defined(HAVE_INET_ATON) /* at least for IPv4 we can rely on the old inet_aton(3) and for IPv6 inet_pton(3) would exist anyway */ if (inet_aton(strptr, &in_val) == 0) return 0; memcpy(addrptr, &in_val, sizeof(struct in_addr)); return 1; #elif defined(HAVE_INET_ADDR) /* at least for IPv4 try to rely on the even older inet_addr(3) */ memset(&in_val, '\0', sizeof(in_val)); if ((in_val.s_addr = inet_addr(strptr)) == ((in_addr_t)-1)) return 0; memcpy(addrptr, &in_val, sizeof(struct in_addr)); return 1; #endif } errno = EAFNOSUPPORT; return 0; #endif } #endif /* !HAVE_GETADDRINFO */ /* 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 #ifdef HAVE_INET_NTOA char *cp; int n; #endif if (family == AF_INET) { #ifdef HAVE_INET_NTOA /* at least for IPv4 we can rely on the old inet_ntoa(3) and for IPv6 inet_ntop(3) would exist anyway */ if ((cp = inet_ntoa(*((struct in_addr *)src))) == NULL) return NULL; n = strlen(cp); if (n > size-1) n = size-1; memcpy(dst, cp, n); dst[n] = '\0'; return dst; #endif } errno = EAFNOSUPPORT; return NULL; #endif } /* minimal output-independent vprintf(3) variant which supports %{c,s,d,%} only */ 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 *cp; char c; int d; int n; int bytes; if (format == NULL) return -1; bytes = 0; while (*format != '\0') { if (*format == '%') { c = *(format+1); if (c == '%') { /* expand "%%" */ cp = &c; n = (int)sizeof(char); } else if (c == 'c') { /* expand "%c" */ c = (char)va_arg(ap, int); cp = &c; n = (int)sizeof(char); } else if (c == 's') { /* expand "%s" */ if ((cp = (char *)va_arg(ap, char *)) == NULL) cp = "(null)"; n = (int)strlen(cp); } else if (c == 'd') { /* expand "%d" */ d = (int)va_arg(ap, int); #ifdef HAVE_SNPRINTF snprintf(ibuf, sizeof(ibuf), "%d", d); /* explicitly secure */ #else sprintf(ibuf, "%d", d); /* implicitly secure */ #endif cp = ibuf; n = (int)strlen(cp); } else { /* any other "%X" */ cp = (char *)format; n = 2; } format += 2; } else { /* plain text */ cp = (char *)format; if ((format = strchr(cp, '%')) == NULL) format = strchr(cp, '\0'); n = (int)(format - cp); } /* perform output operation */ if (output != NULL) if ((n = output(ctx, cp, (size_t)n)) == -1) break; bytes += n; } return bytes; } /* output callback function context for sa_mvsnprintf() */ typedef struct { char *bufptr; size_t buflen; } sa_mvsnprintf_cb_t; /* output callback function for sa_mvsnprintf() */ static int sa_mvsnprintf_cb(void *_ctx, const char *buffer, size_t bufsize) { sa_mvsnprintf_cb_t *ctx = (sa_mvsnprintf_cb_t *)_ctx; if (bufsize > ctx->buflen) return -1; memcpy(ctx->bufptr, buffer, bufsize); ctx->bufptr += bufsize; ctx->buflen -= bufsize; return (int)bufsize; } /* 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 n; sa_mvsnprintf_cb_t ctx; if (format == NULL) return -1; if (buffer != NULL && bufsize == 0) return -1; if (buffer == NULL) /* just determine output length */ n = sa_mvxprintf(NULL, NULL, format, ap); else { /* perform real output */ ctx.bufptr = buffer; ctx.buflen = bufsize; n = sa_mvxprintf(sa_mvsnprintf_cb, &ctx, format, ap); if (n != -1 && ctx.buflen == 0) n = -1; if (n != -1) *(ctx.bufptr) = '\0'; } return n; } /* 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; /* pass through to va_list based variant */ va_start(ap, format); chars = sa_mvsnprintf(buffer, bufsize, format, ap); va_end(ap); return chars; } /* 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_RC(SA_ERR_ARG); /* allocate and initialize new address object */ if ((saa = (sa_addr_t *)malloc(sizeof(sa_addr_t))) == NULL) return SA_RC(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_RC(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 sf; socklen_t sl; struct sockaddr *sa; struct sockaddr_un un; #ifdef HAVE_GETADDRINFO struct addrinfo ai_hints; struct addrinfo *ai = NULL; int err; #else struct sockaddr_in sa4; #ifdef AF_INET6 struct sockaddr_in6 sa6; #endif struct hostent *he; #endif struct servent *se; int bIPv6; int bNumeric; const char *cpHost; const char *cpPort; char *cpProto; unsigned int nPort; const char *cpPath; char uribuf[1024]; char *cp; int i; size_t n; int k; /* argument sanity check(s) */ if (saa == NULL || uri == NULL) return SA_RC(SA_ERR_ARG); /* on-the-fly create or just take over URI */ va_start(ap, uri); k = sa_mvsnprintf(uribuf, sizeof(uribuf), uri, ap); va_end(ap); if (k == -1) return SA_RC(SA_ERR_MEM); /* initialize result variables */ sa = NULL; sl = 0; sf = 0; /* 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; /* mandatory(!) socket address structure initialization */ memset(&un, 0, sizeof(un)); /* fill-in socket address structure */ n = strlen(cpPath); if (n == 0) return SA_RC(SA_ERR_ARG); if ((n+1) > sizeof(un.sun_path)) return SA_RC(SA_ERR_MEM); if (cpPath[0] != '/') { if (getcwd(un.sun_path, sizeof(un.sun_path)-(n+1)) == NULL) return SA_RC(SA_ERR_MEM); cp = un.sun_path + strlen(un.sun_path); } else cp = un.sun_path; memcpy(cp, cpPath, n+1); un.sun_family = AF_LOCAL; /* provide results */ sa = (struct sockaddr *)&un; sl = (socklen_t)sizeof(un); sf = AF_LOCAL; } else if (strncmp(uri, "inet://", 7) == 0) { /* parse URI into host, port and protocol parts */ cpHost = uri+7; bIPv6 = FALSE; if (cpHost[0] == '[') { /* IPv6 address (see RFC2732) */ #ifndef AF_INET6 return SA_RC(SA_ERR_IMP); #else bIPv6 = TRUE; cpHost++; if ((cp = strchr(cpHost, ']')) == NULL) return SA_RC(SA_ERR_ARG); *cp++ = '\0'; if (*cp != ':') return SA_RC(SA_ERR_ARG); cp++; #endif } else { /* IPv4 address or hostname */ if ((cp = strrchr(cpHost, ':')) == NULL) return SA_RC(SA_ERR_ARG); *cp++ = '\0'; } cpPort = cp; cpProto = "tcp"; if ((cp = strchr(cpPort, '#')) != NULL) { *cp++ = '\0'; cpProto = 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 = (unsigned int)atoi(cpPort); else { if ((se = getservbyname(cpPort, cpProto)) == NULL) return SA_RC(SA_ERR_SYS); nPort = ntohs(se->s_port); } #ifdef HAVE_GETADDRINFO memset(&ai_hints, 0, sizeof(ai_hints)); ai_hints.ai_family = PF_UNSPEC; if ((err = getaddrinfo(cpHost, NULL, &ai_hints, &ai)) != 0) { if (err == EAI_MEMORY) return SA_RC(SA_ERR_MEM); else if (err == EAI_SYSTEM) return SA_RC(SA_ERR_SYS); else return SA_RC(SA_ERR_ARG); } sa = ai->ai_addr; sl = ai->ai_addrlen; sf = ai->ai_family; if (sf == AF_INET) ((struct sockaddr_in *)sa)->sin_port = htons(nPort); else if (sf == AF_INET6) ((struct sockaddr_in6 *)sa)->sin6_port = htons(nPort); else return SA_RC(SA_ERR_ARG); #else /* !HAVE_GETADDRINFO */ /* mandatory(!) socket address structure initialization */ memset(&sa4, 0, sizeof(sa4)); #ifdef AF_INET6 memset(&sa6, 0, sizeof(sa6)); #endif /* resolve host by trying to parse it as either directly an IPv4 or IPv6 address or by resolving it to either an IPv4 or IPv6 address */ if (!bIPv6 && sa_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 = (socklen_t)sizeof(sa4); sf = AF_INET; } #ifdef AF_INET6 else if (bIPv6 && sa_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 = (socklen_t)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 = (socklen_t)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 = (socklen_t)sizeof(sa6); sf = AF_INET6; } #endif else return SA_RC(SA_ERR_ARG); } else return SA_RC(SA_ERR_ARG); #endif /* !HAVE_GETADDRINFO */ } else return SA_RC(SA_ERR_ARG); /* fill-in result address structure */ if (saa->saBuf != NULL) free(saa->saBuf); if ((saa->saBuf = (struct sockaddr *)malloc((size_t)sl)) == NULL) return SA_RC(SA_ERR_MEM); memcpy(saa->saBuf, sa, (size_t)sl); saa->slBuf = sl; saa->nFamily = (int)sf; #ifdef HAVE_GETADDRINFO if (ai != NULL) freeaddrinfo(ai); #endif return SA_OK; } /* import "struct sockaddr" into address object */ sa_rc_t sa_addr_s2a(sa_addr_t *saa, const struct sockaddr *sabuf, socklen_t salen) { /* argument sanity check(s) */ if (saa == NULL || sabuf == NULL || salen == 0) return SA_RC(SA_ERR_ARG); /* make sure we import only supported addresses */ if (!( sabuf->sa_family == AF_LOCAL || sabuf->sa_family == AF_INET #ifdef AF_INET6 || sabuf->sa_family == AF_INET6 #endif )) return SA_RC(SA_ERR_USE); /* create result address structure */ if (saa->saBuf != NULL) free(saa->saBuf); if ((saa->saBuf = (struct sockaddr *)malloc((size_t)salen)) == NULL) return SA_RC(SA_ERR_MEM); memcpy(saa->saBuf, sabuf, (size_t)salen); saa->slBuf = salen; /* remember family */ saa->nFamily = (int)(sabuf->sa_family); return SA_OK; } /* export address object into URI */ sa_rc_t sa_addr_a2u(const sa_addr_t *saa, char **uri) { char uribuf[1024]; struct sockaddr_un *un; struct sockaddr_in *sa4; #ifdef AF_INET6 struct sockaddr_in6 *sa6; #endif char caHost[512]; unsigned int nPort; /* argument sanity check(s) */ if (saa == NULL || uri == NULL) return SA_RC(SA_ERR_ARG); /* export object contents */ if (saa->nFamily == AF_LOCAL) { un = (struct sockaddr_un *)((void *)saa->saBuf); if ( ( saa->slBuf >= (socklen_t)(&(((struct sockaddr_un *)0)->sun_path[0])) && un->sun_path[0] == '\0') || (size_t)(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. This has been verified under FreeBSD, Linux and Solaris. */ if (sa_msnprintf(uribuf, sizeof(uribuf), "unix:/NOT-BOUND") == -1) return SA_RC(SA_ERR_FMT); } else { if (sa_msnprintf(uribuf, sizeof(uribuf), "unix:%s", un->sun_path) == -1) return SA_RC(SA_ERR_FMT); } } else if (saa->nFamily == AF_INET) { sa4 = (struct sockaddr_in *)((void *)saa->saBuf); if (sa_inet_ntop(AF_INET, &sa4->sin_addr.s_addr, caHost, sizeof(caHost)) == NULL) return SA_RC(SA_ERR_NET); nPort = ntohs(sa4->sin_port); if (sa_msnprintf(uribuf, sizeof(uribuf), "inet://%s:%d", caHost, nPort) == -1) return SA_RC(SA_ERR_FMT); } #ifdef AF_INET6 else if (saa->nFamily == AF_INET6) { sa6 = (struct sockaddr_in6 *)((void *)saa->saBuf); if (sa_inet_ntop(AF_INET6, &sa6->sin6_addr.s6_addr, caHost, sizeof(caHost)) == NULL) return SA_RC(SA_ERR_NET); nPort = ntohs(sa6->sin6_port); if (sa_msnprintf(uribuf, sizeof(uribuf), "inet://[%s]:%d", caHost, nPort) == -1) return SA_RC(SA_ERR_FMT); } #endif else return SA_RC(SA_ERR_INT); /* pass result to caller */ *uri = strdup(uribuf); return SA_OK; } /* export address object into "struct sockaddr" */ sa_rc_t sa_addr_a2s(const sa_addr_t *saa, struct sockaddr **sabuf, socklen_t *salen) { /* argument sanity check(s) */ if (saa == NULL || sabuf == NULL || salen == 0) return SA_RC(SA_ERR_ARG); /* export underlying address structure */ if ((*sabuf = (struct sockaddr *)malloc((size_t)saa->slBuf)) == NULL) return SA_RC(SA_ERR_MEM); memmove(*sabuf, saa->saBuf, (size_t)saa->slBuf); *salen = saa->slBuf; return SA_OK; } sa_rc_t sa_addr_match(const sa_addr_t *saa1, const sa_addr_t *saa2, int prefixlen) { const unsigned char *ucp1, *ucp2; unsigned int uc1, uc2, mask; size_t l1, l2; int nBytes; int nBits; #ifdef AF_INET6 int i; const unsigned char *ucp0; #endif unsigned int np1, np2; int bMatchPort; /* argument sanity check(s) */ if (saa1 == NULL || saa2 == NULL) return SA_RC(SA_ERR_ARG); /* short circuiting for wildcard matching */ if (prefixlen == 0) return SA_OK; /* determine address representation pointer and size */ if (saa1->nFamily == AF_LOCAL) { np1 = 0; np2 = 0; ucp1 = (const unsigned char *)(((struct sockaddr_un *)saa1->saBuf)->sun_path); ucp2 = (const unsigned char *)(((struct sockaddr_un *)saa2->saBuf)->sun_path); l1 = strlen(((struct sockaddr_un *)saa1->saBuf)->sun_path) * 8; l2 = strlen(((struct sockaddr_un *)saa2->saBuf)->sun_path) * 8; if (prefixlen < 0) { if (l1 != l2) return SA_RC(SA_ERR_MTC); nBits = (int)l1; } else { if ((int)l1 < prefixlen || (int)l2 < prefixlen) return SA_RC(SA_ERR_MTC); nBits = prefixlen; } } #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 "IPv4-mapped IPv6 address" (::ffff:1.2.3.4). For details see RFC 2373. */ if (saa1->nFamily == AF_INET6) { np1 = (unsigned int)(((struct sockaddr_in6 *)saa1->saBuf)->sin6_port); np2 = (unsigned int)(((struct sockaddr_in *)saa2->saBuf)->sin_port); ucp1 = (const unsigned char *)&(((struct sockaddr_in6 *)saa1->saBuf)->sin6_addr); ucp2 = (const unsigned char *)&(((struct sockaddr_in *)saa2->saBuf)->sin_addr); ucp0 = ucp1; ucp1 += 12; } else { np1 = (unsigned int)(((struct sockaddr_in *)saa1->saBuf)->sin_port); np2 = (unsigned int)(((struct sockaddr_in6 *)saa2->saBuf)->sin6_port); ucp1 = (const unsigned char *)&(((struct sockaddr_in *)saa1->saBuf)->sin_addr); ucp2 = (const unsigned char *)&(((struct sockaddr_in6 *)saa2->saBuf)->sin6_addr); ucp0 = ucp2; ucp2 += 12; } for (i = 0; i < 10; i++) if ((int)ucp0[i] != 0x00) return SA_RC(SA_ERR_MTC); if (!((int)ucp0[10] == 0xFF && (int)ucp0[11] == 0xFF)) return SA_RC(SA_ERR_MTC); nBits = 32; } #endif else if (saa1->nFamily == AF_INET) { np1 = (unsigned int)(((struct sockaddr_in *)saa1->saBuf)->sin_port); np2 = (unsigned int)(((struct sockaddr_in *)saa2->saBuf)->sin_port); ucp1 = (const unsigned char *)&(((struct sockaddr_in *)saa1->saBuf)->sin_addr); ucp2 = (const unsigned char *)&(((struct sockaddr_in *)saa2->saBuf)->sin_addr); nBits = 32; } #ifdef AF_INET6 else if (saa1->nFamily == AF_INET6) { np1 = (unsigned int)(((struct sockaddr_in6 *)saa1->saBuf)->sin6_port); np2 = (unsigned int)(((struct sockaddr_in6 *)saa2->saBuf)->sin6_port); ucp1 = (const unsigned char *)&(((struct sockaddr_in6 *)saa1->saBuf)->sin6_addr); ucp2 = (const unsigned char *)&(((struct sockaddr_in6 *)saa2->saBuf)->sin6_addr); nBits = 128; } #endif else return SA_RC(SA_ERR_INT); /* make sure we do not compare than possible */ if (prefixlen > (nBits+1)) return SA_RC(SA_ERR_ARG); /* support equal matching (= all bits plus optionally port) */ bMatchPort = FALSE; if (prefixlen < 0) { if (prefixlen < -1) bMatchPort = TRUE; prefixlen = nBits; } /* perform address representation comparison (assumption guaranteed by API: network byte order is used) */ nBytes = (prefixlen / 8); nBits = (prefixlen % 8); if (nBytes > 0) { if (memcmp(ucp1, ucp2, (size_t)nBytes) != 0) return SA_RC(SA_ERR_MTC); } if (nBits > 0) { uc1 = (unsigned int)ucp1[nBytes]; uc2 = (unsigned int)ucp2[nBytes]; mask = ((unsigned int)0xFF << (8-nBits)) & (unsigned int)0xFF; if ((uc1 & mask) != (uc2 & mask)) return SA_RC(SA_ERR_MTC); } /* optionally perform additional port matching */ if (bMatchPort) if (np1 != np2) return SA_RC(SA_ERR_MTC); return SA_OK; } /* set timeouts if timeouts or done in kernel */ static sa_rc_t sa_socket_settimeouts(const sa_t *sa) { /* stop processing if socket is still not allocated */ if (sa->fdSocket == -1) return SA_OK; #if defined(SO_RCVTIMEO) && defined(USE_SO_RCVTIMEO) && defined(SO_SNDTIMEO) && defined(USE_SO_SNDTIMEO) 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 < (int)(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 <= 0 ? 0 : 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) { int nType; int nProto; #if !(defined(IPPROTO_TCP) && defined(IPPROTO_UDP)) struct protoent *pe; #endif sa_rc_t rv; /* argument sanity check(s) */ if (sa == NULL) return SA_RC(SA_ERR_ARG); /* only perform operation if socket still does not exist */ if (sa->fdSocket != -1) return SA_RC(SA_ERR_USE); /* 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_RC(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 defined(IPPROTO_TCP) && defined(IPPROTO_UDP) if (nType == SOCK_STREAM) nProto = IPPROTO_TCP; else if (nType == SOCK_DGRAM) nProto = IPPROTO_UDP; else return SA_RC(SA_ERR_INT); #else if (nType == SOCK_STREAM) pe = getprotobyname("tcp"); else if (nType == SOCK_DGRAM) pe = getprotobyname("udp"); else return SA_RC(SA_ERR_INT); if (pe == NULL) return SA_RC(SA_ERR_SYS); nProto = pe->p_proto; #endif } else return SA_RC(SA_ERR_INT); /* create the underlying socket */ if ((sa->fdSocket = socket(nFamily, nType, nProto)) == -1) return SA_RC(SA_ERR_SYS); /* optionally set kernel timeouts */ 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; } /* internal destruction of underlying socket */ static sa_rc_t sa_socket_kill(sa_t *sa) { /* argument sanity check(s) */ if (sa == NULL) return SA_RC(SA_ERR_ARG); /* check context */ if (sa->fdSocket == -1) return SA_RC(SA_ERR_USE); /* close socket */ (void)close(sa->fdSocket); sa->fdSocket = -1; return SA_OK; } /* create abstract socket object */ sa_rc_t sa_create(sa_t **sap) { sa_t *sa; int i; /* argument sanity check(s) */ if (sap == NULL) return SA_RC(SA_ERR_ARG); /* allocate and initialize socket object */ if ((sa = (sa_t *)malloc(sizeof(sa_t))) == NULL) return SA_RC(SA_ERR_MEM); /* init object attributes */ sa->eType = SA_TYPE_STREAM; sa->fdSocket = -1; sa->nReadLen = 0; sa->nReadSize = 0; sa->cpReadBuf = NULL; sa->nWriteLen = 0; sa->nWriteSize = 0; sa->cpWriteBuf = NULL; /* init timeval object attributes */ for (i = 0; i < (int)(sizeof(sa->tvTimeout)/sizeof(sa->tvTimeout[0])); i++) { sa->tvTimeout[i].tv_sec = 0; sa->tvTimeout[i].tv_usec = 0; } /* init options object attributes */ for (i = 0; i < (int)(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); SA_SC_ASSIGN(sa, select, select, NULL); SA_SC_ASSIGN(sa, read, read, NULL); SA_SC_ASSIGN(sa, write, write, NULL); SA_SC_ASSIGN(sa, recvfrom, recvfrom, NULL); SA_SC_ASSIGN(sa, sendto, sendto, 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_RC(SA_ERR_ARG); /* kill underlying socket */ (void)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_RC(SA_ERR_ARG); if (!(type == SA_TYPE_STREAM || type == SA_TYPE_DATAGRAM)) return SA_RC(SA_ERR_ARG); /* kill underlying socket if type changes */ if (sa->eType != type) (void)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, sa_timeout_t id, long sec, long usec) { int i; sa_rc_t rv; /* argument sanity check(s) */ if (sa == NULL) return SA_RC(SA_ERR_ARG); if (id == SA_TIMEOUT_ALL) { for (i = 0; i < (int)(sizeof(sa->tvTimeout)/sizeof(sa->tvTimeout[0])); i++) { sa->tvTimeout[i].tv_sec = sec; sa->tvTimeout[i].tv_usec = usec; } } else { sa->tvTimeout[id].tv_sec = sec; sa->tvTimeout[id].tv_usec = usec; } /* try to already set timeouts */ if ((rv = sa_socket_settimeouts(sa)) != SA_OK) return SA_RC(rv); return SA_OK; } /* configure I/O buffers */ sa_rc_t sa_buffer(sa_t *sa, sa_buffer_t id, size_t size) { char *cp; /* argument sanity check(s) */ if (sa == NULL) return SA_RC(SA_ERR_ARG); if (id == SA_BUFFER_READ) { /* configure read/incoming buffer */ if (sa->nReadLen > (int)size) return SA_RC(SA_ERR_USE); if (size > 0) { if (sa->cpReadBuf == NULL) cp = (char *)malloc(size); else cp = (char *)realloc(sa->cpReadBuf, size); if (cp == NULL) return SA_RC(SA_ERR_MEM); sa->cpReadBuf = cp; sa->nReadSize = (int)size; } else { if (sa->cpReadBuf != NULL) free(sa->cpReadBuf); sa->cpReadBuf = NULL; sa->nReadSize = 0; } } else if (id == SA_BUFFER_WRITE) { /* configure write/outgoing buffer */ if (sa->nWriteLen > (int)size) return SA_RC(SA_ERR_USE); if (size > 0) { if (sa->cpWriteBuf == NULL) cp = (char *)malloc(size); else cp = (char *)realloc(sa->cpWriteBuf, size); if (cp == NULL) return SA_RC(SA_ERR_MEM); sa->cpWriteBuf = cp; sa->nWriteSize = (int)size; } else { if (sa->cpWriteBuf != NULL) free(sa->cpWriteBuf); sa->cpWriteBuf = NULL; sa->nWriteSize = 0; } } else return SA_RC(SA_ERR_ARG); return SA_OK; } /* configure socket option */ sa_rc_t sa_option(sa_t *sa, sa_option_t id, ...) { sa_rc_t rv; va_list ap; /* argument sanity check(s) */ if (sa == NULL) return SA_RC(SA_ERR_ARG); /* process option */ rv = SA_OK; va_start(ap, id); switch (id) { case SA_OPTION_NAGLE: { #if defined(IPPROTO_TCP) && defined(TCP_NODELAY) int mode = ((int)va_arg(ap, int) ? 1 : 0); sa->optInfo[SA_OPTION_NAGLE].value = mode; sa->optInfo[SA_OPTION_NAGLE].todo = TRUE; #else rv = SA_ERR_IMP; #endif break; } case SA_OPTION_LINGER: { #if defined(SO_LINGER) int amount = (int)va_arg(ap, int); 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: { #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: { #if defined(SO_REUSEPORT) int mode = ((int)va_arg(ap, int) ? 1 : 0); sa->optInfo[SA_OPTION_REUSEPORT].value = mode; sa->optInfo[SA_OPTION_REUSEPORT].todo = TRUE; #else rv = SA_ERR_IMP; #endif break; } case SA_OPTION_NONBLOCK: { int mode = (int)va_arg(ap, int); sa->optInfo[SA_OPTION_NONBLOCK].value = mode; sa->optInfo[SA_OPTION_NONBLOCK].todo = TRUE; break; } default: { rv = SA_ERR_ARG; } } va_end(ap); /* 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 */ sa_rc_t sa_syscall(sa_t *sa, sa_syscall_t id, void (*fptr)(void), void *fctx) { sa_rc_t rv; /* argument sanity check(s) */ if (sa == NULL || fptr == NULL) return SA_RC(SA_ERR_ARG); /* assign system call */ rv = SA_OK; switch (id) { case SA_SYSCALL_CONNECT: SA_SC_ASSIGN(sa, connect, fptr, fctx); break; case SA_SYSCALL_ACCEPT: SA_SC_ASSIGN(sa, accept, fptr, fctx); break; case SA_SYSCALL_SELECT: SA_SC_ASSIGN(sa, select, fptr, fctx); break; case SA_SYSCALL_READ: SA_SC_ASSIGN(sa, read, fptr, fctx); break; case SA_SYSCALL_WRITE: SA_SC_ASSIGN(sa, write, fptr, fctx); break; case SA_SYSCALL_RECVFROM: SA_SC_ASSIGN(sa, recvfrom, fptr, fctx); break; case SA_SYSCALL_SENDTO: SA_SC_ASSIGN(sa, sendto, fptr, fctx); break; default: rv = SA_ERR_ARG; } return SA_RC(rv); } /* bind socket to a local address */ sa_rc_t sa_bind(sa_t *sa, const sa_addr_t *laddr) { sa_rc_t rv; struct sockaddr_un *un; /* argument sanity check(s) */ if (sa == NULL || laddr == NULL) return SA_RC(SA_ERR_ARG); /* lazy creation of underlying socket */ if (sa->fdSocket == -1) if ((rv = sa_socket_init(sa, laddr->nFamily)) != SA_OK) return SA_RC(rv); /* remove a possibly existing old Unix Domain socket on filesystem */ if (laddr->nFamily == AF_LOCAL) { un = (struct sockaddr_un *)((void *)laddr->saBuf); (void)unlink(un->sun_path); } /* perform bind operation on underlying socket */ if (bind(sa->fdSocket, laddr->saBuf, laddr->slBuf) == -1) return SA_RC(SA_ERR_SYS); return SA_OK; } /* connect socket to a remote address */ sa_rc_t sa_connect(sa_t *sa, const sa_addr_t *raddr) { int flags, n, error; fd_set rset, wset; socklen_t len; sa_rc_t rv; struct timeval *tv; struct timeval tv_buf; /* argument sanity check(s) */ if (sa == NULL || raddr == NULL) return SA_RC(SA_ERR_ARG); /* connecting is only possible for stream communication */ if (sa->eType != SA_TYPE_STREAM) return SA_RC(SA_ERR_USE); /* lazy creation of underlying socket */ if (sa->fdSocket == -1) if ((rv = sa_socket_init(sa, raddr->nFamily)) != SA_OK) return SA_RC(rv); /* prepare return code decision */ rv = SA_OK; error = 0; /* temporarily switch underlying socket to non-blocking mode (necessary under timeout-aware operation only) */ flags = 0; if (!SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_CONNECT])) { flags = fcntl(sa->fdSocket, F_GETFL, 0); (void)fcntl(sa->fdSocket, F_SETFL, flags|O_NONBLOCK); } /* perform the connect operation */ if ((n = SA_SC_CALL_3(sa, connect, sa->fdSocket, raddr->saBuf, raddr->slBuf)) < 0) { if (errno != EINTR && errno != EINPROGRESS) { /* we have to perform the following post-processing under EINPROGRESS anway, but actually also for EINTR according to Unix Network Programming, volume 1, section 5.9, W. Richard Stevens: "What we are doing [] is restarting the interrupted system call ourself. This is fine for accept, along with the functions such as read, write, select and open. But there is one function that we cannot restart ourself: connect. If this function returns EINTR, we cannot call it again, as doing so will return an immediate error. When connect is interrupted by a caught signal and is not automatically restarted, we must call select to wait for the connection to complete, as we describe in section 15.3." */ error = errno; goto done; } } /* 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); if (!SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_CONNECT])) { memcpy(&tv_buf, &sa->tvTimeout[SA_TIMEOUT_CONNECT], sizeof(struct timeval)); tv = &tv_buf; } else tv = NULL; do { n = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &rset, &wset, (fd_set *)NULL, tv); } while (n == -1 && errno == EINTR); /* decide on return semantic */ if (n < 0) { error = errno; goto done; } else if (n == 0) { (void)close(sa->fdSocket); /* stop TCP three-way handshake */ sa->fdSocket = -1; rv = SA_ERR_TMT; goto done; } /* fetch pending error */ len = (socklen_t)sizeof(error); if (getsockopt(sa->fdSocket, SOL_SOCKET, SO_ERROR, (void *)&error, &len) < 0) error = errno; done: /* reset socket flags (necessary under timeout-aware operation only) */ if (!SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_CONNECT])) (void)fcntl(sa->fdSocket, F_SETFL, flags); /* optionally set errno */ if (error != 0) { (void)close(sa->fdSocket); /* just in case */ sa->fdSocket = -1; errno = error; rv = SA_ERR_SYS; } return SA_RC(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_RC(SA_ERR_ARG); /* listening is only possible for stream communication */ if (sa->eType != SA_TYPE_STREAM) return SA_RC(SA_ERR_USE); /* at least sa_bind() has to be already performed */ if (sa->fdSocket == -1) return SA_RC(SA_ERR_USE); /* perform listen operation on underlying socket */ if (listen(sa->fdSocket, backlog) == -1) return SA_RC(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; int n; fd_set fds; union { struct sockaddr_un un; struct sockaddr_in sa4; #ifdef AF_INET6 struct sockaddr_in6 sa6; #endif } sa_buf; socklen_t sa_size; struct timeval tv; int s; int i; /* argument sanity check(s) */ if (sa == NULL || caddr == NULL || csa == NULL) return SA_RC(SA_ERR_ARG); /* accepting connections is only possible for stream communication */ if (sa->eType != SA_TYPE_STREAM) return SA_RC(SA_ERR_USE); /* at least sa_listen() has to be already performed */ if (sa->fdSocket == -1) return SA_RC(SA_ERR_USE); /* if timeout is enabled, perform a smart-blocking wait */ if (!SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_ACCEPT])) { FD_ZERO(&fds); FD_SET(sa->fdSocket, &fds); memcpy(&tv, &sa->tvTimeout[SA_TIMEOUT_ACCEPT], sizeof(struct timeval)); do { n = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &fds, (fd_set *)NULL, (fd_set *)NULL, &tv); } while (n == -1 && errno == EINTR); 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_size = (socklen_t)sizeof(sa_buf); do { s = SA_SC_CALL_3(sa, accept, sa->fdSocket, (struct sockaddr *)&sa_buf, &sa_size); } while (s == -1 && errno == EINTR); if (s == -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_size)) != SA_OK) { (void)sa_addr_destroy(*caddr); return SA_RC(rv); } /* create result socket object */ if ((rv = sa_create(csa)) != SA_OK) { (void)sa_addr_destroy(*caddr); return SA_RC(rv); } /* fill-in child socket */ (*csa)->fdSocket = s; /* copy-over original system calls */ SA_SC_COPY((*csa), sa, connect); SA_SC_COPY((*csa), sa, accept); SA_SC_COPY((*csa), sa, select); SA_SC_COPY((*csa), sa, read); SA_SC_COPY((*csa), sa, write); SA_SC_COPY((*csa), sa, recvfrom); SA_SC_COPY((*csa), sa, sendto); /* copy-over original timeout values */ for (i = 0; i < (int)(sizeof(sa->tvTimeout)/sizeof(sa->tvTimeout[0])); i++) { (*csa)->tvTimeout[i].tv_sec = sa->tvTimeout[i].tv_sec; (*csa)->tvTimeout[i].tv_usec = sa->tvTimeout[i].tv_usec; } return SA_OK; } /* determine remote address */ sa_rc_t sa_getremote(sa_t *sa, 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_size; /* argument sanity check(s) */ if (sa == NULL || raddr == NULL) return SA_RC(SA_ERR_ARG); /* peers exist only for stream communication */ if (sa->eType != SA_TYPE_STREAM) return SA_RC(SA_ERR_USE); /* at least sa_connect() or sa_accept() has to be already performed */ if (sa->fdSocket == -1) return SA_RC(SA_ERR_USE); /* determine remote address of underlying socket */ sa_size = (socklen_t)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_size)) != SA_OK) { (void)sa_addr_destroy(*raddr); return SA_RC(rv); } return SA_OK; } /* determine local address */ sa_rc_t sa_getlocal(sa_t *sa, sa_addr_t **laddr) { sa_rc_t rv; union { struct sockaddr_in sa4; #ifdef AF_INET6 struct sockaddr_in6 sa6; #endif } sa_buf; socklen_t sa_size; /* argument sanity check(s) */ if (sa == NULL || laddr == NULL) return SA_RC(SA_ERR_ARG); /* at least sa_bind() has to be already performed */ if (sa->fdSocket == -1) return SA_RC(SA_ERR_USE); /* determine local address of underlying socket */ sa_size = (socklen_t)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_size)) != SA_OK) { (void)sa_addr_destroy(*laddr); return SA_RC(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_RC(SA_ERR_ARG); /* if still no socket exists, say this explicitly */ if (sa->fdSocket == -1) return SA_RC(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; #if !(defined(SO_RCVTIMEO) && defined(USE_SO_RCVTIMEO) && defined(SO_SNDTIMEO) && defined(USE_SO_SNDTIMEO)) fd_set fds; struct timeval tv; #endif /* if timeout is enabled, perform explicit/smart blocking instead of implicitly/hard blocking in the read(2) system call */ #if !(defined(SO_RCVTIMEO) && defined(USE_SO_RCVTIMEO) && defined(SO_SNDTIMEO) && defined(USE_SO_SNDTIMEO)) if (!SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_READ])) { FD_ZERO(&fds); FD_SET(sa->fdSocket, &fds); memcpy(&tv, &sa->tvTimeout[SA_TIMEOUT_READ], sizeof(struct timeval)); do { rv = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &fds, (fd_set *)NULL, (fd_set *)NULL, &tv); } while (rv == -1 && errno == EINTR); if (rv == 0) { errno = ETIMEDOUT; return -1; } } #endif /* perform read operation on underlying socket */ do { rv = (int)SA_SC_CALL_3(sa, read, sa->fdSocket, cpBuf, (size_t)nBufLen); } while (rv == -1 && errno == EINTR); #if defined(SO_RCVTIMEO) && defined(USE_SO_RCVTIMEO) && defined(SO_SNDTIMEO) && defined(USE_SO_SNDTIMEO) if (rv == -1 && errno == EWOULDBLOCK) errno = ETIMEDOUT; #endif return rv; } /* read data from socket */ sa_rc_t sa_read(sa_t *sa, char *cpBuf, size_t nBufReq, size_t *nBufRes) { int n; sa_rc_t rv; int res; /* argument sanity check(s) */ if (sa == NULL || cpBuf == NULL || nBufReq == 0) return SA_RC(SA_ERR_ARG); /* reading is only possible for stream communication */ if (sa->eType != SA_TYPE_STREAM) return SA_RC(SA_ERR_USE); /* at least a connection has to exist */ if (sa->fdSocket == -1) return SA_RC(SA_ERR_USE); /* perform read operation */ rv = SA_OK; if (sa->nReadSize == 0) { /* user-space unbuffered I/O */ if (sa->nWriteLen > 0) (void)sa_flush(sa); res = sa_read_raw(sa, cpBuf, (int)nBufReq); if (res == 0) rv = SA_ERR_EOF; else if (res < 0 && errno == ETIMEDOUT) rv = SA_ERR_TMT; else if (res < 0) rv = SA_ERR_SYS; } else { /* user-space buffered I/O */ res = 0; for (;;) { if ((int)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 { if (sa->nReadLen > 0) { /* fetch already existing buffer contents as a start */ memmove(cpBuf, sa->cpReadBuf, (size_t)sa->nReadLen); nBufReq -= sa->nReadLen; cpBuf += sa->nReadLen; res += sa->nReadLen; sa->nReadLen = 0; } if (sa->nWriteLen > 0) (void)sa_flush(sa); if ((int)nBufReq >= sa->nReadSize) { /* buffer is too small at all, so read directly */ n = sa_read_raw(sa, cpBuf, (int)nBufReq); if (n > 0) res += n; else if (n == 0) rv = (res == 0 ? SA_ERR_EOF : SA_OK); else if (n < 0 && errno == ETIMEDOUT) rv = (res == 0 ? SA_ERR_TMT : SA_OK); else if (n < 0) rv = (res == 0 ? SA_ERR_SYS : SA_OK); } else { /* fill buffer with new data */ n = sa_read_raw(sa, sa->cpReadBuf, sa->nReadSize); if (n < 0 && errno == ETIMEDOUT) /* timeout on this read, but perhaps ok as a whole */ rv = (res == 0 ? SA_ERR_TMT : SA_OK); else if (n < 0) /* error on this read, but perhaps ok as a whole */ rv = (res == 0 ? SA_ERR_SYS : SA_OK); else 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; } } /* pass number of actually read bytes to caller */ if (nBufRes != NULL) *nBufRes = (size_t)res; return SA_RC(rv); } /* read data from socket until [CR]LF (convenience 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; sa_rc_t rv; /* argument sanity check(s) */ if (sa == NULL || cpBuf == NULL || nBufReq == 0) return SA_RC(SA_ERR_ARG); /* reading is only possible for stream communication */ if (sa->eType != SA_TYPE_STREAM) return SA_RC(SA_ERR_USE); /* at least a connection has to exist */ if (sa->fdSocket == -1) return SA_RC(SA_ERR_USE); /* we just perform a plain sa_read() per character, because if buffers are enabled, this is not as stupid as it looks at the first hand and if buffers are disabled, there is no better solution anyway. */ rv = SA_OK; res = 0; while (res < (nBufReq-1)) { rv = sa_read(sa, &c, 1, &n); if (rv != SA_OK) break; if (n == 0) break; cpBuf[res++] = c; if (c == '\n') break; } cpBuf[res] = '\0'; /* pass number of actually read characters to caller */ if (nBufRes != NULL) *nBufRes = res; return SA_RC(rv); } /* internal raw write operation */ static int sa_write_raw(sa_t *sa, const char *cpBuf, int nBufLen) { int rv; #if !(defined(SO_RCVTIMEO) && defined(USE_SO_RCVTIMEO) && defined(SO_SNDTIMEO) && defined(USE_SO_SNDTIMEO)) fd_set fds; struct timeval tv; #endif /* if timeout is enabled, perform explicit/smart blocking instead of implicitly/hard blocking in the write(2) system call */ #if !(defined(SO_RCVTIMEO) && defined(USE_SO_RCVTIMEO) && defined(SO_SNDTIMEO) && defined(USE_SO_SNDTIMEO)) if (!SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_WRITE])) { FD_ZERO(&fds); FD_SET(sa->fdSocket, &fds); memcpy(&tv, &sa->tvTimeout[SA_TIMEOUT_WRITE], sizeof(struct timeval)); do { rv = SA_SC_CALL_5(sa, select, sa->fdSocket+1, (fd_set *)NULL, &fds, (fd_set *)NULL, &tv); } while (rv == -1 && errno == EINTR); if (rv == 0) { errno = ETIMEDOUT; return -1; } } #endif /* perform write operation on underlying socket */ do { rv = (int)SA_SC_CALL_3(sa, write, sa->fdSocket, cpBuf, (size_t)nBufLen); } while (rv == -1 && errno == EINTR); #if defined(SO_RCVTIMEO) && defined(USE_SO_RCVTIMEO) && defined(SO_SNDTIMEO) && defined(USE_SO_SNDTIMEO) if (rv == -1 && errno == EWOULDBLOCK) errno = ETIMEDOUT; #endif return rv; } /* write data to socket */ sa_rc_t sa_write(sa_t *sa, const char *cpBuf, size_t nBufReq, size_t *nBufRes) { int n; int res; sa_rc_t rv; /* argument sanity check(s) */ if (sa == NULL || cpBuf == NULL || nBufReq == 0) return SA_RC(SA_ERR_ARG); /* writing is only possible for stream communication */ if (sa->eType != SA_TYPE_STREAM) return SA_RC(SA_ERR_USE); /* at least a connection has to exist */ if (sa->fdSocket == -1) return SA_RC(SA_ERR_USE); rv = SA_OK; if (sa->nWriteSize == 0) { /* user-space unbuffered I/O */ res = sa_write_raw(sa, cpBuf, (int)nBufReq); if (res < 0 && errno == ETIMEDOUT) rv = SA_ERR_TMT; else if (res < 0) rv = SA_ERR_SYS; } else { /* user-space buffered I/O */ if ((int)nBufReq > (sa->nWriteSize - sa->nWriteLen)) { /* not enough space in buffer, so flush buffer first */ (void)sa_flush(sa); } res = 0; if ((int)nBufReq >= sa->nWriteSize) { /* buffer too small at all, so write immediately */ while (nBufReq > 0) { n = sa_write_raw(sa, cpBuf, (int)nBufReq); if (n < 0 && errno == ETIMEDOUT) rv = (res == 0 ? SA_ERR_TMT : SA_OK); else 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 = (int)nBufReq; } } /* pass number of actually written bytes to caller */ if (nBufRes != NULL) *nBufRes = (size_t)res; return SA_RC(rv); } /* output callback function context for sa_writef() */ typedef struct { sa_t *sa; sa_rc_t rv; } sa_writef_cb_t; /* output callback function for sa_writef() */ static int sa_writef_cb(void *_ctx, const char *buffer, size_t bufsize) { size_t n; sa_writef_cb_t *ctx = (sa_writef_cb_t *)_ctx; if ((ctx->rv = sa_write(ctx->sa, buffer, bufsize, &n)) != SA_OK) return -1; return (int)n; } /* write formatted string to socket (convenience function) */ sa_rc_t sa_writef(sa_t *sa, const char *cpFmt, ...) { va_list ap; int n; sa_writef_cb_t ctx; /* argument sanity check(s) */ if (sa == NULL || cpFmt == NULL) return SA_RC(SA_ERR_ARG); /* writing is only possible for stream communication */ if (sa->eType != SA_TYPE_STREAM) return SA_RC(SA_ERR_USE); /* at least a connection has to exist */ if (sa->fdSocket == -1) return SA_RC(SA_ERR_USE); /* format string into temporary buffer */ va_start(ap, cpFmt); ctx.sa = sa; ctx.rv = SA_OK; n = sa_mvxprintf(sa_writef_cb, &ctx, cpFmt, ap); if (n == -1 && ctx.rv == SA_OK) ctx.rv = SA_ERR_FMT; va_end(ap); return ctx.rv; } /* flush write/outgoing I/O buffer */ sa_rc_t sa_flush(sa_t *sa) { int n; sa_rc_t rv; /* argument sanity check(s) */ if (sa == NULL) return SA_RC(SA_ERR_ARG); /* flushing is only possible for stream communication */ if (sa->eType != SA_TYPE_STREAM) return SA_RC(SA_ERR_USE); /* at least a connection has to exist */ if (sa->fdSocket == -1) return SA_RC(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 && errno == ETIMEDOUT) rv = SA_ERR_TMT; else if (n < 0) rv = SA_ERR_SYS; if (n <= 0) break; memmove(sa->cpWriteBuf, sa->cpWriteBuf+n, (size_t)(sa->nWriteLen-n)); sa->nWriteLen -= n; } sa->nWriteLen = 0; } return SA_RC(rv); } /* shutdown a socket connection */ sa_rc_t sa_shutdown(sa_t *sa, const char *flags) { int how; /* argument sanity check(s) */ if (sa == NULL || flags == NULL) return SA_RC(SA_ERR_ARG); /* shutdown is only possible for stream communication */ if (sa->eType != SA_TYPE_STREAM) return SA_RC(SA_ERR_USE); /* at least a connection has to exist */ if (sa->fdSocket == -1) return SA_RC(SA_ERR_USE); /* determine flags for shutdown(2) */ how = 0; if (strcmp(flags, "r") == 0) how = SHUT_RD; else if (strcmp(flags, "w") == 0) how = SHUT_WR; 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)) (void)sa_flush(sa); /* perform shutdown operation on underlying socket */ if (shutdown(sa->fdSocket, how) == -1) return SA_RC(SA_ERR_SYS); return SA_OK; } /* receive data via socket */ 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 { struct sockaddr_in sa4; #ifdef AF_INET6 struct sockaddr_in6 sa6; #endif } sa_buf; socklen_t sa_size; ssize_t n; int k; fd_set fds; struct timeval tv; /* argument sanity check(s) */ if (sa == NULL || buf == NULL || buflen == 0 || raddr == NULL) return SA_RC(SA_ERR_ARG); /* receiving is only possible for datagram communication */ if (sa->eType != SA_TYPE_DATAGRAM) return SA_RC(SA_ERR_USE); /* at least a sa_bind() has to be performed */ if (sa->fdSocket == -1) return SA_RC(SA_ERR_USE); /* if timeout is enabled, perform explicit/smart blocking instead of implicitly/hard blocking in the recvfrom(2) system call */ if (!SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_READ])) { FD_ZERO(&fds); FD_SET(sa->fdSocket, &fds); memcpy(&tv, &sa->tvTimeout[SA_TIMEOUT_READ], sizeof(struct timeval)); do { k = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &fds, (fd_set *)NULL, (fd_set *)NULL, &tv); } while (k == -1 && errno == EINTR); if (k == 0) errno = ETIMEDOUT; if (k <= 0) return SA_RC(SA_ERR_SYS); } /* perform receive operation on underlying socket */ sa_size = (socklen_t)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_size)) != SA_OK) { (void)sa_addr_destroy(*raddr); return rv; } /* pass actual number of received bytes to caller */ if (bufdone != NULL) *bufdone = (size_t)n; return SA_OK; } /* send data via socket */ sa_rc_t sa_send(sa_t *sa, sa_addr_t *raddr, const char *buf, size_t buflen, size_t *bufdone) { ssize_t n; int k; fd_set fds; sa_rc_t rv; struct timeval tv; /* argument sanity check(s) */ if (sa == NULL || buf == NULL || buflen == 0 || raddr == NULL) return SA_RC(SA_ERR_ARG); /* sending is only possible for datagram communication */ if (sa->eType != SA_TYPE_DATAGRAM) return SA_RC(SA_ERR_USE); /* lazy creation of underlying socket */ if (sa->fdSocket == -1) if ((rv = sa_socket_init(sa, raddr->nFamily)) != SA_OK) return rv; /* 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); memcpy(&tv, &sa->tvTimeout[SA_TIMEOUT_WRITE], sizeof(struct timeval)); do { k = SA_SC_CALL_5(sa, select, sa->fdSocket+1, (fd_set *)NULL, &fds, (fd_set *)NULL, &tv); } while (k == -1 && errno == EINTR); if (k == 0) errno = ETIMEDOUT; if (k <= 0) return SA_RC(SA_ERR_SYS); } /* perform send operation on underlying socket */ if ((n = SA_SC_CALL_6(sa, sendto, sa->fdSocket, buf, buflen, 0, raddr->saBuf, raddr->slBuf)) == -1) return SA_RC(SA_ERR_SYS); /* pass actual number of sent bytes to caller */ if (bufdone != NULL) *bufdone = (size_t)n; return SA_OK; } /* send formatted string to socket (convenience function) */ sa_rc_t sa_sendf(sa_t *sa, sa_addr_t *raddr, const char *cpFmt, ...) { va_list ap; va_list apbak; int 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); va_copy(apbak, ap); if ((nBuf = sa_mvsnprintf(NULL, 0, cpFmt, ap)) == -1) return SA_RC(SA_ERR_FMT); va_copy(ap, apbak); if ((nBuf+1) > (int)sizeof(caBuf)) { /* requires a larger buffer, so allocate dynamically */ if ((cpBuf = (char *)malloc((size_t)(nBuf+1))) == NULL) return SA_RC(SA_ERR_MEM); } else { /* fits into small buffer, so allocate statically */ cpBuf = caBuf; } rv = SA_OK; if (sa_mvsnprintf(cpBuf, (size_t)(nBuf+1), cpFmt, ap) == -1) rv = SA_ERR_FMT; va_end(ap); /* pass-through to sa_send() */ if (rv == SA_OK) rv = sa_send(sa, raddr, cpBuf, (size_t)nBuf, NULL); /* cleanup dynamically allocated buffer */ if ((nBuf+1) > (int)sizeof(caBuf)) free(cpBuf); return rv; } /* return error string */ char *sa_error(sa_rc_t rv) { char *sz; /* translate result value into corresponding string */ if (rv == SA_OK) sz = "Everything Ok"; else if (rv == SA_ERR_ARG) sz = "Invalid Argument"; else if (rv == SA_ERR_USE) sz = "Invalid Use Or Context"; else if (rv == SA_ERR_MEM) sz = "Not Enough Memory"; else if (rv == SA_ERR_MTC) sz = "Matching Failed"; else if (rv == SA_ERR_EOF) sz = "End Of Communication"; else if (rv == SA_ERR_TMT) sz = "Communication Timeout"; else if (rv == SA_ERR_SYS) sz = "Operating System Error"; else if (rv == SA_ERR_NET) sz = "Networking Error"; else if (rv == SA_ERR_FMT) sz = "Formatting Error"; else if (rv == SA_ERR_IMP) sz = "Implementation Not Available"; else if (rv == SA_ERR_INT) sz = "Internal Error"; else sz = "Invalid Result Code"; return sz; } @ 1.28 log @Imported OSSP sa 1.2.5 @ text @a219 1 SA_SC_DECLARE_1(struct hostent *, gethostbyname, const char *name) d657 1 a657 1 else if ((he = SA_SC_CALL_1(sa, gethostbyname, cpHost)) != NULL) { a1186 1 SA_SC_ASSIGN(sa, gethostbyname, gethostbyname, NULL); a1415 1 case SA_SYSCALL_GETHOSTBYNAME: SA_SC_ASSIGN(sa, gethostbyname, fptr, fctx); break; a1658 1 SA_SC_COPY((*csa), sa, gethostbyname); @ 1.27 log @import OSSP sa 1.2.4 @ text @d270 2 a276 1 #endif d279 1 d737 1 a737 1 sa_rc_t sa_addr_a2u(sa_addr_t *saa, char **uri) d798 1 a798 1 sa_rc_t sa_addr_a2s(sa_addr_t *saa, struct sockaddr **sabuf, socklen_t *salen) d813 1 a813 1 sa_rc_t sa_addr_match(sa_addr_t *saa1, sa_addr_t *saa2, int prefixlen) d939 1 a939 1 static sa_rc_t sa_socket_settimeouts(sa_t *sa) d1227 1 a1227 1 sa_socket_kill(sa); d1426 1 a1426 1 sa_rc_t sa_bind(sa_t *sa, sa_addr_t *laddr) d1454 1 a1454 1 sa_rc_t sa_connect(sa_t *sa, sa_addr_t *raddr) d2136 1 a2136 1 sa_rc_t sa_shutdown(sa_t *sa, char *flags) @ 1.26 log @Adjust copyright messages for new year 2005. @ text @d213 8 a220 7 SA_SC_DECLARE_3(int, connect, int, const struct sockaddr *, socklen_t) SA_SC_DECLARE_3(int, accept, int, struct sockaddr *, socklen_t *) SA_SC_DECLARE_5(int, select, int, fd_set *, fd_set *, fd_set *, struct timeval *) SA_SC_DECLARE_3(ssize_t, read, int, void *, size_t) SA_SC_DECLARE_3(ssize_t, write, int, const void *, size_t) 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) d501 2 a502 2 char *cpHost; char *cpPort; d563 1 a563 1 cpHost = (char *)(uri+7); d656 1 a656 1 else if ((he = gethostbyname(cpHost)) != NULL) { d944 1 a944 1 if (SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_READ])) { d950 1 a950 1 if (SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_WRITE])) { d993 1 a993 1 linger.l_linger = sa->optInfo[i].value; d1179 8 a1186 7 SA_SC_ASSIGN(sa, connect, connect, NULL); SA_SC_ASSIGN(sa, accept, accept, NULL); SA_SC_ASSIGN(sa, select, select, NULL); SA_SC_ASSIGN(sa, read, read, NULL); SA_SC_ASSIGN(sa, write, write, NULL); SA_SC_ASSIGN(sa, recvfrom, recvfrom, NULL); SA_SC_ASSIGN(sa, sendto, sendto, NULL); d1344 1 a1344 1 int amount = ((int)va_arg(ap, int) ? 1 : 0); d1409 8 a1416 7 case SA_SYSCALL_CONNECT: SA_SC_ASSIGN(sa, connect, fptr, fctx); break; case SA_SYSCALL_ACCEPT: SA_SC_ASSIGN(sa, accept, fptr, fctx); break; case SA_SYSCALL_SELECT: SA_SC_ASSIGN(sa, select, fptr, fctx); break; case SA_SYSCALL_READ: SA_SC_ASSIGN(sa, read, fptr, fctx); break; case SA_SYSCALL_WRITE: SA_SC_ASSIGN(sa, write, fptr, fctx); break; case SA_SYSCALL_RECVFROM: SA_SC_ASSIGN(sa, recvfrom, fptr, fctx); break; case SA_SYSCALL_SENDTO: SA_SC_ASSIGN(sa, sendto, fptr, fctx); break; d1459 1 d1516 4 a1519 2 if (!SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_CONNECT])) tv = &sa->tvTimeout[SA_TIMEOUT_CONNECT]; d1523 1 a1523 1 n = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &rset, &wset, NULL, tv); d1597 1 d1617 1 d1619 1 a1619 2 n = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &fds, NULL, NULL, &sa->tvTimeout[SA_TIMEOUT_ACCEPT]); d1660 1 d1770 1 d1779 1 d1781 1 a1781 2 rv = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &fds, NULL, NULL, &sa->tvTimeout[SA_TIMEOUT_READ]); d1950 1 d1959 1 d1961 1 a1961 2 rv = SA_SC_CALL_5(sa, select, sa->fdSocket+1, NULL, &fds, NULL, &sa->tvTimeout[SA_TIMEOUT_WRITE]); d2186 1 d2205 1 d2207 1 a2207 2 k = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &fds, NULL, NULL, &sa->tvTimeout[SA_TIMEOUT_READ]); d2243 1 d2263 1 d2265 1 a2265 2 k = SA_SC_CALL_5(sa, select, sa->fdSocket+1, NULL, &fds, NULL, &sa->tvTimeout[SA_TIMEOUT_WRITE]); d2288 1 d2300 1 d2303 1 a2303 1 va_end(ap); a2312 1 va_start(ap, cpFmt); @ 1.25 log @import latest OSSP sa with changes around restarting interrupted system calls @ text @d3 3 a5 3 ** Copyright (c) 2001-2004 Ralf S. Engelschall ** Copyright (c) 2001-2004 The OSSP Project ** Copyright (c) 2001-2004 Cable & Wireless @ 1.24 log @restart accept(2) after interrupted system call @ text @d3 3 a5 3 ** Copyright (c) 2001-2003 Ralf S. Engelschall ** Copyright (c) 2001-2003 The OSSP Project ** Copyright (c) 2001-2003 Cable & Wireless Deutschland d1455 1 d1470 1 d1472 1 a1472 8 if (SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_CONNECT])) { /* standard/non-timeout-aware connect operation */ if (SA_SC_CALL_3(sa, connect, sa->fdSocket, raddr->saBuf, raddr->slBuf) < 0) rv = SA_ERR_SYS; } else { /* emulated/timeout-aware connect operation */ error = 0; d1474 4 a1477 1 /* temporarily switch underlying socket to non-blocking mode */ d1480 1 d1482 16 a1497 24 /* perform the connect operation */ if ((n = SA_SC_CALL_3(sa, connect, sa->fdSocket, raddr->saBuf, raddr->slBuf)) < 0) { if (errno != EINPROGRESS) { error = errno; goto done; } } /* 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 = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &rset, &wset, NULL, &sa->tvTimeout[SA_TIMEOUT_CONNECT]); } while (n == -1 && errno == EINTR); /* decide on return semantic */ if (n < 0) { d1501 1 a1501 6 else if (n == 0) { (void)close(sa->fdSocket); /* stop TCP three-way handshake */ sa->fdSocket = -1; rv = SA_ERR_TMT; goto done; } d1503 39 a1541 8 /* fetch pending error */ len = (socklen_t)sizeof(error); if (getsockopt(sa->fdSocket, SOL_SOCKET, SO_ERROR, (void *)&error, &len) < 0) error = errno; done: /* reset socket flags */ d1544 6 a1549 7 /* optionally set errno */ if (error != 0) { (void)close(sa->fdSocket); /* just in case */ sa->fdSocket = -1; errno = error; rv = SA_ERR_SYS; } d1551 1 @ 1.23 log @import most recent lib_sa @ text @d1605 4 a1608 1 if ((s = SA_SC_CALL_3(sa, accept, sa->fdSocket, (struct sockaddr *)&sa_buf, &sa_size)) == -1) @ 1.22 log @correct spelling: privileges, convenient; @ text @d32 3 a34 1 #include "l2_config.h" d42 1 a42 1 #include /* for isXXX() */ d107 1 a107 1 #if !defined(HAVE_SSIZE_T) d119 1 a119 1 union { void (*any)(); \ d126 1 a126 1 union { void (*any)(); \ d133 1 a133 1 union { void (*any)(); \ d140 1 a140 1 union { void (*any)(); \ d147 1 a147 1 union { void (*any)(); \ d154 1 a154 1 union { void (*any)(); \ d161 1 a161 1 union { void (*any)(); \ d170 1 a170 1 (sa)->scSysCall.sc_##fn.fptr.any = (void (*)())(ptr); \ d185 1 a185 1 : ((sa)->scSysCall.sc_##fn.fptr.std)() ) d255 1 d282 1 d290 1 d293 1 d334 1 a334 1 n = sizeof(char); d340 1 a340 1 n = sizeof(char); d346 1 a346 1 n = strlen(cp); d357 1 a357 1 n = strlen(cp); d371 1 a371 1 n = format - cp; d375 1 a375 1 if ((n = output(ctx, cp, n)) == -1) d398 1 a398 1 return bufsize; d486 5 a494 1 int bIPv6; d496 1 d498 1 d508 2 a509 1 int n; d517 1 a517 1 sa_mvsnprintf(uribuf, sizeof(uribuf), uri, ap); d519 2 d557 1 a557 1 sl = sizeof(un); d609 22 d643 1 a643 1 sl = sizeof(sa4); d651 1 a651 1 sl = sizeof(sa6); d662 1 a662 1 sl = sizeof(sa4); d672 1 a672 1 sl = sizeof(sa6); d681 1 d689 1 a689 1 if ((saa->saBuf = (struct sockaddr *)malloc(sl)) == NULL) d691 1 a691 1 memcpy(saa->saBuf, sa, sl); d693 6 a698 1 saa->nFamily = sf; d722 1 a722 1 if ((saa->saBuf = (struct sockaddr *)malloc(salen)) == NULL) d724 1 a724 1 memcpy(saa->saBuf, sabuf, salen); d728 1 a728 1 saa->nFamily = sabuf->sa_family; d754 1 a754 1 || saa->slBuf < sizeof(struct sockaddr_un)) d759 7 a765 3 sa_msnprintf(uribuf, sizeof(uribuf), "unix:/NOT-BOUND"); else sa_msnprintf(uribuf, sizeof(uribuf), "unix:%s", un->sun_path); d769 2 a770 1 sa_inet_ntop(AF_INET, &sa4->sin_addr.s_addr, caHost, sizeof(caHost)); d772 2 a773 1 sa_msnprintf(uribuf, sizeof(uribuf), "inet://%s:%d", caHost, nPort); d778 2 a779 1 sa_inet_ntop(AF_INET6, &sa6->sin6_addr.s6_addr, caHost, sizeof(caHost)); d781 2 a782 1 sa_msnprintf(uribuf, sizeof(uribuf), "inet://[%s]:%d", caHost, nPort); d802 1 a802 1 if ((*sabuf = (struct sockaddr *)malloc(saa->slBuf)) == NULL) d804 1 a804 1 memmove(*sabuf, saa->saBuf, saa->slBuf); d843 1 a843 1 nBits = l1; d846 1 a846 1 if (l1 < prefixlen || l2 < prefixlen) d873 1 a873 1 if (ucp0[i] != 0x00) d875 1 a875 1 if (!(ucp0[10] == 0xFF && ucp0[11] == 0xFF)) d916 1 a916 1 if (memcmp(ucp1, ucp2, nBytes) != 0) d920 3 a922 3 uc1 = ucp1[nBytes]; uc2 = ucp2[nBytes]; mask = (0xFF << (8-nBits)) & 0xFF; d942 1 a942 1 #if defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO) d971 1 a971 1 for (i = 0; i < (sizeof(sa->optInfo)/sizeof(sa->optInfo[0])); i++) { d1135 1 a1135 1 close(sa->fdSocket); d1166 1 a1166 1 for (i = 0; i < (sizeof(sa->tvTimeout)/sizeof(sa->tvTimeout[0])); i++) { d1172 1 a1172 1 for (i = 0; i < (sizeof(sa->optInfo)/sizeof(sa->optInfo[0])); i++) { d1200 1 a1200 1 sa_socket_kill(sa); d1242 1 a1242 1 for (i = 0; i < (sizeof(sa->tvTimeout)/sizeof(sa->tvTimeout[0])); i++) { d1270 1 a1270 1 if (sa->nReadLen > size) d1280 1 a1280 1 sa->nReadSize = size; d1291 1 a1291 1 if (sa->nWriteLen > size) d1301 1 a1301 1 sa->nWriteSize = size; d1396 1 a1396 1 sa_rc_t sa_syscall(sa_t *sa, sa_syscall_t id, void (*fptr)(), void *fctx) d1438 1 a1438 1 unlink(un->sun_path); d1481 1 a1481 1 fcntl(sa->fdSocket, F_SETFL, flags|O_NONBLOCK); d1511 1 a1511 1 close(sa->fdSocket); /* stop TCP three-way handshake */ d1518 1 a1518 1 len = sizeof(error); d1525 1 a1525 1 fcntl(sa->fdSocket, F_SETFL, flags); d1529 1 a1529 1 close(sa->fdSocket); /* just in case */ d1604 1 a1604 1 sa_size = sizeof(sa_buf); d1612 1 a1612 1 sa_addr_destroy(*caddr); d1618 1 a1618 1 sa_addr_destroy(*caddr); d1635 1 a1635 1 for (i = 0; i < (sizeof(sa->tvTimeout)/sizeof(sa->tvTimeout[0])); i++) { d1668 1 a1668 1 sa_size = sizeof(sa_buf); d1676 1 a1676 1 sa_addr_destroy(*raddr); d1704 1 a1704 1 sa_size = sizeof(sa_buf); d1712 1 a1712 1 sa_addr_destroy(*laddr); d1740 1 a1740 1 #if !(defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO)) d1746 1 a1746 1 #if !(defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO)) d1763 1 a1763 1 rv = SA_SC_CALL_3(sa, read, sa->fdSocket, cpBuf, nBufLen); d1766 1 a1766 1 #if defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO) d1798 2 a1799 2 sa_flush(sa); res = sa_read_raw(sa, cpBuf, nBufReq); d1811 1 a1811 1 if (nBufReq <= sa->nReadLen) { d1821 1 a1821 1 memmove(cpBuf, sa->cpReadBuf, sa->nReadLen); d1828 2 a1829 2 sa_flush(sa); if (nBufReq >= sa->nReadSize) { d1831 1 a1831 1 n = sa_read_raw(sa, cpBuf, nBufReq); d1900 1 a1900 1 if (n <= 0) d1919 1 a1919 1 #if !(defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO)) d1925 1 a1925 1 #if !(defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO)) d1942 1 a1942 1 rv = SA_SC_CALL_3(sa, write, sa->fdSocket, cpBuf, nBufLen); d1945 1 a1945 1 #if defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO) d1975 1 a1975 1 res = sa_write_raw(sa, cpBuf, nBufReq); d1983 1 a1983 1 if (nBufReq > (sa->nWriteSize - sa->nWriteLen)) { d1985 1 a1985 1 sa_flush(sa); d1988 1 a1988 1 if (nBufReq >= sa->nWriteSize) { d1991 1 a1991 1 n = sa_write_raw(sa, cpBuf, nBufReq); d2007 1 a2007 1 res = nBufReq; d2039 1 a2039 1 size_t n; d2059 2 d2095 1 a2095 1 memmove(sa->cpWriteBuf, sa->cpWriteBuf+n, sa->nWriteLen-n); d2133 1 a2133 1 sa_flush(sa); d2153 2 a2154 1 size_t n; d2175 1 a2175 1 n = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &fds, NULL, NULL, d2177 2 a2178 2 } while (n == -1 && errno == EINTR); if (n == 0) d2180 1 a2180 1 if (n <= 0) d2185 1 a2185 1 sa_size = sizeof(sa_buf); d2194 1 a2194 1 sa_addr_destroy(*raddr); d2200 1 a2200 1 *bufdone = n; d2208 2 a2209 1 size_t n; d2232 1 a2232 1 n = SA_SC_CALL_5(sa, select, sa->fdSocket+1, NULL, &fds, NULL, d2234 2 a2235 2 } while (n == -1 && errno == EINTR); if (n == 0) d2237 1 a2237 1 if (n <= 0) d2247 1 a2247 1 *bufdone = n; d2256 1 a2256 1 size_t nBuf; d2267 2 a2268 1 nBuf = sa_mvsnprintf(NULL, 0, cpFmt, ap); d2270 1 a2270 1 if ((nBuf+1) > sizeof(caBuf)) { d2272 1 a2272 1 if ((cpBuf = (char *)malloc(nBuf+1)) == NULL) d2280 3 a2282 1 sa_mvsnprintf(cpBuf, nBuf+1, cpFmt, ap); d2286 2 a2287 1 rv = sa_send(sa, raddr, cpBuf, nBuf, NULL); d2290 1 a2290 1 if ((nBuf+1) > sizeof(caBuf)) d2310 2 @ 1.21 log @extend copyright messages based on CVS information @ text @d1819 1 a1819 1 /* read data from socket until [CR]LF (convinience function) */ d1984 1 a1984 1 /* write formatted string to socket (convinience function) */ d2197 1 a2197 1 /* send formatted string to socket (convinience function) */ @ 1.21.2.1 log @correct spelling: privileges, convenient; @ text @d1819 1 a1819 1 /* read data from socket until [CR]LF (convenience function) */ d1984 1 a1984 1 /* write formatted string to socket (convenience function) */ d2197 1 a2197 1 /* send formatted string to socket (convenience function) */ @ 1.20 log @Upgrade to OSSP sa 1.0.1 @ text @d3 3 a5 3 ** Copyright (c) 2001-2002 Ralf S. Engelschall ** Copyright (c) 2001-2002 The OSSP Project ** Copyright (c) 2001-2002 Cable & Wireless Deutschland @ 1.19 log @we are sure that config.h exists @ text @d48 1 a48 1 #include /* for "PF_XXX", "AF_XXX" and "SOCK_XXX" */ d91 13 d219 7 a225 1 d238 1 d293 1 a293 1 if ((cp = inet_ntoa(*((struct in_addr *)src))) == NULL) d312 1 a312 1 char ibuf[((sizeof(int)*8)/3)+10]; d319 1 a319 1 if (format == NULL || ap == NULL) d401 1 a401 1 if (format == NULL || ap == NULL) d405 1 a405 1 if (buffer == NULL) d512 1 a512 1 /* parse URI and resolve contents. d632 1 a632 1 memcpy(&sa6.sin6_addr.s6_addr, he->h_addr_list[0], d714 1 a714 1 than the expected one. Then there is actually no path at all. d803 1 a803 1 /* special case of comparing a regular IPv4 address (1.2.3.4) with an d860 1 a860 1 /* perform address representation comparison d887 4 d892 11 a902 13 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); } d908 93 d1009 1 d1028 1 a1028 1 if (nFamily == AF_LOCAL) d1062 6 a1067 1 sa_socket_settimeouts(sa); d1120 6 d1184 1 d1201 3 a1203 2 /* optionally set kernel timeouts */ sa_socket_settimeouts(sa); d1227 1 a1227 1 return SA_RC(SA_ERR_SYS); d1248 1 a1248 1 return SA_RC(SA_ERR_SYS); a1279 1 /* enable/disable Nagle's Algorithm (see RFC898) */ d1282 2 a1283 7 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; d1291 3 a1293 8 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; d1300 7 a1306 2 #ifdef SA_OPTION_REUSEPORT case SA_OPTION_REUSEPORT: d1308 3 d1312 1 a1312 1 /* enable/disable reusability of binding to address or port */ d1314 4 a1317 9 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; a1318 5 default: flag = 0; break; } if (setsockopt(sa->fdSocket, SOL_SOCKET, flag, (const void *)&mode, (socklen_t)sizeof(mode)) < 0) rv = SA_ERR_SYS; a1321 2 /* enable/disable non-blocking I/O mode */ int flags; d1323 2 a1324 14 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; d1333 9 a1341 1 return SA_RC(rv); d1363 1 a1363 1 default: rv = SA_ERR_ARG; d1409 1 a1409 1 /* connecting is only possible for stream communication */ d1442 1 a1442 1 goto done; d1494 1 a1494 1 /* listening is only possible for stream communication */ d1522 1 a1522 1 socklen_t sa_len; d1530 1 a1530 1 /* accepting connections is only possible for stream communication */ d1546 1 a1546 1 if (n == 0) d1553 2 a1554 2 sa_len = sizeof(sa_buf); if ((s = SA_SC_CALL_3(sa, accept, sa->fdSocket, (struct sockaddr *)&sa_buf, &sa_len)) == -1) d1560 1 a1560 1 if ((rv = sa_addr_s2a(*caddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) { d1602 1 a1602 1 socklen_t sa_len; d1608 1 a1608 1 /* peers exist only for stream communication */ d1617 2 a1618 2 sa_len = sizeof(sa_buf); if (getpeername(sa->fdSocket, (struct sockaddr *)&sa_buf, &sa_len) < 0) d1624 1 a1624 1 if ((rv = sa_addr_s2a(*raddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) { d1642 1 a1642 1 socklen_t sa_len; d1653 2 a1654 2 sa_len = sizeof(sa_buf); if (getsockname(sa->fdSocket, (struct sockaddr *)&sa_buf, &sa_len) < 0) d1660 1 a1660 1 if ((rv = sa_addr_s2a(*laddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) { d1693 1 a1693 1 /* if timeout is enabled, perform explicit/smart blocking instead d1700 1 a1700 1 rv = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &fds, NULL, NULL, d1734 1 a1734 1 /* reading is only possible for stream communication */ d1799 1 a1799 1 if (n == 0) d1812 1 a1812 1 /* pass number of actually read bytes to caller */ d1831 1 a1831 1 /* reading is only possible for stream communication */ d1872 1 a1872 1 /* if timeout is enabled, perform explicit/smart blocking instead d1879 1 a1879 1 rv = SA_SC_CALL_5(sa, select, sa->fdSocket+1, NULL, &fds, NULL, d1913 1 a1913 1 /* writing is only possible for stream communication */ d1980 2 a1981 2 n = -1; return n; d1995 1 a1995 1 /* writing is only possible for stream communication */ d2023 1 a2023 1 /* flushing is only possible for stream communication */ d2059 1 a2059 1 /* shutdown is only possible for stream communication */ d2073 1 a2073 1 else if (strcmp(flags, "rw") == 0) d2078 4 d2090 1 a2090 1 sa_rc_t sa_recv(sa_t *sa, char *buf, size_t buflen, size_t *bufdone, sa_addr_t **raddr) d2099 1 a2099 1 socklen_t sa_len; d2107 1 a2107 1 /* receiving is only possible for datagram communication */ d2115 1 a2115 1 /* if timeout is enabled, perform explicit/smart blocking instead d2121 1 a2121 1 n = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &fds, NULL, NULL, d2124 1 a2124 1 if (n == 0) d2131 3 a2133 3 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) d2139 1 a2139 1 if ((rv = sa_addr_s2a(*raddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) { d2152 1 a2152 1 sa_rc_t sa_send(sa_t *sa, const char *buf, size_t buflen, size_t *bufdone, sa_addr_t *raddr) d2162 1 a2162 1 /* sending is only possible for datagram communication */ d2171 1 a2171 1 /* if timeout is enabled, perform explicit/smart blocking instead d2177 1 a2177 1 n = SA_SC_CALL_5(sa, select, sa->fdSocket+1, NULL, &fds, NULL, d2180 1 a2180 1 if (n == 0) d2195 40 @ 1.18 log @upgrade to OSSP sa 0.9.2 and release OSSP l2 0.9.1 with it @ text @d92 1 a92 1 #if defined(HAVE_CONFIG_H) && !defined(HAVE_SSIZE_T) @ 1.17 log @update to latest OSSP SA @ text @d2 4 a5 4 ** SA - OSSP Socket Abstraction Library ** Copyright (c) 2001 Ralf S. Engelschall ** Copyright (c) 2001 The OSSP Project ** Copyright (c) 2001 Cable & Wireless Deutschland d7 2 a8 2 ** This file is part of OSSP SA, a socket abstraction library which ** can be found at http://www.ossp.org/pkg/sa/. d48 1 a48 1 #include /* for "AF_XXX" and "SOCK_XXX" */ d54 13 d80 11 d157 1 a157 1 } while(0) d164 1 a164 1 } while(0) d241 1 d246 6 a265 1 struct in_addr in_val; d270 1 d273 1 a273 1 if ((cp = inet_ntoa(src)) == NULL) d281 1 d391 1 a391 1 ctx.buflen = bufsize - 1; d393 4 a397 4 if (n != -1 && ctx.buflen == 0) n = -1; if (n != -1) *(ctx.bufptr) = '\0'; d422 1 a422 1 return SA_ERR_ARG; d426 1 a426 1 return SA_ERR_MEM; d442 1 a442 1 return SA_ERR_ARG; d471 1 a471 1 int nPort; d480 1 a480 1 return SA_ERR_ARG; d507 1 a507 1 return SA_ERR_ARG; d509 1 a509 1 return SA_ERR_MEM; d512 1 a512 1 return SA_ERR_MEM; d532 1 a532 1 return SA_ERR_IMP; d537 1 a537 1 return SA_ERR_ARG; d540 1 a540 1 return SA_ERR_ARG; d547 1 a547 1 return SA_ERR_ARG; d567 1 a567 1 nPort = atoi(cpPort); d570 1 a570 1 return SA_ERR_SYS; d620 1 a620 1 return SA_ERR_ARG; d623 1 a623 1 return SA_ERR_ARG; d626 1 a626 1 return SA_ERR_ARG; d632 1 a632 1 return SA_ERR_MEM; d645 1 a645 1 return SA_ERR_ARG; d654 1 a654 1 return SA_ERR_USE; d660 1 a660 1 return SA_ERR_MEM; d680 1 a680 1 int nPort; d684 1 a684 1 return SA_ERR_ARG; d715 1 a715 1 return SA_ERR_INT; d728 1 a728 1 return SA_ERR_ARG; d732 1 a732 1 return SA_ERR_MEM; d750 2 d754 2 a755 2 if (saa1 == NULL || saa2 == NULL || prefixlen < -1) return SA_ERR_ARG; d763 2 d769 1 a769 1 if (prefixlen == -1) { d771 1 a771 1 return SA_ERR_MTC; d776 1 a776 1 return SA_ERR_MTC; d786 2 d794 2 d803 1 a803 1 return SA_ERR_MTC; d805 1 a805 1 return SA_ERR_MTC; d810 2 d818 2 d823 1 a824 1 } d826 1 a826 1 return SA_ERR_INT; d829 2 a830 2 if (prefixlen > nBits) return SA_ERR_ARG; d832 5 a836 2 /* support equal matching (= all bits) */ if (prefixlen == -1) d838 1 d846 1 a846 1 return SA_ERR_MTC; d853 1 a853 1 return SA_ERR_MTC; d855 6 d871 3 a873 3 &sa->tvTimeout[SA_TIMEOUT_READ], sizeof(sa->tvTimeout[SA_TIMEOUT_READ])) < 0) return SA_ERR_SYS; d877 3 a879 3 &sa->tvTimeout[SA_TIMEOUT_WRITE], sizeof(sa->tvTimeout[SA_TIMEOUT_WRITE])) < 0) return SA_ERR_SYS; d891 1 d893 1 a893 1 char *cpProto; d897 1 a897 1 return SA_ERR_ARG; d901 1 a901 1 return SA_ERR_USE; d909 1 a909 1 return SA_ERR_INT; d919 8 d928 1 a928 1 cpProto = "tcp"; d930 1 a930 1 cpProto = "udp"; d932 3 a934 3 return SA_ERR_INT; if ((pe = getprotobyname(cpProto)) == NULL) return SA_ERR_SYS; d936 1 d939 1 a939 1 return SA_ERR_INT; d943 1 a943 1 return SA_ERR_SYS; d956 1 a956 1 return SA_ERR_ARG; d960 1 a960 1 return SA_ERR_USE; d977 1 a977 1 return SA_ERR_ARG; d981 1 a981 1 return SA_ERR_MEM; d1019 1 a1019 1 return SA_ERR_ARG; d1039 1 a1039 1 return SA_ERR_ARG; d1041 1 a1041 1 return SA_ERR_ARG; d1060 1 a1060 1 return SA_ERR_ARG; d1086 1 a1086 1 return SA_ERR_ARG; d1091 1 a1091 1 return SA_ERR_USE; d1098 1 a1098 1 return SA_ERR_SYS; d1112 1 a1112 1 return SA_ERR_USE; d1119 1 a1119 1 return SA_ERR_SYS; d1130 2 a1131 1 return SA_ERR_ARG; d1144 1 a1144 1 return SA_ERR_ARG; d1159 1 a1159 1 (void *)&mode, sizeof(mode)) < 0) d1166 39 d1209 4 d1231 1 a1231 1 return rv; d1237 3 d1241 16 a1256 18 return SA_ERR_ARG; if (id == SA_SYSCALL_CONNECT) SA_SC_ASSIGN(sa, connect, fptr, fctx); else if (id == SA_SYSCALL_ACCEPT) SA_SC_ASSIGN(sa, accept, fptr, fctx); else if (id == SA_SYSCALL_SELECT) SA_SC_ASSIGN(sa, select, fptr, fctx); else if (id == SA_SYSCALL_READ) SA_SC_ASSIGN(sa, read, fptr, fctx); else if (id == SA_SYSCALL_WRITE) SA_SC_ASSIGN(sa, write, fptr, fctx); else if (id == SA_SYSCALL_RECVFROM) SA_SC_ASSIGN(sa, recvfrom, fptr, fctx); else if (id == SA_SYSCALL_SENDTO) SA_SC_ASSIGN(sa, sendto, fptr, fctx); else return SA_ERR_ARG; return SA_OK; d1267 1 a1267 1 return SA_ERR_ARG; d1272 1 a1272 1 return rv; d1282 1 a1282 1 return SA_ERR_SYS; d1297 1 a1297 1 return SA_ERR_ARG; d1301 1 a1301 1 return SA_ERR_USE; d1306 1 a1306 1 return rv; d1358 1 a1358 1 if (getsockopt(sa->fdSocket, SOL_SOCKET, SO_ERROR, &error, &len) < 0) d1374 1 a1374 1 return rv; d1382 1 a1382 1 return SA_ERR_ARG; d1386 1 a1386 1 return SA_ERR_USE; d1390 1 a1390 1 return SA_ERR_USE; d1394 1 a1394 1 return SA_ERR_SYS; d1418 1 a1418 1 return SA_ERR_ARG; d1422 1 a1422 1 return SA_ERR_USE; d1426 1 a1426 1 return SA_ERR_USE; d1437 1 a1437 1 return SA_ERR_TMT; d1439 1 a1439 1 return SA_ERR_SYS; d1445 1 a1445 1 return SA_ERR_SYS; d1449 1 a1449 1 return rv; d1452 1 a1452 1 return rv; d1458 1 a1458 1 return rv; d1496 1 a1496 1 return SA_ERR_ARG; d1500 1 a1500 1 return SA_ERR_USE; d1504 1 a1504 1 return SA_ERR_USE; d1509 1 a1509 1 return SA_ERR_SYS; d1513 1 a1513 1 return rv; d1516 1 a1516 1 return rv; d1536 1 a1536 1 return SA_ERR_ARG; d1540 1 a1540 1 return SA_ERR_USE; d1545 1 a1545 1 return SA_ERR_SYS; d1549 1 a1549 1 return rv; d1552 1 a1552 1 return rv; d1563 1 a1563 1 return SA_ERR_ARG; d1567 1 a1567 1 return SA_ERR_USE; d1618 1 a1618 1 size_t res; d1622 1 a1622 1 return SA_ERR_ARG; d1626 1 a1626 1 return SA_ERR_USE; d1630 1 a1630 1 return SA_ERR_USE; d1649 1 a1649 1 while (1) { d1704 1 a1704 1 *nBufRes = res; d1706 1 a1706 1 return rv; d1719 1 a1719 1 return SA_ERR_ARG; d1723 1 a1723 1 return SA_ERR_USE; d1727 1 a1727 1 return SA_ERR_USE; d1751 1 a1751 1 return rv; d1795 2 a1796 2 size_t n; size_t res; d1801 1 a1801 1 return SA_ERR_ARG; d1805 1 a1805 1 return SA_ERR_USE; d1809 1 a1809 1 return SA_ERR_USE; d1852 1 a1852 1 *nBufRes = res; d1854 1 a1854 1 return rv; d1883 1 a1883 1 return SA_ERR_ARG; d1887 1 a1887 1 return SA_ERR_USE; d1891 1 a1891 1 return SA_ERR_USE; d1906 1 a1906 1 size_t n; d1911 1 a1911 1 return SA_ERR_ARG; d1915 1 a1915 1 return SA_ERR_USE; d1919 1 a1919 1 return SA_ERR_USE; d1937 1 a1937 1 return rv; d1947 1 a1947 1 return SA_ERR_ARG; d1951 1 a1951 1 return SA_ERR_USE; d1955 1 a1955 1 return SA_ERR_USE; d1966 1 a1966 1 return SA_ERR_ARG; d1970 1 a1970 1 return SA_ERR_SYS; d1991 1 a1991 1 return SA_ERR_ARG; d1995 1 a1995 1 return SA_ERR_USE; d1999 1 a1999 1 return SA_ERR_USE; d2013 1 a2013 1 return SA_ERR_SYS; d2020 1 a2020 1 return SA_ERR_SYS; d2046 1 a2046 1 return SA_ERR_ARG; d2050 1 a2050 1 return SA_ERR_USE; d2069 1 a2069 1 return SA_ERR_SYS; d2074 1 a2074 1 return SA_ERR_SYS; @ 1.16 log @upgrade to latest and greatest OSSP SA @ text @d72 5 d500 1 a500 1 return SA_ERR_ARG; d615 9 d1071 55 a1522 4 /* trigger a write buffer flush */ if (sa->nWriteLen > 0) sa_flush(sa); d1527 2 d1557 2 d1988 1 @ 1.15 log @Upgrade to the latest and greatest OSSP SA. @ text @d54 18 a198 8 /* boolean values */ #ifndef FALSE #define FALSE (0) #endif #ifndef TRUE #define TRUE (!FALSE) #endif a202 5 /* backward compatibility for AF_LOCAL */ #if !defined(AF_LOCAL) && defined(AF_UNIX) #define AF_LOCAL AF_UNIX #endif d427 1 d480 1 a480 1 memcpy(un.sun_path, cpPath, n+1); d489 1 a489 1 /* parse URI */ d491 4 a494 1 if ((cp = strrchr(cpHost, ':')) == NULL) d496 17 a512 1 *cp++ = '\0'; d514 5 a531 5 cpProto = "tcp"; if ((cp = strchr(cpPort, '#')) != NULL) { *cp++ = '\0'; cpProto = cp; } d543 3 a545 3 /* 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) { d553 1 a553 1 else if (sa_inet_pton(AF_INET6, cpHost, &sa6.sin6_addr.s6_addr) == 1) { a605 7 struct sockaddr_un *un; struct sockaddr_in *sa4; #ifdef AF_INET6 struct sockaddr_in6 *sa6; #endif int sf; d618 2 a619 22 /* resolve family */ sf = 0; 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 if (sf == 0 && sizeof(struct sockaddr_in6) == salen) { sa6 = (struct sockaddr_in6 *)((void *)sabuf); if (sa6->sin6_family == AF_INET6) sf = AF_INET6; } #endif if (sf == 0) return SA_ERR_ARG; saa->nFamily = sf; d643 10 a652 1 sa_msnprintf(uribuf, sizeof(uribuf), "unix:%s", un->sun_path); a653 3 #ifdef AF_INET6 else if (saa->nFamily == AF_INET || saa->nFamily == AF_INET6) { #else d655 5 a659 6 #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); } d661 6 a666 5 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); } a667 2 sa_msnprintf(uribuf, sizeof(uribuf), "inet://%s:%d", caHost, nPort); } a697 1 int nFamily; d700 4 d709 3 a711 3 /* match short circuiting */ if (saa1->nFamily != saa2->nFamily) return SA_ERR_MTC; d714 1 a714 2 nFamily = saa1->nFamily; if (nFamily == AF_LOCAL) { d730 26 a755 1 else if (nFamily == AF_INET) { d761 1 a761 1 else if (nFamily == AF_INET6) { d1173 1 d1191 1 d1228 1 d1537 1 d1555 1 d1558 3 a1560 1 sa_read(sa, &c, 1, &n); d1573 1 a1573 1 return SA_OK; @ 1.14 log @Upgrade to latest OSSP SA snapshot. This time by using SA_PREFIX to hide SA inside the l2_util_ namespace prefix. @ text @d3 3 a5 2 ** Copyright (c) 2001 The OSSP Project (http://www.ossp.org/) ** Copyright (c) 2001 Cable & Wireless Deutschland (http://www.cw.com/de/) d37 2 a38 2 #include /* for "va_xxx()" and "va_list" */ #include /* for "strxxx()" and "size_t" */ d40 1 a40 1 #include /* for isxxx() */ d49 1 a49 1 #include /* for "inet_xtoy" */ d54 120 d176 3 a178 17 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 { 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 */ d189 4 d246 2 a247 2 /* 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) a248 2 char *bufptr; char *bufend; d255 1 d257 17 a273 11 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); d275 1 a275 1 /* implement "%s" */ a278 4 if ((bufptr + n) > bufend) n = bufend - bufptr; memcpy(bufptr, cp, n); bufptr += n; d281 1 a281 1 /* implement "%d" */ d288 2 a289 3 n = strlen(ibuf); memcpy(bufptr, ibuf, n); bufptr += n; d292 3 a294 3 *bufptr++ = '%'; if (bufptr < bufend) *bufptr++ = c; d296 8 d305 5 a309 2 else *bufptr++ = c; d311 46 a356 2 *bufptr = '\0'; return (bufptr - buffer); a364 4 /* argument sanity check(s) */ if (buffer == NULL || bufsize == 0 || format == NULL) return 0; a456 2 if (cpPath[0] != '/') return SA_ERR_ARG; d463 2 d467 7 d485 1 a485 1 if ((cp = strchr(cpHost, ':')) == NULL) d557 2 d560 2 d563 2 a564 4 /* make sure result variables are set */ if (sa == NULL || sl == 0 || sf == 0) return SA_ERR_INT; d691 98 d838 3 d866 1 d875 25 a899 11 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; d947 1 a947 1 sa_rc_t sa_timeout(sa_t *sa, long sec, long usec) d949 2 d955 13 a967 7 /* 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; d973 1 a973 1 sa_rc_t sa_buffers(sa_t *sa, size_t rsize, size_t wsize) d981 20 a1000 14 /* make sure buffered were already flushed sufficiently */ if (sa->nReadLen > rsize || sa->nWriteLen > 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; d1002 20 a1021 5 else { if (sa->cpReadBuf != NULL) free(sa->cpReadBuf); sa->cpReadBuf = NULL; sa->nReadSize = 0; d1023 1 d1025 2 a1026 17 /* 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; } d1028 21 d1102 1 a1102 1 if (!sa->bTimeout) { d1104 1 a1104 1 if (connect(sa->fdSocket, raddr->saBuf, raddr->slBuf) < 0) d1116 1 a1116 1 if ((n = connect(sa->fdSocket, raddr->saBuf, raddr->slBuf)) < 0) { d1133 2 a1134 1 n = select(sa->fdSocket+1, &rset, &wset, NULL, &sa->tvTimeout); d1143 2 a1144 1 error = ETIMEDOUT; d1160 1 d1204 1 d1219 1 a1219 1 if (sa->bTimeout) { d1223 2 a1224 1 n = select(sa->fdSocket+1, &fds, NULL, NULL, &sa->tvTimeout); d1227 1 a1227 1 errno = ETIMEDOUT; d1234 1 a1234 1 if ((s = accept(sa->fdSocket, (struct sockaddr *)&sa_buf, &sa_len)) == -1) d1250 2 d1254 15 d1369 1 d1371 1 d1375 2 a1376 1 if (sa->bTimeout) { d1380 2 a1381 1 rv = select(sa->fdSocket+1, &fds, NULL, NULL, &sa->tvTimeout); d1388 1 d1392 1 a1392 1 rv = read(sa->fdSocket, cpBuf, nBufLen); d1395 5 d1433 2 d1465 2 d1473 4 a1476 1 if (n < 0) d1544 1 d1546 1 d1550 2 a1551 1 if (sa->bTimeout) { d1555 2 a1556 1 rv = select(sa->fdSocket+1, NULL, &fds, NULL, &sa->tvTimeout); d1563 1 d1567 1 a1567 1 rv = write(sa->fdSocket, cpBuf, nBufLen); d1570 5 d1601 3 a1603 1 if (res < 0) d1617 3 a1619 1 if (n < 0) d1643 17 d1665 1 a1665 2 char caBuf[1024]; sa_rc_t rv; d1681 3 a1683 1 n = sa_mvsnprintf(caBuf, sizeof(caBuf), cpFmt, ap); d1686 1 a1686 4 /* write result buffer to socket */ rv = sa_write(sa, caBuf, n, &n); return rv; d1712 3 a1714 1 if (n < 0) d1789 1 a1789 1 if (sa->bTimeout) { d1793 2 a1794 1 n = select(sa->fdSocket+1, &fds, NULL, NULL, &sa->tvTimeout); d1804 2 a1805 2 if ((n = recvfrom(sa->fdSocket, buf, buflen, 0, (struct sockaddr *)&sa_buf, &sa_len)) == -1) d1845 1 a1845 1 if (sa->bTimeout) { d1849 2 a1850 1 n = select(sa->fdSocket+1, NULL, &fds, NULL, &sa->tvTimeout); d1859 1 a1859 1 if ((n = sendto(sa->fdSocket, buf, buflen, 0, raddr->saBuf, raddr->slBuf)) == -1) d1867 19 @ 1.13 log @- upgrade to latest SA - use SA_PREFIX feature for library embedding without conflicts @ text @d34 15 a48 16 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include a50 1 #define SA_PREFIX l2_ut_ d55 3 a57 4 struct sockaddr *saBuf; socklen_t slBuf; int nFamily; int nProto; d62 10 a71 9 int sSocket; int bTimeout; struct timeval tvTimeout; int nReadLen; int nReadSize; char *cpReadBuf; int nWriteLen; int nWriteSize; char *cpWriteBuf; d74 9 a82 1 /* make sure AF_LOCAL define exists */ d87 2 a88 5 /* 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) d90 3 d96 6 a101 5 if (inet_aton(strptr, &in_val)) { memcpy(addrptr, &in_val, sizeof(struct in_addr)); return 1; } return 0; d104 2 a105 1 return -1; a106 3 #else #error "neither inet_pton nor inet_aton available" #endif d108 2 a109 5 /* 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) d111 3 d119 10 a128 9 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; d131 2 a132 1 return -1; d134 39 d174 1 a174 1 #error "neither inet_ntop nor inet_ntoa available" d176 12 a187 13 /* 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) { int rv; rv = vsprintf(str, fmt, ap); if (rv > size) { fprintf(stderr, "ERROR: vsprintf(3) buffer overflow!\n"); abort(); d189 2 a191 3 #else #error "neither vsnprintf nor vsprintf available" #endif d193 2 a194 5 /* 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, ...) d196 1 a197 1 int rv; d199 7 a205 2 va_start(ap, fmt); rv = sa_vsnprintf(str, size, fmt, ap); d207 39 a245 1 return rv; a246 1 #endif d248 2 a249 1 sa_rc_t sa_u2a(sa_addr_t **saa, const char *uri, ...) d252 1 a252 1 int nPort; d255 1 a261 1 struct protoent *pe; a262 3 int i; char *cpProto; int nProto; d265 3 d270 2 a271 1 int sf; d273 1 a273 1 /* argument sanity check */ d279 1 a279 1 sa_vsnprintf(uribuf, sizeof(uribuf), uri, ap); d282 9 a290 1 /* parse URI into protocol, host and port parts */ d292 49 a340 23 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; /* resolve port */ bNumeric = 1; for (i = 0; cpPort[i] != '\0'; i++) { if (!isdigit((int)cpPort[i])) { bNumeric = 0; break; a341 8 } if (bNumeric) nPort = atoi(cpPort); else { if ((se = getservbyname(cpPort, cpProto)) == NULL) return SA_ERR_SYS; nPort = ntohs(se->s_port); } d343 2 a344 2 /* mandatory(!) socket address structure initialization */ memset(&sa4, 0, sizeof(sa4)); d346 1 a346 1 memset(&sa6, 0, sizeof(sa6)); d349 3 a351 23 /* 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) { a353 1 memcpy(&sa4.sin_addr.s_addr, he->h_addr_list[0], sizeof(sa4.sin_addr.s_addr)); d359 1 a359 1 else if (he->h_addrtype == AF_INET6) { a361 1 memcpy(&sa6.sin6_addr.s6_addr, he->h_addr_list[0], sizeof(sa6.sin6_addr.s6_addr)); d367 22 d390 9 a398 5 if (sa == NULL) return SA_ERR_ARG; /* create result address structure */ if ((*saa = (sa_addr_t *)malloc(sizeof(sa_addr_t))) == NULL) d400 4 a403 8 if (((*saa)->saBuf = (struct sockaddr *)malloc(sl)) == NULL) { free(*saa); return SA_ERR_MEM; } memcpy((*saa)->saBuf, sa, sl); (*saa)->slBuf = sl; (*saa)->nFamily = sf; (*saa)->nProto = nProto; d407 2 a408 1 sa_rc_t sa_s2a(sa_addr_t **saa, const struct sockaddr *sabuf, socklen_t salen) d410 1 a414 1 struct protoent *pe; d417 1 d422 3 a424 4 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); d426 2 a427 3 } memcpy((*saa)->saBuf, sabuf, salen); (*saa)->slBuf = salen; d429 1 a429 1 /* fill in family */ d431 6 a436 1 if (sizeof(struct sockaddr_in) == salen) { d442 1 a442 1 else if (sizeof(struct sockaddr_in6) == salen) { d448 3 a450 1 (*saa)->nFamily = sf; a451 5 /* fill in protocol */ if ((pe = getprotobyname("tcp")) != NULL) (*saa)->nProto = pe->p_proto; else (*saa)->nProto = 0; d455 2 a456 1 sa_rc_t sa_a2u(const sa_addr_t *saa, char **uri) d459 1 a459 1 struct protoent *pe; d467 1 d470 5 a474 6 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); d477 17 a493 4 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); a494 1 #endif d496 3 a498 2 return SA_ERR_ARG; sa_snprintf(uribuf, sizeof(uribuf), "%s://%s:%d", pe->p_name, caHost, nPort); d500 1 d504 2 a505 1 sa_rc_t sa_a2s(const sa_addr_t *saa, struct sockaddr **sabuf, socklen_t *salen) d507 1 d511 1 d516 1 d520 2 a521 1 static sa_rc_t sa_socket_init(sa_t *sa, int family, int proto) d523 4 a526 1 int type; d528 1 d531 10 a540 4 if (proto == IPPROTO_TCP) type = SOCK_STREAM; else if (proto == IPPROTO_UDP) type = SOCK_DGRAM; d542 25 a566 4 return SA_ERR_ARG; if (sa->sSocket != -1) return SA_ERR_USE; if ((sa->sSocket = socket(family, type, proto)) == -1) d568 1 d572 1 d575 1 d578 9 a586 4 if (sa->sSocket != -1) { close(sa->sSocket); sa->sSocket = -1; } d590 1 d595 5 d602 13 a614 15 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; } d616 1 d620 1 d623 1 d626 2 d629 2 d636 1 d640 20 d662 1 d665 9 a673 10 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; } d677 1 d682 1 d685 2 d688 38 a725 9 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; d729 1 d733 1 d735 1 d738 4 a741 2 if (sa->sSocket == -1) if ((rv = sa_socket_init(sa, laddr->nFamily, laddr->nProto)) != SA_OK) d743 9 a751 1 if (bind(sa->sSocket, laddr->saBuf, laddr->slBuf) == -1) d753 1 d757 1 d765 2 a766 1 if (sa == NULL) d769 7 a775 2 if (sa->sSocket == -1) if ((rv = sa_socket_init(sa, raddr->nFamily, raddr->nProto)) != SA_OK) a777 4 if (!sa->bTimeout) return connect(sa->sSocket, raddr->saBuf, raddr->slBuf); error = 0; d779 8 d788 11 a798 2 /* remember socket flags */ flags = fcntl(sa->sSocket, F_GETFL, 0); d800 12 a811 2 /* switch to non-blocking mode */ fcntl(sa->sSocket, F_SETFL, flags|O_NONBLOCK); d813 2 a814 3 /* perform the connect */ if ((n = connect(sa->sSocket, raddr->saBuf, raddr->slBuf)) < 0) { if (errno != EINPROGRESS) { d818 4 a821 1 } d823 4 a826 22 /* 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; } d828 1 a828 4 /* fetch pending error */ len = sizeof(error); if (getsockopt(sa->sSocket, SOL_SOCKET, SO_ERROR, &error, &len) < 0) error = errno; d830 2 a831 1 done: d833 5 a837 7 /* reset socket flags */ fcntl(sa->sSocket, F_SETFL, flags); /* optionally set errno */ if (error != 0) { errno = error; rv = SA_ERR_SYS; a838 1 d842 1 d845 1 d848 7 a854 2 if (sa->sSocket == -1) /* at least sa_bind() has to be already performed */ d856 3 a858 1 if (listen(sa->sSocket, backlog) == -1) d860 1 d864 1 d879 2 a880 1 if (sa == NULL) d882 3 a884 2 if (sa->sSocket == -1) /* at least sa_listen() has to be already performed */ d886 6 d894 1 a894 1 FD_SET(sa->sSocket, &fds); d896 1 a896 1 n = select(sa->sSocket+1, &fds, NULL, NULL, &sa->tvTimeout); d903 2 d906 1 a906 1 if ((s = accept(sa->sSocket, (struct sockaddr *)&sa_buf, &sa_len)) == -1) d908 6 a913 1 if ((rv = sa_s2a(caddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) d915 3 d919 1 a919 1 free(*caddr); d922 2 a923 1 (*csa)->sSocket = s; d927 1 d939 2 a940 1 if (sa == NULL) d942 10 d953 1 a953 1 if (getpeername(sa->sSocket, (struct sockaddr *)&sa_buf, &sa_len) < 0) d955 3 a957 1 if ((rv = sa_s2a(raddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) d959 5 d967 1 d979 2 a980 1 if (sa == NULL) d982 6 d989 1 a989 1 if (getsockname(sa->sSocket, (struct sockaddr *)&sa_buf, &sa_len) < 0) d991 6 a996 1 if ((rv = sa_s2a(laddr, (struct sockaddr *)&sa_buf, sa_len)) != SA_OK) d998 2 d1003 1 d1006 1 d1009 8 a1016 1 *fd = sa->sSocket; d1020 1 d1026 2 d1030 1 a1030 1 FD_SET(sa->sSocket, &fds); d1032 1 a1032 1 rv = select(sa->sSocket+1, &fds, NULL, NULL, &sa->tvTimeout); d1039 2 d1042 1 a1042 1 rv = read(sa->sSocket, cpBuf, nBufLen); d1044 1 d1048 1 d1052 1 a1052 1 int rv; d1055 1 d1057 11 a1067 3 return 0; /* flush write buffer */ d1070 2 d1073 18 a1090 25 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; d1093 18 a1110 4 /* fill buffer with new data */ n = sa_read_raw(sa, sa->cpReadBuf, sa->nReadSize); if (n <= 0) rv = SA_ERR_SYS; d1112 12 a1123 2 sa->nReadLen = n; continue; d1126 1 a1127 1 break; d1129 2 d1133 1 d1137 2 a1138 1 sa_rc_t sa_readfrom(sa_t *sa, char *buf, size_t buflen, size_t *bufdone, sa_addr_t **raddr) d1140 1 a1140 8 sa_rc_t rv; union { struct sockaddr_in sa4; #ifdef AF_INET6 struct sockaddr_in6 sa6; #endif } sa_buf; socklen_t sa_len; d1142 1 a1142 1 fd_set fds; d1144 2 a1145 1 if (sa == NULL || buf == NULL || buflen == 0 || raddr == NULL) a1146 20 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; } d1148 7 a1154 5 sa_rc_t sa_readline(sa_t *sa, char *cpBuf, size_t nBufReq, size_t *nBufRes) { char c; size_t n; size_t res; d1156 4 a1159 2 if (sa == NULL) return SA_ERR_ARG; d1170 2 d1174 1 d1178 1 d1184 2 d1188 1 a1188 1 FD_SET(sa->sSocket, &fds); d1190 1 a1190 1 rv = select(sa->sSocket+1, NULL, &fds, NULL, &sa->tvTimeout); d1197 2 d1200 1 a1200 1 rv = write(sa->sSocket, cpBuf, nBufLen); d1202 1 d1206 1 d1211 1 d1213 2 a1214 1 if (sa == NULL) d1217 14 a1230 3 if (nBufReq > (sa->nWriteSize - sa->nWriteLen)) { /* not enough space in buffer, so flush buffer */ sa_flush(sa); d1232 25 a1256 10 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; d1259 2 a1260 6 else { /* (again) enough sprace in buffer, so store data */ memmove(sa->cpWriteBuf+sa->nWriteLen, cpBuf, nBufReq); sa->nWriteLen += nBufReq; res = nBufReq; } a1262 2 return SA_OK; } d1264 1 a1264 23 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; d1267 2 a1268 1 sa_rc_t sa_printf(sa_t *sa, const char *cpFmt, ...) d1273 1 d1275 2 a1276 1 if (sa == NULL) d1278 10 d1289 1 a1289 2 n = sa_vsnprintf(caBuf, sizeof(caBuf), cpFmt, ap); sa_write(sa, caBuf, n, &n); d1291 5 a1295 1 return SA_OK; d1298 1 d1302 1 d1304 1 d1307 22 a1328 6 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; d1330 1 a1330 2 sa->nWriteLen = 0; return SA_OK; d1333 1 d1338 1 d1341 10 d1358 107 a1464 1 if (shutdown(sa->sSocket, how) == -1) d1466 5 @ 1.12 log @Upgrade to the latest version of the Socket Abstraction (SA) library which is now maintained externally and will be comitted into its own module soon. This upgrade fixes the UDP protocol handling. @ text @d30 4 a33 1 /* system headers */ d51 2 a52 2 /* own headers */ #include "l2_config.h" d55 1 d57 4 a60 4 struct sockaddr *saa_buf; socklen_t saa_len; int saa_family; int saa_proto; d63 1 d76 1 d81 1 d103 1 d131 1 d149 1 d188 1 d192 1 a192 1 /* create or just take over URI */ d285 1 a285 1 if (((*saa)->saa_buf = (struct sockaddr *)malloc(sl)) == NULL) { d289 4 a292 4 memcpy((*saa)->saa_buf, sa, sl); (*saa)->saa_len = sl; (*saa)->saa_family = sf; (*saa)->saa_proto = nProto; d311 1 a311 1 if (((*saa)->saa_buf = (struct sockaddr *)malloc(salen)) == NULL) { d315 2 a316 2 memcpy((*saa)->saa_buf, sabuf, salen); (*saa)->saa_len = salen; d332 1 a332 1 (*saa)->saa_family = sf; d336 1 a336 1 (*saa)->saa_proto = pe->p_proto; d338 1 a338 1 (*saa)->saa_proto = 0; d355 1 a355 1 if ((pe = getprotobynumber(saa->saa_proto)) == NULL) d357 2 a358 2 if (saa->saa_family == AF_INET) { sa4 = (struct sockaddr_in *)((void *)saa->saa_buf); d363 2 a364 2 else if (saa->saa_family == AF_INET6) { sa6 = (struct sockaddr_in6 *)((void *)saa->saa_buf); d381 1 a381 1 if ((*sabuf = (struct sockaddr *)malloc(saa->saa_len)) == NULL) d383 2 a384 2 memmove(*sabuf, saa->saa_buf, saa->saa_len); *salen = saa->saa_len; d411 1 a411 1 if (sa->sSocket == -1) { d499 1 a499 1 if ((rv = sa_socket_init(sa, laddr->saa_family, laddr->saa_proto)) != SA_OK) d501 1 a501 1 if (bind(sa->sSocket, laddr->saa_buf, laddr->saa_len) == -1) d517 1 a517 1 if ((rv = sa_socket_init(sa, raddr->saa_family, raddr->saa_proto)) != SA_OK) d521 1 a521 1 return connect(sa->sSocket, raddr->saa_buf, raddr->saa_len); d533 1 a533 1 if ((n = connect(sa->sSocket, raddr->saa_buf, raddr->saa_len)) < 0) { d648 2 d669 2 d679 8 d900 1 a900 1 if ((n = sendto(sa->sSocket, buf, buflen, 0, raddr->saa_buf, raddr->saa_len)) == -1) @ 1.11 log @Allow the result parameter to be NULL if the caller wants to ignore the number written/read bytes. @ text @d2 1 a2 1 ** L2 - OSSP Logging Library d6 2 a7 2 ** This file is part of OSSP L2, a flexible logging library which ** can be found at http://www.ossp.org/pkg/l2/. d27 1 a27 1 ** l2_ut_sa.c: socket abstraction library d49 1 a49 1 #include "l2_p.h" d379 2 d383 6 d391 1 a391 1 if ((sa->sSocket = socket(family, SOCK_STREAM, proto)) == -1) @ 1.10 log @implement sa_readfrom() and sa_writeto() functions @ text @d682 1 d684 1 a684 1 if (sa == NULL) d691 1 a691 1 *nBufRes = 0; d698 1 a698 1 *nBufRes += nBufReq; d706 1 a706 1 *nBufRes += sa->nReadLen; d713 1 a713 1 *nBufRes += n; d730 2 d748 1 a748 1 if (sa == NULL || buf == NULL || buflen == 0 || bufdone == NULL || raddr == NULL) d766 2 a767 1 *bufdone = n; d775 1 d779 2 a780 2 *nBufRes = 0; while ((*nBufRes) < (nBufReq-1)) { d784 1 a784 1 cpBuf[(*nBufRes)++] = c; d788 3 a790 1 cpBuf[(*nBufRes)] = '\0'; d819 1 d828 1 a830 1 *nBufRes = 0; d837 1 a837 1 *nBufRes += n; d844 1 a844 1 *nBufRes = nBufReq; d846 2 d856 1 a856 1 if (sa == NULL || buf == NULL || buflen == 0 || bufdone == NULL || raddr == NULL) d871 2 a872 1 *bufdone = n; @ 1.9 log @Implement sa_getremote() and sa_getlocal() @ text @d732 1 a732 1 sa_rc_t sa_readfrom(sa_t *sa, char *buf, size_t buflen, size_t *bufdone, sa_addr_t *addr) d735 9 d745 20 a764 5 if (sa->sSocket == -1) if ((rv = sa_socket_init(sa, addr->saa_family, addr->saa_proto)) != SA_OK) return rv; /* FIXME: NOT YET IMPLEMENTED */ return SA_ERR_INT; d841 1 a841 1 sa_rc_t sa_writeto(sa_t *sa, const char *buf, size_t buflen, size_t *bufdone, sa_addr_t *addr) d843 2 a844 1 sa_rc_t rv; d846 17 a862 5 if (sa->sSocket == -1) if ((rv = sa_socket_init(sa, addr->saa_family, addr->saa_proto)) != SA_OK) return rv; /* FIXME: NOT YET IMPLEMENTED */ return SA_ERR_INT; @ 1.8 log @Implement sa_{bind,listen,accept}() to make the SA library also useful for server applications. @ text @d585 1 a585 1 } sa4a6; d605 2 a606 2 sa_len = sizeof(sa4a6); if ((s = accept(sa->sSocket, (struct sockaddr *)&sa4a6, &sa_len)) == -1) d608 1 a608 1 if ((rv = sa_s2a(caddr, (struct sockaddr *)&sa4a6, sa_len)) != SA_OK) d615 38 @ 1.7 log @portability fixes for solaris @ text @d59 12 a376 12 struct sa_st { int sSocket; int bTimeout; struct timeval tvTimeout; int nReadLen; int nReadSize; char *cpReadBuf; int nWriteLen; int nWriteSize; char *cpWriteBuf; }; d477 2 d482 3 a484 2 /* NOT YET IMPLEMENTED */ return SA_ERR_INT; d563 1 a563 1 sa_rc_t sa_listen(sa_t *sa) d565 8 a572 2 /* FIXME: NOT YET IMPLEMENTED */ return SA_ERR_INT; d575 1 a575 1 sa_rc_t sa_accept(sa_t *sa, sa_t **sa_new) d577 39 a615 2 /* FIXME: NOT YET IMPLEMENTED */ return SA_ERR_INT; @ 1.6 log @add Dmalloc support to L2 @ text @d298 1 a298 1 sa4 = (struct sockaddr_in *)sabuf; d304 1 a304 1 sa6 = (struct sockaddr_in6 *)sabuf; d335 1 a335 1 sa4 = (struct sockaddr_in *)saa->saa_buf; d341 1 a341 1 sa6 = (struct sockaddr_in6 *)saa->saa_buf; @ 1.5 log @Whohoooooo! The first cut for a Socket Abstraction (SA) library. Later it should be moved to its own source tree because it should be a highly reusable library, but until it proofed to be the way we want it, let's stay in L2. This beast allows us to greatly simplify socket handling, because it provides bi-directional socket address conversions (between URIs or "struct sockaddr *" to "sa_addr_t *"), read/write buffering support (readline!) and timeout support (for connect, read, write, etc.). @ text @d49 1 a49 1 #include "l2_config.h" @ 1.4 log @fix function name @ text @d27 1 a27 1 ** l2_ut_sa.c: utility library for socket address handling d30 1 d38 3 d48 1 d52 7 d63 3 a65 2 #ifndef HAVE_INET_PTON #ifdef HAVE_INET_ATON d83 43 d128 13 a140 2 #ifndef NUL #define NUL '\0' d143 1 a143 1 l2_util_sa_t *l2_util_sa_create(int sa_type, ...) a145 1 l2_util_sa_t *rc; a152 1 struct sockaddr_un sau; a157 2 char *cpPath; int nPath; d162 11 d174 43 a216 1 va_start(ap, sa_type); d219 7 a225 15 if (sa_type == L2_UTIL_SA_UNIX) { #if defined(AF_LOCAL) if ((cpPath = va_arg(ap, char *)) == NULL) return NULL; if ((nPath = strlen(cpPath)) >= (sizeof(sau.sun_path)-1)) return NULL; nProto = 0; memset(&sau, 0, sizeof(sau)); sau.sun_family = AF_LOCAL; memcpy(sau.sun_path, cpPath, nPath + 1); sa = (struct sockaddr *)&sau; sl = sizeof(sau); #else return NULL; #endif a226 31 else if (sa_type == L2_UTIL_SA_IP) { if ((cpProto = va_arg(ap, char *)) == NULL) return NULL; if ((cpHost = va_arg(ap, char *)) == NULL) return NULL; if ((cpPort = va_arg(ap, char *)) == NULL) return NULL; /* resolve protocol */ if ((pe = getprotobyname(cpProto)) == NULL) return NULL; nProto = pe->p_proto; /* resolve port */ bNumeric = 1; for (i = 0; cpPort[i] != NUL; i++) { if (!isdigit((int)cpPort[i])) { bNumeric = 0; break; } } if (bNumeric) nPort = atoi(cpPort); else { if ((se = getservbyname(cpPort, cpProto)) == NULL) return NULL; nPort = ntohs(se->s_port); } /* mandatory initialization */ memset(&sa4, 0, sizeof(sa4)); d228 7 a234 1 memset(&sa6, 0, sizeof(sa6)); d236 2 a237 2 /* resolve host */ if (inet_pton(AF_INET, cpHost, &sa4.sin_addr.s_addr) == 1) { d240 1 d243 1 d246 1 a246 1 else if (inet_pton(AF_INET6, cpHost, &sa6.sin6_addr.s6_addr) == 1) { d249 1 d252 1 d255 376 a630 7 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); d632 9 a640 7 #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); d642 51 a692 1 #endif d695 9 a703 3 else return NULL; va_end(ap); d706 23 a728 7 return NULL; if ((rc = (l2_util_sa_t *)malloc(sizeof(l2_util_sa_t))) == NULL) return NULL; if ((rc->sa_buf = (struct sockaddr *)malloc(sl)) == NULL) { free(rc); return NULL; d730 6 a735 3 memcpy(rc->sa_buf, sa, sl); rc->sa_len = sl; rc->sa_proto = nProto; d737 5 a741 1 return rc; d744 1 a744 1 void l2_util_sa_destroy(l2_util_sa_t *sa) d746 17 d764 11 a774 1 return; d776 3 a778 3 if (sa->sa_buf != NULL) free(sa->sa_buf); free(sa); d780 12 a791 1 return; @ 1.3 log @fix mandatory sockaddr_in initialization @ text @d207 1 a207 1 void l2_ut_sa_destroy(l2_util_sa_t *sa) @ 1.2 log @use the L2 prefix @ text @d110 1 d148 5 @ 1.1 log @Add a copy of our SA library to L2 in order to simplify socket channel and socket monitor program. @ text @d103 1 a103 1 if (sa_type == SA_UNIX) { d118 1 a118 1 else if (sa_type == SA_IP) { @