Cygwin: connect: implement resetting a connected DGRAM socket

Following POSIX and Linux, allow a connected DGRAM socket's connection
to be reset (so that the socket becomes unconnected).  This is done by
calling connect and specifing an address whose family is AF_UNSPEC.
This commit is contained in:
Ken Brown 2021-04-23 18:17:57 -04:00
parent 2be07f7554
commit 3b0ba65352
4 changed files with 56 additions and 7 deletions

View File

@ -781,8 +781,20 @@ int
fhandler_socket_inet::connect (const struct sockaddr *name, int namelen) fhandler_socket_inet::connect (const struct sockaddr *name, int namelen)
{ {
struct sockaddr_storage sst; 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; return SOCKET_ERROR;
/* Initialize connect state to "connect_pending". In the SOCK_STREAM /* 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); int res = ::connect (get_socket (), (struct sockaddr *) &sst, namelen);
if (!res) if (!res)
{
if (reset)
connect_state (unconnected);
else
connect_state (connected); connect_state (connected);
}
else if (!is_nonblocking () else if (!is_nonblocking ()
&& res == SOCKET_ERROR && res == SOCKET_ERROR
&& WSAGetLastError () == WSAEWOULDBLOCK) && WSAGetLastError () == WSAEWOULDBLOCK)

View File

@ -894,18 +894,33 @@ fhandler_socket_local::connect (const struct sockaddr *name, int namelen)
{ {
struct sockaddr_storage sst; struct sockaddr_storage sst;
int type = 0; 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) if (reset)
== SOCKET_ERROR) {
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; return SOCKET_ERROR;
if (get_socket_type () != type) if (get_socket_type () != type && !reset)
{ {
WSASetLastError (WSAEPROTOTYPE); WSASetLastError (WSAEPROTOTYPE);
set_winsock_errno (); set_winsock_errno ();
return SOCKET_ERROR; return SOCKET_ERROR;
} }
if (reset)
set_peer_sun_path (NULL);
else
set_peer_sun_path (name->sa_data); set_peer_sun_path (name->sa_data);
/* Don't move af_local_set_cred into af_local_connect which may be called /* Don't move af_local_set_cred into af_local_connect which may be called
@ -933,7 +948,12 @@ fhandler_socket_local::connect (const struct sockaddr *name, int namelen)
int res = ::connect (get_socket (), (struct sockaddr *) &sst, namelen); int res = ::connect (get_socket (), (struct sockaddr *) &sst, namelen);
if (!res) if (!res)
{
if (reset)
connect_state (unconnected);
else
connect_state (connected); connect_state (connected);
}
else if (!is_nonblocking () else if (!is_nonblocking ()
&& res == SOCKET_ERROR && res == SOCKET_ERROR
&& WSAGetLastError () == WSAEWOULDBLOCK) && WSAGetLastError () == WSAEWOULDBLOCK)

View File

@ -1696,6 +1696,13 @@ fhandler_socket_unix::connect (const struct sockaddr *name, int namelen)
conn_unlock (); conn_unlock ();
return -1; 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); connect_state (connect_pending);
conn_unlock (); conn_unlock ();
/* Check validity of name */ /* Check validity of name */

View File

@ -28,3 +28,8 @@ Bug Fixes
- Fix a bug in recognizing a successful completion of connect(2) on a - Fix a bug in recognizing a successful completion of connect(2) on a
datagram socket. 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.