From 060e6855a802a9e9bf2e6905342f704f64a3a26d Mon Sep 17 00:00:00 2001 From: "Andrew M. Kuchling" Date: Sat, 19 Jan 2008 20:47:59 +0000 Subject: Patch #1019808 from Federico Schwindt: Return correct socket error when a default timeout has been set, by using getsockopt() to get the error condition (instead of trying another connect() call, which seems to be a Linuxism). 2.5 bugfix candidate, assuming no one reports any problems with this change. --- Misc/ACKS | 1 + Misc/NEWS | 3 +++ Modules/socketmodule.c | 25 ++++++++++++++++--------- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS index 35cecee..5c87ed1 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -589,6 +589,7 @@ Chad J. Schroeder Sam Schulenburg Stefan Schwarzer Dietmar Schwertberger +Federico Schwindt Barry Scott Steven Scott Nick Seidenman diff --git a/Misc/NEWS b/Misc/NEWS index f7c7aac..b20273d 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1120,6 +1120,9 @@ Extension Modules - Patch #1544279: Improve thread-safety of the socket module by moving the sock_addr_t storage out of the socket object. +- Patch #1019808: fix bug that causes an incorrect error to be returned + when a socket timeout is set and a connection attempt fails. + - Speed up function calls into the math module. - Bug #1588217: don't parse "= " as a soft line break in binascii's diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 0ec4c0b..88d2a70 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -1986,15 +1986,22 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen, #else if (s->sock_timeout > 0.0) { - if (res < 0 && errno == EINPROGRESS && IS_SELECTABLE(s)) { - timeout = internal_select(s, 1); - if (timeout == 0) { - res = connect(s->sock_fd, addr, addrlen); - if (res < 0 && errno == EISCONN) - res = 0; - } - else if (timeout == -1) - res = errno; /* had error */ + if (res < 0 && errno == EINPROGRESS && IS_SELECTABLE(s)) { + timeout = internal_select(s, 1); + if (timeout == 0) { + /* Bug #1019808: in case of an EINPROGRESS, + use getsockopt(SO_ERROR) to get the real + error. */ + socklen_t res_size = sizeof res; + (void)getsockopt(s->sock_fd, SOL_SOCKET, + SO_ERROR, &res, &res_size); + if (res == EISCONN) + res = 0; + errno = res; + } + else if (timeout == -1) { + res = errno; /* had error */ + } else res = EWOULDBLOCK; /* timed out */ } -- cgit v0.12