diff --git a/tests/server/sockfilt.c b/tests/server/sockfilt.c index 7a397687d5..d37f9e6a60 100644 --- a/tests/server/sockfilt.c +++ b/tests/server/sockfilt.c @@ -399,6 +399,146 @@ static void lograw(unsigned char *buffer, ssize_t len) logmsg("'%s'", data); } +/* + * WinSock select() does not support standard file descriptors, + * it can only check SOCKETs. The following function is an attempt + * to re-create a select() function with support for other handle types. + */ +#ifdef USE_WINSOCK +/* + * select() function with support for WINSOCK2 sockets and all + * other handle types supported by WaitForMultipleObjectsEx(). + * + * TODO: Differentiate between read/write/except for non-SOCKET handles. + * + * http://msdn.microsoft.com/en-us/library/windows/desktop/ms687028.aspx + * http://msdn.microsoft.com/en-us/library/windows/desktop/ms741572.aspx + */ +static int select_ws(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout) +{ + int ret = 0, fds = 0, nfd = 0, idx = 0, wsa = 0, error = 0; + long networkevents; + DWORD milliseconds, wait; + WSAEVENT wsaevent, *wsaevents; + WSANETWORKEVENTS wsanetevents; + HANDLE *handles; + int *fdarr; + + /* allocate internal array for the original input handles */ + fdarr = malloc(sizeof(int)*nfds); + if(fdarr == NULL) { + errno = ENOMEM; + return -1; + } + + /* allocate internal array for the internal event handles */ + handles = malloc(sizeof(HANDLE)*nfds); + if(handles == NULL) { + errno = ENOMEM; + return -1; + } + + /* allocate internal array for the internal WINSOCK2 events */ + wsaevents = malloc(sizeof(WSAEVENT)*nfds); + if(wsaevents == NULL) { + errno = ENOMEM; + return -1; + } + + /* loop over the handles in the input descriptor sets */ + for(fds = 0; fds < nfds; fds++) { + networkevents = 0; + handles[nfd] = 0; + + if(FD_ISSET(fds, readfds)) + networkevents |= FD_READ; + + if(FD_ISSET(fds, writefds)) + networkevents |= FD_WRITE; + + if(FD_ISSET(fds, exceptfds)) + networkevents |= FD_CLOSE; + + if(networkevents) { + fdarr[nfd] = fds; + if(fds == fileno(stdin)) { + handles[nfd] = GetStdHandle(STD_INPUT_HANDLE); + } + else if(fds == fileno(stdout)) { + handles[nfd] = GetStdHandle(STD_OUTPUT_HANDLE); + } + else if(fds == fileno(stderr)) { + handles[nfd] = GetStdHandle(STD_ERROR_HANDLE); + } + else { + wsaevent = WSACreateEvent(); + if(wsaevent != WSA_INVALID_EVENT) { + error = WSAEventSelect(fds, wsaevent, networkevents); + if(error != SOCKET_ERROR) { + handles[nfd] = wsaevent; + wsaevents[wsa++] = wsaevent; + } + else { + handles[nfd] = (HANDLE) fds; + WSACloseEvent(wsaevent); + } + } + } + nfd++; + } + } + + /* convert struct timeval to milliseconds */ + if(timeout) { + milliseconds = ((timeout->tv_sec * 1000) + (timeout->tv_usec / 1000)); + } + else { + milliseconds = INFINITE; + } + + /* wait for one of the internal handles to trigger */ + wait = WaitForMultipleObjectsEx(nfd, handles, FALSE, milliseconds, FALSE); + + /* loop over the internal handles returned in the descriptors */ + for(idx = 0; idx < nfd; idx++) { + if(wait != WAIT_OBJECT_0 + idx) { + /* remove from all descriptor sets since this handle did not trigger */ + FD_CLR(fdarr[idx], readfds); + FD_CLR(fdarr[idx], writefds); + FD_CLR(fdarr[idx], exceptfds); + } + else { + /* first try to handle the event with the WINSOCK2 functions */ + error = WSAEnumNetworkEvents(fdarr[idx], NULL, &wsanetevents); + if(error != SOCKET_ERROR) { + /* remove from descriptor set if not ready for read */ + if(!(wsanetevents.lNetworkEvents & FD_READ)) + FD_CLR(fdarr[idx], readfds); + + /* remove from descriptor set if not ready for write */ + if(!(wsanetevents.lNetworkEvents & FD_WRITE)) + FD_CLR(fdarr[idx], writefds); + + /* remove from descriptor set if not exceptional */ + if(!(wsanetevents.lNetworkEvents & FD_CLOSE)) + FD_CLR(fdarr[idx], exceptfds); + } + ret++; + } + } + + for(idx = 0; idx < wsa; idx++) + WSACloseEvent(wsaevents[idx]); + + free(wsaevents); + free(handles); + free(fdarr); + + return ret; +} +#endif + /* sockfdp is a pointer to an established stream or CURL_SOCKET_BAD @@ -447,18 +587,6 @@ static bool juggle(curl_socket_t *sockfdp, FD_ZERO(&fds_write); FD_ZERO(&fds_err); -#ifdef USE_WINSOCK - /* - ** WinSock select() does not support standard file descriptors, - ** it can only check SOCKETs. Since this program in its current - ** state will not work on WinSock based systems, next line is - ** commented out to allow warning-free compilation awaiting the - ** day it will be fixed to also run on WinSock systems. - */ -#else - FD_SET(fileno(stdin), &fds_read); -#endif - switch(*mode) { case PASSIVE_LISTEN: @@ -511,7 +639,11 @@ static bool juggle(curl_socket_t *sockfdp, do { +#ifdef USE_WINSOCK + rc = select_ws((int)maxfd + 1, &fds_read, &fds_write, &fds_err, &timeout); +#else rc = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, &timeout); +#endif if(got_exit_signal) { logmsg("signalled to die, exiting...");