* 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