C OpenSSL questions

If I use SSL_read_ex on an open connection with a client, the program blocks until the client writes something. This means I sort of have to guess when there will be a request and use read only there. But sometimes I want to be able to tell whether the client has anything to ask before I send anything. SSL_peek blocks the same as SSL_read, and SSL_has_pending seems to give 0 every time, seeming to indicate that a read function has to already be deployed in order to know if there is any buffered data from the client to begin with. The underlying BIO object is nonblocking, but I don't think that matters, I think the blocking behaviour is particular to each function in this case.

Does this make any sense? Does anybody have experience with this? Did I write this all wrong, or is it expected behaviour and there is some other way to check if the client wants to write before blocking with SSL_read?

Google is not friendly to OpenSSL questions, always giving the same generic "how to check certificate chain" results, and my scouring of the library reference has yielded nothing on this yet.
 
The traditional way to perform an asynchronous read(2) on a socket is to use fnctl(2) to set OPTION F_SETFL with the option O_NONBLOCK on the socket. This will result in your read(2) call returning (-1) and errno will be set to (EAGAIN) - which means call read(2) again "some time in the future" to see if there is data available. Otherwise your read call will return ssize_t, which is the actual number of bytes read from the socket.

In the OpenSSL world - you can actually just "get" the socket descriptor from the OpenSSL library and use either poll(2) or older style select(2) to see if the socket descriptor is "ready-to-read". Use the OpenSSL SSL_get_fd() call to get the "raw" file descriptor so you can do this.

You can view the FreeBSD manual pages for (each) of the above FreeBSD system function calls with:

shell$ man 2 read
shell$ man 2 poll

Etc.. etc...

What you want to do is to write a poll() loop (or) a select() loop -- so your code can run inside a thread (pthread(3)?) or fork(2) process or even just your main() function -- and occasionally check for socket I/O. You can use the same poll(2) logic to check the file descriptor for "ready-to-write" and ERROR issues as well.

This logic can likely also be done with SSL_poll(2).

This same coding logic also works on Linux, Mac and Windows (unless you are in a WinSock world, then you will need to bend it slightly).

Hope that helps!
 
It helps a bunch! Thank you!

I had seen the SSL_poll() reference in the OpenSSL reference (which is a word-for-word with the man pages) and was really hoping it wasn't that, as I was getting lost in the morass. You laying out the logic made it much clearer and it now feels feasable.

The OpenSSL specs constantly refer to the asynchronous mechanism you describe, but I believe I have set my BIO object to be non blocking, and I still can't get it not to block. I'm probably doing that part wrong. I create the listening BIO with BIO_set_nbio_accept(mybio, 1), and the "1" flag supposedly makes it non-blocking. But maybe when I pop it with BIO_pop and create the final client BIO object ( clientbio=BIO_pop(mybio)), it somehow loses that property. I'll have to look into that, it would be great if I could get it properly non-blocking instead of finding a work around.

This adventure did reveal a logical error in the preceeding code, which once fixed will allow me to continue in my hacky fashion of "guessing" what and when the client will ask.

I will iron out the basic logic, then figure out how to make it non blocking (on the SSL level, using SSL_get_fd if I can't), and then implement threads or forks as a final step. I feel this way it has the best chance of being a robust system. I was dead set on threads, but somebody sold me on forks because then you aren't tied to a single physical cpu and the program becomes more scaleable. We'll see about that, plenty of problems to solve in the interim.

Thanks again, very valuable help.
 
Back
Top