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)
{
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)

View File

@ -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)

View File

@ -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 */

View File

@ -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.