[libxml2] 559501 avoid select and use poll for nanohttp



commit 48b60c3c4d94a2aeb93ae9ff2181ad76b79eddd9
Author: Raphael Prevost <jaguarwan gmail com>
Date:   Sun Aug 23 13:11:01 2009 +0200

    559501 avoid select and use poll for nanohttp
    
    * config.h.in configure.in: detect availability of poll() and poll.h
    * nanohttp.c: switch to use poll instead of select() when possible to
      avoid out of fd set memory errors on very large fds

 config.h.in  |    3 +
 configure.in |    1 +
 nanohttp.c   |  408 +++++++++++++++++++++++++++++++++-------------------------
 3 files changed, 239 insertions(+), 173 deletions(-)
---
diff --git a/config.h.in b/config.h.in
index 736c491..6f45c6c 100644
--- a/config.h.in
+++ b/config.h.in
@@ -136,6 +136,9 @@
 /* Define to 1 if you have the <netinet/in.h> header file. */
 #undef HAVE_NETINET_IN_H
 
+/* Define to 1 if you have the <poll.h> header file. */
+#undef HAVE_POLL_H
+
 /* Define to 1 if you have the `printf' function. */
 #undef HAVE_PRINTF
 
diff --git a/configure.in b/configure.in
index 7c46893..514b7da 100644
--- a/configure.in
+++ b/configure.in
@@ -434,6 +434,7 @@ AC_CHECK_HEADERS([arpa/inet.h], [], [],
 AC_CHECK_HEADERS([netdb.h])
 AC_CHECK_HEADERS([sys/time.h])
 AC_CHECK_HEADERS([sys/select.h])
+AC_CHECK_HEADERS([poll.h])
 AC_CHECK_HEADERS([sys/mman.h])
 AC_CHECK_HEADERS([sys/timeb.h])
 AC_CHECK_HEADERS([signal.h])
diff --git a/nanohttp.c b/nanohttp.c
index 9001ae5..9ae3574 100644
--- a/nanohttp.c
+++ b/nanohttp.c
@@ -54,9 +54,13 @@
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
+#ifndef HAVE_POLL_H
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif
+#else
+#include <poll.h>
+#endif
 #ifdef HAVE_STRINGS_H
 #include <strings.h>
 #endif
@@ -439,51 +443,62 @@ xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) {
  */
 
 static int
-xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt, const char * xmt_ptr, int outlen) {
-
-    int 	total_sent = 0;
+xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt, const char *xmt_ptr, int outlen)
+{
+    int total_sent = 0;
+#ifdef HAVE_POLL_H
+    struct pollfd p;
+#else
+    struct timeval tv;
+    fd_set wfd;
+#endif
 
-    if ( (ctxt->state & XML_NANO_HTTP_WRITE) && (xmt_ptr != NULL ) ) {
+    if ((ctxt->state & XML_NANO_HTTP_WRITE) && (xmt_ptr != NULL)) {
         while (total_sent < outlen) {
             int nsent = send(ctxt->fd, xmt_ptr + total_sent,
-                                      outlen - total_sent, 0);
-            if (nsent>0)
+                             outlen - total_sent, 0);
+
+            if (nsent > 0)
                 total_sent += nsent;
-	    else if ( ( nsent == -1 ) && 
+            else if ((nsent == -1) &&
 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
-	    	      ( socket_errno( ) != EAGAIN ) &&
-#endif
-		        ( socket_errno( ) != EWOULDBLOCK ) ) {
-		__xmlIOErr(XML_FROM_HTTP, 0, "send failed\n");
-		if ( total_sent == 0 )
-		    total_sent = -1;
-		break;
-	    }
-	    else {
-	        /*
-		**  No data sent
-		**  Since non-blocking sockets are used, wait for 
-		**  socket to be writable or default timeout prior
-		**  to retrying.
-		*/
-
-		struct timeval	tv;
-		fd_set		wfd;
-
-		tv.tv_sec = timeout;
-		tv.tv_usec = 0;
-		FD_ZERO( &wfd );
+                     (socket_errno() != EAGAIN) &&
+#endif
+                     (socket_errno() != EWOULDBLOCK)) {
+                __xmlIOErr(XML_FROM_HTTP, 0, "send failed\n");
+                if (total_sent == 0)
+                    total_sent = -1;
+                break;
+            } else {
+                /*
+                 * No data sent
+                 * Since non-blocking sockets are used, wait for
+                 * socket to be writable or default timeout prior
+                 * to retrying.
+                 */
+#ifndef HAVE_POLL_H
+                if (ctxt->fd > FD_SETSIZE)
+                    return -1;
+
+                tv.tv_sec = timeout;
+                tv.tv_usec = 0;
+                FD_ZERO(&wfd);
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable: 4018)
 #endif
-		FD_SET( ctxt->fd, &wfd );
+                FD_SET(ctxt->fd, &wfd);
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
-		(void)select( ctxt->fd + 1, NULL, &wfd, NULL, &tv );
-	    }
-	}
+                (void) select(ctxt->fd + 1, NULL, &wfd, NULL, &tv);
+#else
+                p.fd = ctxt->fd;
+                p.events = POLLOUT;
+                (void) poll(&p, 1, timeout * 1000);
+#endif /* !HAVE_POLL_H */
+            }
+        }
     }
 
     return total_sent;
@@ -500,96 +515,117 @@ xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt, const char * xmt_ptr, int outlen) {
  */
 
 static int
-xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt) {
+xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt)
+{
+#ifdef HAVE_POLL_H
+    struct pollfd p;
+#else
     fd_set rfd;
     struct timeval tv;
+#endif
 
 
     while (ctxt->state & XML_NANO_HTTP_READ) {
-	if (ctxt->in == NULL) {
-	    ctxt->in = (char *) xmlMallocAtomic(65000 * sizeof(char));
-	    if (ctxt->in == NULL) {
-		xmlHTTPErrMemory("allocating input");
-	        ctxt->last = -1;
-		return(-1);
-	    }
-	    ctxt->inlen = 65000;
-	    ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
-	}
-	if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
-	    int delta = ctxt->inrptr - ctxt->in;
-	    int len = ctxt->inptr - ctxt->inrptr;
-	    
-	    memmove(ctxt->in, ctxt->inrptr, len);
-	    ctxt->inrptr -= delta;
-	    ctxt->content -= delta;
-	    ctxt->inptr -= delta;
-	}
+        if (ctxt->in == NULL) {
+            ctxt->in = (char *) xmlMallocAtomic(65000 * sizeof(char));
+            if (ctxt->in == NULL) {
+                xmlHTTPErrMemory("allocating input");
+                ctxt->last = -1;
+                return (-1);
+            }
+            ctxt->inlen = 65000;
+            ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
+        }
+        if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
+            int delta = ctxt->inrptr - ctxt->in;
+            int len = ctxt->inptr - ctxt->inrptr;
+
+            memmove(ctxt->in, ctxt->inrptr, len);
+            ctxt->inrptr -= delta;
+            ctxt->content -= delta;
+            ctxt->inptr -= delta;
+        }
         if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
-	    int d_inptr = ctxt->inptr - ctxt->in;
-	    int d_content = ctxt->content - ctxt->in;
-	    int d_inrptr = ctxt->inrptr - ctxt->in;
-	    char *	tmp_ptr = ctxt->in;
+            int d_inptr = ctxt->inptr - ctxt->in;
+            int d_content = ctxt->content - ctxt->in;
+            int d_inrptr = ctxt->inrptr - ctxt->in;
+            char *tmp_ptr = ctxt->in;
 
-	    ctxt->inlen *= 2;
+            ctxt->inlen *= 2;
             ctxt->in = (char *) xmlRealloc(tmp_ptr, ctxt->inlen);
-	    if (ctxt->in == NULL) {
-		xmlHTTPErrMemory("allocating input buffer");
-		xmlFree( tmp_ptr );
-	        ctxt->last = -1;
-		return(-1);
-	    }
+            if (ctxt->in == NULL) {
+                xmlHTTPErrMemory("allocating input buffer");
+                xmlFree(tmp_ptr);
+                ctxt->last = -1;
+                return (-1);
+            }
             ctxt->inptr = ctxt->in + d_inptr;
             ctxt->content = ctxt->in + d_content;
             ctxt->inrptr = ctxt->in + d_inrptr;
-	}
-	ctxt->last = recv(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK, 0);
-	if (ctxt->last > 0) {
-	    ctxt->inptr += ctxt->last;
-	    return(ctxt->last);
-	}
-	if (ctxt->last == 0) {
-	    return(0);
-	}
-	if (ctxt->last == -1) {
-	    switch (socket_errno()) {
-		case EINPROGRESS:
-		case EWOULDBLOCK:
+        }
+        ctxt->last = recv(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK, 0);
+        if (ctxt->last > 0) {
+            ctxt->inptr += ctxt->last;
+            return (ctxt->last);
+        }
+        if (ctxt->last == 0) {
+            return (0);
+        }
+        if (ctxt->last == -1) {
+            switch (socket_errno()) {
+                case EINPROGRESS:
+                case EWOULDBLOCK:
 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
-		case EAGAIN:
+                case EAGAIN:
+#endif
+                    break;
+
+                case ECONNRESET:
+                case ESHUTDOWN:
+                    return (0);
+
+                default:
+                    __xmlIOErr(XML_FROM_HTTP, 0, "recv failed\n");
+                    return (-1);
+            }
+        }
+#ifdef HAVE_POLL_H
+        p.fd = ctxt->fd;
+        p.events = POLLIN;
+        if ((poll(&p, 1, timeout * 1000) < 1)
+#if defined(EINTR)
+            && (errno != EINTR)
 #endif
-		    break;
+            )
+            return (0);
+#else /* !HAVE_POLL_H */
+        if (ctxt->fd > FD_SETSIZE)
+            return 0;
 
-		case ECONNRESET:
-		case ESHUTDOWN:
-		    return ( 0 );
+        tv.tv_sec = timeout;
+        tv.tv_usec = 0;
+        FD_ZERO(&rfd);
 
-		default:
-		    __xmlIOErr(XML_FROM_HTTP, 0, "recv failed\n");
-		    return(-1);
-	    }
-	}
-
-	tv.tv_sec = timeout;
-	tv.tv_usec = 0;
-	FD_ZERO(&rfd);
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable: 4018)
 #endif
-	FD_SET(ctxt->fd, &rfd);
+
+        FD_SET(ctxt->fd, &rfd);
+
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
-	
-	if ( (select(ctxt->fd+1, &rfd, NULL, NULL, &tv)<1)
+
+        if ((select(ctxt->fd + 1, &rfd, NULL, NULL, &tv) < 1)
 #if defined(EINTR)
-		&& (errno != EINTR)
+            && (errno != EINTR)
 #endif
-	)
-		return(0);
+            )
+            return (0);
+#endif /* !HAVE_POLL_H */
     }
-    return(0);
+    return (0);
 }
 
 /**
@@ -803,87 +839,96 @@ xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) {
 static int
 xmlNanoHTTPConnectAttempt(struct sockaddr *addr)
 {
+#ifndef HAVE_POLL_H
     fd_set wfd;
 #ifdef _WINSOCKAPI_
     fd_set xfd;
 #endif
     struct timeval tv;
+#else /* !HAVE_POLL_H */
+    struct pollfd p;
+#endif /* !HAVE_POLL_H */
     int status;
+
     int addrlen;
+
     SOCKET s;
-    
+
 #ifdef SUPPORT_IP6
     if (addr->sa_family == AF_INET6) {
-	s = socket (PF_INET6, SOCK_STREAM, IPPROTO_TCP);
-	addrlen = sizeof (struct sockaddr_in6);
-    }
-    else
+        s = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
+        addrlen = sizeof(struct sockaddr_in6);
+    } else
 #endif
     {
-	s = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
-	addrlen = sizeof (struct sockaddr_in);
+        s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+        addrlen = sizeof(struct sockaddr_in);
     }
-    if (s==-1) {
+    if (s == -1) {
 #ifdef DEBUG_HTTP
-	perror("socket");
+        perror("socket");
 #endif
-	__xmlIOErr(XML_FROM_HTTP, 0, "socket failed\n");
-	return(-1);
+        __xmlIOErr(XML_FROM_HTTP, 0, "socket failed\n");
+        return (-1);
     }
-    
 #ifdef _WINSOCKAPI_
     {
-	u_long one = 1;
+        u_long one = 1;
 
-	status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
+        status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
     }
 #else /* _WINSOCKAPI_ */
 #if defined(VMS)
     {
-	int enable = 1;
-	status = ioctl(s, FIONBIO, &enable);
+        int enable = 1;
+
+        status = ioctl(s, FIONBIO, &enable);
     }
 #else /* VMS */
 #if defined(__BEOS__) && !defined(__HAIKU__)
-	{
-		bool noblock = true;
-		status = setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &noblock, sizeof(noblock));
-	}
+    {
+        bool noblock = true;
+
+        status =
+            setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &noblock,
+                       sizeof(noblock));
+    }
 #else /* __BEOS__ */
     if ((status = fcntl(s, F_GETFL, 0)) != -1) {
 #ifdef O_NONBLOCK
-	status |= O_NONBLOCK;
+        status |= O_NONBLOCK;
 #else /* O_NONBLOCK */
 #ifdef F_NDELAY
-	status |= F_NDELAY;
+        status |= F_NDELAY;
 #endif /* F_NDELAY */
 #endif /* !O_NONBLOCK */
-	status = fcntl(s, F_SETFL, status);
+        status = fcntl(s, F_SETFL, status);
     }
     if (status < 0) {
 #ifdef DEBUG_HTTP
-	perror("nonblocking");
+        perror("nonblocking");
 #endif
-	__xmlIOErr(XML_FROM_HTTP, 0, "error setting non-blocking IO\n");
-	closesocket(s);
-	return(-1);
+        __xmlIOErr(XML_FROM_HTTP, 0, "error setting non-blocking IO\n");
+        closesocket(s);
+        return (-1);
     }
 #endif /* !__BEOS__ */
 #endif /* !VMS */
 #endif /* !_WINSOCKAPI_ */
 
-    if (connect (s, addr, addrlen) == -1) {
-	switch (socket_errno()) {
-	    case EINPROGRESS:
-	    case EWOULDBLOCK:
-		break;
-	    default:
-		__xmlIOErr(XML_FROM_HTTP, 0, "error connecting to HTTP server");
-		closesocket(s);
-		return(-1);
-	}
-    }	
-    
+    if (connect(s, addr, addrlen) == -1) {
+        switch (socket_errno()) {
+            case EINPROGRESS:
+            case EWOULDBLOCK:
+                break;
+            default:
+                __xmlIOErr(XML_FROM_HTTP, 0,
+                           "error connecting to HTTP server");
+                closesocket(s);
+                return (-1);
+        }
+    }
+#ifndef HAVE_POLL_H
     tv.tv_sec = timeout;
     tv.tv_usec = 0;
 
@@ -891,63 +936,80 @@ xmlNanoHTTPConnectAttempt(struct sockaddr *addr)
 #pragma warning(push)
 #pragma warning(disable: 4018)
 #endif
+    if (s > FD_SETSIZE)
+        return -1;
     FD_ZERO(&wfd);
     FD_SET(s, &wfd);
 
-#ifdef _WINSOCKAPI_    
+#ifdef _WINSOCKAPI_
     FD_ZERO(&xfd);
     FD_SET(s, &xfd);
-    
-    switch(select(s+1, NULL, &wfd, &xfd, &tv))
+
+    switch (select(s + 1, NULL, &wfd, &xfd, &tv))
 #else
-    switch(select(s+1, NULL, &wfd, NULL, &tv))
+    switch (select(s + 1, NULL, &wfd, NULL, &tv))
 #endif
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
+
+#else /* !HAVE_POLL_H */
+    p.fd = s;
+    p.events = POLLOUT;
+    switch (poll(&p, 1, timeout * 1000))
+#endif /* !HAVE_POLL_H */
+
     {
-	case 0:
-	    /* Time out */
-	    __xmlIOErr(XML_FROM_HTTP, 0, "Connect attempt timed out");
-	    closesocket(s);
-	    return(-1);
-	case -1:
-	    /* Ermm.. ?? */
-	    __xmlIOErr(XML_FROM_HTTP, 0, "Connect failed");
-	    closesocket(s);
-	    return(-1);
+        case 0:
+            /* Time out */
+            __xmlIOErr(XML_FROM_HTTP, 0, "Connect attempt timed out");
+            closesocket(s);
+            return (-1);
+        case -1:
+            /* Ermm.. ?? */
+            __xmlIOErr(XML_FROM_HTTP, 0, "Connect failed");
+            closesocket(s);
+            return (-1);
     }
 
-    if ( FD_ISSET(s, &wfd)
+#ifndef HAVE_POLL_H
+    if (FD_ISSET(s, &wfd)
 #ifdef _WINSOCKAPI_
-                           || FD_ISSET(s, &xfd)
+        || FD_ISSET(s, &xfd)
 #endif
-                                                ) {
-	XML_SOCKLEN_T len;
-	len = sizeof(status);
+        )
+#else /* !HAVE_POLL_H */
+    if (p.revents == POLLOUT)
+#endif /* !HAVE_POLL_H */
+    {
+        XML_SOCKLEN_T len;
+
+        len = sizeof(status);
 #ifdef SO_ERROR
-	if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&status, &len) < 0 ) {
-	    /* Solaris error code */
-	    __xmlIOErr(XML_FROM_HTTP, 0, "getsockopt failed\n");
-	    return (-1);
-	}
-#endif
-	if ( status ) {
-	    __xmlIOErr(XML_FROM_HTTP, 0, "Error connecting to remote host");
-	    closesocket(s);
-	    errno = status;
-	    return (-1);
-	}
+        if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &status, &len) <
+            0) {
+            /* Solaris error code */
+            __xmlIOErr(XML_FROM_HTTP, 0, "getsockopt failed\n");
+            return (-1);
+        }
+#endif
+        if (status) {
+            __xmlIOErr(XML_FROM_HTTP, 0,
+                       "Error connecting to remote host");
+            closesocket(s);
+            errno = status;
+            return (-1);
+        }
     } else {
-	/* pbm */
-	__xmlIOErr(XML_FROM_HTTP, 0, "select failed\n");
-	closesocket(s);
-	return (-1);
+        /* pbm */
+        __xmlIOErr(XML_FROM_HTTP, 0, "select failed\n");
+        closesocket(s);
+        return (-1);
     }
-    
-    return(s);
+
+    return (s);
 }
- 
+
 /**
  * xmlNanoHTTPConnectHost:
  * @host:  the host name



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]