diff --git a/contrib/src/upnp/poll.patch b/contrib/src/upnp/poll.patch new file mode 100644 index 0000000000000000000000000000000000000000..cc05c8d3ab446ca405a2e0b4f6b99adbf8366040 --- /dev/null +++ b/contrib/src/upnp/poll.patch @@ -0,0 +1,428 @@ + upnp/src/genlib/net/http/httpreadwrite.c | 89 +++++++++++++++------------------------- + upnp/src/genlib/net/sock.c | 103 ++++++++++++++++++---------------------------- + upnp/src/ssdp/ssdp_ctrlpt.c | 155 +++++++++++++++++++++++++-------------------------------------------- + 3 files changed, 129 insertions(+), 218 deletions(-) + +diff --git a/upnp/src/genlib/net/http/httpreadwrite.c b/upnp/src/genlib/net/http/httpreadwrite.c +index 27e9c3a5..69eb0a1f 100644 +--- a/upnp/src/genlib/net/http/httpreadwrite.c ++++ b/upnp/src/genlib/net/http/httpreadwrite.c +@@ -58,6 +58,7 @@ + #include <assert.h> + #include <stdarg.h> + #include <string.h> ++#include <poll.h> + + #include "posix_overwrites.h" + +@@ -97,61 +98,39 @@ const int CHUNK_TAIL_SIZE = 10; + * + * \return 0 if successful, else -1. + */ +-static int Check_Connect_And_Wait_Connection( +- /*! [in] socket. */ +- SOCKET sock, +- /*! [in] result of connect. */ +- int connect_res) +-{ +- struct timeval tmvTimeout = {DEFAULT_TCP_CONNECT_TIMEOUT, 0}; +- int result; +- #ifdef _WIN32 +- struct fd_set fdSet; +- #else +- fd_set fdSet; +- #endif +- FD_ZERO(&fdSet); +- FD_SET(sock, &fdSet); +- +- if (connect_res < 0) { +- #ifdef _WIN32 +- if (WSAEWOULDBLOCK == WSAGetLastError()) { +- #else +- if (EINPROGRESS == errno) { +- #endif +- result = select( +- (int)sock + 1, NULL, &fdSet, NULL, &tmvTimeout); +- if (result < 0) { +- #ifdef _WIN32 +- /* WSAGetLastError(); */ +- #else +- /* errno */ +- #endif +- return -1; +- } else if (result == 0) { +- /* timeout */ +- return -1; +- #ifndef _WIN32 +- } else { +- int valopt = 0; +- socklen_t len = sizeof(valopt); +- if (getsockopt(sock, +- SOL_SOCKET, +- SO_ERROR, +- (void *)&valopt, +- &len) < 0) { +- /* failed to read delayed error */ +- return -1; +- } else if (valopt) { +- /* delayed error = valopt */ +- return -1; +- } +- #endif +- } +- } +- } +- +- return 0; ++static int Check_Connect_And_Wait_Connection(SOCKET sock, int connect_res) { ++ struct timeval tmvTimeout = {DEFAULT_TCP_CONNECT_TIMEOUT, 0}; ++ int result; ++ struct pollfd fds[1]; ++ ++ fds[0].fd = sock; ++ fds[0].events = POLLOUT; ++ ++ if (connect_res < 0) { ++ result = poll(fds, 1, tmvTimeout.tv_sec * 1000 + tmvTimeout.tv_usec / 1000); ++ ++ if (result < 0) { ++ /* Error in poll */ ++ return -1; ++ } else if (result == 0) { ++ /* Timeout */ ++ return -1; ++ } else { ++ int valopt = 0; ++ socklen_t len = sizeof(valopt); ++ ++ /* Check if the socket is now writable (connected) */ ++ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *)&valopt, &len) < 0) { ++ /* Failed to read delayed error */ ++ return -1; ++ } else if (valopt) { ++ /* Delayed error = valopt */ ++ return -1; ++ } ++ } ++ } ++ ++ return 0; + } + #endif /* UPNP_ENABLE_BLOCKING_TCP_CONNECTIONS */ + +diff --git a/upnp/src/genlib/net/sock.c b/upnp/src/genlib/net/sock.c +index 396c692a..b8a980f0 100644 +--- a/upnp/src/genlib/net/sock.c ++++ b/upnp/src/genlib/net/sock.c +@@ -56,6 +56,7 @@ + #include <fcntl.h> /* for F_GETFL, F_SETFL, O_NONBLOCK */ + #include <string.h> + #include <time.h> ++#include <poll.h> + + #ifdef UPNP_ENABLE_OPEN_SSL + #include <openssl/ssl.h> +@@ -156,85 +157,59 @@ int sock_destroy(SOCKINFO *info, int ShutdownMethod) + * \li \c UPNP_E_TIMEDOUT - Timeout + * \li \c UPNP_E_SOCKET_ERROR - Error on socket calls + */ +-static int sock_read_write( +- /*! [in] Socket Information Object. */ +- SOCKINFO *info, +- /*! [out] Buffer to get data to or send data from. */ +- char *buffer, +- /*! [in] Size of the buffer. */ +- size_t bufsize, +- /*! [in] timeout value. */ +- int *timeoutSecs, +- /*! [in] Boolean value specifying read or write option. */ +- int bRead) +-{ +- int retCode; +- fd_set readSet; +- fd_set writeSet; +- struct timeval timeout; +- long numBytes; +- time_t start_time = time(NULL); +- SOCKET sockfd = info->socket; +- long bytes_sent = 0; +- size_t byte_left = 0; +- ssize_t num_written; +- +- FD_ZERO(&readSet); +- FD_ZERO(&writeSet); +- if (bRead) +- FD_SET(sockfd, &readSet); +- else +- FD_SET(sockfd, &writeSet); +- timeout.tv_sec = *timeoutSecs; +- timeout.tv_usec = 0; +- while (1) { +- if (*timeoutSecs < 0) +- retCode = select((int)sockfd + 1, +- &readSet, +- &writeSet, +- NULL, +- NULL); +- else +- retCode = select((int)sockfd + 1, +- &readSet, +- &writeSet, +- NULL, +- &timeout); +- if (retCode == 0) +- return UPNP_E_TIMEDOUT; +- if (retCode == -1) { +- if (errno == EINTR) +- continue; +- return UPNP_E_SOCKET_ERROR; +- } else +- /* read or write. */ +- break; +- } ++static int sock_read_write(SOCKINFO *info, char *buffer, size_t bufsize, int *timeoutSecs, int bRead) { ++ int retCode; ++ struct pollfd fds[1]; ++ time_t start_time = time(NULL); ++ SOCKET sockfd = info->socket; ++ long bytes_sent = 0; ++ size_t byte_left = 0; ++ ssize_t num_written; ++ long numBytes; ++ ++ fds[0].fd = sockfd; ++ fds[0].events = (bRead ? POLLIN : POLLOUT); ++ ++ while (1) { ++ int timeoutMillis = (*timeoutSecs < 0) ? -1 : (*timeoutSecs * 1000); ++ ++ retCode = poll(fds, 1, timeoutMillis); ++ ++ if (retCode == 0) ++ return UPNP_E_TIMEDOUT; ++ else if (retCode == -1) { ++ if (errno == EINTR) ++ continue; ++ return UPNP_E_SOCKET_ERROR; ++ } else ++ /* read or write. */ ++ break; ++ } ++ + #ifdef SO_NOSIGPIPE +- { +- int old; +- int set = 1; +- socklen_t olen = sizeof(old); +- getsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &old, &olen); +- setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof(set)); ++ { ++ int old; ++ int set = 1; ++ socklen_t olen = sizeof(old); ++ getsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &old, &olen); ++ setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof(set)); + #endif + if (bRead) { + #ifdef UPNP_ENABLE_OPEN_SSL + if (info->ssl) { + numBytes = (long)SSL_read( +- info->ssl, buffer, (size_t)bufsize); ++ info->ssl, buffer, bufsize); + } else { + #endif + /* read data. */ +- numBytes = (long)recv( +- sockfd, buffer, bufsize, MSG_NOSIGNAL); ++ numBytes = (long)recv(sockfd, buffer, (int)bufsize, MSG_NOSIGNAL); + #ifdef UPNP_ENABLE_OPEN_SSL + } + #endif + } else { + byte_left = bufsize; + bytes_sent = 0; +- while (byte_left != (size_t)0) { ++ while (byte_left != 0) { + #ifdef UPNP_ENABLE_OPEN_SSL + if (info->ssl) { + num_written = SSL_write(info->ssl, +diff --git a/upnp/src/ssdp/ssdp_ctrlpt.c b/upnp/src/ssdp/ssdp_ctrlpt.c +index 8644c746..050b4916 100644 +--- a/upnp/src/ssdp/ssdp_ctrlpt.c ++++ b/upnp/src/ssdp/ssdp_ctrlpt.c +@@ -40,6 +40,7 @@ + #include "config.h" + + #include "upnputil.h" ++#include <poll.h> + + #ifdef INCLUDE_CLIENT_APIS + #if EXCLUDE_SSDP == 0 +@@ -597,6 +598,7 @@ int SearchByTarget(int Hnd, int Mx, char *St, void *Cookie) + struct in_addr addrv4; + SOCKET max_fd = 0; + int retVal; ++ int numCopies = 0; + + /*ThreadData *ThData; */ + ThreadPoolJob job; +@@ -674,105 +676,60 @@ int SearchByTarget(int Hnd, int Mx, char *St, void *Cookie) + HandleUnlock(); + /* End of lock */ + +- FD_ZERO(&wrSet); +- if (gSsdpReqSocket4 != INVALID_SOCKET) { +- setsockopt(gSsdpReqSocket4, +- IPPROTO_IP, +- IP_MULTICAST_IF, +- (char *)&addrv4, +- sizeof(addrv4)); +- FD_SET(gSsdpReqSocket4, &wrSet); +- max_fd = max(max_fd, gSsdpReqSocket4); +- } +- #ifdef UPNP_ENABLE_IPV6 +- if (gSsdpReqSocket6 != INVALID_SOCKET) { +- setsockopt(gSsdpReqSocket6, +- IPPROTO_IPV6, +- IPV6_MULTICAST_IF, +- (char *)&gIF_INDEX, +- sizeof(gIF_INDEX)); +- FD_SET(gSsdpReqSocket6, &wrSet); +- max_fd = max(max_fd, gSsdpReqSocket6); +- } +- #endif +- ret = select((int)max_fd + 1, NULL, &wrSet, NULL, NULL); +- if (ret == -1) { +- strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); +- UpnpPrintf(UPNP_INFO, +- SSDP, +- __FILE__, +- __LINE__, +- "SSDP_LIB: Error in select(): %s\n", +- errorBuffer); +- UpnpCloseSocket(gSsdpReqSocket4); +- #ifdef UPNP_ENABLE_IPV6 +- UpnpCloseSocket(gSsdpReqSocket6); +- #endif +- return UPNP_E_INTERNAL_ERROR; +- } +- #ifdef UPNP_ENABLE_IPV6 +- if (gSsdpReqSocket6 != INVALID_SOCKET && +- FD_ISSET(gSsdpReqSocket6, &wrSet)) { +- int NumCopy = 0; +- +- while (NumCopy < NUM_SSDP_COPY) { +- UpnpPrintf(UPNP_INFO, +- SSDP, +- __FILE__, +- __LINE__, +- ">>> SSDP SEND M-SEARCH >>>\n%s\n", +- ReqBufv6UlaGua); +- sendto(gSsdpReqSocket6, +- ReqBufv6UlaGua, +- strlen(ReqBufv6UlaGua), +- 0, +- (struct sockaddr *)&__ss_v6, +- sizeof(struct sockaddr_in6)); +- NumCopy++; +- imillisleep(SSDP_PAUSE); +- } +- NumCopy = 0; +- inet_pton(AF_INET6, SSDP_IPV6_LINKLOCAL, &destAddr6->sin6_addr); +- while (NumCopy < NUM_SSDP_COPY) { +- UpnpPrintf(UPNP_INFO, +- SSDP, +- __FILE__, +- __LINE__, +- ">>> SSDP SEND M-SEARCH >>>\n%s\n", +- ReqBufv6); +- sendto(gSsdpReqSocket6, +- ReqBufv6, +- strlen(ReqBufv6), +- 0, +- (struct sockaddr *)&__ss_v6, +- sizeof(struct sockaddr_in6)); +- NumCopy++; +- imillisleep(SSDP_PAUSE); +- } +- } +- #endif /* IPv6 */ +- if (gSsdpReqSocket4 != INVALID_SOCKET && +- FD_ISSET(gSsdpReqSocket4, &wrSet)) { +- int NumCopy = 0; +- while (NumCopy < NUM_SSDP_COPY) { +- UpnpPrintf(UPNP_INFO, +- SSDP, +- __FILE__, +- __LINE__, +- ">>> SSDP SEND M-SEARCH >>>\n%s\n", +- ReqBufv4); +- sendto(gSsdpReqSocket4, +- ReqBufv4, +- strlen(ReqBufv4), +- 0, +- (struct sockaddr *)&__ss_v4, +- sizeof(struct sockaddr_in)); +- NumCopy++; +- imillisleep(SSDP_PAUSE); +- } +- } +- +- return 1; ++ struct pollfd fds[2]; ++ int nfds = 0; ++ ++ if (gSsdpReqSocket4 != INVALID_SOCKET) { ++ setsockopt(gSsdpReqSocket4, IPPROTO_IP, IP_MULTICAST_IF, (char *)&addrv4, sizeof(addrv4)); ++ fds[nfds].fd = gSsdpReqSocket4; ++ fds[nfds].events = POLLOUT; ++ nfds++; ++ } ++#ifdef UPNP_ENABLE_IPV6 ++ if (gSsdpReqSocket6 != INVALID_SOCKET) { ++ setsockopt(gSsdpReqSocket6, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&gIF_INDEX, sizeof(gIF_INDEX)); ++ fds[nfds].fd = gSsdpReqSocket6; ++ fds[nfds].events = POLLOUT; ++ nfds++; ++ } ++#endif ++ ret = poll(fds, nfds, -1); // Wait indefinitely for the sockets to become writable ++ if (ret == -1) { ++ strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); ++ UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, "SSDP_LIB: Error in poll(): %s\n", errorBuffer); ++ UpnpCloseSocket(gSsdpReqSocket4); ++#ifdef UPNP_ENABLE_IPV6 ++ UpnpCloseSocket(gSsdpReqSocket6); ++#endif ++ return UPNP_E_INTERNAL_ERROR; ++ } ++#ifdef UPNP_ENABLE_IPV6 ++ if (gSsdpReqSocket6 != INVALID_SOCKET && FD_ISSET(gSsdpReqSocket6, &wrSet)) { ++ while (numCopies < NUM_SSDP_COPY) { ++ UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, ">>> SSDP SEND M-SEARCH >>>\n%s\n", ReqBufv6UlaGua); ++ sendto(gSsdpReqSocket6, ReqBufv6UlaGua, (int)strlen(ReqBufv6UlaGua), 0, (struct sockaddr *)&__ss_v6, sizeof(struct sockaddr_in6)); ++ numCopies++; ++ imillisleep(SSDP_PAUSE); ++ } ++ numCopies = 0; ++ inet_pton(AF_INET6, SSDP_IPV6_LINKLOCAL, &destAddr6->sin6_addr); ++ while (numCopies < NUM_SSDP_COPY) { ++ UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, ">>> SSDP SEND M-SEARCH >>>\n%s\n", ReqBufv6); ++ sendto(gSsdpReqSocket6, ReqBufv6, (int)strlen(ReqBufv6), 0, (struct sockaddr *)&__ss_v6, sizeof(struct sockaddr_in6)); ++ numCopies++; ++ imillisleep(SSDP_PAUSE); ++ } ++ } ++#endif /* IPv6 */ ++ if (gSsdpReqSocket4 != INVALID_SOCKET && FD_ISSET(gSsdpReqSocket4, &wrSet)) { ++ while (numCopies < NUM_SSDP_COPY) { ++ UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, ">>> SSDP SEND M-SEARCH >>>\n%s\n", ReqBufv4); ++ sendto(gSsdpReqSocket4, ReqBufv4, (int)strlen(ReqBufv4), 0, (struct sockaddr *)&__ss_v4, sizeof(struct sockaddr_in)); ++ numCopies++; ++ imillisleep(SSDP_PAUSE); ++ } ++ } ++ return 1; + } + #endif /* EXCLUDE_SSDP */ + #endif /* INCLUDE_CLIENT_APIS */ diff --git a/contrib/src/upnp/rules.mak b/contrib/src/upnp/rules.mak index 24c0f4b78bf3350f31925bebfff8f5de936fac5f..b6c9c9c250603b0422b5d3bafe4829e4f4b031cc 100644 --- a/contrib/src/upnp/rules.mak +++ b/contrib/src/upnp/rules.mak @@ -17,6 +17,7 @@ upnp: pupnp-release-$(UPNP_VERSION).tar.gz .sum-upnp ifeq ($(OS),Windows_NT) $(APPLY) $(SRC)/upnp/libupnp-windows.patch endif + $(APPLY) $(SRC)/upnp/poll.patch $(UPDATE_AUTOCONFIG) && cd $(UNPACK_DIR) && mv config.guess config.sub $(MOVE)