diff --git a/winsup/cygwin/fhandler_socket_inet.cc b/winsup/cygwin/fhandler_socket_inet.cc index 4ecb31a27..f6bb8c503 100644 --- a/winsup/cygwin/fhandler_socket_inet.cc +++ b/winsup/cygwin/fhandler_socket_inet.cc @@ -785,11 +785,13 @@ fhandler_socket_inet::connect (const struct sockaddr *name, int namelen) if (get_inet_addr_inet (name, namelen, &sst, &namelen) == SOCKET_ERROR) return SOCKET_ERROR; - /* Initialize connect state to "connect_pending". State is ultimately set - to "connected" or "connect_failed" in wait_for_events when the FD_CONNECT - event occurs. Note that the underlying OS sockets are always non-blocking - and a successfully initiated non-blocking Winsock connect always returns - WSAEWOULDBLOCK. Thus it's safe to rely on event handling. + /* Initialize connect state to "connect_pending". In the SOCK_STREAM + case, the state is ultimately set to "connected" or "connect_failed" in + wait_for_events when the FD_CONNECT event occurs. Note that the + underlying OS sockets are always non-blocking in this case and a + successfully initiated non-blocking Winsock connect always returns + WSAEWOULDBLOCK. Thus it's safe to rely on event handling. For DGRAM + sockets, however, connect can return immediately. Check for either unconnected or connect_failed since in both cases it's allowed to retry connecting the socket. It's also ok (albeit ugly) to @@ -801,7 +803,9 @@ fhandler_socket_inet::connect (const struct sockaddr *name, int namelen) connect_state (connect_pending); int res = ::connect (get_socket (), (struct sockaddr *) &sst, namelen); - if (!is_nonblocking () + if (!res) + connect_state (connected); + else if (!is_nonblocking () && res == SOCKET_ERROR && WSAGetLastError () == WSAEWOULDBLOCK) res = wait_for_events (FD_CONNECT | FD_CLOSE, 0); @@ -824,8 +828,7 @@ fhandler_socket_inet::connect (const struct sockaddr *name, int namelen) Convert to POSIX/Linux compliant EISCONN. */ else if (err == WSAEINVAL && connect_state () == listener) WSASetLastError (WSAEISCONN); - /* Any other error except WSAEALREADY during connect_pending means the - connect failed. */ + /* Any other error except WSAEALREADY means the connect failed. */ else if (connect_state () == connect_pending && err != WSAEALREADY) connect_state (connect_failed); set_winsock_errno (); diff --git a/winsup/cygwin/fhandler_socket_local.cc b/winsup/cygwin/fhandler_socket_local.cc index ad7dd0a98..1c8d48b58 100644 --- a/winsup/cygwin/fhandler_socket_local.cc +++ b/winsup/cygwin/fhandler_socket_local.cc @@ -914,11 +914,13 @@ fhandler_socket_local::connect (const struct sockaddr *name, int namelen) if (get_socket_type () == SOCK_STREAM) af_local_set_cred (); - /* Initialize connect state to "connect_pending". State is ultimately set - to "connected" or "connect_failed" in wait_for_events when the FD_CONNECT - event occurs. Note that the underlying OS sockets are always non-blocking - and a successfully initiated non-blocking Winsock connect always returns - WSAEWOULDBLOCK. Thus it's safe to rely on event handling. + /* Initialize connect state to "connect_pending". In the SOCK_STREAM + case, the state is ultimately set to "connected" or "connect_failed" in + wait_for_events when the FD_CONNECT event occurs. Note that the + underlying OS sockets are always non-blocking in this case and a + successfully initiated non-blocking Winsock connect always returns + WSAEWOULDBLOCK. Thus it's safe to rely on event handling. For DGRAM + sockets, however, connect can return immediately. Check for either unconnected or connect_failed since in both cases it's allowed to retry connecting the socket. It's also ok (albeit ugly) to @@ -930,7 +932,9 @@ fhandler_socket_local::connect (const struct sockaddr *name, int namelen) connect_state (connect_pending); int res = ::connect (get_socket (), (struct sockaddr *) &sst, namelen); - if (!is_nonblocking () + if (!res) + connect_state (connected); + else if (!is_nonblocking () && res == SOCKET_ERROR && WSAGetLastError () == WSAEWOULDBLOCK) res = wait_for_events (FD_CONNECT | FD_CLOSE, 0); @@ -953,8 +957,7 @@ fhandler_socket_local::connect (const struct sockaddr *name, int namelen) Convert to POSIX/Linux compliant EISCONN. */ else if (err == WSAEINVAL && connect_state () == listener) WSASetLastError (WSAEISCONN); - /* Any other error except WSAEALREADY during connect_pending means the - connect failed. */ + /* Any other error except WSAEALREADY means the connect failed. */ else if (connect_state () == connect_pending && err != WSAEALREADY) connect_state (connect_failed); set_winsock_errno (); diff --git a/winsup/cygwin/release/3.2.1 b/winsup/cygwin/release/3.2.1 index c1ada5d50..7662c7114 100644 --- a/winsup/cygwin/release/3.2.1 +++ b/winsup/cygwin/release/3.2.1 @@ -12,7 +12,7 @@ Bug Fixes - Fix values returned by select(2) for shutdown sockets. Addresses: https://cygwin.com/pipermail/cygwin-developers/2021-April/012092.html -- Introduce a new hypotl(3) function not suffering unnecesswry overflows. +- Introduce a new hypotl(3) function not suffering unnecessary overflows. Addresses: https://cygwin.com/pipermail/cygwin/2021-April/248302.html - Fix path handling for paths spanning native symlinks. @@ -25,3 +25,6 @@ Bug Fixes - Handle two race conditions in pseudo console usage. Addresses: https://cygwin.com/pipermail/cygwin/2021-April/248292.html + +- Fix a bug in recognizing a successful completion of connect(2) on a + datagram socket.