Shaw Graham George wrote:
Sure.
1. The server receives the HTTP request, using SSL_read() and
SSL_pending(). The request contains a Keep-Alive request.
2. The server writes the data out to another process.
3. The server then it sits on an event handler that multiplexes a
select() (or Windows equivalent) on sockets it has an interest in, and
other events such as receiving data from other processes.
What is the sleep/wakeup IO mechanism you are employing on windows ?
WaitForMultipleObjects() ?
Side track: Is it possible to make the window platform listen on > 31
sockets at once per thread ? (or whatever is small limit was)
At this time
it actually has no interest in any events at the socket, as it is
waiting for the processing to complete.
I take this to mean you revoke all interest in the socket
readability/writability. So the server is no oblivious to what the
client is doing.
4. The SSL client lose patience with a lack of response, and does an
SSL shutdown and socket close.
Okay you closed your ears to the read event ? On Unix the select() has
an exceptfds which can be used to pickup a socket error/close (but may
not be reliable if there is readable data first, since by convention of
TCPs orderly shutdown that has to be eaten before the socket close can
be seen).
5. An event is detected, and the server receives the result from the
background processing.
I take this event to mean a read wakeup on channel facing the request
processing process ?
6. It adds write interest to the socket and goes back to sitting on the
event handler.
7. An event is detected and the server then performs an SSL_write() to
the (non-existent) client, which is successful.
This write may succeed due to kernel buffering and the unread data still
in the read buffer of the kernel until that is read the normal TCP
shutdown/close condition may not be seen. Or it may fail SSL_write() ==
-1 && SSL_get_error() == SSL_ERROR_SYSCALL.
But the problem here is that your application is being single minded, in
that it has shut its ears to processing more TCP level data (even tho
the SSL protocol handling layer might require some read processing to
take place, even during writes, but you cut of the SSL protocol layer's
source of data).
I can understand why you do it, since you don't want the application to
be holding onto data relating to the next pipelined request just yet as
you have no intention on servicing it.
What you really wanted in this scenario is continue to observe read
interest in the client TCP socket but use an SSL_peek() call. I have
called for this API call before, that is an OpenSSL API function that
allows WANT_READ processing to take place but does not destructively
return application data.
Since OpenSSL doesn't have a SSL_peek() call and your application could
hold onto a small buffer of extraneous application data then it would be
possible to over-read by one (before you drop read interest). This
would not detect the situation where the client wrote multiple requests
to the server, waited a short time, then reverted to sending a SSL
shutdown notify and closing the socket.
What you really wanted to know was out-of-band indication from the
kernel that the client reset the connection. Knowing that client had
TCP send shutdown is not useful, only if a connection reset was known
about before, which requires the client to have actually sent a TCP
reset packet (which I think occurs in the situation you are in, due to
the WSAGetLastError() == WSAECONNABORTED.
8. It then adds read interest in the socket, as it is a Keep-Alive
socket, so it is waiting for the next HTTP request. It goes back to
sitting on the event handler.
9. An event is detected and the server then performs:
9a. SSL_read() which fails (return code is -1).
9b. SSL_get_error() which returns SSL_ERROR_SYSCALL.
9c. ERR_get_error() which returns 0.
In the original code SSL_get_shutdown() would not be called unless
SSL_get_error() returns SSL_ERROR_ZERO_RETURN, but I added an extra
debug call after the call to SSL_get_error(), and it did not show
SSL_RECEIVED_SHUTDOWN.
And I have now added a call to WSAGetLastError() after the call to
ERR_get_error(), and it returns WSAECONNABORTED.
So I do get a read event on the socket. I do call SSL_read. It fails.
But the shutdown is apparently not received, as:
a. SSL_get_error() does not return SSL_ERROR_ZERO_RETURN
b. SSL_get_shutdown() does not show SSL_RECEIVED_SHUTDOWN
I hope that's clear.
Okay knowing that WSAGetLastError() == WSAECONNABORTED as this time is
irrelevant, since any SSL_read() == -1 && SSL_get_error() ==
SSL_ERROR_SYSCALL would always be a sitution to cleanup and close the
socket. Since OpenSSL already processes the Winsock API error returns
for WANT_READ and WANT_WRITE on non-blocking sockets itself. Getting a
SSL_ERROR_SYSCALL is not a recoverable situation. Work through my code
snippet to see exactly this behavior.
So after reading it all it seems you want to detect when a client has
gone away before your processing has created a response, maybe so you
can cancel the processing and save cycles.
There is no mechanism that will be able to detect this 100% if you
include the possibility of HTTP request pipelining and that your
application serializes request processing on a per socket basis. If you
remove one of these factors then it should be possible to detect
impatient clients by continuing to maintain read interest in the socket
and if necessary storing the application data over-read for when its
needed to process the next request. This may catch most situation you
want to catch.
One way of ensuring you never get a pipelined request is to move the
object being served to a unique IP address / TCP port combination per
object per page load. I'm not sure if the pipelining rules for HTTP
would allow differing Host: headers to be pipelined in the same
connection (if the DNS resolution and port resolution pointed to a HTTP
socket your HTTP client connection pool already had open). If it
clearly states you can't then changing the host of the object and
setting up an alias the other side maybe another option.
HTH
Darryl
PS: Would appreciate replies / references on any info to allow windows
to scale socket handling upto at least 4 figure open sockets.
______________________________________________________________________
OpenSSL Project http://www.openssl.org
User Support Mailing List openssl-users@openssl.org
Automated List Manager [EMAIL PROTECTED]