Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/winsup
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2014-10-11 16:14:29 +0400
committerCorinna Vinschen <corinna@vinschen.de>2014-10-11 16:14:29 +0400
commit2483fa271906edb01c1aa9ea1a9c5c7e0fc6a8c0 (patch)
treec630d3bf82cb6d4d63582b5a6caf423906b6a3dc /winsup
parent9f64fd80819b80513fadfe842622cf6d3853c1c0 (diff)
* 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')
-rw-r--r--winsup/cygwin/ChangeLog13
-rw-r--r--winsup/cygwin/fhandler_socket.cc96
-rw-r--r--winsup/cygwin/poll.cc5
-rw-r--r--winsup/cygwin/select.cc14
4 files changed, 71 insertions, 57 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 4c558dd19..332bc33fd 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,5 +1,18 @@
2014-10-11 Corinna Vinschen <corinna@vinschen.de>
+ * 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.
+
+2014-10-11 Corinna Vinschen <corinna@vinschen.de>
+
* fhandler_socket.cc (fhandler_socket::evaluate_events): Slightly
rearrange code. Rephrase a comment.
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;
}
diff --git a/winsup/cygwin/poll.cc b/winsup/cygwin/poll.cc
index 17411a098..2b6f8a90a 100644
--- a/winsup/cygwin/poll.cc
+++ b/winsup/cygwin/poll.cc
@@ -115,8 +115,9 @@ poll (struct pollfd *fds, nfds_t nfds, int timeout)
So it looks like there's actually no good reason to
return POLLERR. */
fds[i].revents |= POLLIN;
- /* Handle failed connect. */
- if (FD_ISSET(fds[i].fd, write_fds)
+ /* Handle failed connect. A failed connect implicitly sets
+ POLLOUT, if requested, but it doesn't set POLLIN. */
+ if ((fds[i].events & POLLIN)
&& (sock = cygheap->fdtab[fds[i].fd]->is_socket ())
&& sock->connect_state () == connect_failed)
fds[i].revents |= (POLLIN | POLLERR);
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 6a396852a..c72cd0c76 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -480,16 +480,10 @@ set_bits (select_record *me, fd_set *readfds, fd_set *writefds,
UNIX_FD_SET (me->fd, writefds);
if (me->except_on_write && (sock = me->fh->is_socket ()))
{
- /* Special AF_LOCAL handling. */
- if (!me->read_ready && sock->connect_state () == connect_pending
- && sock->af_local_connect ())
- {
- if (me->read_selected)
- UNIX_FD_SET (me->fd, readfds);
- sock->connect_state (connect_failed);
- }
- else
- sock->connect_state (connected);
+ /* Set readfds entry in case of a failed connect. */
+ if (!me->read_ready && me->read_selected
+ && sock->connect_state () == connect_failed)
+ UNIX_FD_SET (me->fd, readfds);
}
ready++;
}