mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2024-12-25 23:21:26 +03:00
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
This commit is contained in:
parent
d80d0728bf
commit
48b60c3c4d
@ -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
|
||||
|
||||
|
@ -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])
|
||||
|
406
nanohttp.c
406
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) {
|
||||
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
|
||||
|
||||
int total_sent = 0;
|
||||
|
||||
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 ) &&
|
||||
(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.
|
||||
*/
|
||||
(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;
|
||||
|
||||
struct timeval tv;
|
||||
fd_set wfd;
|
||||
|
||||
tv.tv_sec = timeout;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO( &wfd );
|
||||
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 + 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;
|
||||
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;
|
||||
|
||||
ctxt->inlen *= 2;
|
||||
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;
|
||||
|
||||
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;
|
||||
break;
|
||||
|
||||
case ECONNRESET:
|
||||
case ESHUTDOWN:
|
||||
return ( 0 );
|
||||
case ECONNRESET:
|
||||
case ESHUTDOWN:
|
||||
return (0);
|
||||
|
||||
default:
|
||||
__xmlIOErr(XML_FROM_HTTP, 0, "recv failed\n");
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
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
|
||||
)
|
||||
return (0);
|
||||
#else /* !HAVE_POLL_H */
|
||||
if (ctxt->fd > FD_SETSIZE)
|
||||
return 0;
|
||||
|
||||
tv.tv_sec = timeout;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO(&rfd);
|
||||
|
||||
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);
|
||||
}
|
||||
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 (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
|
||||
|
Loading…
Reference in New Issue
Block a user