This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: SSL socket methods don't retry on EINTR?
Type: behavior Stage: needs patch
Components: SSL Versions: Python 3.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: alex, christian.heimes, dstufft, erlendaasland, janssen, njs, pitrou, vstinner
Priority: normal Keywords:

Created on 2017-12-11 10:45 by pitrou, last changed 2022-04-11 14:58 by admin.

Messages (4)
msg308026 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2017-12-11 10:45
Some time ago, PEP 475 was accepted in order to automatically retry system calls on EINTR, but the _ssl module wasn't touched.

However, it seems that OpenSSL socket calls can fail with EINTR:
https://stackoverflow.com/questions/24188013/openssl-and-signals
msg308028 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2017-12-11 11:12
"it seems that OpenSSL socket calls can fail with EINTR: ..."

You are easily test by raising a signal: see Lib/test/test_eintr.py which stress Python functions by sending a signal every 100 ms while Python is blocked in a syscall.

If there is a bug, sure, it must be fixed ;-)

It was very tricky to handle EINTR properly in the socket module. While most Python functions are thin wrapper to syscalls with no timeout, almost every socket functions have a timeout. So I wrote sock_call() to factorize the code. This function calls select() internally to check if the socket is "ready", but also updates the timeout, etc.

A few other Python are retried on EINTR and update a timeout, like select.select(), time.sleep(), threading.Lock.acquire() and signal.sigtimedwait().
msg308029 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2017-12-11 11:14
See bpo-23618 for handling EINTR in socket and bpo-23834 for sock_call().
msg308031 - (view) Author: Julien Palard (mdk) * (Python committer) Date: 2017-12-11 11:28
Looks like this behavior is documented in the bio_should_retry(3) man page.

Basically bio_should_retry() tells if the error was non-fatal:

    int BIO_fd_should_retry(int i)
    {
        int err;

        if ((i == 0) || (i == -1)) {
            err = get_last_sys_error();

            return BIO_fd_non_fatal_error(err);
        }
        return 0;
    }
History
Date User Action Args
2022-04-11 14:58:55adminsetgithub: 76456
2021-06-11 19:32:59erlendaaslandsetnosy: + erlendaasland
2019-05-07 20:25:20mdksetnosy: - mdk
2017-12-11 11:28:00mdksetnosy: + mdk
messages: + msg308031
2017-12-11 11:17:36christian.heimessetassignee: christian.heimes ->
2017-12-11 11:17:30christian.heimessetassignee: christian.heimes
components: + SSL
stage: needs patch
2017-12-11 11:14:08vstinnersetmessages: + msg308029
2017-12-11 11:12:26vstinnersetmessages: + msg308028
2017-12-11 10:45:05pitroucreate