Bill Janssen
2007-12-02 20:23:01 UTC
An interesting question has come up in the development of the SSL module.
The function ssl.wrap_socket() takes a flag, do_handshake_on_connect,
which tells it whether to do the SSL handshake before returning an
SSLSocket object to the caller. If the socket being wrapped is
non-blocking, the code in wrap_socket() must invoke do_handshake()
multiple times, and effectively block until the handshake is done.
Right now, I'm doing it with this loop:
if do_handshake_on_connect:
# have to loop to support non-blocking sockets
while True:
try:
self.do_handshake()
break
except SSLError, err:
if err.args[0] == SSL_ERROR_WANT_READ:
select.select([self], [], [])
elif err.args[0] == SSL_ERROR_WANT_WRITE:
select.select([], [self], [])
else:
raise
But this seems fragile to me. "select" and/or "poll" is awfully
system-dependent. What I'd like to do is just use the socket API,
something like:
blocking = self.getblocking()
try:
self.setblocking(1)
self.do_handshake()
finally:
self.setblocking(blocking)
But there's no "getblocking" method on sockets. Instead, there's
"gettimeout". So I'd write something like
timeout = self.gettimeout()
try:
self.setblocking(1)
self.do_handshake()
finally:
if (timeout == 0.0):
self.setblocking(0)
But my mother taught me never to test for equality against
floating-point zero. But in this case it might just fly...
Or, should I just set the timeout:
timeout = self.gettimeout()
try:
self.settimeout(None)
self.do_handshake()
finally:
self.settimeout(timeout)
This is the solution I'm leaning towards...
Any recommendations?
Bill
The function ssl.wrap_socket() takes a flag, do_handshake_on_connect,
which tells it whether to do the SSL handshake before returning an
SSLSocket object to the caller. If the socket being wrapped is
non-blocking, the code in wrap_socket() must invoke do_handshake()
multiple times, and effectively block until the handshake is done.
Right now, I'm doing it with this loop:
if do_handshake_on_connect:
# have to loop to support non-blocking sockets
while True:
try:
self.do_handshake()
break
except SSLError, err:
if err.args[0] == SSL_ERROR_WANT_READ:
select.select([self], [], [])
elif err.args[0] == SSL_ERROR_WANT_WRITE:
select.select([], [self], [])
else:
raise
But this seems fragile to me. "select" and/or "poll" is awfully
system-dependent. What I'd like to do is just use the socket API,
something like:
blocking = self.getblocking()
try:
self.setblocking(1)
self.do_handshake()
finally:
self.setblocking(blocking)
But there's no "getblocking" method on sockets. Instead, there's
"gettimeout". So I'd write something like
timeout = self.gettimeout()
try:
self.setblocking(1)
self.do_handshake()
finally:
if (timeout == 0.0):
self.setblocking(0)
But my mother taught me never to test for equality against
floating-point zero. But in this case it might just fly...
Or, should I just set the timeout:
timeout = self.gettimeout()
try:
self.settimeout(None)
self.do_handshake()
finally:
self.settimeout(timeout)
This is the solution I'm leaning towards...
Any recommendations?
Bill