diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 1cf415295..af6cd049b 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,17 @@ +2004-04-03 Corinna Vinschen + + * fhandler.h (class fhandler_socket): Remove has_been_closed member. + * fhandler_socket.cc (fhandler_socket::recvfrom): Revert to + overlapped I/O. + (fhandler_socket::recvmsg): Ditto. + (fhandler_socket::sendto): Ditto. + (fhandler_socket::sendmsg): Ditto. + * net.cc (wsock_event::prepare): Ditto. + (wsock_event::wait): Ditto. Evaluate overlapped result also after + calling CancelIo (thanks to Patrick Samson ). + (wsock_event::release): Remove. + * wsock_event.h: Revert to overlapped I/O. + 2004-04-02 Corinna Vinschen * net.cc (wsock_event::release): Use NULL handle in call to diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index a38b50a55..0b5c71299 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -377,7 +377,6 @@ class fhandler_socket: public fhandler_base struct _WSAPROTOCOL_INFOA *prot_info_ptr; char *sun_path; int had_connect_or_listen; - int has_been_closed; public: fhandler_socket (); diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index 7f028ba0b..79e63e1ad 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -122,7 +122,7 @@ get_inet_addr (const struct sockaddr *in, int inlen, /* fhandler_socket */ fhandler_socket::fhandler_socket () - : fhandler_base (), sun_path (NULL), has_been_closed (0) + : fhandler_base (), sun_path (NULL) { set_need_fork_fixup (); prot_info_ptr = (LPWSAPROTOCOL_INFOA) cmalloc (HEAP_BUF, @@ -714,7 +714,7 @@ int fhandler_socket::recvfrom (void *ptr, size_t len, int flags, struct sockaddr *from, int *fromlen) { - int res = SOCKET_ERROR; + int res; DWORD ret; flags &= MSG_WINMASK; @@ -726,28 +726,19 @@ fhandler_socket::recvfrom (void *ptr, size_t len, int flags, { WSABUF wsabuf = { len, (char *) ptr }; - if (is_nonblocking () || has_been_closed) - res = WSARecvFrom (get_socket (), &wsabuf, 1, (ret = 0, &ret), - (DWORD *) &flags, from, fromlen, NULL, NULL); + if (is_nonblocking ()) + res = WSARecvFrom (get_socket (), &wsabuf, 1, &ret, (DWORD *) &flags, + from, fromlen, + NULL, NULL); else { wsock_event wsock_evt; - long evt = (FD_CLOSE | ((flags & MSG_OOB) ? FD_OOB : FD_READ)); - if (wsock_evt.prepare (get_socket (), evt)) - { - do - { - res = WSARecvFrom (get_socket (), &wsabuf, 1, - (ret = 0, &ret), (DWORD *) &flags, - from, fromlen, NULL, NULL); - } - while (res == SOCKET_ERROR - && WSAGetLastError () == WSAEWOULDBLOCK - && !has_been_closed - && !(res = wsock_evt.wait (get_socket (), - has_been_closed))); - wsock_evt.release (get_socket ()); - } + res = WSARecvFrom (get_socket (), &wsabuf, 1, &ret, (DWORD *) &flags, + from, fromlen, + wsock_evt.prepare (), NULL); + + if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING) + ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags); } } @@ -785,7 +776,7 @@ fhandler_socket::recvmsg (struct msghdr *msg, int flags, ssize_t tot) struct sockaddr *from = (struct sockaddr *) msg->msg_name; int *fromlen = from ? &msg->msg_namelen : NULL; - int res = SOCKET_ERROR; + int res; if (!winsock2_active) { @@ -852,29 +843,21 @@ fhandler_socket::recvmsg (struct msghdr *msg, int flags, ssize_t tot) DWORD ret; - if (is_nonblocking () || has_been_closed) + if (is_nonblocking ()) res = WSARecvFrom (get_socket (), - wsabuf, iovcnt, (ret = 0, &ret), (DWORD *) &flags, - from, fromlen, NULL, NULL); + wsabuf, iovcnt, &ret, (DWORD *) &flags, + from, fromlen, + NULL, NULL); else { wsock_event wsock_evt; - long evt = (FD_CLOSE | ((flags & MSG_OOB) ? FD_OOB : FD_READ)); - if (wsock_evt.prepare (get_socket (), evt)) - { - do - { - res = WSARecvFrom (get_socket (), wsabuf, iovcnt, - (ret = 0, &ret), (DWORD *) &flags, - from, fromlen, NULL, NULL); - } - while (res == SOCKET_ERROR - && WSAGetLastError () == WSAEWOULDBLOCK - && !has_been_closed - && !(res = wsock_evt.wait (get_socket (), - has_been_closed))); - wsock_evt.release (get_socket ()); - } + res = WSARecvFrom (get_socket (), + wsabuf, iovcnt, &ret, (DWORD *) &flags, + from, fromlen, + wsock_evt.prepare (), NULL); + + if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING) + ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags); } if (res == SOCKET_ERROR) @@ -917,9 +900,9 @@ fhandler_socket::sendto (const void *ptr, size_t len, int flags, sockaddr_in sin; if (to && !get_inet_addr (to, tolen, &sin, &tolen)) - return -1; + return SOCKET_ERROR; - int res = SOCKET_ERROR; + int res; DWORD ret; if (!winsock2_active) @@ -930,35 +913,21 @@ fhandler_socket::sendto (const void *ptr, size_t len, int flags, { WSABUF wsabuf = { len, (char *) ptr }; - if (is_nonblocking () || has_been_closed) - res = WSASendTo (get_socket (), &wsabuf, 1, (ret = 0, &ret), + if (is_nonblocking ()) + res = WSASendTo (get_socket (), &wsabuf, 1, &ret, flags & MSG_WINMASK, (to ? (const struct sockaddr *) &sin : NULL), tolen, NULL, NULL); else { wsock_event wsock_evt; - if (wsock_evt.prepare (get_socket (), FD_CLOSE | FD_WRITE)) - { - do - { - res = WSASendTo (get_socket (), &wsabuf, 1, (ret = 0, &ret), - flags & MSG_WINMASK, - (to ? (const struct sockaddr *) &sin : NULL), - tolen, NULL, NULL); - if (res != SOCKET_ERROR - || WSAGetLastError () != WSAEWOULDBLOCK) - break; - if (ret > 0) - { - res = 0; - break; - } - } - while (!(res = wsock_evt.wait (get_socket (), has_been_closed)) - && !has_been_closed); - wsock_evt.release (get_socket ()); - } + res = WSASendTo (get_socket (), &wsabuf, 1, &ret, + flags & MSG_WINMASK, + (to ? (const struct sockaddr *) &sin : NULL), tolen, + wsock_evt.prepare (), NULL); + + if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING) + ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags); } } @@ -998,7 +967,7 @@ fhandler_socket::sendmsg (const struct msghdr *msg, int flags, ssize_t tot) struct iovec *const iov = msg->msg_iov; const int iovcnt = msg->msg_iovlen; - int res = SOCKET_ERROR; + int res; if (!winsock2_active) { @@ -1067,34 +1036,21 @@ fhandler_socket::sendmsg (const struct msghdr *msg, int flags, ssize_t tot) DWORD ret; - if (is_nonblocking () || has_been_closed) - res = WSASendTo (get_socket (), wsabuf, iovcnt, (ret = 0, &ret), - flags, (struct sockaddr *) msg->msg_name, - msg->msg_namelen, NULL, NULL); + if (is_nonblocking ()) + res = WSASendTo (get_socket (), wsabuf, iovcnt, &ret, flags, + (struct sockaddr *) msg->msg_name, + msg->msg_namelen, + NULL, NULL); else { wsock_event wsock_evt; - if (wsock_evt.prepare (get_socket (), FD_CLOSE | FD_WRITE)) - { - do - { - res = WSASendTo (get_socket (), wsabuf, iovcnt, - (ret = 0, &ret), flags, - (struct sockaddr *) msg->msg_name, - msg->msg_namelen, NULL, NULL); - if (res != SOCKET_ERROR - || WSAGetLastError () != WSAEWOULDBLOCK) - break; - if (ret > 0) - { - res = 0; - break; - } - } - while (!(res = wsock_evt.wait (get_socket (), has_been_closed)) - && !has_been_closed); - wsock_evt.release (get_socket ()); - } + res = WSASendTo (get_socket (), wsabuf, iovcnt, &ret, flags, + (struct sockaddr *) msg->msg_name, + msg->msg_namelen, + wsock_evt.prepare (), NULL); + + if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING) + ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags); } if (res == SOCKET_ERROR) diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index 32b9f1f3e..c0c5b84c6 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -50,83 +50,59 @@ extern "C" int sscanf (const char *, const char *, ...); } /* End of "C" section */ -bool -wsock_event::prepare (int sock, long event_mask) +LPWSAOVERLAPPED +wsock_event::prepare () { - WSASetLastError (0); - if ((event = WSACreateEvent ()) == WSA_INVALID_EVENT) - debug_printf ("WSACreateEvent: %E"); - else if (WSAEventSelect (sock, event, event_mask) == SOCKET_ERROR) - { - debug_printf ("WSAEventSelect: %E"); - WSACloseEvent (event); - event = WSA_INVALID_EVENT; - } - return event != WSA_INVALID_EVENT; -} + LPWSAOVERLAPPED ret = NULL; -int -wsock_event::wait (int sock, int &closed) -{ - int ret = SOCKET_ERROR; - int wsa_err = 0; - WSAEVENT ev[2] = { event, signal_arrived }; - switch (WSAWaitForMultipleEvents (2, ev, FALSE, WSA_INFINITE, FALSE)) + SetLastError (0); + if ((event = WSACreateEvent ()) != WSA_INVALID_EVENT) { - case WSA_WAIT_EVENT_0: - WSANETWORKEVENTS evts; - if (!WSAEnumNetworkEvents (sock, event, &evts)) - { - if (evts.lNetworkEvents & FD_READ) - { - if (evts.iErrorCode[FD_READ_BIT]) - wsa_err = evts.iErrorCode[FD_READ_BIT]; - else - ret = 0; - } - else if (evts.lNetworkEvents & FD_WRITE) - { - if (evts.iErrorCode[FD_WRITE_BIT]) - wsa_err = evts.iErrorCode[FD_WRITE_BIT]; - else - ret = 0; - } - if (evts.lNetworkEvents & FD_CLOSE) - { - closed = 1; - if (!wsa_err) - { - if (evts.iErrorCode[FD_CLOSE_BIT]) - wsa_err = evts.iErrorCode[FD_CLOSE_BIT]; - else - ret = 0; - } - } - if (wsa_err) - WSASetLastError (wsa_err); - } - break; - case WSA_WAIT_EVENT_0 + 1: - WSASetLastError (WSAEINTR); - break; - default: - WSASetLastError (WSAEFAULT); + memset (&ovr, 0, sizeof ovr); + ovr.hEvent = event; + ret = &ovr; } + else if (GetLastError () == ERROR_PROC_NOT_FOUND) /* winsock2 not available */ + WSASetLastError (0); + + debug_printf ("%d = wsock_event::prepare ()", ret); return ret; } -void -wsock_event::release (int sock) +int +wsock_event::wait (int socket, LPDWORD flags) { - int last_err = WSAGetLastError (); - /* KB 168349: NT4 fails if the event parameter is not NULL. */ - WSAEventSelect (sock, NULL, 0); + int ret = SOCKET_ERROR; + WSAEVENT ev[2] = { event, signal_arrived }; + DWORD len; + + switch (WSAWaitForMultipleEvents (2, ev, FALSE, WSA_INFINITE, FALSE)) + { + case WSA_WAIT_EVENT_0: + if (WSAGetOverlappedResult (socket, &ovr, &len, FALSE, flags)) + ret = (int) len; + break; + case WSA_WAIT_EVENT_0 + 1: + if (!CancelIo ((HANDLE) socket)) + { + debug_printf ("CancelIo() %E, fallback to blocking io"); + WSAGetOverlappedResult (socket, &ovr, &len, TRUE, flags); + } + else if (WSAGetOverlappedResult (socket, &ovr, &len, FALSE, flags) + && len > 0) + ret = (int) len; + else + WSASetLastError (WSAEINTR); + break; + case WSA_WAIT_FAILED: + break; + default: /* Should be impossible. *LOL* */ + WSASetLastError (WSAEFAULT); + break; + } WSACloseEvent (event); - unsigned long non_block = 0; - if (ioctlsocket (sock, FIONBIO, &non_block)) - debug_printf ("return to blocking failed: %d", WSAGetLastError ()); - else - WSASetLastError (last_err); + event = NULL; + return ret; } WSADATA wsadata; diff --git a/winsup/cygwin/wsock_event.h b/winsup/cygwin/wsock_event.h index 5383a797b..3f8638134 100644 --- a/winsup/cygwin/wsock_event.h +++ b/winsup/cygwin/wsock_event.h @@ -14,13 +14,19 @@ details. */ class wsock_event { WSAEVENT event; + WSAOVERLAPPED ovr; public: wsock_event () : event (NULL) {}; + ~wsock_event () + { + if (event) + WSACloseEvent (event); + event = NULL; + }; /* The methods are implemented in net.cc */ - bool prepare (int sock, long event_mask); - int wait (int sock, int &closed); - void release (int sock); + LPWSAOVERLAPPED prepare (); + int wait (int socket, LPDWORD flags); }; #endif /* __WSOCK_EVENT_H__ */