classification
Title: Inappropriate error received using socket timeout
Type: behavior Stage: needs patch
Components: Library (Lib) Versions: Python 3.1, Python 3.2, Python 2.7
process
Status: closed Resolution: out of date
Dependencies: Superseder:
Assigned To: Nosy List: BreamoreBoy, dmeranda, evgeni_popov, pitrou, troels
Priority: normal Keywords:

Created on 2003-09-12 16:56 by evgeni_popov, last changed 2010-08-19 12:33 by pitrou. This issue is now closed.

Messages (7)
msg18140 - (view) Author: Popov (evgeni_popov) Date: 2003-09-12 16:56
When using the timeout option with a socket object 
(python 2.3), I don't have the same behaviour under 
Windows than under Linux / Mac.

Specifically, if trying to connect to an unopened port of 
the localhost, I get a timeout exception on Windows 
(tested under W2K Server), whereas I get a "111 - 
Connection Refused" exception on Linux and "22 - Invalid 
Argument" on Mac (OS X).

Even if the error message under Mac is not really 
appropriate (someone said to me he got the 
right 'Connection Refused' on his MAC), I think that the 
behaviour under Linux and Mac is the right one, in that it
sends (quickly) an error message and not timeouting.

Note that when using blocking socket the behaviour is 
ok under all platforms: they each return back quickly 
a "Connection refused" error message (err codes are 
different depending on the platform (61=Mac,
111=Linux, 10061=Windows)). FYI, I don't use firewall or 
similar prog on my windows box (but that should not 
matter, because it does work in blocking mode, so that 
can't be a firewall problem).

I heard that the timeout option was implemented based 
on Timothy O'Malley timeoutsocket.py. Then, maybe the 
pb can come from the usage of select in the connection 
function: select is not asked to get back exceptions in 
the returned triple, whereas I think some errors can be
returned back through this mean under Windows 
(according to Tip 25 of Jon C. Snader book's "Effective 
TCP/IP Programming"). So, by not checking the returned 
exceptions, we would miss the "connection refused" 
error and get instead the timeout error...
msg18141 - (view) Author: Troels Walsted Hansen (troels) Date: 2004-06-02 08:51
Logged In: YES 
user_id=32863

The Windows part of this bug is a duplicate of bug #777597.
msg18142 - (view) Author: Deron Meranda (dmeranda) Date: 2007-03-09 16:53
This is also a problem under HP-UX 11.0 with Python 2.5

The socket connect_ex() will return errno 22 EINVAL instead of
the more appropriate 239 ECONNREFUSED when connecting to a
non-listening socket ... but only if a socket timeout is being
used.

A system call trace reveils a little more what is going on.
For the python code

  import socket
  s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
  s.settimeout(15.0)
  res = s.connect_ex( ('127.0.0.1', 8099) )  # An unused port number

the system call sequence is as follows:

Calling socket.socket()
  socket(AF_INET, SOCK_STREAM, 0)  = 3
Calling s.settimeout(15.0)
  fcntl(3, F_GETFL, 0)     = 2
  fcntl(3, F_SETFL, 65538) = 0
Calling s.connect_ex(...)
  connect(3, 0x400b43f0, 16)  = -1  -> ERR#245 EINPROGRESS
  poll(0x7cff1914, 1, 15000)  = 1
  connect(3, 0x400b43f0, 16)  = -1  -> ERR#22 EINVAL

If the call to settimeout is removed, then an ERR#239 ECONNREFUSED
is returned by the first connect() and no subsequent poll+connect
is attempted.  With the timeout set, note that the poll() returns
immediately no timeout actually occurs.

Note that tracing the same code under Linux shows the exact same
set of system calls, but that the second connect() call returns
ECONNREFUSED instead.

So this appears to be a specific behavior of HP-UX (and
perhaps other Unixes).

Excerpted from the HP man pages for connect(2):

  [EINVAL] The socket has already been shut down or
           has a listen() active on it; addrlen is
           a bad value; an attempt was made to
           connect() an AF_UNIX socket to an NFS-
           mounted (remote) name; the X.121 address
           length is zero, negative, or greater
           than 15 digits.

           For datagram sockets, if addrlen is a
           bad value, the peer address is no longer
           maintained by the system.

  [ECONNREFUSED] The attempt to connect was forcefully
                 rejected.

  [EINPROGRESS] Nonblocking I/O is enabled using
                O_NONBLOCK, O_NDELAY, or FIOSNBIO, and
                the connection cannot be completed
                immediately.  This is not a failure.
                Make the connect() call again a few
                seconds later.  Alternatively, wait for
                completion by calling select() and
                selecting for write.
msg18143 - (view) Author: Deron Meranda (dmeranda) Date: 2007-03-09 18:49
Verified that AIX 5.2 works fine, it returns an ECONNREFUSED in
all cases.

Some interesting related links though:

Twisted bug# 2022
   http://twistedmatrix.com/trac/ticket/2022

"Non-blocking BSD socket connections" by D.J. Bernstein
   http://cr.yp.to/docs/connect.html

There's also an interesting comment in Apache's APR change
notes for APR 0.9 <http://www.apache.org/dist/apr/CHANGES-APR-0.9>
which seems to indicate that perhaps doing a second connect()
is wrong:

  "*) Non-blocking connects shouldn't be calling connect a second
      time.  According to Single Unix, a non-blocking connect has
      succeeded when the select pops successfully.  It has failed
      if the select failed.  The second connect was causing 502's
      in the httpd-proxy.  [John Barbee barbee@veribox.net]"

If the APR comment is correct, then perhaps this is a Python
bug after all??
msg56744 - (view) Author: Jean-Paul Calderone (exarkun) * (Python committer) Date: 2007-10-25 13:35
The APR comment is indeed correct, so this is probably a Python bug.
msg114270 - (view) Author: Mark Lawrence (BreamoreBoy) * Date: 2010-08-18 19:43
I've tried reproducing this on Windows Vista but sorry I can't make any sense out of it.  I've assumed that a unit test can be based around code given in msg18142.
msg114356 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2010-08-19 12:33
I'm not sure in what way the error is inappropriate. Python simply propagates whatever errno the C library sets on failure.

As for the comment that connect() shouldn't be called twice, this was fixed in 2.6 by r60101.
History
Date User Action Args
2010-08-19 12:33:02pitrousetstatus: open -> closed

nosy: + pitrou
messages: + msg114356

resolution: out of date
2010-08-18 19:43:58BreamoreBoysettitle: Inappropriate error received using socket timeout on Windows. -> Inappropriate error received using socket timeout
components: + Library (Lib), - Windows

nosy: + BreamoreBoy
versions: + Python 3.1, Python 2.7, Python 3.2, - Python 2.6
messages: + msg114270
stage: needs patch
2009-04-05 18:25:19georg.brandllinkissue836058 superseder
2009-04-05 18:25:19georg.brandlunlinkissue836058 dependencies
2009-02-14 20:12:01exarkunsetnosy: - exarkun
2009-02-14 12:10:20ajaksu2settitle: Inappropriate error received using socket timeout -> Inappropriate error received using socket timeout on Windows.
type: behavior
versions: + Python 2.6, - Python 2.3
2009-02-14 12:09:25ajaksu2linkissue836058 dependencies
2007-10-25 13:35:09exarkunsetnosy: + exarkun
messages: + msg56744
2003-09-12 16:56:21evgeni_popovcreate