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:
parent
2be07f7554
commit
3b0ba65352
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue