Hello @jvdprng, thank you for your answer.
It is nice that you reply today because I’m almost done implementing tlslib in my lib, I’ve got the TLSBuffer and TLSSocket mostly done (I’m still not compliant with some WantToRead/WantToWrite), the TLSConfiguration is not done yet but that’s easier than the rest.
I’ve implemented the TLSSocket as such in my work: socket.py, the files at src/examples/simple_client.py and src/examples/simple_server.py showcase how it works.
It boils down to the following (the actual code contains lengthy docstrings):
class TLSSocket:
def __exit__(self, exc_type, exc_value, traceback):
if exc_type:
self.fail()
else:
self.close()
def shutdown(self, how: int) -> None:
if how in (socket.SHUT_RD, socket.SHUT_RDWR):
# force close the receiving end
logger.debug("Fake receiving %s", short_name(alerts.CloseNotify()))
self._buffer._state.process(alerts.CloseNotify()) # noqa: SLF001
if how in (socket.SHUT_WR, socket.SHUT_RDWR):
self._buffer.close_sending_end()
self.flush()
self._socket.shutdown(how)
def fail(self) -> None:
self._buffer.fail()
self.flush()
self._socket.close()
def close(self) -> None:
self._buffer.close_sending_end()
self.flush()
# is_closed() => True when the receiving end is closed, False otherwise
if not self._buffer.is_closed():
e = "the peer didn't send a CloseNotify yet"
raise tlslib.WantReadError(e)
self._socket.close()
In this version the user must explicitly call shutdown(SHUT_RD) if he doesn’t care about truncation. If he cares about truncation he gotta call recv() until it returns b''. There’s no force argument, the user must explicitly shutdowns read, or receive everything.
I solved the forked-server problem thanks to a TLSContext(Client|Server).wrap_socket function. In the parent process (the one that accept()) I create a regular socket (i.e. import socket, not import tlslib). In the child process (the one that recv()/send()) I wrap/upgrade the regular TCP socket to a TLS one using this function. I’ve tested other things but they were less elegant.