The _ssl module uses an helper function check_socket_and_wait_for_timeout() to poll until the socket is ready (got data or became writable). check_socket_and_wait_for_timeout() always uses the socket timeout. If select() or poll() is interrupted by a signal (fails with EINTR), check_socket_and_wait_for_timeout() is restarted with the same timeout, which doesn't respect the contract of the timeout: the operation must timeout if it takes more than timeout seconds. The code must be modified to recompute the timeout, as done in the new sock_call() function of Modules/socketmodule.c (issue #23618). At least, the timeout must decreases when select()/poll() fails with EINTR. Currently, the timeout is reset after each read/write/handshake operation. IMO the timeout must apply on the total duration of the ssl method, not be reset. But changing this may break backward compatibility :-/ Note: if the signal handler raises an exception, the ssl method fails with the exception. This issue is specific to signal handlers not raising an exception.
test_ssl_bug.patch: Modify test_handshake_timeout() of test_ssl to show the bug: test_handshake_timeout() hangs with the patch (which sends a signal every millisecond).
Here is a patch to fix the issue: recompute the timeout. It's unclear to me if we should reset the timeout after each successful read/write, or if the timeout is "global" (total duration of the ssl method). I asked the question on the python-dev mailing list. https://mail.python.org/pipermail/python-dev/2015-April/139001.html My patch uses a global timeout (never reset the timeout), whereas socket.sendall() resets the timeout at each send() success.