* 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.
This commit is contained in:
parent
9f64fd8081
commit
2483fa2719
|
@ -1,3 +1,16 @@
|
|||
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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue