OSSP CVS Repository

ossp - Check-in [898]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 898
Date: 2001-Sep-09 17:54:31 (local)
2001-Sep-09 15:54:31 (UTC)
User:rse
Branch:
Comment: 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.).

Tickets:
Inspections:
Files:
ossp-pkg/l2/l2_ut_sa.c      1.4 -> 1.5     671 inserted, 96 deleted
ossp-pkg/l2/l2_ut_sa.h      1.2 -> 1.3     43 inserted, 16 deleted

ossp-pkg/l2/l2_ut_sa.c 1.4 -> 1.5

--- l2_ut_sa.c   2001/09/08 22:05:46     1.4
+++ l2_ut_sa.c   2001/09/09 15:54:31     1.5
@@ -24,9 +24,10 @@
 **  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 **  SUCH DAMAGE.
 **
-**  l2_ut_sa.c: utility library for socket address handling
+**  l2_ut_sa.c: socket abstraction library
 */
 
+/* system headers */
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
@@ -34,6 +35,9 @@
 #include <unistd.h>
 #include <ctype.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/time.h>
 #include <netdb.h>
 #include <sys/types.h>
 #include <sys/un.h>
@@ -41,15 +45,24 @@
 #include <sys/socket.h>
 #include <arpa/inet.h>
 
+/* own headers */
 #include "l2_config.h"
 #include "l2_ut_sa.h"
 
+struct sa_addr_st {
+    struct sockaddr *saa_buf;
+    socklen_t        saa_len;
+    int              saa_family;
+    int              saa_proto;
+};
+
 #if !defined(AF_LOCAL) && defined(AF_UNIX)
 #define AF_LOCAL AF_UNIX
 #endif
 
-#ifndef HAVE_INET_PTON
-#ifdef HAVE_INET_ATON
+#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)
 {
     struct in_addr in_val;
@@ -67,16 +80,69 @@
 #else
 #error "neither inet_pton nor inet_aton available"
 #endif
+
+#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)
+{
+    struct in_addr in_val;
+    char *cp;
+    int n;
+
+    if (family == AF_INET) {
+        if ((cp = inet_ntoa(src)) != NULL) {
+            n = strlen(cp);
+            if (n > size-1)
+                n = size-1;
+            memcpy(dst, cp, n);
+            dst[n] = '\0';
+            return 1;
+        }
+        return 0;
+    }
+    errno = EAFNOSUPPORT;
+    return -1;
+}
+#else
+#error "neither inet_ntop nor inet_ntoa available"
+#endif
+
+#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();
+    }
+}
+#else
+#error "neither vsnprintf nor vsprintf available"
 #endif
 
-#ifndef NUL
-#define NUL '\0'
+#if defined(HAVE_SNPRINTF)
+#define sa_snprintf snprintf
+#else
+static int sa_snprintf(char *str, size_t size, const char *fmt, ...)
+{
+    va_list ap;
+    int rv;
+
+    va_start(ap, fmt);
+    rv = sa_vsnprintf(str, size, fmt, ap);
+    va_end(ap);
+    return rv;
+}
 #endif
 
-l2_util_sa_t *l2_util_sa_create(int sa_type, ...)
+sa_rc_t sa_u2a(sa_addr_t **saa, const char *uri, ...)
 {
     va_list ap;
-    l2_util_sa_t *rc;
     int nPort;
     socklen_t sl;
     struct sockaddr *sa;
@@ -84,135 +150,644 @@
 #ifdef AF_INET6
     struct sockaddr_in6 sa6;
 #endif
-    struct sockaddr_un sau;
     struct hostent *he;
     struct servent *se;
     struct protoent *pe;
     int bNumeric;
     int i;
-    char *cpPath;
-    int   nPath;
     char *cpProto;
     int   nProto;
     char *cpHost;
     char *cpPort;
+    char uribuf[1024];
+    char *cp;
+    int sf;
+
+    if (saa == NULL || uri == NULL)
+        return SA_ERR_ARG;
+
+    /* create or just take over URI */
+    va_start(ap, uri);
+    sa_vsnprintf(uribuf, sizeof(uribuf), uri, ap);
+    va_end(ap);
 
-    va_start(ap, sa_type);
-    sa = NULL;
-    sl = 0;
-    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
+    /* parse URI into protocol, host and port parts */
+    uri = uribuf;
+    cpProto = "tcp";
+    if ((cp = strstr(uri, "://")) != NULL) {
+        cpProto = (char *)uri;
+        *cp = '\0';
+        uri = cp+3;
     }
-    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);
+    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;
         }
+    }
+    if (bNumeric)
+        nPort = atoi(cpPort);
+    else {
+        if ((se = getservbyname(cpPort, cpProto)) == NULL)
+            return SA_ERR_SYS;
+        nPort = ntohs(se->s_port);
+    }
 
-        /* mandatory initialization */
-        memset(&sa4, 0, sizeof(sa4));
+    /* mandatory(!) socket address structure initialization */
+    memset(&sa4, 0, sizeof(sa4));
 #ifdef AF_INET6
-        memset(&sa6, 0, sizeof(sa6));
+    memset(&sa6, 0, sizeof(sa6));
 #endif
-        /* resolve host */
-        if (inet_pton(AF_INET, cpHost, &sa4.sin_addr.s_addr) == 1) {
+
+    /* 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) {
             sa4.sin_family = AF_INET;
             sa4.sin_port = htons(nPort);
+            memcpy(&sa4.sin_addr.s_addr, he->h_addr_list[0], sizeof(sa4.sin_addr.s_addr));
             sa = (struct sockaddr *)&sa4;
             sl = sizeof(sa4);
+            sf = AF_INET;
         }
 #ifdef AF_INET6
-        else if (inet_pton(AF_INET6, cpHost, &sa6.sin6_addr.s6_addr) == 1) {
+        else if (he->h_addrtype == AF_INET6) {
             sa6.sin6_family = AF_INET6;
             sa6.sin6_port = htons(nPort);
+            memcpy(&sa6.sin6_addr.s6_addr, he->h_addr_list[0], sizeof(sa6.sin6_addr.s6_addr));
             sa = (struct sockaddr *)&sa6;
             sl = sizeof(sa6);
+            sf = AF_INET6;
         }
 #endif
-        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);
-            }
+    }
+    if (sa == NULL)
+        return SA_ERR_ARG;
+        
+    /* create result address structure */
+    if ((*saa = (sa_addr_t *)malloc(sizeof(sa_addr_t))) == NULL)
+        return SA_ERR_MEM;
+    if (((*saa)->saa_buf = (struct sockaddr *)malloc(sl)) == NULL) {
+        free(*saa);
+        return SA_ERR_MEM;
+    }
+    memcpy((*saa)->saa_buf, sa, sl);
+    (*saa)->saa_len = sl;
+    (*saa)->saa_family = sf;
+    (*saa)->saa_proto = nProto;
+    return SA_OK;
+}
+
+sa_rc_t sa_s2a(sa_addr_t **saa, const struct sockaddr *sabuf, socklen_t salen)
+{
+    struct sockaddr_in *sa4;
 #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);
-            }
+    struct sockaddr_in6 *sa6;
 #endif
-        }
+    struct protoent *pe;
+    int sf;
+
+    if (saa == NULL || sabuf == NULL || salen == 0)
+        return SA_ERR_ARG;
+
+    /* create result address structure */
+    if ((*saa = (sa_addr_t *)malloc(sizeof(sa_addr_t))) == NULL)
+        return SA_ERR_MEM;
+    if (((*saa)->saa_buf = (struct sockaddr *)malloc(salen)) == NULL) {
+        free(*saa);
+        return SA_ERR_MEM;
     }
+    memcpy((*saa)->saa_buf, sabuf, salen);
+    (*saa)->saa_len = salen;
+
+    /* fill in family */
+    sf = 0;
+    if (sizeof(struct sockaddr_in) == salen) {
+        sa4 = (struct sockaddr_in *)sabuf;
+        if (sa4->sin_family == AF_INET)
+            sf = AF_INET;
+    }
+#ifdef AF_INET6
+    else if (sizeof(struct sockaddr_in6) == salen) {
+        sa6 = (struct sockaddr_in6 *)sabuf;
+        if (sa6->sin6_family == AF_INET6)
+            sf = AF_INET6;
+    }
+#endif
+    (*saa)->saa_family = sf;
+
+    /* fill in protocol */
+    if ((pe = getprotobyname("tcp")) != NULL)
+        (*saa)->saa_proto = pe->p_proto;
     else
-        return NULL;
-    va_end(ap);
+        (*saa)->saa_proto = 0;
+    return SA_OK;
+}
 
-    if (sa == NULL)
-        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;
+sa_rc_t sa_a2u(const sa_addr_t *saa, char **uri)
+{
+    char uribuf[1024];
+    struct protoent *pe;
+    struct sockaddr_in *sa4;
+#ifdef AF_INET6
+    struct sockaddr_in6 *sa6;
+#endif
+    char caHost[512];
+    int nPort;
+
+    if (saa == NULL || uri == NULL)
+        return SA_ERR_ARG;
+    if ((pe = getprotobynumber(saa->saa_proto)) == NULL)
+        return SA_ERR_SYS;
+    if (saa->saa_family == AF_INET) {
+        sa4 = (struct sockaddr_in *)saa->saa_buf;
+        inet_ntop(AF_INET, &sa4->sin_addr.s_addr, caHost, sizeof(caHost));
+        nPort = ntohs(sa4->sin_port);
     }
-    memcpy(rc->sa_buf, sa, sl);
-    rc->sa_len = sl;
-    rc->sa_proto = nProto;
+#ifdef AF_INET6
+    else if (saa->saa_family == AF_INET6) {
+        sa6 = (struct sockaddr_in6 *)saa->saa_buf;
+        inet_ntop(AF_INET6, &sa6->sin6_addr.s6_addr, caHost, sizeof(caHost));
+        nPort = ntohs(sa6->sin6_port);
+    }
+#endif
+    else
+        return SA_ERR_ARG;
+    sa_snprintf(uribuf, sizeof(uribuf), "%s://%s:%d", pe->p_name, caHost, nPort);
+    *uri = strdup(uribuf);
+    return SA_OK;
+}
+
+sa_rc_t sa_a2s(const sa_addr_t *saa, struct sockaddr **sabuf, socklen_t *salen)
+{
+    if (saa == NULL || sabuf == NULL || salen == 0)
+        return SA_ERR_ARG;
 
-    return rc;
+    if ((*sabuf = (struct sockaddr *)malloc(saa->saa_len)) == NULL)
+        return SA_ERR_MEM;
+    memmove(*sabuf, saa->saa_buf, saa->saa_len);
+    *salen = saa->saa_len;
+    return SA_OK;
 }
 
-void l2_util_sa_destroy(l2_util_sa_t *sa)
+struct sa_st {
+    int   sSocket;
+    int   bTimeout;
+    struct timeval tvTimeout;
+    int   nReadLen;
+    int   nReadSize;
+    char *cpReadBuf;
+    int   nWriteLen;
+    int   nWriteSize;
+    char *cpWriteBuf;
+};
+
+static sa_rc_t sa_socket_init(sa_t *sa, int family, int proto)
 {
     if (sa == NULL)
-        return;
+        return SA_ERR_ARG;
+    if (sa->sSocket != -1)
+        return SA_ERR_USE;
+    if ((sa->sSocket = socket(family, SOCK_STREAM, proto)) == -1)
+        return SA_ERR_SYS;
+    return SA_OK;
+}
+
+static sa_rc_t sa_socket_kill(sa_t *sa)
+{
+    if (sa == NULL)
+        return SA_ERR_ARG;
+    if (sa->sSocket == -1) {
+        close(sa->sSocket);
+        sa->sSocket = -1;
+    }
+    return SA_OK;
+}
+
+sa_rc_t sa_create(sa_t **sap)
+{
+    sa_t *sa;
 
-    if (sa->sa_buf != NULL)
-        free(sa->sa_buf);
+    if ((sa = (sa_t *)malloc(sizeof(sa_t))) == NULL)
+        return SA_ERR_MEM;
+    sa->sSocket    = -1;
+    sa->bTimeout   = 0;
+    sa->nReadLen   = 0;
+    sa->nReadSize  = 1024;
+    if ((sa->cpReadBuf = (char *)malloc(sa->nReadSize)) == NULL) {
+        free(sa);
+        return SA_ERR_MEM;
+    }
+    sa->nWriteLen  = 0;
+    sa->nWriteSize = 1024;
+    if ((sa->cpWriteBuf = (char *)malloc(sa->nWriteSize)) == NULL) {
+        free(sa->cpReadBuf);
+        free(sa);
+        return SA_ERR_MEM;
+    }
+    *sap = sa;
+    return SA_OK;
+}
+
+sa_rc_t sa_destroy(sa_t *sa)
+{
+    if (sa == NULL)
+        return SA_ERR_ARG;
+    sa_socket_kill(sa);
+    if (sa->cpReadBuf != NULL)
+        free(sa->cpReadBuf);
+    if (sa->cpWriteBuf != NULL)
+        free(sa->cpWriteBuf);
     free(sa);
+    return SA_OK;
+}
+
+sa_rc_t sa_timeout(sa_t *sa, long sec, long usec)
+{
+    if (sa == NULL)
+        return SA_ERR_ARG;
+    if (sec == 0 && usec == 0) {
+        sa->bTimeout = 0;
+        sa->tvTimeout.tv_sec  = 0;
+        sa->tvTimeout.tv_usec = 0;
+    }
+    else {
+        sa->bTimeout = 1;
+        sa->tvTimeout.tv_sec  = sec;
+        sa->tvTimeout.tv_usec = usec;
+    }
+    return SA_OK;
+}
+
+sa_rc_t sa_buffers(sa_t *sa, size_t rsize, size_t wsize)
+{
+    char *cp;
+
+    if (sa == NULL)
+        return SA_ERR_ARG;
+    if (sa->nReadLen > rsize || sa->nWriteLen > wsize)
+        return SA_ERR_ARG;
+    if ((cp = (char *)realloc(sa->cpReadBuf, rsize)) == NULL)
+        return SA_ERR_SYS;
+    sa->cpReadBuf = cp;
+    sa->nReadSize  = rsize;
+    if ((cp = (char *)realloc(sa->cpWriteBuf, wsize)) == NULL)
+        return SA_ERR_SYS;
+    sa->cpWriteBuf = cp;
+    sa->nWriteSize = wsize;
+    return SA_OK;
+}
+
+sa_rc_t sa_bind(sa_t *sa, sa_addr_t *laddr)
+{
+    sa_rc_t rv;
+
+    if (sa->sSocket == -1)
+        if ((rv = sa_socket_init(sa, laddr->saa_family, laddr->saa_proto)) != SA_OK)
+            return rv;
+    /* NOT YET IMPLEMENTED */
+    return SA_ERR_INT;
+}
+
+sa_rc_t sa_connect(sa_t *sa, sa_addr_t *raddr)
+{
+    int flags, n, error;
+    fd_set rset, wset;
+    socklen_t len;
+    sa_rc_t rv;
+
+    if (sa == NULL)
+        return SA_ERR_ARG;
+
+    if (sa->sSocket == -1)
+        if ((rv = sa_socket_init(sa, raddr->saa_family, raddr->saa_proto)) != SA_OK)
+            return rv;
+
+    if (!sa->bTimeout)
+        return connect(sa->sSocket, raddr->saa_buf, raddr->saa_len);
+
+    error = 0;
+    rv = SA_OK;
+
+    /* remember socket flags */
+    flags = fcntl(sa->sSocket, F_GETFL, 0);
+
+    /* switch to non-blocking mode */
+    fcntl(sa->sSocket, F_SETFL, flags|O_NONBLOCK);
+
+    /* perform the connect */
+    if ((n = connect(sa->sSocket, raddr->saa_buf, raddr->saa_len)) < 0) {
+        if (errno != EINPROGRESS) {
+            error = errno;
+            goto done;
+        }
+    }
+
+    /* if connect completed immediately */
+    if (n == 0)
+        goto done; 
+
+    /* wait for read or write possibility */
+    FD_ZERO(&rset);
+    FD_ZERO(&wset);
+    FD_SET(sa->sSocket, &rset);
+    FD_SET(sa->sSocket, &wset);
+    do {
+        n = select(sa->sSocket+1, &rset, &wset, NULL, &sa->tvTimeout);
+    } while (n == -1 && errno == EINTR);
+
+    /* decide on return semantic */
+    if (n < 0) {
+        error = errno;
+        goto done;
+    }
+    else if (n == 0) {
+        error = ETIMEDOUT;
+        goto done;
+    }
+
+    /* fetch pending error */
+    len = sizeof(error);
+    if (getsockopt(sa->sSocket, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
+        error = errno;
+
+    done:
+
+    /* reset socket flags */
+    fcntl(sa->sSocket, F_SETFL, flags);
+
+    /* optionally set errno */
+    if (error != 0) {
+        errno = error;
+        rv = SA_ERR_SYS;
+    }
+
+    return rv;
+}
+
+sa_rc_t sa_listen(sa_t *sa)
+{
+    /* FIXME: NOT YET IMPLEMENTED */
+    return SA_ERR_INT;
+}
+
+sa_rc_t sa_accept(sa_t *sa, sa_t **sa_new)
+{
+    /* FIXME: NOT YET IMPLEMENTED */
+    return SA_ERR_INT;
+}
+
+static int sa_read_raw(sa_t *sa, char *cpBuf, int nBufLen)
+{
+    int rv;
+    fd_set fds;
+
+    if (sa->bTimeout) {
+        FD_ZERO(&fds);
+        FD_SET(sa->sSocket, &fds);
+        do {
+            rv = select(sa->sSocket+1, &fds, NULL, NULL, &sa->tvTimeout);
+        } while (rv == -1 && errno == EINTR);
+        if (rv == 0) {
+            errno = ETIMEDOUT;
+            return -1;
+        }
+    }
+    do {
+        rv = read(sa->sSocket, cpBuf, nBufLen);
+    } while (rv == -1 && errno == EINTR);
+    return rv;
+}
+
+sa_rc_t sa_read(sa_t *sa, char *cpBuf, size_t nBufReq, size_t *nBufRes)
+{
+    int n;
+    int rv;
+
+    if (sa == NULL)
+        return 0;
+    
+    /* flush write buffer */
+    if (sa->nWriteLen > 0)
+        sa_flush(sa);
+    rv = SA_OK;
+    *nBufRes = 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;
+            *nBufRes += 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;
+                *nBufRes += 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)
+                    *nBufRes += n;
+                else if (n <= 0)
+                    rv = SA_ERR_SYS;
+            }
+            else {
+                /* fill buffer with new data */
+                n = sa_read_raw(sa, sa->cpReadBuf, sa->nReadSize);
+                if (n <= 0)
+                    rv = SA_ERR_SYS;
+                else {
+                    sa->nReadLen = n;
+                    continue;
+                }
+            }
+        }
+        break;
+    }
+    return rv;
+}
+
+sa_rc_t sa_readfrom(sa_t *sa, char *buf, size_t buflen, size_t *bufdone, sa_addr_t *addr)
+{
+    sa_rc_t rv;
+
+    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;
+}
+
+sa_rc_t sa_readline(sa_t *sa, char *cpBuf, size_t nBufReq, size_t *nBufRes)
+{
+    char c;
+    size_t n;
+
+    if (sa == NULL)
+        return SA_ERR_ARG;
+    *nBufRes = 0;
+    while ((*nBufRes) < (nBufReq-1)) {
+        sa_read(sa, &c, 1, &n);
+        if (n <= 0)
+            break;
+        cpBuf[(*nBufRes)++] = c;
+        if (c == '\n')
+            break;
+    }
+    cpBuf[(*nBufRes)] = '\0';
+    return SA_OK;
+}
+
+static int sa_write_raw(sa_t *sa, const char *cpBuf, int nBufLen)
+{
+    int rv;
+    fd_set fds;
+
+    if (sa->bTimeout) {
+        FD_ZERO(&fds);
+        FD_SET(sa->sSocket, &fds);
+        do {
+            rv = select(sa->sSocket+1, NULL, &fds, NULL, &sa->tvTimeout);
+        } while (rv == -1 && errno == EINTR);
+        if (rv == 0) {
+            errno = ETIMEDOUT;
+            return -1;
+        }
+    }
+    do {
+        rv = write(sa->sSocket, cpBuf, nBufLen);
+    } while (rv == -1 && errno == EINTR);
+    return rv;
+}
+
+sa_rc_t sa_write(sa_t *sa, const char *cpBuf, size_t nBufReq, size_t *nBufRes)
+{
+    size_t n;
+
+    if (sa == NULL)
+        return SA_ERR_ARG;
+
+    if (nBufReq > (sa->nWriteSize - sa->nWriteLen)) {
+        /* not enough space in buffer, so flush buffer */
+        sa_flush(sa);
+    }
+    if (nBufReq >= sa->nWriteSize) {
+        /* buffer too small at all, so write immediately */
+        *nBufRes = 0;
+        while (nBufReq > 0) {
+            n = sa_write_raw(sa, cpBuf, nBufReq);
+            if (n <= 0)
+                break;
+            nBufReq  -= n;
+            cpBuf    += n;
+            *nBufRes += n;
+        }
+    }
+    else {
+        /* (again) enough sprace in buffer, so store data */
+        memmove(sa->cpWriteBuf+sa->nWriteLen, cpBuf, nBufReq);
+        sa->nWriteLen += nBufReq;
+        *nBufRes = nBufReq;
+    }
+    return SA_OK;
+}
+
+sa_rc_t sa_writeto(sa_t *sa, const char *buf, size_t buflen, size_t *bufdone, sa_addr_t *addr)
+{
+    sa_rc_t rv;
+
+    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;
+}
+
+sa_rc_t sa_printf(sa_t *sa, const char *cpFmt, ...)
+{
+    va_list ap;
+    size_t n;
+    char caBuf[1024];
+
+    if (sa == NULL)
+        return SA_ERR_ARG;
+    va_start(ap, cpFmt);
+    n = sa_vsnprintf(caBuf, sizeof(caBuf), cpFmt, ap);
+    sa_write(sa, caBuf, n, &n);
+    va_end(ap);
+    return SA_OK;
+}
+
+sa_rc_t sa_flush(sa_t *sa)
+{
+    size_t n;
+
+    if (sa == NULL)
+        return SA_ERR_ARG;
+    while (sa->nWriteLen > 0) {
+        n = sa_write_raw(sa, sa->cpWriteBuf, sa->nWriteLen);
+        if (n <= 0)
+            break;
+        memmove(sa->cpWriteBuf, sa->cpWriteBuf+n, sa->nWriteLen-n);
+        sa->nWriteLen -= n;
+    }
+    sa->nWriteLen = 0;
+    return SA_OK;
+}
+
+sa_rc_t sa_shutdown(sa_t *sa, char *flags)
+{
+    int how;
 
-    return;
+    if (sa == NULL || flags == NULL)
+        return SA_ERR_ARG;
+    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)
+        how = SHUT_RDWR;
+    if (shutdown(sa->sSocket, how) == -1)
+        return SA_ERR_SYS;
+    return SA_OK;
 }
 


ossp-pkg/l2/l2_ut_sa.h 1.2 -> 1.3

--- l2_ut_sa.h   2001/09/06 17:17:41     1.2
+++ l2_ut_sa.h   2001/09/09 15:54:31     1.3
@@ -24,31 +24,58 @@
 **  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 **  SUCH DAMAGE.
 **
-**  l2_ut_sa.h: utility library for socket address handling
+**  l2_ut_sa.h: socket abstraction library
 */
 
 #ifndef __L2_UT_SA_H__
 #define __L2_UT_SA_H__
 
-#include <netdb.h>
+#include <string.h>
 #include <sys/types.h>
-#include <netinet/in.h>
 #include <sys/socket.h>
-#include <arpa/inet.h>
 
-typedef struct {
-    struct sockaddr *sa_buf;
-    socklen_t        sa_len;
-    int              sa_proto;
-} l2_util_sa_t;
-
-enum {
-    L2_UTIL_SA_UNIX,
-    L2_UTIL_SA_IP
-};
+struct sa_st;
+typedef struct sa_st sa_t;
 
-l2_util_sa_t *l2_util_sa_create(int, ...);
-void          l2_util_sa_destroy(l2_util_sa_t *);
+struct sa_addr_st;
+typedef struct sa_addr_st sa_addr_t;
+
+typedef enum {
+    SA_OK,
+    SA_ERR_ARG,
+    SA_ERR_USE,
+    SA_ERR_MEM,
+    SA_ERR_SYS,
+    SA_ERR_INT
+} sa_rc_t;
+
+sa_rc_t sa_u2a      (sa_addr_t **asaa, const char *uri, ...);
+sa_rc_t sa_s2a      (sa_addr_t **saa, const struct sockaddr *sabuf, socklen_t salen);
+sa_rc_t sa_a2u      (const sa_addr_t *saa, char **uri);
+sa_rc_t sa_a2s      (const sa_addr_t *saa, struct sockaddr **sabuf, socklen_t *salen);
+
+sa_rc_t sa_create   (sa_t **sa);
+sa_rc_t sa_destroy  (sa_t *sa);
+
+sa_rc_t sa_timeout  (sa_t *sa, long sec, long usec);
+sa_rc_t sa_buffers  (sa_t *sa, size_t rsize, size_t wsize);
+
+sa_rc_t sa_bind     (sa_t *sa, sa_addr_t *laddr);
+sa_rc_t sa_connect  (sa_t *sa, sa_addr_t *raddr);
+sa_rc_t sa_listen   (sa_t *sa);
+sa_rc_t sa_accept   (sa_t *sa, sa_t **sa_new);
+
+sa_rc_t sa_getremote(sa_t *sa, sa_addr_t *raddr);
+sa_rc_t sa_getlocal (sa_t *sa, sa_addr_t *laddr);
+
+sa_rc_t sa_read     (sa_t *sa, char *buf, size_t buflen, size_t *bufdone);
+sa_rc_t sa_readfrom (sa_t *sa, char *buf, size_t buflen, size_t *bufdone, sa_addr_t *addr);
+sa_rc_t sa_readline (sa_t *sa, char *buf, size_t buflen, size_t *bufdone);
+sa_rc_t sa_write    (sa_t *sa, const char *buf, size_t buflen, size_t *bufdone);
+sa_rc_t sa_writeto  (sa_t *sa, const char *buf, size_t buflen, size_t *bufdone, sa_addr_t *addr);
+sa_rc_t sa_printf   (sa_t *sa, const char *fmt, ...);
+sa_rc_t sa_flush    (sa_t *sa);
+sa_rc_t sa_shutdown (sa_t *sa, char *flags);
 
 #endif /* __L2_UT_SA_H__ */
 

CVSTrac 2.0.1