dear ressl fellows,

when trying to properly reimplement a curses client (i.e. handling stdin
with select) with a tls connection using ressl (i.e. handling a server
socket with select), I stumbled upon conflicting recommendations in man
pages regarding whether to use blocking sockets in BIOs.

The BIO_read(3) tells me to use non blocking sockets and select() to
figure out if there's work for me to do on the writing side and vice versa:

> One technique sometimes used with blocking sockets is to use a system
> call (such as select(), poll() or equivalent) to determine when data
> is available and then call read() to read the data. The
> equivalent with BIOs (that is call select() on the underlying I/O
> structure and then call BIO_read()to read the data) should not be
> used because a single call to BIO_read() can cause several reads
> (and writes in the case of SSL BIOs) on the underlying I/O structure
> and may block as a result.
> Instead select() (or equivalent) should be combined with non blocking
> I/O so successive reads will request a retry instead of blocking.

However the BIO_should_retry(3) man page then warns me, that the ASN.1
parser does not really work with non blocking reads from BIOs:

> The OpenSSL ASN1 functions cannot gracefully deal with non blocking
> I/O: that is they cannot retry after a partial read or write. This is
> usually worked around by only passing the relevant data to ASN1
> functions when the entire structure can be read or written.

Now I could make the app multi threaded and use a blocking tls_read in
one thread, while handling user interactions in another. But this leaves
no way to abort pending read/write actions in the tls thread.

So far so bad. Looks like with the ressl BIO API, I can not reliably use
either socket.



Now I noticed that libtls's tls_client.c only allows for tls_connect
which creates blocking sockets only or tls_connect_socket which appears
to use the underlying socket's blocking state. The socket itself is
opaque to me, so that I can not call select() to see if data is pending
there which is a surprisingly missing feature, considering tls_read
blocking non-abort-ably in SSL_read.

tls_read can also return a surprising TLS_WRITE_AGAIN on non-blocking
sockets, where I think it should handle this condition for the caller.

Maybe my use case just is not very common, but maybe someone can help me
out with a proper way to use the API with a client waiting for input on
multiple fds.

On a related note I wonder what the correct way is to cancel a blocking
tls operation from another thread.

TIA,

  erdgeist

Reply via email to