diff --git a/winsup/cygwin/fhandler_socket_inet.cc b/winsup/cygwin/fhandler_socket_inet.cc index f6bb8c503..30eab4099 100644 --- a/winsup/cygwin/fhandler_socket_inet.cc +++ b/winsup/cygwin/fhandler_socket_inet.cc @@ -781,8 +781,20 @@ int fhandler_socket_inet::connect (const struct sockaddr *name, int namelen) { struct sockaddr_storage sst; + bool reset = (name->sa_family == AF_UNSPEC + && get_socket_type () == SOCK_DGRAM); - if (get_inet_addr_inet (name, namelen, &sst, &namelen) == SOCKET_ERROR) + if (reset) + { + if (connect_state () == unconnected) + return 0; + /* To reset a connected DGRAM socket, call Winsock's connect + function with the address member of the sockaddr structure + filled with zeroes. */ + memset (&sst, 0, sizeof sst); + sst.ss_family = get_addr_family (); + } + else if (get_inet_addr_inet (name, namelen, &sst, &namelen) == SOCKET_ERROR) return SOCKET_ERROR; /* Initialize connect state to "connect_pending". In the SOCK_STREAM @@ -804,7 +816,12 @@ fhandler_socket_inet::connect (const struct sockaddr *name, int namelen) int res = ::connect (get_socket (), (struct sockaddr *) &sst, namelen); if (!res) - connect_state (connected); + { + if (reset) + connect_state (unconnected); + else + connect_state (connected); + } else if (!is_nonblocking () && res == SOCKET_ERROR && WSAGetLastError () == WSAEWOULDBLOCK) diff --git a/winsup/cygwin/fhandler_socket_local.cc b/winsup/cygwin/fhandler_socket_local.cc index 1c8d48b58..bd4081622 100644 --- a/winsup/cygwin/fhandler_socket_local.cc +++ b/winsup/cygwin/fhandler_socket_local.cc @@ -894,19 +894,34 @@ fhandler_socket_local::connect (const struct sockaddr *name, int namelen) { struct sockaddr_storage sst; int type = 0; + bool reset = (name->sa_family == AF_UNSPEC + && get_socket_type () == SOCK_DGRAM); - if (get_inet_addr_local (name, namelen, &sst, &namelen, &type, connect_secret) - == SOCKET_ERROR) + if (reset) + { + if (connect_state () == unconnected) + return 0; + /* To reset a connected DGRAM socket, call Winsock's connect + function with the address member of the sockaddr structure + filled with zeroes. */ + memset (&sst, 0, sizeof sst); + sst.ss_family = get_addr_family (); + } + else if (get_inet_addr_local (name, namelen, &sst, &namelen, &type, + connect_secret) == SOCKET_ERROR) return SOCKET_ERROR; - if (get_socket_type () != type) + if (get_socket_type () != type && !reset) { WSASetLastError (WSAEPROTOTYPE); set_winsock_errno (); return SOCKET_ERROR; } - set_peer_sun_path (name->sa_data); + if (reset) + set_peer_sun_path (NULL); + else + set_peer_sun_path (name->sa_data); /* Don't move af_local_set_cred into af_local_connect which may be called via select, possibly running under another identity. Call early here, @@ -933,7 +948,12 @@ fhandler_socket_local::connect (const struct sockaddr *name, int namelen) int res = ::connect (get_socket (), (struct sockaddr *) &sst, namelen); if (!res) - connect_state (connected); + { + if (reset) + connect_state (unconnected); + else + connect_state (connected); + } else if (!is_nonblocking () && res == SOCKET_ERROR && WSAGetLastError () == WSAEWOULDBLOCK) diff --git a/winsup/cygwin/fhandler_socket_unix.cc b/winsup/cygwin/fhandler_socket_unix.cc index 252bcd9a9..a2428e952 100644 --- a/winsup/cygwin/fhandler_socket_unix.cc +++ b/winsup/cygwin/fhandler_socket_unix.cc @@ -1696,6 +1696,13 @@ fhandler_socket_unix::connect (const struct sockaddr *name, int namelen) conn_unlock (); return -1; } + if (name->sa_family == AF_UNSPEC && get_socket_type () == SOCK_DGRAM) + { + connect_state (unconnected); + peer_sun_path (NULL); + conn_unlock (); + return 0; + } connect_state (connect_pending); conn_unlock (); /* Check validity of name */ diff --git a/winsup/cygwin/release/3.2.1 b/winsup/cygwin/release/3.2.1 index 7662c7114..6ebe68fa6 100644 --- a/winsup/cygwin/release/3.2.1 +++ b/winsup/cygwin/release/3.2.1 @@ -28,3 +28,8 @@ Bug Fixes - Fix a bug in recognizing a successful completion of connect(2) on a datagram socket. + +- Fix connect(2) when called with an address structure whose family is + AF_UNSPEC. As specified by POSIX and Linux, this is allowed on + datagram sockets, and its effect is to reset the socket's peer + address.