--- fhandler_socket.cc.org 2003-06-03 09:14:03.000000000 +0200 +++ fhandler_socket.cc 2003-06-03 11:05:18.000000000 +0200 @@ -33,6 +33,7 @@ #include "sigproc.h" #include "wsock_event.h" #include "cygthread.h" +#include "select.h" #include #define ENTROPY_SOURCE_DEV_UNIT 9 @@ -125,6 +126,7 @@ struct sock_thread_data int socket; sockaddr *peer; int *len; + int winsock_err; int ret; }; @@ -132,7 +134,42 @@ static DWORD WINAPI connect_thread (void *arg) { sock_thread_data *std = (sock_thread_data *) arg; + unsigned long nonblocking = 1; + + ioctlsocket (std->socket, FIONBIO, &nonblocking); + std->ret = ::connect (std->socket, std->peer, *std->len); + std->winsock_err = WSAGetLastError (); + if (std->ret && std->winsock_err == WSAEWOULDBLOCK) + { + winsock_fd_set wrfds; + winsock_fd_set excfds; + + WINSOCK_FD_ZERO (&wrfds); + WINSOCK_FD_ZERO (&excfds); + WINSOCK_FD_SET ((HANDLE) std->socket, &wrfds); + WINSOCK_FD_SET ((HANDLE) std->socket, &excfds); + + if ((std->ret = WINSOCK_SELECT (0, NULL, &wrfds, &excfds, NULL)) > 0) + if (WINSOCK_FD_ISSET ((HANDLE) std->socket, &wrfds)) + /* connect has succeded */ + std->ret = 0; + else + { + std->ret = -1; + for (;;) + { + int winsock_err_len = sizeof(std->winsock_err); + getsockopt (std->socket, SOL_SOCKET, SO_ERROR, + (char *) &std->winsock_err, &winsock_err_len); + /* The socket error can not be 0 if socket is set in excfds */ + if (std->winsock_err) + break; + low_priority_sleep (0); + } + } + } + return 0; } @@ -140,7 +177,15 @@ static DWORD WINAPI accept_thread (void *arg) { sock_thread_data *std = (sock_thread_data *) arg; - std->ret = ::accept (std->socket, std->peer, std->len); + + winsock_fd_set rdfds; + + WINSOCK_FD_ZERO(&rdfds); + WINSOCK_FD_SET((HANDLE)std->socket, &rdfds); + + std->ret = WINSOCK_SELECT (0, &rdfds, NULL, NULL, NULL); + std->winsock_err = WSAGetLastError (); + return 0; } @@ -532,13 +577,20 @@ fhandler_socket::connect (const struct s if (!is_nonblocking ()) { - sock_thread_data cd = { get_socket (), (sockaddr *) &sin, &namelen, -1 }; + unsigned long nonblocking = 0; + sock_thread_data cd = { get_socket (), (sockaddr *) &sin, &namelen, 0, -1 }; cygthread *thread = new cygthread (connect_thread, &cd, "connect"); HANDLE waitevt = CreateEvent(&sec_none_nih, FALSE, TRUE, NULL); interrupted = thread->detach (waitevt); CloseHandle (waitevt); - if (!interrupted) - res = cd.ret; + ioctlsocket (get_socket (), FIONBIO, &nonblocking); + if (interrupted) + WSASetLastError (WSAEINPROGRESS); + else + { + WSASetLastError (cd.winsock_err); + res = cd.ret; + } } else res = ::connect (get_socket (), (sockaddr *) &sin, namelen); @@ -640,14 +692,20 @@ fhandler_socket::accept (struct sockaddr if (!is_nonblocking ()) { - sock_thread_data ad = { get_socket (), peer, len, -1 }; + sock_thread_data ad = { get_socket (), NULL, 0, 0, -1 }; cygthread *thread = new cygthread (accept_thread, &ad, "accept"); HANDLE waitevt = CreateEvent(&sec_none_nih, FALSE, TRUE, NULL); BOOL interrupted = thread->detach (waitevt); CloseHandle (waitevt); if (interrupted) return -1; - res = ad.ret; + if (ad.ret > 0) + res = ::accept (get_socket (), peer, len); + else + { + WSASetLastError (ad.winsock_err); + res = ad.ret; + } } else res = ::accept (get_socket (), peer, len);