summaryrefslogtreecommitdiffstats
path: root/winsup/cygwin/fhandler_socket.cc
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2014-10-11 12:14:29 +0000
committerCorinna Vinschen <corinna@vinschen.de>2014-10-11 12:14:29 +0000
commit2483fa271906edb01c1aa9ea1a9c5c7e0fc6a8c0 (patch)
treec630d3bf82cb6d4d63582b5a6caf423906b6a3dc /winsup/cygwin/fhandler_socket.cc
parent9f64fd80819b80513fadfe842622cf6d3853c1c0 (diff)
downloadcygnal-2483fa271906edb01c1aa9ea1a9c5c7e0fc6a8c0.tar.gz
cygnal-2483fa271906edb01c1aa9ea1a9c5c7e0fc6a8c0.tar.bz2
cygnal-2483fa271906edb01c1aa9ea1a9c5c7e0fc6a8c0.zip
* fhandler_socket.cc (fhandler_socket::evaluate_events): Handle
connect_state and af_local_connect connect call here, once, independent of FD_CONNECT being requested. Add comment to explain why. (fhandler_socket::connect): Drop connect_state handling and calling af_local_connect. Move remaining AF_LOCAL stuff prior to calling ::connect and explain why. Simplify error case. * poll.cc (poll): Handle connect state independently of POLLOUT being requested for the descriptor to allow setting POLLIN if connect failed. Add comment. * select.cc (set_bits): Drop connect_state and AF_LOCAL handling here.
Diffstat (limited to 'winsup/cygwin/fhandler_socket.cc')
-rw-r--r--winsup/cygwin/fhandler_socket.cc96
1 files changed, 51 insertions, 45 deletions
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
index 93cfddf6a..f0258c31e 100644
--- a/winsup/cygwin/fhandler_socket.cc
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -621,7 +621,26 @@ fhandler_socket::evaluate_events (const long event_mask, long &events,
wsock_events->events |= evts.lNetworkEvents;
events_now = (wsock_events->events & event_mask);
if (evts.lNetworkEvents & FD_CONNECT)
- wsock_events->connect_errorcode = evts.iErrorCode[FD_CONNECT_BIT];
+ {
+ wsock_events->connect_errorcode = evts.iErrorCode[FD_CONNECT_BIT];
+ /* Setting the connect_state and calling the AF_LOCAL handshake
+ here allows to handle this stuff from a single point. This
+ is independent of FD_CONNECT being requested. Consider a
+ server calling connect(2) and then immediately poll(2) with
+ only polling for POLLIN (example: postfix), or select(2) just
+ asking for descriptors ready to read). */
+ if (wsock_events->connect_errorcode)
+ connect_state (connect_failed);
+ else if (get_addr_family () == AF_LOCAL
+ && get_socket_type () == SOCK_STREAM
+ && af_local_connect ())
+ {
+ wsock_events->connect_errorcode = WSAGetLastError ();
+ connect_state (connect_failed);
+ }
+ else
+ connect_state (connected);
+ }
UNLOCK_EVENTS;
if ((evts.lNetworkEvents & FD_OOB) && wsock_events->owner)
kill (wsock_events->owner, SIGURG);
@@ -1084,21 +1103,35 @@ out:
int
fhandler_socket::connect (const struct sockaddr *name, int namelen)
{
- bool in_progress = false;
struct sockaddr_storage sst;
- DWORD err;
int type;
if (get_inet_addr (name, namelen, &sst, &namelen, &type, connect_secret)
== SOCKET_ERROR)
return SOCKET_ERROR;
- if (get_addr_family () == AF_LOCAL && get_socket_type () != type)
+ if (get_addr_family () == AF_LOCAL)
{
- WSASetLastError (WSAEPROTOTYPE);
- set_winsock_errno ();
- return SOCKET_ERROR;
+ if (get_socket_type () != type)
+ {
+ WSASetLastError (WSAEPROTOTYPE);
+ set_winsock_errno ();
+ return SOCKET_ERROR;
+ }
+
+ 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,
+ because af_local_connect is called in wait_for_events. */
+ if (get_socket_type () == SOCK_STREAM)
+ af_local_set_cred ();
}
+
+ /* Initialize connect state to "connect_pending". State is ultimately set
+ to "connected" or "connect_failed" in wait_for_events when the FD_CONNECT
+ event occurs. */
+ connect_state (connect_pending);
int res = ::connect (get_socket (), (struct sockaddr *) &sst, namelen);
if (!is_nonblocking ()
@@ -1106,48 +1139,21 @@ fhandler_socket::connect (const struct sockaddr *name, int namelen)
&& WSAGetLastError () == WSAEWOULDBLOCK)
res = wait_for_events (FD_CONNECT | FD_CLOSE, 0);
- if (!res)
- err = 0;
- else
+ if (res)
{
- err = WSAGetLastError ();
- /* Special handling for connect to return the correct error code
- when called on a non-blocking socket. */
- if (is_nonblocking ())
- {
- if (err == WSAEWOULDBLOCK || err == WSAEALREADY)
- in_progress = true;
-
- if (err == WSAEWOULDBLOCK)
- WSASetLastError (err = WSAEINPROGRESS);
- }
- if (err == WSAEINVAL)
- WSASetLastError (err = WSAEISCONN);
+ DWORD err = WSAGetLastError ();
+
+ /* Winsock returns WSAEWOULDBLOCK if the non-blocking socket cannot be
+ conected immediately. Convert to POSIX/Linux compliant EINPROGRESS. */
+ if (is_nonblocking () && err == WSAEWOULDBLOCK)
+ WSASetLastError (WSAEINPROGRESS);
+ /* Winsock returns WSAEINVAL if the socket is already a listener.
+ Convert to POSIX/Linux compliant EISCONN. */
+ else if (err == WSAEINVAL)
+ WSASetLastError (WSAEISCONN);
set_winsock_errno ();
}
- if (get_addr_family () == AF_LOCAL && (!res || in_progress))
- set_peer_sun_path (name->sa_data);
-
- if (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM)
- {
- af_local_set_cred (); /* Don't move into af_local_connect since
- af_local_connect is called from select,
- possibly running under another identity. */
- if (!res && af_local_connect ())
- {
- set_winsock_errno ();
- return SOCKET_ERROR;
- }
- }
-
- if (err == WSAEINPROGRESS || err == WSAEALREADY)
- connect_state (connect_pending);
- else if (err)
- connect_state (connect_failed);
- else
- connect_state (connected);
-
return res;
}