diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 8319031..05c46ce 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,4 +1,7 @@ -$Id: Changelog.txt,v 1.255 2012/02/06 16:32:07 nanard Exp $ +$Id: Changelog.txt,v 1.256 2012/02/07 00:21:51 nanard Exp $ + +2012/02/06: + Make HTTP (SOAP) sockets non blocking. 2012/02/05: Compile ok with -ansi flag. diff --git a/miniupnpd/miniupnpd.c b/miniupnpd/miniupnpd.c index 9ea1d84..1a7b4fb 100644 --- a/miniupnpd/miniupnpd.c +++ b/miniupnpd/miniupnpd.c @@ -1,4 +1,4 @@ -/* $Id: miniupnpd.c,v 1.142 2012/02/04 23:34:39 nanard Exp $ */ +/* $Id: miniupnpd.c,v 1.143 2012/02/07 00:21:52 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2012 Thomas Bernard @@ -1091,9 +1091,7 @@ main(int argc, char * * argv) struct upnphttp * e = 0; struct upnphttp * next; fd_set readset; /* for select() */ -#ifdef ENABLE_EVENTS fd_set writeset; -#endif struct timeval timeout, timeofday, lasttimeofday = {0, 0}; int max_fd = -1; #ifdef USE_MINIUPNPDCTL @@ -1359,6 +1357,7 @@ main(int argc, char * * argv) /* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */ FD_ZERO(&readset); + FD_ZERO(&writeset); if (sudp >= 0) { @@ -1396,10 +1395,15 @@ main(int argc, char * * argv) i = 0; /* active HTTP connections count */ for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next) { - if((e->socket >= 0) && (e->state <= 2)) + if(e->socket >= 0) { - FD_SET(e->socket, &readset); - max_fd = MAX( max_fd, e->socket); + if(e->state <= EWaitingForHttpContent) + FD_SET(e->socket, &readset); + else if(e->state == ESendingAndClosing) + FD_SET(e->socket, &writeset); + else + continue; + max_fd = MAX(max_fd, e->socket); i++; } } @@ -1434,15 +1438,10 @@ main(int argc, char * * argv) #endif #ifdef ENABLE_EVENTS - FD_ZERO(&writeset); upnpevents_selectfds(&readset, &writeset, &max_fd); #endif -#ifdef ENABLE_EVENTS if(select(max_fd+1, &readset, &writeset, 0, &timeout) < 0) -#else - if(select(max_fd+1, &readset, 0, 0, &timeout) < 0) -#endif { if(quitting) goto shutdown; if(errno == EINTR) continue; /* interrupted by a signal, start again */ @@ -1539,10 +1538,13 @@ main(int argc, char * * argv) /* LIST_FOREACH macro is not available under linux */ for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next) { - if( (e->socket >= 0) && (e->state <= 2) - &&(FD_ISSET(e->socket, &readset)) ) + if(e->socket >= 0) { - Process_upnphttp(e); + if(FD_ISSET(e->socket, &readset) || + FD_ISSET(e->socket, &writeset)) + { + Process_upnphttp(e); + } } } /* process incoming HTTP connections */ @@ -1623,7 +1625,7 @@ main(int argc, char * * argv) for(e = upnphttphead.lh_first; e != NULL; ) { next = e->entries.le_next; - if(e->state >= 100) + if(e->state >= EToDelete) { LIST_REMOVE(e, entries); Delete_upnphttp(e); diff --git a/miniupnpd/upnpevents.c b/miniupnpd/upnpevents.c index 28d090d..1ef545c 100644 --- a/miniupnpd/upnpevents.c +++ b/miniupnpd/upnpevents.c @@ -1,4 +1,4 @@ -/* $Id: upnpevents.c,v 1.19 2012/02/06 16:21:24 nanard Exp $ */ +/* $Id: upnpevents.c,v 1.20 2012/02/06 23:41:15 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2008-2012 Thomas Bernard @@ -368,11 +368,16 @@ static void upnp_event_send(struct upnp_event_notify * obj) "upnp_event_send", obj->buffer + obj->sent); i = send(obj->s, obj->buffer + obj->sent, obj->tosend - obj->sent, 0); if(i<0) { - syslog(LOG_NOTICE, "%s: send(): %m", "upnp_event_send"); - obj->state = EError; - return; + if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) { + syslog(LOG_NOTICE, "%s: send(): %m", "upnp_event_send"); + obj->state = EError; + return; + } else { + /* EAGAIN or EWOULDBLOCK or EINTR : no data sent */ + i = 0; + } } - else if(i != (obj->tosend - obj->sent)) + if(i != (obj->tosend - obj->sent)) syslog(LOG_NOTICE, "%s: %d bytes send out of %d", "upnp_event_send", i, obj->tosend - obj->sent); obj->sent += i; diff --git a/miniupnpd/upnphttp.c b/miniupnpd/upnphttp.c index 70e21fe..19f9b75 100644 --- a/miniupnpd/upnphttp.c +++ b/miniupnpd/upnphttp.c @@ -1,4 +1,4 @@ -/* $Id: upnphttp.c,v 1.66 2012/02/01 11:13:30 nanard Exp $ */ +/* $Id: upnphttp.c,v 1.67 2012/02/07 00:21:54 nanard Exp $ */ /* Project : miniupnp * Website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author : Thomas Bernard @@ -24,6 +24,7 @@ #include "miniupnpdpath.h" #include "upnpsoap.h" #include "upnpevents.h" +#include "upnputils.h" struct upnphttp * New_upnphttp(int s) @@ -36,6 +37,8 @@ New_upnphttp(int s) return NULL; memset(ret, 0, sizeof(struct upnphttp)); ret->socket = s; + if(!set_non_blocking(s)) + syslog(LOG_WARNING, "New_upnphttp::set_non_blocking(): %m"); return ret; } @@ -47,7 +50,7 @@ CloseSocket_upnphttp(struct upnphttp * h) syslog(LOG_ERR, "CloseSocket_upnphttp: close(%d): %m", h->socket); } h->socket = -1; - h->state = 100; + h->state = EToDelete; } void @@ -159,24 +162,11 @@ intervening space) by either an integer or the keyword "infinite". */ static void Send404(struct upnphttp * h) { -/* - static const char error404[] = "HTTP/1.1 404 Not found\r\n" - "Connection: close\r\n" - "Content-type: text/html\r\n" - "\r\n" - "404 Not Found" - "

Not Found

The requested URL was not found" - " on this server.\r\n"; - int n; - n = send(h->socket, error404, sizeof(error404) - 1, 0); - if(n < 0) - { - syslog(LOG_ERR, "Send404: send(http): %m"); - }*/ static const char body404[] = "404 Not Found" "

Not Found

The requested URL was not found" " on this server.\r\n"; + h->respflags = FLAG_HTML; BuildResp2_upnphttp(h, 404, "Not Found", body404, sizeof(body404) - 1); @@ -187,25 +177,11 @@ Send404(struct upnphttp * h) static void Send501(struct upnphttp * h) { -/* - static const char error501[] = "HTTP/1.1 501 Not Implemented\r\n" - "Connection: close\r\n" - "Content-type: text/html\r\n" - "\r\n" - "501 Not Implemented" - "

Not Implemented

The HTTP Method " - "is not implemented by this server.\r\n"; - int n; - n = send(h->socket, error501, sizeof(error501) - 1, 0); - if(n < 0) - { - syslog(LOG_ERR, "Send501: send(http): %m"); - } -*/ static const char body501[] = "501 Not Implemented" "

Not Implemented

The HTTP Method " "is not implemented by this server.\r\n"; + h->respflags = FLAG_HTML; BuildResp2_upnphttp(h, 501, "Not Implemented", body501, sizeof(body501) - 1); @@ -296,7 +272,7 @@ ProcessHTTPPOST_upnphttp(struct upnphttp * h) else { /* waiting for remaining data */ - h->state = 1; + h->state = EWaitingForHttpContent; } } @@ -546,12 +522,13 @@ Process_upnphttp(struct upnphttp * h) { char buf[2048]; int n; + if(!h) return; switch(h->state) { - case 0: - n = recv(h->socket, buf, 2048, 0); + case EWaitingForHttpRequest: + n = recv(h->socket, buf, sizeof(buf), 0); if(n<0) { if(errno != EAGAIN && @@ -559,14 +536,14 @@ Process_upnphttp(struct upnphttp * h) errno != EINTR) { syslog(LOG_ERR, "recv (state0): %m"); - h->state = 100; + h->state = EToDelete; } /* if errno is EAGAIN, EWOULDBLOCK or EINTR, try again later */ } else if(n==0) { syslog(LOG_WARNING, "HTTP Connection closed unexpectedly"); - h->state = 100; + h->state = EToDelete; } else { @@ -586,8 +563,8 @@ Process_upnphttp(struct upnphttp * h) } } break; - case 1: - n = recv(h->socket, buf, 2048, 0); + case EWaitingForHttpContent: + n = recv(h->socket, buf, sizeof(buf), 0); if(n<0) { if(errno != EAGAIN && @@ -595,27 +572,38 @@ Process_upnphttp(struct upnphttp * h) errno != EINTR) { syslog(LOG_ERR, "recv (state1): %m"); - h->state = 100; + h->state = EToDelete; } /* if errno is EAGAIN, EWOULDBLOCK or EINTR, try again later */ } else if(n==0) { syslog(LOG_WARNING, "HTTP Connection closed inexpectedly"); - h->state = 100; + h->state = EToDelete; } else { - /*fwrite(buf, 1, n, stdout);*/ /* debug */ - h->req_buf = (char *)realloc(h->req_buf, n + h->req_buflen); - memcpy(h->req_buf + h->req_buflen, buf, n); - h->req_buflen += n; - if((h->req_buflen - h->req_contentoff) >= h->req_contentlen) + void * tmp = realloc(h->req_buf, n + h->req_buflen); + if(!tmp) { - ProcessHTTPPOST_upnphttp(h); + syslog(LOG_ERR, "memory allocation error %m"); + h->state = EToDelete; + } + else + { + h->req_buf = tmp; + memcpy(h->req_buf + h->req_buflen, buf, n); + h->req_buflen += n; + if((h->req_buflen - h->req_contentoff) >= h->req_contentlen) + { + ProcessHTTPPOST_upnphttp(h); + } } } break; + case ESendingAndClosing: + SendRespAndClose_upnphttp(h); + break; default: syslog(LOG_WARNING, "Unexpected state: %d", h->state); } @@ -725,30 +713,34 @@ BuildResp_upnphttp(struct upnphttp * h, void SendRespAndClose_upnphttp(struct upnphttp * h) { - char * p; ssize_t n; - size_t len; - p = h->res_buf; - len = h->res_buflen; - while (len > 0) + + while (h->res_sent < h->res_buflen) { - n = send(h->socket, p, len, 0); + n = send(h->socket, h->res_buf + h->res_sent, + h->res_buflen - h->res_sent, 0); if(n<0) { + if(errno == EINTR) + continue; /* try again immediatly */ + if(errno == EAGAIN || errno == EWOULDBLOCK) + { + /* try again later */ + h->state = ESendingAndClosing; + return; + } syslog(LOG_ERR, "send(res_buf): %m"); - if (errno != EINTR) - break; /* avoid infinite loop */ + break; /* avoid infinite loop */ } else if(n == 0) { - syslog(LOG_ERR, "send(res_buf): %zd bytes sent (out of %zu)", - n, len); + syslog(LOG_ERR, "send(res_buf): %d bytes sent (out of %d)", + h->res_sent, h->res_buflen); break; } else { - p += n; - len -= n; + h->res_sent += n; } } CloseSocket_upnphttp(h); diff --git a/miniupnpd/upnphttp.h b/miniupnpd/upnphttp.h index c8462be..70278c3 100644 --- a/miniupnpd/upnphttp.h +++ b/miniupnpd/upnphttp.h @@ -1,4 +1,4 @@ -/* $Id: upnphttp.h,v 1.25 2011/11/18 11:21:18 nanard Exp $ */ +/* $Id: upnphttp.h,v 1.26 2012/02/07 00:21:54 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2011 Thomas Bernard @@ -23,6 +23,13 @@ ... >= 100 - to be deleted */ +enum httpStates { + EWaitingForHttpRequest = 0, + EWaitingForHttpContent, + ESendingAndClosing, + EToDelete = 100 +}; + enum httpCommands { EUnknown = 0, EGet, @@ -38,7 +45,7 @@ struct upnphttp { int ipv6; struct in6_addr clientaddr_v6; #endif - int state; + enum httpStates state; char HttpVer[16]; /* request */ char * req_buf; @@ -59,9 +66,8 @@ struct upnphttp { /* response */ char * res_buf; int res_buflen; + int res_sent; int res_buf_alloclen; - /*int res_contentlen;*/ - /*int res_contentoff;*/ /* header length */ LIST_ENTRY(upnphttp) entries; };