[openssl-users] [openssl-dev] How to use BIO_do_connect(), blocking and non-blocking with timeout, coping with errors

David von Oheimb David.von.Oheimb at siemens.com
Tue Sep 5 12:12:23 UTC 2017


/[ Further below I quote my first two messages including my original
questions and tentative code,//
// since Cc'ing to openssl-users did not work when I tried first. In
this way I hope to get further, //
// more detailed responses by people with specific experience on the
issues I mentioned,//
// possibly even concrete feedback how to enhance my code or where to
find a better solution. ]/


On 09/01/2017 06:32 PM, Salz, Rich via openssl-users wrote:
>
> FWIW, there’s a ‘libtls’ library from the libre folks that might be
> worth looking at.
>
This looks very nice. Yet is this of any practical benefit when using
OpenSSL?

> If you come up with useful snippets we can start by posting them to
> the wiki, for example
>
Which wiki do you mean? I could not find anything related on
https://wiki.openssl.org/

Anyway, most people (including me) would not search through wikis for
finding useful code,
and it would be much more useful if code like the bio_connect() function
I mentioned below
was readily available within the OpenSSL libraries, in an official
high-level API.
/[ Since this is worth a topic of its own, I'll write more on this in my
next email. ]/

More low-level code that is already used by the crypto lib itself (e.g.,
using select() in rand_unix.c)
would be better packaged into abstractions within that library, for
instance the socket_wait() function
for waiting on a socket with a timeout that I proposed below. I'd
contribute pull requests for those I'm aware of.


On 29.08.2017 16:15, Salz, Rich via openssl-dev wrote:
>>     Getting the client connect right appears surprisingly messy when one
>>     needs to cope with all kinds of network error situations including
>>     domain name resolution issues and temporarily unreachable servers.
>>     Both indefinitely blocking and non-blocking behavior (i.e., connection
>>     attempts with and without a timeout) should be supported.
> It is a complicated issue and hard to get right for all definitions of right for all applications ☺
Hmm - on the one hand, good to get confirmation that I did not just miss
a simple way of out the maze, ...
> A set of API’s that set up all the TLS “metadata”, and took a connected socket might be a way through the maze.  For example:
>     SSL *SSL_connection(int socket, const char *servername, …whatever…)
... on the other hand, it's a pity that such a high-level API does not
(yet) exist, at least not in OpenSSL.

How about adding at least some clearly useful abstractions like the
below socket_wait() function,
which would reduce code duplication in the OpenSSL crypto lib and apps
and help application developers?

Maybe other OpenSSL users have specific experience on error and timeout
handling for BIO_do_connect() etc.
and can comment in more detail on the (approximate) solution,
bio_connect(), that I gave below?

On 28.08.2017 13:46, David von Oheimb wrote:
> Hi all,
>
> I'm currently enhancing HTTP(S) clients based on OpenSSL in several
> flavors, in particular a CMP client, which in turn uses simple HTTP
> clients for contacting CRL distribution points or OCSP responders.
>
> Getting the client connect right appears surprisingly messy when one
> needs to cope with all kinds of network error situations including
> domain name resolution issues and temporarily unreachable servers.
> Both indefinitely blocking and non-blocking behavior (i.e., connection
> attempts with and without a timeout) should be supported.
>
> Since these are pretty general problems I wonder why there there is
> rather limited support via generic higher-level OpenSSL or C library
> functions, or at least I was unable to find it. Instead, the OpenSSL
> apps contain code that calls BIO_do_connect directly (or the equivalent
> BIO_do_handshake), in particular query_responder() in apps/ocsp.c.
> (The situation is similar for the subsequent exchange of data via the
> BIO, optionally with a timeout).
>
> So I constructed my own abstraction, called bio_connect, which took
> quite some effort testing network error situations. Please see below its
> code including comments on some strange behavior I experienced and my
> workarounds for that. Does this code make sense, or do I miss anything?
>
> How about adding such a function for instance to crypto/bio/bio_lib.c?
>
> BTW, my code uses a handy generic helper function, socket_wait, for
> waiting for read/write form/to a socket, with a given timeout. Since
> several instances of that pretty common code pattern using select() are
> spread over the OpenSSL apps (and crypto lib), I suggest adding this
> function to the library. Where would be a good place to put it?
>
> Thanks,
> 	David
>> /* returns -1 on error, 0 on timeout, 1 on success */
>> int bio_connect(BIO *bio, int timeout) {
>>     int blocking;
>>     time_t max_time;
>>     int rv;
>>
>>     blocking = timeout == 0;
>>     max_time = timeout != 0 ? time(NULL) + timeout : 0;
>>
>>     if (!blocking)
>>         BIO_set_nbio(bio, 1);
>>  retry:
>>     rv = BIO_do_connect(bio);
>>     if (rv <= 0 && (errno == ETIMEDOUT /* in blocking case,
>>           despite blocking BIO, BIO_do_connect() timed out */ ||
>>           ERR_GET_REASON(ERR_peek_error()) == ETIMEDOUT/* when non-blocking,
>>           BIO_do_connect() timed out early with rv == -1 and errno == 0 */)) {
>>         ERR_clear_error();
>>         (void)BIO_reset(bio); /* otherwise, blocking next connect() may crash
>>                              and non-blocking next BIO_do_connect() will fail */
>>         goto retry;
>>     }
>>     if (!blocking && rv <= 0 && BIO_should_retry(bio)) {
>>         int fd;
>>         if (BIO_get_fd(bio, &fd) <= 0)
>>             return -1;
>>         rv = socket_wait(fd, 1, max_time - time(NULL));
>>         if (rv > 0)
>>             /* for some reason, select() may wrongly have returned success */
>>             goto retry;
>>     }
>>     return rv;
>> }
>> /* returns < 0 on error, 0 on timeout, >0 on success */
>> int socket_wait(int fd, int for_read, int timeout)
>> {
>>     fd_set confds;
>>     struct timeval tv;
>>
>>     if (timeout <= 0)
>>         return 0;
>>
>>     FD_ZERO(&confds);
>>     openssl_fdset(fd, &confds);
>>     tv.tv_usec = 0;
>>     tv.tv_sec = timeout;
>>     return select(fd + 1, for_read ? &confds : NULL,
>>                   for_read ? NULL : &confds, NULL, &tv);
>> }

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mta.openssl.org/pipermail/openssl-users/attachments/20170905/44ffe81c/attachment.html>


More information about the openssl-users mailing list