mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	Issue #23618: Refactor internal_connect()
On Windows, internal_connect() now reuses internal_connect_select() and always calls getsockopt().
This commit is contained in:
		
							parent
							
								
									dd88d3db45
								
							
						
					
					
						commit
						b6c15bcad3
					
				
					 1 changed files with 30 additions and 79 deletions
				
			
		| 
						 | 
				
			
			@ -2299,7 +2299,8 @@ sock_setsockopt(PySocketSockObject *s, PyObject *args)
 | 
			
		|||
 | 
			
		||||
    if (PyArg_ParseTuple(args, "iii:setsockopt",
 | 
			
		||||
                         &level, &optname, &flag)) {
 | 
			
		||||
        res = setsockopt(s->sock_fd, level, optname, &flag, sizeof flag);
 | 
			
		||||
        res = setsockopt(s->sock_fd, level, optname,
 | 
			
		||||
                         (char*)&flag, sizeof flag);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        PyErr_Clear();
 | 
			
		||||
| 
						 | 
				
			
			@ -2450,7 +2451,17 @@ static int
 | 
			
		|||
internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
 | 
			
		||||
                 int *timeoutp)
 | 
			
		||||
{
 | 
			
		||||
    int err, res, timeout;
 | 
			
		||||
#ifdef MS_WINDOWS
 | 
			
		||||
#  define GET_ERROR WSAGetLastError()
 | 
			
		||||
#  define IN_PROGRESS_ERR WSAEWOULDBLOCK
 | 
			
		||||
#  define TIMEOUT_ERR WSAEWOULDBLOCK
 | 
			
		||||
#else
 | 
			
		||||
#  define GET_ERROR errno
 | 
			
		||||
#  define IN_PROGRESS_ERR EINPROGRESS
 | 
			
		||||
#  define TIMEOUT_ERR EWOULDBLOCK
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    int res, err, in_progress, timeout;
 | 
			
		||||
 | 
			
		||||
    timeout = 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2458,105 +2469,45 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
 | 
			
		|||
    res = connect(s->sock_fd, addr, addrlen);
 | 
			
		||||
    Py_END_ALLOW_THREADS
 | 
			
		||||
 | 
			
		||||
#ifdef MS_WINDOWS
 | 
			
		||||
 | 
			
		||||
    if (res < 0)
 | 
			
		||||
        err = WSAGetLastError();
 | 
			
		||||
        err = GET_ERROR;
 | 
			
		||||
    else
 | 
			
		||||
        err = res;
 | 
			
		||||
    in_progress = (err == IN_PROGRESS_ERR);
 | 
			
		||||
 | 
			
		||||
    if (s->sock_timeout > 0 && err == WSAEWOULDBLOCK && IS_SELECTABLE(s)) {
 | 
			
		||||
        /* This is a mess.  Best solution: trust select */
 | 
			
		||||
        fd_set fds;
 | 
			
		||||
        fd_set fds_exc;
 | 
			
		||||
        struct timeval tv;
 | 
			
		||||
        int conv;
 | 
			
		||||
 | 
			
		||||
        _PyTime_AsTimeval_noraise(s->sock_timeout, &tv, _PyTime_ROUND_CEILING);
 | 
			
		||||
 | 
			
		||||
        Py_BEGIN_ALLOW_THREADS
 | 
			
		||||
        FD_ZERO(&fds);
 | 
			
		||||
        FD_SET(s->sock_fd, &fds);
 | 
			
		||||
        FD_ZERO(&fds_exc);
 | 
			
		||||
        FD_SET(s->sock_fd, &fds_exc);
 | 
			
		||||
        res = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int),
 | 
			
		||||
                     NULL, &fds, &fds_exc, &tv);
 | 
			
		||||
        Py_END_ALLOW_THREADS
 | 
			
		||||
 | 
			
		||||
        if (res == 0) {
 | 
			
		||||
            err = WSAEWOULDBLOCK;
 | 
			
		||||
            timeout = 1;
 | 
			
		||||
        }
 | 
			
		||||
        else if (res > 0) {
 | 
			
		||||
            if (FD_ISSET(s->sock_fd, &fds)) {
 | 
			
		||||
                /* The socket is in the writable set - this
 | 
			
		||||
                   means connected */
 | 
			
		||||
                err = 0;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                /* As per MS docs, we need to call getsockopt()
 | 
			
		||||
                   to get the underlying error */
 | 
			
		||||
                int res_size;
 | 
			
		||||
 | 
			
		||||
                /* It must be in the exception set */
 | 
			
		||||
                assert(FD_ISSET(s->sock_fd, &fds_exc));
 | 
			
		||||
 | 
			
		||||
                res_size = sizeof res;
 | 
			
		||||
                if (!getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR,
 | 
			
		||||
                                    (char *)&res, &res_size)) {
 | 
			
		||||
                    err = res;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    err = WSAGetLastError();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            /* select() failed */
 | 
			
		||||
            err = WSAGetLastError();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
    if (res < 0)
 | 
			
		||||
        err = errno;
 | 
			
		||||
    else
 | 
			
		||||
        err = 0;
 | 
			
		||||
 | 
			
		||||
    if (s->sock_timeout > 0 && err == EINPROGRESS && IS_SELECTABLE(s)) {
 | 
			
		||||
 | 
			
		||||
    if (s->sock_timeout > 0 && in_progress && IS_SELECTABLE(s)) {
 | 
			
		||||
        timeout = internal_connect_select(s);
 | 
			
		||||
 | 
			
		||||
        if (timeout == 0) {
 | 
			
		||||
            /* Bug #1019808: in case of an EINPROGRESS,
 | 
			
		||||
               use getsockopt(SO_ERROR) to get the real
 | 
			
		||||
               error. */
 | 
			
		||||
        if (timeout == 1) {
 | 
			
		||||
            /* timed out */
 | 
			
		||||
            err = TIMEOUT_ERR;
 | 
			
		||||
        }
 | 
			
		||||
        else if (timeout == 0) {
 | 
			
		||||
            socklen_t res_size = sizeof res;
 | 
			
		||||
            if (!getsockopt(s->sock_fd, SOL_SOCKET,
 | 
			
		||||
                            SO_ERROR, &res, &res_size)) {
 | 
			
		||||
            if (!getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR,
 | 
			
		||||
                            (char*)&res, &res_size)) {
 | 
			
		||||
                if (res == EISCONN)
 | 
			
		||||
                    res = 0;
 | 
			
		||||
                err = res;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                /* getsockopt() failed */
 | 
			
		||||
                err = errno;
 | 
			
		||||
                err = GET_ERROR;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (timeout == -1) {
 | 
			
		||||
            /* select failed */
 | 
			
		||||
            err = errno;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            err = EWOULDBLOCK;                      /* timed out */
 | 
			
		||||
            /* select() failed */
 | 
			
		||||
            err = GET_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
    *timeoutp = timeout;
 | 
			
		||||
 | 
			
		||||
    assert(err >= 0);
 | 
			
		||||
    return err;
 | 
			
		||||
 | 
			
		||||
#undef GET_ERROR
 | 
			
		||||
#undef IN_PROGRESS_ERR
 | 
			
		||||
#undef TIMEOUT_ERR
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* s.connect(sockaddr) method */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue