gnutls_record_recv timeout with blocking sockets

Sam Varshavchik mrsam at courier-mta.com
Mon May 23 16:01:41 CEST 2011


Giuseppe Scrivano writes:

> Hello,
>
> 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  
happen.

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
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: </pipermail/attachments/20110523/4ceb214e/attachment.pgp>


More information about the Gnutls-devel mailing list