[newlib-cygwin] Cygwin: connect: implement resetting a connected DGRAM socket
Ken Brown
kbrown@sourceware.org
Tue Apr 27 14:16:07 GMT 2021
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=3b0ba6535218631b1ab467cd29d36b1eae4a0af6
commit 3b0ba6535218631b1ab467cd29d36b1eae4a0af6
Author: Ken Brown <kbrown@cornell.edu>
Date: Fri Apr 23 18:17:57 2021 -0400
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.
Diff:
---
winsup/cygwin/fhandler_socket_inet.cc | 21 +++++++++++++++++++--
winsup/cygwin/fhandler_socket_local.cc | 30 +++++++++++++++++++++++++-----
winsup/cygwin/fhandler_socket_unix.cc | 7 +++++++
winsup/cygwin/release/3.2.1 | 5 +++++
4 files changed, 56 insertions(+), 7 deletions(-)
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.
More information about the Cygwin-cvs
mailing list