Ah, Ok. I can clean that up ;)
In my existing server (not posted):
- it is single-threaded
- the SSL peer cert authentication works
- the server loses some requests because only accept() is non-blocking.
In the code I posted in the OP:
- it is single-threaded
- it is almost entirely non-blocking
- the server DOES NOT lose requests if peer auth is turned OFF
- if peer auth is ON, the server gives Net::SSLeay errors and destroys the listening socket
-David. | [reply] |
Your first server only has the problem that it is missing new accepts while being busy but it still has to complete authentication before you serve the request, which is more likely to be the source of the blocking than local servicing of requests alone. The code posted in the OP attempts to force everything into a synchronous handling. But of course the authentication is not part of your synchronous handling and your attempted solution is certainly breaking it - but I think this probably isn't just a code-fixing issue but more likely a question of writing code that is asynchronous (so cannot be single-threaded) where it needs to be i.e. that respects the asynchronous nature of the requests and authentications occurring at a lower layer than you have control over when using the modules you have selected.
I'd be inclined instead to conform as closely as possible to the examples shown in Chapter 16 of Programming Perl, which covers everything discussed so far, except that your processing is synchronous and Chapter 16 (when the relevant sections are considered together - they are of course split up for more general purposes than just yours) appears to me to advocate an asynchronous multi-threaded approach.
And re Thread::Queue, you said you already did that in the first solution. And yet you say now that solution was ALSO single-threaded? I think you are missing the point of that module.
| [reply] |
Err, no :) It's a bit more complicated (for good reason).
Indeed the HTTPS (original, unposted) server is single-threaded and embarassingly multiplexed (accept only). It has a reference to a "Dispatcher" object - also in the same thread.
The Dispatcher object when instantiated creates two Thread::Queue::Any objects. It does (obviously) import Threads, but is passed to the HTTPS server's package in such a way as that package does *not* import Threads.
After creating the queue objects, Dispatcher's constructor creates a new thread, passing it the two queue objects, wherein the new thread enters a loop dequeuing requests from one queue, and enqueuing responses to the other queue.
The HTTPS daemon accesses the Dispatcher through its methods: dispatchRequest, pendingReponses, retrieveResponse. Those methods interact *only* with the two queue objects (always in the main thread in which the HTTPS daemon resides).
Why?
IO::Socket::SSL objects break badly when Threads is imported in the same scope (and "no threads" doesn't help ;)
That whole mess was devised so that the work implied by HTTPS requests could be farmed out to a number of "worker" threads from the Dispatcher, without ever letting the HTTPS server's package be exposed to the Threads module.
All of that was quite successful. Thelonius and yourself are quite right to suggest that the SSL handshakes were being missed while previous (blocking) requests were being serviced. The code in the OP was almost there, however the state-machine was wrong because it did not fully emulate the work done by IO::Socket::SSL's accept() method in a multiplexing fashion.
The server code Thelonius posted resolved that issue.
-David.
| [reply] |