Issue #12343: Add some notes on behaviour of non-blocking SSL sockets.
This commit is contained in:
commit
f08310f08b
|
@ -440,27 +440,16 @@ SSL sockets provide the following methods of :ref:`socket-objects`:
|
|||
the same limitation)
|
||||
- :meth:`~socket.socket.shutdown()`
|
||||
|
||||
They also have the following additional methods and attributes:
|
||||
However, since the SSL (and TLS) protocol has its own framing atop
|
||||
of TCP, the SSL sockets abstraction can, in certain respects, diverge from
|
||||
the specification of normal, OS-level sockets. See especially the
|
||||
:ref:`notes on non-blocking sockets <ssl-nonblocking>`.
|
||||
|
||||
SSL sockets also have the following additional methods and attributes:
|
||||
|
||||
.. method:: SSLSocket.do_handshake()
|
||||
|
||||
Performs the SSL setup handshake. If the socket is non-blocking, this method
|
||||
may raise :exc:`SSLError` with the value of the exception instance's
|
||||
``args[0]`` being either :const:`SSL_ERROR_WANT_READ` or
|
||||
:const:`SSL_ERROR_WANT_WRITE`, and should be called again until it stops
|
||||
raising those exceptions. Here's an example of how to do that::
|
||||
|
||||
while True:
|
||||
try:
|
||||
sock.do_handshake()
|
||||
break
|
||||
except ssl.SSLError as err:
|
||||
if err.args[0] == ssl.SSL_ERROR_WANT_READ:
|
||||
select.select([sock], [], [])
|
||||
elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
|
||||
select.select([], [sock], [])
|
||||
else:
|
||||
raise
|
||||
Performs the SSL setup handshake.
|
||||
|
||||
.. method:: SSLSocket.getpeercert(binary_form=False)
|
||||
|
||||
|
@ -949,6 +938,42 @@ would probably handle each client connection in a separate thread, or put
|
|||
the sockets in non-blocking mode and use an event loop).
|
||||
|
||||
|
||||
.. _ssl-nonblocking:
|
||||
|
||||
Notes on non-blocking sockets
|
||||
-----------------------------
|
||||
|
||||
When working with non-blocking sockets, there are several things you need
|
||||
to be aware of:
|
||||
|
||||
- Calling :func:`~select.select` tells you that the OS-level socket can be
|
||||
read from (or written to), but it does not imply that there is sufficient
|
||||
data at the upper SSL layer. For example, only part of an SSL frame might
|
||||
have arrived. Therefore, you must be ready to handle :meth:`SSLSocket.recv`
|
||||
and :meth:`SSLSocket.send` failures, and retry after another call to
|
||||
:func:`~select.select`.
|
||||
|
||||
(of course, similar provisions apply when using other primitives such as
|
||||
:func:`~select.poll`)
|
||||
|
||||
- The SSL handshake itself will be non-blocking: the
|
||||
:meth:`SSLSocket.do_handshake` method has to be retried until it returns
|
||||
successfully. Here is a synopsis using :func:`~select.select` to wait for
|
||||
the socket's readiness::
|
||||
|
||||
while True:
|
||||
try:
|
||||
sock.do_handshake()
|
||||
break
|
||||
except ssl.SSLError as err:
|
||||
if err.args[0] == ssl.SSL_ERROR_WANT_READ:
|
||||
select.select([sock], [], [])
|
||||
elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
|
||||
select.select([], [sock], [])
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
.. _ssl-security:
|
||||
|
||||
Security considerations
|
||||
|
|
Loading…
Reference in New Issue