[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