Boost logo

Boost Users :

Subject: [Boost-users] [asio] SSL enabled http server3 example is blocking
From: Mariusz Wojtysiak (zxspeccy.cpp_at_[hidden])
Date: 2009-09-07 08:11:57


Hello,

I noticed, that my ssl server implemented with boost::asio, which use
pool of 10 threads, use only first working thread.
Even if I put long running operation (like: std::cin > c; ) in handler
of ssl request, request from second client is hung until running
operation finish in first thread.

Similar problem was described in archived post: "[asio] SSL enabled
http server3 example is blocking"

http://groups.google.pl/group/boost-list/browse_frm/thread/c26432c90020e6d9/81febf05c3db485a?hl=pl&ie=UTF-8&q=SSL+enabled+http+server3+example+is+blocking#81febf05c3db485a

After a few hours of debugging asio, I found a reason:
Class openssl_stream_service implement ssl operations (like
async_handshake, async_write_some...) using strand_ member, which is
type of io_service::strand.

This causes that two ssl operations using the same ssl stream cannot
be running in the same time.

Here is piece of code, which I had on my server to handle client
request:

void Request::handleClientRequest()
{
boost::asio::async_read_until( m_sessionPtr->getSocket(),
m_headerBuffer, '\n',
                boost::bind( &Request::readHeaderHandler, shared_from_this(),
                                        boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred ) );

}

void Request::readHeaderHandler( const boost::system::error_code
&error, std::size_t bytesTransferred )
{
  // long running operation
 char c;
}

Method readHeaderHandler() is called from io_service::strand, so
during this long running operation any other requests from clients
have to wait!

Solution it simple and works fine for me:
Instead of calling long operations directly in handler, post operation
to io_service, like here:

void Request::readHeaderHandler( const boost::system::error_code
&error, std::size_t bytesTransferred )
{
  m_ioService.post( boost::bind
( &Request::executeCommandHandler::executeCommandHandler,
shared_from_this() ) );
}

void Request::executeCommandHandler()
{
  // long running operation
 char c;
}

This way, readHeaderHandler() return immediately from current srand
operation (so other client's request may be handled) and
executeCommandHandler() is called a bit later.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net