From 11f55a9672d3b5d3eaa5d15d5a67618fb640c153 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Sun, 6 Jan 2013 22:29:52 +0100 Subject: tests/server/sockfilt.c: Fixed support for listening sockets This commit fixes support for sockets that are ready to accept a new connection and have previously been put into listening mode. It also includes changes which are the result of investigation regarding Windows STDIN. These changes are the preparation for further improvements regarding support for reading data from STDIN on Windows. Open issue: WaitForMultipleObjectsEx does not support PIPE handles which are returned by GetStdHandle while running without a GUI. --- tests/server/sockfilt.c | 142 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 108 insertions(+), 34 deletions(-) (limited to 'tests/server') diff --git a/tests/server/sockfilt.c b/tests/server/sockfilt.c index 38015e22f..8acad9611 100644 --- a/tests/server/sockfilt.c +++ b/tests/server/sockfilt.c @@ -420,43 +420,53 @@ static int select_ws(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { long networkevents; - DWORD milliseconds, wait, idx; + DWORD milliseconds, wait, idx, avail, events, inputs; WSAEVENT wsaevent, *wsaevents; WSANETWORKEVENTS wsanetevents; - HANDLE *handles; - curl_socket_t *fdarr; + INPUT_RECORD *inputrecords; + HANDLE handle, *handles; + curl_socket_t *fdarr, *wsasocks; int error, fds; DWORD nfd = 0, wsa = 0; int ret = 0; + /* check if the input value is valid */ if(nfds < 0) { SET_SOCKERRNO(EINVAL); return -1; } + /* check if we got descriptors, sleep in case we got none */ if(!nfds) { - Sleep(1000*timeout->tv_sec + timeout->tv_usec/1000); + Sleep((timeout->tv_sec * 1000) + (timeout->tv_usec / 1000)); return 0; } /* allocate internal array for the original input handles */ fdarr = malloc(nfds * sizeof(curl_socket_t)); if(fdarr == NULL) { - errno = ENOMEM; + SET_SOCKERRNO(ENOMEM); return -1; } /* allocate internal array for the internal event handles */ handles = malloc(nfds * sizeof(HANDLE)); if(handles == NULL) { - errno = ENOMEM; + SET_SOCKERRNO(ENOMEM); + return -1; + } + + /* allocate internal array for the internal socket handles */ + wsasocks = malloc(nfds * sizeof(curl_socket_t)); + if(wsasocks == NULL) { + SET_SOCKERRNO(ENOMEM); return -1; } /* allocate internal array for the internal WINSOCK2 events */ wsaevents = malloc(nfds * sizeof(WSAEVENT)); if(wsaevents == NULL) { - errno = ENOMEM; + SET_SOCKERRNO(ENOMEM); return -1; } @@ -466,14 +476,15 @@ static int select_ws(int nfds, fd_set *readfds, fd_set *writefds, handles[nfd] = 0; if(FD_ISSET(fds, readfds)) - networkevents |= FD_READ; + networkevents |= FD_READ|FD_ACCEPT|FD_CLOSE; if(FD_ISSET(fds, writefds)) - networkevents |= FD_WRITE; + networkevents |= FD_WRITE|FD_CONNECT; if(FD_ISSET(fds, exceptfds)) - networkevents |= FD_CLOSE; + networkevents |= FD_OOB; + /* only wait for events for which we actually care */ if(networkevents) { fdarr[nfd] = (curl_socket_t)fds; if(fds == fileno(stdin)) { @@ -491,10 +502,12 @@ static int select_ws(int nfds, fd_set *readfds, fd_set *writefds, error = WSAEventSelect(fds, wsaevent, networkevents); if(error != SOCKET_ERROR) { handles[nfd] = wsaevent; - wsaevents[wsa++] = wsaevent; + wsasocks[wsa] = (curl_socket_t)fds; + wsaevents[wsa] = wsaevent; + wsa++; } else { - handles[nfd] = (HANDLE) fds; + handles[nfd] = (HANDLE)fds; WSACloseEvent(wsaevent); } } @@ -516,36 +529,97 @@ static int select_ws(int nfds, fd_set *readfds, fd_set *writefds, /* 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); + fds = fdarr[idx]; + handle = handles[idx]; + + /* check if the current internal handle was triggered */ + if(wait != WAIT_FAILED && (wait - WAIT_OBJECT_0) >= idx && + WaitForSingleObjectEx(handle, 0, FALSE) == WAIT_OBJECT_0) { + /* try to handle the event with STD* handle functions */ + if(fds == fileno(stdin)) { + /* check if there is no data in the input buffer */ + if(!stdin->_cnt) { + /* check if we are getting data from a PIPE */ + if(!GetConsoleMode(handle, &avail)) { + /* check if there is no data from PIPE input */ + if(!PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL)) + avail = 0; + if(!avail) + FD_CLR(fds, readfds); + } /* check if there is no data from keyboard input */ + else if (!_kbhit()) { + /* check if there are INPUT_RECORDs in the input buffer */ + if(GetNumberOfConsoleInputEvents(handle, &events)) { + if(events > 0) { + /* remove INPUT_RECORDs from the input buffer */ + inputrecords = (INPUT_RECORD*)malloc(events * + sizeof(INPUT_RECORD)); + if(inputrecords) { + if(!ReadConsoleInput(handle, inputrecords, + events, &inputs)) + inputs = 0; + free(inputrecords); + } + + /* check if we got all inputs, otherwise clear buffer */ + if(events != inputs) + FlushConsoleInputBuffer(handle); + } + } + + /* remove from descriptor set since there is no real data */ + FD_CLR(fds, readfds); + } + } + + /* stdin is never ready for write or exceptional */ + FD_CLR(fds, writefds); + FD_CLR(fds, exceptfds); + } + else if(fds == fileno(stdout) || fds == fileno(stderr)) { + /* stdout and stderr are never ready for read or exceptional */ + FD_CLR(fds, readfds); + FD_CLR(fds, exceptfds); + } + else { + /* try to handle the event with the WINSOCK2 functions */ + error = WSAEnumNetworkEvents(fds, NULL, &wsanetevents); + if(error != SOCKET_ERROR) { + /* remove from descriptor set if not ready for read/accept/close */ + if(!(wsanetevents.lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE))) + FD_CLR(fds, readfds); + + /* remove from descriptor set if not ready for write/connect */ + if(!(wsanetevents.lNetworkEvents & (FD_WRITE|FD_CONNECT))) + FD_CLR(fds, writefds); + + /* remove from descriptor set if not exceptional */ + if(!(wsanetevents.lNetworkEvents & FD_OOB)) + FD_CLR(fds, exceptfds); + } + } + + /* check if the event has not been filtered using specific tests */ + if(FD_ISSET(fds, readfds) || FD_ISSET(fds, writefds) || + FD_ISSET(fds, exceptfds)) { + ret++; + } } 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++; + /* remove from all descriptor sets since this handle did not trigger */ + FD_CLR(fds, readfds); + FD_CLR(fds, writefds); + FD_CLR(fds, exceptfds); } } - for(idx = 0; idx < wsa; idx++) + for(idx = 0; idx < wsa; idx++) { + WSAEventSelect(wsasocks[idx], NULL, 0); WSACloseEvent(wsaevents[idx]); + } free(wsaevents); + free(wsasocks); free(handles); free(fdarr); -- cgit v1.2.3