Fix deadlocks due to invalid handling of SSL sockets and select #504
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
SSL sockets can't be used with
select()
in the same way raw sockets would, since the OS socket readable/writable state is not always identical to the one of the SSL stack. See also:https://docs.python.org/3/library/ssl.html#notes-on-non-blocking-sockets
For instance, websockify is currently unable to proxy a connection to a SSL target - unless the server-side sends data first.
In this case, the OS socket is reported as readable - due to SSL protocol data like sessions tickets being exchanged - while the SSL socket is not readable since application data hasn't been received from the server-side yet. As SSL sockets are read from (and written to) in a blocking fashion, the current implementation then simply stalls. For an example, see here:
Screen.Recording.2022-01-08.at.19.14.27.3.mov
The following patch tries to leave most of the existing socket handling logic intact while addressing the special handling required for SSL sockets. In particular, SSL sockets are now put in non-blocking mode, so that false-positive readable reports from
select()
don't lead to a deadlock but an exception. (Unfortunately, theSSLSocket.pending()
API doesn't seem to work reliably to archive the same with blocking SSL sockets.. :-/)In addition, the patch introduces an assertion to ensure the internal buffer size is equal or above 16kb so that all available data can be directly read from a SSL socket in a single call. Otherwise, there would be additional (annoying) handling required to make sure no data is accidentally left behind when a SSL socket would be only partially read. In this case,
select()
wouldn't report this socket as readable again - unless new data is received - since the rest of the data has already been read and buffered by the SSL socket layer.