How do you do timed-out persistent/keep alive SSL connections with blocking sockets?
A previous question asked if changing one line of code implemented persistent SSL connections. After seeing that question's responses, and checking the dearth of SSL documentation, the following appear true:
for the server, a persistent connection is simply doing repeated requests/responses between SSL_accept() and SSL_set_shutdown().
according to this page, the client has to indicate how many requests there will be by sending the appropriate "Content-length:" header or using an agreed-upon terminating request.
However, there's no guarantee the client will send what it's supposed to. Therefore, it would seem a server using blocking sockets can hang indefinitely on a SSL_read() while waiting for additional requests that never arrive. (SSL_CTX_set_timeout() doesn't appear to cause a subsequent SSL_read() to exit early, so it's not clear how to do timed-out connections as described at this Wikipedia page if sockets are blocking.)
Apparently, a server can indicate it won't do keep-alive by returning a "Connection: Close" header with a response, so I've ended up with the following code, which at least should always correctly do a single request/response per connection:
while TRUE do
begin // wait for incoming TCP connection
if notzero(listen(listen_socket, 100)) then continue; // listen failed
client_len := SizeOf(sa_cli);
sock := accept(listen_socket, @sa_cli, @client_len); // create socket for connection
if sock = INVALID_SOCKET then continue; // accept failed
ssl := SSL_new(ctx); // TCP connection ready, create ssl structure
if assigned(ssl) then
begin
SSL_set_fd(ssl, sock); // assign socket to ssl structure
if SSL_accept(ssl) = 1 then // handshake worked
begin
request := '';
repeat // gather request
bytesin := SSL_read(ssl, buffer, sizeof(buffer)-1);
if bytesin > 0 then
begin
buffer[bytesin] := #0;
request := request + b开发者_JS百科uffer;
end;
until SSL_pending(ssl) <= 0;
if notempty(request) then
begin // decide on response, avoid keep-alive
response := 'HTTP/1.0 200 OK'#13#10'Connection: Close'#13#10 + etc;
SSL_write(ssl, pchar(response)^, length(response));
end; // else read empty or failed
end; // else handshake failed
SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN or SSL_RECEIVED_SHUTDOWN);
CloseSocket(sock);
SSL_free(ssl);
end; // else ssl creation failed
end; // infinite while
Two questions:
(1) Since SSL_accept() must be true to reach SSL_read(), is it true SSL_read() can never hang waiting for the first request?
(2) How should this code be modified to do timed-out persistent/keep alive SSL connections with blocking sockets (if that's even possible)?
To quote this letter, "The only way to ensure that indefinite blocking is avoided is to use nonblocking I/O." So, I guess I'll give up trying to timeout blocked SSL_read()s.
(1) if the client connects but does not send a request (DoS attack, for instance), then SSL_read() would hang.
(2) try calling setsockopt(SO_RCVTIMEO)
on the accepted SOCKET
to set a reading timeout on it.
精彩评论