[ python-Bugs-1462352 ] socket.ssl won't work together with socket.settimeout on Win

SourceForge.net noreply at sourceforge.net
Sat Apr 8 15:00:18 CEST 2006


Bugs item #1462352, was opened at 2006-03-31 14:11
Message generated for change (Comment added) made by tim_one
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1462352&group_id=5470

Please note that this message will contain a full copy of the comment thread,
including the initial issue submission, for this request,
not just the latest update.
Category: Windows
Group: Python 2.4
Status: Closed
Resolution: Fixed
Priority: 6
Submitted By: Georg Brandl (gbrandl)
>Assigned to: Trent Mick (tmick)
Summary: socket.ssl won't work together with socket.settimeout on Win

Initial Comment:
Symptoms:

>>> import socket
>>> s = socket.socket()
>>> s.settimeout(30.0)
>>> s.connect(("gmail.org", 995))
>>> ss = socket.ssl(s)
Traceback (most recent call last):
   File "<stdin>", line 1, in ?
   File "C:\python24\lib\socket.py", line 74, in ssl
     return _realssl(sock, keyfile, certfile)
 socket.sslerror: (2, 'The operation did not complete
(read)')

This does not occur on Unix, where
test_socket_ssl.test_timeout runs smoothly.

----------------------------------------------------------------------

>Comment By: Tim Peters (tim_one)
Date: 2006-04-08 09:00

Message:
Logged In: YES 
user_id=31435

Yup, saw that, but I'd like input from Trent (it's his box):
 why is it timing out at all?  30 seconds is a huge blob of
time, and none of the other buildbots are timing out.  When
I disabled test_socket_ssl's test_timeout, _all_ buildbot
slaves were timing out (because gmail.org simply wasn't
responding to anyone at the time).

IOW, there may be a Win2K-specific bug in the Python
implementation here (note that Trent's is the only Win2K
slave we have).

----------------------------------------------------------------------

Comment By: Georg Brandl (gbrandl)
Date: 2006-04-08 08:52

Message:
Logged In: YES 
user_id=849994

Now one Windows buildbot turned red again since the timeout
didn't raise socket.timeout but socket.error... :-|

----------------------------------------------------------------------

Comment By: Tim Peters (tim_one)
Date: 2006-04-08 08:48

Message:
Logged In: YES 
user_id=31435

Whoa -- good eye, Martin!  Thank you.  Looks like bugs all
over the place.

FYI, I later rehabilitated the disabled part of
test_socket_ssl, and removed the Windows special-casing, in
revs 43734 (trunk) and 43735 (2.4 branch).

----------------------------------------------------------------------

Comment By: Martin v. Löwis (loewis)
Date: 2006-04-08 05:18

Message:
Logged In: YES 
user_id=21627

The problem is that WIN32 isn't initially defined.
WinSock2.h has this structure:

#if !defined(WIN32) && !defined(_WIN64)
#include <pshpack4.h>
#endif

#include <windows.h>

#if !defined(WIN32) && !defined(_WIN64)
#include <poppack.h>
#endif

Even though WIN32 is initially not defined, it is defined
at the end of WinSock2.h, so that the poppack.h is not
included. That leaves a pragma pack(push,4) on the pack
stack. I haven't traced where exactly WIN32 is defined,
but it probably comes from Ole2.h.

Fixed in 43731 and 43732. Not sure whether anything needs to
be done to the test suite.


----------------------------------------------------------------------

Comment By: Tim Peters (tim_one)
Date: 2006-04-08 03:48

Message:
Logged In: YES 
user_id=31435

Normal MS struct member alignment is definitely screwed up
inside _ssl.c, but still don't know how that happens. 
sizeof this struct should be 16, but is reported as 12 when
the source is inside _ssl.c:

struct dummy {
    int a;
    double x;
};

(note that in the details in previous comments, the double
&Sock->sock_timeout was not 8-byte aligned in _ssl.c, but
was in socketmodule.c).  I don't see any MS packing pragmas
in any of the OpenSSL .h files either.

----------------------------------------------------------------------

Comment By: Tim Peters (tim_one)
Date: 2006-04-08 02:05

Message:
Logged In: YES 
user_id=31435

As a sanity check on all those details, inside newPySSLObject()

*(double *)((char *)&Sock->sock_timeout + 4)

is in fact 30.0.

----------------------------------------------------------------------

Comment By: Tim Peters (tim_one)
Date: 2006-04-08 01:25

Message:
Logged In: YES 
user_id=31435

I did a data breakpoint on the 8 bytes in the sock_timeout
member, and it never triggered:  nothing stores anything
there to change 30.0 to 0.0.

Instead, socketmodule.c and _ssl.c have different views of
where the members of a PySocketSockObject live.  WRT
socketmodule.c sock_settimeout's `s`, and _ssl.c
newPySSLObject's `Sock` (which are the same object in the
test case), the debugger agrees about the addresses at which
these members live:

&s->_ob_next    0x0096c3e8
&s->_ob_prev    0x0096c3ec
&s->ob_refcnt   0x0096c3f0
&s->ob_type     0x0096c3f4
&s->sock_fd     0x0096c3f8
&s->sock_family 0x0096c3fc
&s->sock_type   0x0096c400
&s->sock_proto  0x0096c404
&s->sock_addr   0x0096c408
&s->errorhandler 0x0096c488

But there's a radical disconnect about where it thinks
sock_timeout lives:

&s->sock_timeout    0x0096c490
&Sock->sock_timeout 0x0096c48c

Indeed,

    printf("%d\n", sizeof(PySocketSockObject));

displays different results:

socketmodule.c: 176
_ssl.c:         172

I'm unclear about why.  Doing

    printf("%d\n", sizeof(sock_addr_t));

prints 128 in both modules, so there's not an obvious
difference there.

----------------------------------------------------------------------

Comment By: Tim Peters (tim_one)
Date: 2006-04-01 21:08

Message:
Logged In: YES 
user_id=31435

BTW, does anyone understand why this part of my first
comment was true?:

"""
check_socket_and_wait_for_timeout() takes the "else if
(s->sock_timeout == 0.0)" path and and returns
SOCKET_IS_NONBLOCKING.
"""

How did s->sock_timeout become 0?  s.settimeout(30.0) was
called, and the same s was passed to socket.ssl().  I don't
understand this at all:

>>> s.connect(("gmail.org", 995))
>>> s.gettimeout()
30.0
>>> s._sock
<socket object, fd=1920, family=2, type=1, protocol=0>
>>> s._sock.gettimeout()
30.0
>>> ss = socket.ssl(s)

but a breakpoint in newPySSLObject() right there shows that
Sock->sock_timeout is 0.0.  HTF did that happen?

If I poke 30.0 (under the debugger) into Sock->sock_timeout
at the start of newPySSLObject(), the constructor finishes
unexceptionally.

----------------------------------------------------------------------

Comment By: Tim Peters (tim_one)
Date: 2006-04-01 20:57

Message:
Logged In: YES 
user_id=31435

gmail.com happened to respond when I tried it today, so I
can confirm (alas) that the patch at

http://pastebin.com/633224

made no difference to the outcome on Windows.

----------------------------------------------------------------------

Comment By: Tim Peters (tim_one)
Date: 2006-03-31 20:36

Message:
Logged In: YES 
user_id=31435

Because the

s.connect(("gmail.org", 995))

line started timing out on all (non-Windows) buildbot slaves
some hours ago, causing all test runs to fail, I disabled
test_timeout on all boxes for now (on trunk & on 2.4 branch).

----------------------------------------------------------------------

Comment By: Tim Peters (tim_one)
Date: 2006-03-31 18:23

Message:
Logged In: YES 
user_id=31435

Note that this is a problem in 2.4 and trunk.

The sample code worked fine earlier today if (and only if) I
left out the .settimeout() call.

Note that buildbot test runs are failing in trunk and 2.4
branch now on non-Windows boxes, because the

s.connect(("gmail.org", 995))

line is timing out (the new test is disabled on Windows, and
that's why the Windows buildbots are still passing).  At the
moment, that's timing out on my Windows box too.  We clearly
need a more reliable net address to connect to.

On Bug Day IRC, "arekm" last asked that I try this patch on
 Windows:

http://pastebin.com/633224

Unfortunately, I haven't been able to get beyond the
s.connect(("gmail.org", 995)) line since then, so still
don't know whether that helps.  Nothing else did ;-)

On Windows, in newPySSLObject(),
"ret = SSL_connect(self->ssl);" returns -1
"err = SSL_get_error(self->ssl, ret);" returns 2
"if (err == SSL_ERROR_WANT_READ)" triggers.
check_socket_and_wait_for_timeout() takes the "else if
(s->sock_timeout == 0.0)" path and and returns
SOCKET_IS_NONBLOCKING.
newPySSLObject() breaks out of its loop then, and does
"PySSL_SetError(self, ret); goto fail;"

----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1462352&group_id=5470


More information about the Python-bugs-list mailing list