Hello. I’m attempting to use SSL within my Fiber-based Actor framework
( http://revactor.org) and running into problems incorporating SSL.
As far as I can discern, OpenSSL::SSL::SSLSocket#sysread and #syswrite
are
non-blocking (please correct me if this is wrong) if the socket is in
the
read/write ready state to begin with, which is great.
However, #connect and #accept, which (I believe) do the SSL handshaking,
both block.
Is there any way to do a non-blocking SSL handshake?
After investigating the issue some more, it appears that this is
impossible
without a C extension.
The ossl_start_ssl() function in ossl_ssl.c, which is used by both
OpenSSL::SSL::SSLSocket#connect and #accept, contains a loop which calls
SSL_connect() or SSL_accept() repeatedly. If either of these functions
needs the socket to be in a readable or writable state,
rb_io_wait_readable() or rb_io_wait_writable() is called, blocking the
application.
Has there been any consideration as to adding something like
OpenSSL::SSL::SSLSocket#connect_nonblock and #accept_nonblock to go
along
with Socket#connect_nonblock and Socket#accept_nonblock?
On Fri, 8 Feb 2008 05:38:57 +0900, “Tony A.” [email protected]
wrote:
Has there been any consideration as to adding something like
OpenSSL::SSL::SSLSocket#connect_nonblock and #accept_nonblock to go along
with Socket#connect_nonblock and Socket#accept_nonblock?
Well, I managed to create a subclass of OpenSSL::SSL::SSLSocket in a C
extension which implements #connect_nonblock and #accept_nonblock. It
was
quite a hack: #connect and #accept both call the static C function
ossl_ssl_setup(), which for whatever reason is not called from #initialize.
I managed to do it by finding a third method, #session=, which also
calls
ossl_ssl_setup(). I couldn’t really figure out what this is for…
there’s
a whole OpenSSL::SSL::Session class defined in ossl_ssl_session.c, but
the
Init function for this file is never called, so while it’s linked into
the
OpenSSL C extension, it’s not accessible in the Ruby environment.
I fed #session= a bogus parameter (nil), and fortunately the method
calls
ossl_ssl_setup() before doing any typechecking on its arguments. This
meant
I could catch the exception it threw due to the bogus argument, but
ossl_ssl_setup() was still called.
Changing the ossl_start_ssl() function that #connect and #accept call
into a
non-blocking one was pretty trivial: I just had it raise exceptions for
when
it needed more data to complete the connection, rather than calling
rb_io_wait_readable() / rb_io_wait_writable(). If there’s any interest
I
can contribute the code back to the OpenSSL extension, but since it’s so
trivial I’d encourage someone on the OpenSSL team to implement it
themselves.
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.