On Wed, Mar 05, 2008 at 10:01:26AM -0500, Geoff Thorpe wrote:
> Hi Thor,
>
> On Sun, 2008-03-02 at 23:21 -0500, Thor Lancelot Simon wrote:
> > > FWIW, this is not really the right way of implementing async support in
> > > openssl. "Completion" events are not always going to be related to file
> > > descriptors in any clear way

> >
> > Certainly if the file in question is one for a Unix device driver, and
> > that device driver is in use for asynchronous hardware-accellerated crypto
> > operations, there will, in fact, be a perfectly clear relationship.

>
> Well, maybe in the cases you're interested in, but this is not an
> assumption I'm prepared to make w.r.t. abstractions. Even for crypto
> drivers that are fd-based, it would be lazy/inefficient for there to be
> a fd *per-operation* - ie. whilst a process's communication with a
> driver might very well be fd-based, the presence of data on that fd
> wouldn't necessarily indicate which asynchronous operation had
> completed. And even on unix, completions could occur via signals, IPC
> (of various forms), whatever. If openssl is to provide support for
> asynchronous completion, there needs to be a general interface for it.


Well, I did not suggest that one would ever use a file descriptor per
operation. But, let me try again.

Note first that that OpenSSL does not abstract I/O completion waiting
(the API provides SSL_read(), SSL_write(), SSL_connect(), SSL_shutdown(),
but *not* SSL_poll() or SSL_select). When I proposed correcting this,
last year, I got a pretty strongly negative reception.

Note next that there are already a nontrivial number of nontrivial
applications using the existing non-blocking select()/poll() driven API
to OpenSSL, despite its warts. This API *already* requires, quite
explicitly, extracting the file descriptor from each SSL session and
adding those descriptors to a select() or poll() set. Applications are
already written to this API and it does not abstract completion waiting
as you suggest it should (I happen to agree with you, but neither you
nor I can adjust all of everyone else's code out there in the world!).
This API also *already* requires any operations that would block to be
reissued at the SSL layer by retrying exactly the same operation again
after the file descriptor for that session comes up ready with select
or poll.

I do not love this API, but it is what all the existing, non-threaded
non-blocking OpenSSL API consumers are written to, and I think it would
be a considerable mistake to change it now.

So, given my "note first" and "note second" I believe I have established
that, to do non-blocking I/O in a single-threaded application with OpenSSL,
one must already:

1) Dip beneath the SSL abstraction layer to get the file
descriptor for each session.

2) Use select() or poll() to wait on all those file descriptors.

3) Retry operations, exactly as issued prior to completion waiting,
when their sessions' descriptors come up ready in select or
poll (whether to select for read-ready or write-ready is known
by the WANT_READ or WANT_WRITE SSL errors returned when the
operation would block).

I propose, then, to extend the existing interface to accomodate non-blocking
operation of ENGINEs themselves, by:

4) Adding a method to probe whether an ENGINE supports non-blocking
operation.

5) Adding a method, for such ENGINEs, to get the file descriptor to
add to the select or poll set (or, on other platforms, what must
nonetheless be a file-descriptor-based completion waiting
mechanism functionally equivalent to select or poll, because
this is what the current API requires already) the application
must already be using for I/O, to find out if any operations
have completed on the underlying cryptographic device.

6) Adding a second method, for such ENGINEs, to find out whether
the request for a given SSL session completed.

4) Adding one more return value when an SSL-level operation would
block, WANT_CRYPTO, which means that the application must add
the ENGINE-specified fd from #5 above to its select or poll
set.

Given the already existing API for non-blocking operation in OpenSSL, I
must confess I am pretty much baffled how else it _could_ work. I do not
think it is possible to abstract the completion waiting mechanism so that
it doesn't involve file descriptors because you cannot use some other such
mechanism in tandem with select or poll (which the API already needs)
since those explicitly sleep the application until a descriptor comes
ready.

However, it's basically trivial for an ENGINE which itself is notified by
some other mechanism to arrange to wake the application via a file
descriptor by simply looping a pipe or socket back to itself and writing
a byte or message there, FWIW.

Unfortunately, I don't have code I can offer as patches against OpenSSL-
current for this; what I have are patches against a proprietary vendor-
modified OpenSSL which doesn't use the ENGINE interface but uses something
functionally equivalent to it. I am proposing to reimplement as free code
but I'm somewhat hesitant to spend what I estimate as at least two weeks
of effort if there's a lack of consensus that this is the right way to
go...

Thor
__________________________________________________ ____________________
OpenSSL Project http://www.openssl.org
Development Mailing List openssl-dev@openssl.org
Automated List Manager majordomo@openssl.org