[xiph-cvs] cvs commit: net resolver.c sock.c sock.h

Michael Smith msmith at xiph.org
Fri Nov 22 05:02:51 PST 2002



msmith      02/11/22 08:02:51

  Modified:    .        resolver.c sock.c sock.h
  Log:
  Karl Heyes: patches for better networking code. IPv6 support (complete? Not
  sure).

Revision  Changes    Path
1.5       +134 -120  net/resolver.c

Index: resolver.c
===================================================================
RCS file: /usr/local/cvsroot/net/resolver.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- resolver.c	5 Aug 2002 14:48:03 -0000	1.4
+++ resolver.c	22 Nov 2002 13:02:51 -0000	1.5
@@ -13,174 +13,188 @@
 #ifndef _WIN32
 #include <netdb.h>
 #include <sys/socket.h>
-#include <pthread.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #else
 #include <winsock2.h>
-#define sethostent(x)
 #endif
 
+#include "../thread/thread.h"
 #include "resolver.h"
 #include "sock.h"
 
 /* internal function */
 
-static void _lock_resolver(void);
-static void _unlock_resolver(void);
-static char *_lookup(const char *what, char *buff, int len);
 static int _isip(const char *what);
 
 /* internal data */
 
-#ifdef _WIN32
-#define mutex_t CRITICAL_SECTION
-#else
-#define mutex_t pthread_mutex_t
-#endif
-
 static mutex_t _resolver_mutex;
 static int _initialized = 0;
 
-char *resolver_getname(const char *ip, char *buff, int len)
+#ifdef HAVE_INET_PTON
+static int _isip(const char *what)
 {
-	if (!_isip(ip)) {
-		strncpy(buff, ip, len);
-		return buff;
-	}
+    union {
+        struct in_addr v4addr;
+        struct in6_addr v6addr;
+    } addr_u;
+
+    if (inet_pton(AF_INET, what, &addr_u.v4addr) <= 0)
+        return inet_pton(AF_INET6, what, &addr_u.v6addr) > 0 ? 1 : 0;
 
-	return _lookup(ip, buff, len);
+    return 1;
 }
 
-char *resolver_getip(const char *name, char *buff, int len)
+#else
+static int _isip(const char *what)
 {
-	if (_isip(name)) {
-		strncpy(buff, name, len);
-		return buff;
-	}
+    struct in_addr inp;
 
-	return _lookup(name, buff, len);
+    return inet_aton(what, &inp);
 }
+#endif
 
-static int _isip(const char *what)
+
+#if defined (HAVE_GETNAMEINFO) && defined (HAVE_GETADDRINFO)
+char *resolver_getname(const char *ip, char *buff, int len)
 {
-#ifdef HAVE_IPV6
-	union {
-		struct in_addr v4addr;
-		struct in6_addr v6addr;
-	} addr_u;
+    struct addrinfo *head = NULL, hints;
+    char *ret = NULL;
 
-	if (inet_pton(AF_INET, what, &addr_u.v4addr) <= 0)
-		return inet_pton(AF_INET6, what, &addr_u.v6addr) > 0 ? 1 : 0;
+    if (!_isip(ip)) {
+        strncpy(buff, ip, len);
+        buff [len-1] = '\0';
+        return buff;
+    }
+
+    memset (&hints, 0, sizeof (hints));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags = AI_CANONNAME;
+    if (getaddrinfo (ip, NULL, &hints, &head))
+        return NULL;
+
+    if (head)
+    {
+        if (getnameinfo(head->ai_addr, head->ai_addrlen, buff, len, NULL, 
+                    0, NI_NAMEREQD) == 0)
+            ret = buff;
 
-	return 1;
-#else
-	struct in_addr inp;
+        freeaddrinfo (head);
+    }
 
-	return inet_aton(what, &inp);
-#endif
+    return ret;
 }
 
-static char *_lookup(const char *what, char *buff, int len)
+
+char *resolver_getip(const char *name, char *buff, int len)
 {
-	/* linux doesn't appear to have getipnodebyname as of glibc-2.2.3, so the IPV6 lookup is untested */
-#ifdef HAVE_GETIPNODEBYNAME
-	int err;
-#else
-	struct in_addr inp;
-#endif
-	struct hostent *host = NULL;
-	char *temp;
+    struct addrinfo *head, hints;
+    char *ret = NULL;
 
-	/* do a little sanity checking */
-	if (what == NULL || buff == NULL || len <= 0)
-		return NULL;
-
-#ifdef HAVE_GETIPNODEBYNAME
-	host = getipnodebyname(what, AF_INET6, AI_DEFAULT, &err);
-	if (host) {
-		if (_isip(what))
-			strncpy(buff, host->h_name, len);
-		else
-			inet_ntop(host->h_addrtype, host->h_addr_list[0], buff, len);
-		
-		freehostent(host);
-	} else
-		buff = NULL;
-#else
-	if (_isip(what)) {
-		/* gotta lock calls for now, since gethostbyname and such
-		 * aren't threadsafe */
-		_lock_resolver();
-		host = gethostbyaddr((char *)&inp, sizeof(struct in_addr), AF_INET);
-		_unlock_resolver();
-		if (host == NULL) {
-			buff = NULL;
-		} else {
-			strncpy(buff, host->h_name, len);
-		}
-	} else {
-		_lock_resolver();
-		host = gethostbyname(what);
-		_unlock_resolver();
-
-		if (host == NULL) {
-			buff = NULL;
-		} else {
-            // still need to be locked here? 
-			temp = inet_ntoa(*(struct in_addr *)host->h_addr);
-			strncpy(buff, temp, len);
-		}
-	}
+    if (_isip(name)) {
+        strncpy(buff, name, len);
+        buff [len-1] = '\0';
+        return buff;
+    }
+
+    memset (&hints, 0, sizeof (hints));
+    hints . ai_family = AF_UNSPEC;
+    hints . ai_socktype = SOCK_STREAM;
+    if (getaddrinfo (name, NULL, &hints, &head))
+        return NULL;
+
+    if (head)
+    {
+        if (getnameinfo(head->ai_addr, head->ai_addrlen, buff, len, NULL, 
+                    0, NI_NUMERICHOST) == 0)
+            ret = buff;
+        freeaddrinfo (head);
+    }
 
-#endif
-	return buff;
+    return ret;
 }
 
-void resolver_initialize()
-{
-	/* initialize the lib if we havne't done so already */
-
-	if (!_initialized) {
-		_initialized = 1;
-#ifndef _WIN32
-		pthread_mutex_init(&_resolver_mutex, NULL);
 #else
-		InitializeCriticalSection(&_resolver_mutex);
-#endif
 
-		/* keep dns connects (TCP) open */
-		sethostent(1);
-	}
+char *resolver_getname(const char *ip, char *buff, int len)
+{
+    struct hostent *host;
+    char *ret = NULL;
+    struct in_addr addr;
+
+    if (! _isip(ip))
+    {
+        strncpy(buff, ip, len);
+        buff [len-1] = '\0';
+        return buff;
+    }
+
+    thread_mutex_lock(&_resolver_mutex);
+    if (inet_aton (ip, &addr)) {
+        if ((host=gethostbyaddr (&addr, sizeof (struct in_addr), AF_INET)))
+        {
+            ret = strncpy (buff, host->h_name, len);
+            buff [len-1] = '\0';
+        }
+    }
+
+    thread_mutex_unlock(&_resolver_mutex);
+    return ret;
 }
 
-void resolver_shutdown(void)
+char *resolver_getip(const char *name, char *buff, int len)
 {
-	if (_initialized) {
-#ifndef _WIN32
-		pthread_mutex_destroy(&_resolver_mutex);
-#else
-		DeleteCriticalSection(&_resolver_mutex);
-#endif
+    struct hostent *host;
+    char *ret = NULL;
 
-		_initialized = 0;
-	}
+    if (_isip(name))
+    {
+        strncpy(buff, name, len);
+        buff [len-1] = '\0';
+        return buff;
+    }
+    thread_mutex_lock(&_resolver_mutex);
+    host = gethostbyname(name);
+    if (host)
+    {
+        char * temp = inet_ntoa(*(struct in_addr *)host->h_addr);
+        ret = strncpy(buff, temp, len);
+        buff [len-1] = '\0';
+    }
+    thread_mutex_unlock(&_resolver_mutex);
+
+    return ret;
 }
+#endif
+
 
-static void _lock_resolver()
+void resolver_initialize()
 {
-#ifndef _WIN32
-	pthread_mutex_lock(&_resolver_mutex);
-#else
-	EnterCriticalSection(&_resolver_mutex);
+    /* initialize the lib if we havne't done so already */
+
+    if (!_initialized)
+    {
+        _initialized = 1;
+        thread_mutex_create (&_resolver_mutex);
+
+        /* keep dns connects (TCP) open */
+#ifdef HAVE_SETHOSTENT
+        sethostent(1);
 #endif
+    }
 }
 
-static void _unlock_resolver()
+void resolver_shutdown(void)
 {
-#ifndef _WIN32
-	pthread_mutex_unlock(&_resolver_mutex);
-#else
-	LeaveCriticalSection(&_resolver_mutex);
-#endif	
+    if (_initialized)
+    {
+        thread_mutex_destroy(&_resolver_mutex);
+        _initialized = 0;
+#ifdef HAVE_ENDHOSTENT
+        endhostent();
+#endif
+    }
 }
+

<p><p>1.7       +261 -95   net/sock.c

Index: sock.c
===================================================================
RCS file: /usr/local/cvsroot/net/sock.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- sock.c	31 Jul 2002 15:00:12 -0000	1.6
+++ sock.c	22 Nov 2002 13:02:51 -0000	1.7
@@ -47,10 +47,6 @@
 #include "sock.h"
 #include "resolver.h"
 
-#ifndef _WIN32
-extern int errno;
-#endif
-
 /* sock_initialize
 **
 ** initializes the socket library.  you must call this
@@ -118,7 +114,24 @@
 */
 int sock_recoverable(int error)
 {
-	return (error == 0 || error == EAGAIN || error == EINTR || error == EINPROGRESS || error == EWOULDBLOCK);
+    return (error == 0 || error == EAGAIN || error == EINTR || 
+            error == EINPROGRESS || error == EWOULDBLOCK);
+}
+
+int sock_stalled (int error)
+{
+    return error == EAGAIN || error == EINPROGRESS || error == EWOULDBLOCK || 
+        error == EALREADY;
+}
+
+int sock_success (int error)
+{
+    return error == 0;
+}
+
+int sock_connect_pending (int error)
+{
+    return error == EINPROGRESS || error == EALREADY;
 }
 
 /* sock_valid_socket
@@ -127,13 +140,14 @@
 */
 int sock_valid_socket(sock_t sock)
 {
-	int ret;
-	int optval, optlen;
+    int ret;
+    int optval;
+    socklen_t optlen;
 
-	optlen = sizeof(int);
-	ret = getsockopt(sock, SOL_SOCKET, SO_TYPE, &optval, &optlen);
+    optlen = sizeof(int);
+    ret = getsockopt(sock, SOL_SOCKET, SO_TYPE, &optval, &optlen);
 
-	return (ret == 0);
+    return (ret == 0);
 }
 
 /* inet_aton
@@ -180,13 +194,15 @@
 int sock_set_nolinger(sock_t sock)
 {
         struct linger lin = { 0, 0 };
-	return setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&lin, sizeof(struct linger));
+	return setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&lin, 
+            sizeof(struct linger));
 }
 
 int sock_set_keepalive(sock_t sock)
 {
         int keepalive = 1;
-	return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive, sizeof(int));
+	return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive, 
+            sizeof(int));
 }
 
 /* sock_close
@@ -202,12 +218,51 @@
 #endif
 }
 
+/* sock_writev
+ *
+ * write multiple buffers at once, return bytes actually written
+ */
+#ifdef HAVE_WRITEV
+
+ssize_t sock_writev (int sock, const struct iovec *iov, const size_t count)
+{
+    return writev (sock, iov, count);
+}
+
+#else
+
+ssize_t sock_writev (int sock, const struct iovec *iov, const size_t count)
+{
+    int i = count, accum = 0, ret;
+    const struct iovec *v = iov;
+
+    while (i)
+    {
+        if (v->iov_base && v->iov_len)
+        {
+            ret = sock_write_bytes (sock, v->iov_base, v->iov_len);
+            if (ret == -1 && accum==0)
+                return -1;
+            if (ret == -1)
+                ret = 0;
+            accum += ret;
+            if (ret < (int)v->iov_len)
+                break;
+        }
+        v++;
+        i--;
+    }
+    return accum;
+}
+
+#endif
+
 /* sock_write_bytes
 **
 ** write bytes to the socket
 ** this function will _NOT_ block
 */
-int sock_write_bytes(sock_t sock, const char *buff, const int len)
+int sock_write_bytes(sock_t sock, const void *buff, const size_t len)
 {
         /* sanity check */
         if (!buff) {
@@ -301,96 +356,206 @@
         }
 }
 
-/* sock_connect_wto
-**
-** Connect to hostname on specified port and return the created socket.
-** timeout specifies the maximum time to wait for this to finish and
-** returns when it expires whether it connected or not
-** setting timeout to 0 disable the timeout.
-*/
+/* see if a connection can be written to
+** return -1 unable to check
+** return 0 for not yet
+** return 1 for ok 
+*/
+int sock_connected (int sock, unsigned timeout)
+{
+    fd_set wfds;
+    int val = SOCK_ERROR;
+    socklen_t size = sizeof val;
+    struct timeval tv;
+
+    tv.tv_sec = timeout;
+    tv.tv_usec = 0;
+
+    FD_ZERO(&wfds);
+    FD_SET(sock, &wfds);
+
+    switch (select(sock + 1, NULL, &wfds, NULL, &tv))
+    {
+        case 0:  return SOCK_TIMEOUT;
+        default: if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &val, &size) < 0)
+                     val = SOCK_ERROR;
+        case -1: return val;
+    }
+}
+
+#ifdef HAVE_GETADDRINFO
+
+int sock_connect_non_blocking (const char *hostname, const unsigned port)
+{
+    int sock = SOCK_ERROR;
+    struct addrinfo *ai, *head, hints;
+    char service[8];
+
+    memset (&hints, 0, sizeof (hints));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+
+    snprintf (service, sizeof (service), "%u", port);
+
+    if (getaddrinfo (hostname, service, &hints, &head))
+        return SOCK_ERROR;
+
+    ai = head;
+    while (ai)
+    {
+        if ((sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol)) 
+                > -1)
+        {
+            sock_set_blocking (sock, SOCK_NONBLOCK);
+            if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 && 
+                    !sock_connect_pending(sock_error()))
+            {
+                sock_close (sock);
+                sock = SOCK_ERROR;
+            }
+            else
+                break;
+        }
+        ai = ai->ai_next;
+    }
+    if (head) freeaddrinfo (head);
+    
+    return sock;
+}
+
+
 sock_t sock_connect_wto(const char *hostname, const int port, const int timeout)
 {
-	sock_t  sock;
-	struct sockaddr_in sin, server;
-	char ip[20];
+    int sock = SOCK_ERROR;
+    struct addrinfo *ai, *head, hints;
+    char service[8];
+
+    memset (&hints, 0, sizeof (hints));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    snprintf (service, sizeof (service), "%u", port);
+
+    if (getaddrinfo (hostname, service, &hints, &head))
+        return SOCK_ERROR;
+
+    ai = head;
+    while (ai)
+    {
+        if ((sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol)) 
+                > -1)
+        {
+            if (timeout)
+            {
+                sock_set_blocking (sock, SOCK_NONBLOCK);
+                if (connect (sock, ai->ai_addr, ai->ai_addrlen) < 0)
+                {
+                    int ret = sock_connected (sock, timeout);
+                    if (ret <= 0)
+                    {
+                        sock_close (sock);
+                        sock = SOCK_ERROR;
+                    }
+                }
+                sock_set_blocking(sock, SOCK_BLOCK);
+            }
+            else
+            {
+                if (connect (sock, ai->ai_addr, ai->ai_addrlen) < 0)
+                {
+                    sock_close (sock);
+                    sock = SOCK_ERROR;
+                }
+            }
+        }
+        ai = ai->ai_next;
+    }
+    if (head) freeaddrinfo (head);
 
-	if (!hostname || !hostname[0]) {
-		return SOCK_ERROR;
-	} else if (port <= 0) {
-		return SOCK_ERROR;
-	}
-		
-	sock = socket(AF_INET, SOCK_STREAM, 0);
-	if (sock == SOCK_ERROR) { 
-		sock_close(sock); 
-		return SOCK_ERROR; 
-	}
+    return sock;
+}
 
-	memset(&sin, 0, sizeof(struct sockaddr_in));
-	memset(&server, 0, sizeof(struct sockaddr_in));
+#else
 
-	if (!resolver_getip(hostname, ip, 20))
-		return SOCK_ERROR;
-	
-	if (inet_aton(ip, (struct in_addr *)&sin.sin_addr) == 0) {
-		sock_close(sock);
-		return SOCK_ERROR;
-	}
 
-	memcpy(&server.sin_addr, &sin.sin_addr, sizeof(struct sockaddr_in));
+int sock_try_connection (int sock, const char *hostname, const unsigned port)
+{
+    struct sockaddr_in sin, server;
+    char ip[20];
 
-	server.sin_family = AF_INET;
-	server.sin_port = htons(port);
+    if (!hostname || !hostname[0] || port == 0)
+        return -1;
 
-	/* if we have a timeout, use select, if not, use connect straight. */
-	/* dunno if this is portable, and it sure is complicated for such a 
-	   simple thing to want to do.  damn BSD sockets! */
-	if (timeout > 0) {
-		fd_set wfds;
-		struct timeval tv;
-		int retval;
-		int val;
-		int valsize = sizeof(int);
-
-		FD_ZERO(&wfds);
-		FD_SET(sock, &wfds);
-		tv.tv_sec = timeout;
-		tv.tv_usec = 0;
-
-		sock_set_blocking(sock, SOCK_NONBLOCK);
-		retval = connect(sock, (struct sockaddr *)&server, sizeof(server));
-		if (retval == 0) {
-			sock_set_blocking(sock, SOCK_BLOCK);
-			return sock;
-		} else {
-			if (!sock_recoverable(sock_error())) {
-				sock_close(sock);
-				return SOCK_ERROR;
-			}
-		}
+    memset(&sin, 0, sizeof(struct sockaddr_in));
+    memset(&server, 0, sizeof(struct sockaddr_in));
 
-		if (select(sock + 1, NULL, &wfds, NULL, &tv)) {
-			retval = getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *)&val, (int *)&valsize);
-			if ((retval == 0) && (val == 0)) {
-				sock_set_blocking(sock, SOCK_BLOCK);
-				return sock;
-			} else {
-				sock_close(sock);
-				return SOCK_ERROR;
-			}
-		} else {
-			sock_close(sock);
-			return SOCK_ERROR;
-		}
-       } else {
-	  	if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == 0) {
-			return sock;
-		} else {
-			sock_close(sock);
-			return SOCK_ERROR;
-		}
-       }
+    if (!resolver_getip(hostname, ip, 20))
+    {
+        sock_close (sock);
+        return -1;
+    }
+
+    if (inet_aton(ip, (struct in_addr *)&sin.sin_addr) == 0)
+    {
+        sock_close(sock);
+        return -1;
+    }
+
+    memcpy(&server.sin_addr, &sin.sin_addr, sizeof(struct sockaddr_in));
+
+    server.sin_family = AF_INET;
+    server.sin_port = htons(port);
+
+    return connect(sock, (struct sockaddr *)&server, sizeof(server));
+}
+
+int sock_connect_non_blocking (const char *hostname, const unsigned port)
+{
+    int sock;
+
+    sock = socket(AF_INET, SOCK_STREAM, 0);
+    if (sock == -1)
+        return -1;
+
+    sock_set_blocking (sock, SOCK_NONBLOCK);
+    sock_try_connection (sock, hostname, port);
+    
+    return sock;
+}
+
+sock_t sock_connect_wto(const char *hostname, const int port, const int timeout)
+{
+    int sock;
+
+    sock = socket(AF_INET, SOCK_STREAM, 0);
+    if (sock == -1)
+        return -1;
+
+    if (timeout)
+    {
+        sock_set_blocking (sock, SOCK_NONBLOCK);
+        if (sock_try_connection (sock, hostname, port) < 0)
+        {
+            int ret = sock_connected (sock, timeout);
+            if (ret <= 0)
+            {
+                sock_close (sock);
+                return SOCK_ERROR;
+            }
+        }
+        sock_set_blocking(sock, SOCK_BLOCK);
+    }
+    else
+    {
+        if (sock_try_connection (sock, hostname, port) < 0)
+        {
+            sock_close (sock);
+            sock = SOCK_ERROR;
+        }
+    }
+    return sock;
 }
+#endif
+
 
 /* sock_get_server_socket
 **
@@ -426,7 +591,8 @@
                 if (inet_pton(AF_INET, ip, &((struct sockaddr_in*)&sa)->sin_addr) > 0) {
                         ((struct sockaddr_in*)&sa)->sin_family = AF_INET;
                         ((struct sockaddr_in*)&sa)->sin_port = htons(port);
-		} else if (inet_pton(AF_INET6, ip, &((struct sockaddr_in6*)&sa)->sin6_addr) > 0) {
+		} else if (inet_pton(AF_INET6, ip, 
+                    &((struct sockaddr_in6*)&sa)->sin6_addr) > 0) {
                         sa_family = AF_INET6;
                         sa_len = sizeof (struct sockaddr_in6);
                         ((struct sockaddr_in6*)&sa)->sin6_family = AF_INET6;
@@ -480,7 +646,7 @@
 {
         struct sockaddr_in sin;
         int ret;
-	int slen;
+	socklen_t slen;
 
         if (!sock_valid_socket(serversock))
                 return SOCK_ERROR;

<p><p>1.5       +22 -1     net/sock.h

Index: sock.h
===================================================================
RCS file: /usr/local/cvsroot/net/sock.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- sock.h	22 Mar 2002 21:44:29 -0000	1.4
+++ sock.h	22 Nov 2002 13:02:51 -0000	1.5
@@ -26,9 +26,25 @@
 #include <winsock2.h>
 #endif
 
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#else
+#ifndef _SYS_UIO_H
+struct iovec
+{
+    void   *iov_base;
+    size_t iov_len;
+};
+#endif
+#endif
+
 typedef int sock_t;
 
+/* The following values are based on unix avoiding errno value clashes */
+#define SOCK_SUCCESS 0
 #define SOCK_ERROR -1
+#define SOCK_TIMEOUT -2
+
 #define SOCK_BLOCK 0
 #define SOCK_NONBLOCK 1
 
@@ -41,6 +57,7 @@
 char *sock_get_localip(char *buff, int len);
 int sock_error(void);
 int sock_recoverable(int error);
+int sock_stalled (int error);
 int sock_valid_socket(sock_t sock);
 int sock_set_blocking(sock_t sock, const int block);
 int sock_set_nolinger(sock_t sock);
@@ -49,11 +66,15 @@
 
 /* Connection related socket functions */
 sock_t sock_connect_wto(const char *hostname, const int port, const int timeout);
+int sock_connect_non_blocking (const char *host, const unsigned port);
+int sock_connected (int sock, unsigned timeout);
 
 /* Socket write functions */
-int sock_write_bytes(sock_t sock, const char *buff, const int len);
+int sock_write_bytes(sock_t sock, const void *buff, const size_t len);
 int sock_write(sock_t sock, const char *fmt, ...);
 int sock_write_string(sock_t sock, const char *buff);
+ssize_t sock_writev (int sock, const struct iovec *iov, const size_t count);
+
 
 /* Socket read functions */
 int sock_read_bytes(sock_t sock, char *buff, const int len);

<p><p>--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the commits mailing list