[gnutls-help] Asynchronous operation.
carlo at alinoe.com
Sat Oct 27 00:20:13 CEST 2018
I wrote a library (GPL) that aims for not creating more threads
than CPU cores. This library provides a thread pool and does
all timer and socket/filedescriptor monitoring.
At the moment I can create a TCP connection and read/write data
in a 100% non-blocking way by means of callback functions (well,
not really - but that would be the same); when it is possible
to write data and I have data, a function is called that allows
me to do that: write the data. When a socket has data then a
function is called that allows me to read that data.
I now wish to add TLS layer to this. In order to (still) never
put a thread to sleep (except a specialized one that does the calls
to epoll) I need this gnutls to provided the following
interface: it should call a callback function (that I configured)
to tell me that it is interested in reading and/or writing (not
to get actual data or write it - just to tell me that it is ready
to do so). When there is nothing to do for the library, it should
return from whatever function I called (it should never go to sleep
internally, or internally wait for anything (like sockets or a timer)).
When the library indicates it is interested in reading or writing
data, I will call functions of the library as soon as this is possible;
ie, when the library wants to read I can provide it a non-blocking
fd that it can read from, or I can do reading and buffering myself
and call a function of the library providing a buffer pointer and
the number of characters available in the buffer.
[ Ideal would be when the gnutls also provided an end-of-message
detection function that I could use to know when I have a complete
message, so that my library can provide strictly contiguous messages,
but this is not absolutely necessary (the result I'd expect is that the
library will make a copy of the data that I provide; which is slower,
but that is ok I suppose). If each message always starts with a header
that contains the total length of that message then I provide
the end-of-message decoder myself of course. ]
I'm a bit lost however... it seems kind of clear, but not entirely ;).
Is there client example code available somewhere that shows how
this can be done?
Many thanks for your time,
PS In case anyone is interested; my library in question exists of many
git submodules, each of which alone hardly ever make a whole; the only
currently existing repository that brings it all together is
and the submodule that I'd add the TLS to will be
PS2 About the end-of-message detection: I don't want to ever copy
data around in memory unless absolutely necessary: data is read from
a socket into a buffer that is considerably larger than the average
message size; whenever all data in the buffer is processed, it starts
again at the beginning of the buffer. Only in the event that data
comes in faster than it can be processed it might happen that a
message wraps over the end into a newly allocated block. In that case
(which should seldom happen) I prefer to make a copy into a new buffer
to make the message contiguous because decoding contiguous messages
is usually much faster and normally they are contiguous anyway.
In order to know if a (new) message wraps over the end of the current
buffer I simply look if 1) the current memory block is full, 2) there
is no 'end-of-message' between where we are and the end of the current
block. This can of course be done much much faster than decoding
the message, especially for binary protocols that simply have the
length of a message in the header of each message (or have fixed size
Carlo Wood <carlo at alinoe.com>
More information about the Gnutls-help