gnutls_handshake() thread problem
jay.janra at gmail.com
Mon Nov 22 10:42:03 CET 2010
I install a signal handler for SIGIO - call it sig_handler() and then open a
socket and make it asynchronous and non-blocking. The program then goes to
sleep waiting for the server to respond.
I am using the GNUTLS library for ftp (FTPeS) transfers so, as soon as the
TCP/IP connection is established with the ftp server, the server responds
with a 220 'hello' message.
When the 220 message arrives, my program receives the SIGIO and the
sig_handler function is automatically invoked. I use the sig_handler()
function to send back an 'AUTH TLS' message requesting that the server sets
up TLS encryption on the connection. This is done just in the sig_handler()
function which is effectively an interrupt handler, and does not 'wake up'
the main thread. when the AUTH TLS message has been sent, the interrupt
terminates and the program goes back to sleep.
The server responds with a 234 message accepting TLS as a method of
encryption. At this point the main thread is woken up to start the handshake
process and it calls gnutls_handshake(). As it's using a non-blocking
socket, it returns immediately and the main thread goes to sleep waiting for
a response from the server. The handshake response from the server is
received and triggers the sig_handler() again which this time calls
gnutls_handshake() to continue the handshake process, this goes on until the
handshake is complete. When the handshake is complete, the main thread is
woken up again to start the authentication.
The interrupt that was triggered by the servers response was causing
sig_handler() and hence gnutls_handshake() to be called before the previous
call to gnutls_handshake() (from the initial call from the main thread) had
completed. I am running the code on a busy server so I am at the mercy of
the scheduler and sometimes the thread running the previous call to
gnutls_handshake() was 'swapped out' when the interrupt arrived. So, when my
process next got CPU time, it was the interrupt that ran and not the end of
the gnutls_handshake() call.
I assume you would not normally expect a remote host to respond to a block
of handshake data without the call to gnutls_handshake() that sent the
previous block of data to the server, to have completed. The scheduler on a
busy machine together with asynchronous, non-blocking sockets add the
possibility of unintentionally adding a virtual thread to the program with
the sig_handler function, and calling gnutls_handshake concurrently.
There are numerous reasons why I have coded this the way I have. There are
any number of ways to stop this concurrency happening, masking signals,
mutexes, putting the call to gnutls_handshake() in a while loop in the main
thread etc, but unless you know that it's needed, you don't put it in
because it's added complexity in the program.
On Fri, Nov 19, 2010 at 3:07 PM, Nikos Mavrogiannopoulos <nmav at gnutls.org>wrote:
> On 11/19/2010 03:46 PM, Jay Anra wrote:
> > answering your question: 'Do you call gnutls_handshake in parallel from
> > different threads?'
> > Sort of, although not explicitly. It's a consequence of using
> > sockets. The concurrency comes
> > from the interrupt generated by the SIGIO signal, which gets sent to my
> > process when data arrives on the socket.
> > Obviously I have no control over the timing of this signal, so it may
> > concurrent calls to gnutls_handshake()
> > or it may not.
> I still cannot understand why you need to call gnutls_handshake() in a
> concurrent way. Could you explain your scenario? In any case all gnutls
> functions are reentrant as long as each session is handled in a single
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Gnutls-help