gnutls_record_recv timeout with blocking sockets
mrsam at courier-mta.com
Mon May 23 16:01:41 CEST 2011
Giuseppe Scrivano writes:
> In wget we are using something like the following pseudo-code to
> check if a call to `gnutls_record_recv' will be blocking:
> gnutls_record_check_pending (session) || select_fd (fd, timeout);
You must use non-blocking sockets for this to work.
gnutls just read()s from the socket. If there's nothing to read, read()
blocks until there's something to read. gnutls_record_recv() reads from the
socket. If it has not received an entire record, it reads again, until it
does, then you it returns and tells you what's been read. If the socket is
empty before gnutls receives the entire record, gnutls_record_recv keeps
reading, and it will block.
gnutls_record_check_pending() is just an indication that there's something
still left over from the previous record that your app still hasn't
retrieved using gnutls_record_recv(), yet. Your next call to
gnutls_record_recv() will get that stuff, instead of reading from the socket.
Only if the socket is non-blocking, read() fails with EAGAIN/EWOULDBLOCK, and
gnutls returns accordingly, but the socket must be non-blocking for that to
Note that on Linux, select/poll on blocking sockets is not reliable. See
BUGS in select(2) for more info. Neither gnutls, nor anything else, can
reliably implement a no-delay read() from a blocking socket. select/poll
only works "most" of the time. If "most" of the time is good enough for you,
that's one thing, but rarely "most" of the time will be satisfactory.
> Is it possible to know in advance if `gnutls_record_recv' will block or
> not? Any suggestion how I could handle properly the --read-timeout in
> wget when TLS is used? Am I missing something?
You must use non-blocking sockets. You do not need to use
gnutls_record_check_pending(). You just call gnutls_record_recv() first and
foremost. With a non-blocking sockets it never blocks, and always returns
without delay. If it gives you back a GNUTLS_E_INTERRUPTED or
GNUTLS_E_AGAIN, you know that the socket must be readable before you have a
reasonable expectation that gnutls_record_recv() will give you something
when you call it again. It may still return
GNUTLS_E_INTERRUPTED/GNUTLS_E_AGAIN the second time too; but you're
guaranteed to get that again unless the socket becomes readable first.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Size: 198 bytes
Desc: not available
More information about the Gnutls-devel