Boost logo

Boost :

From: Christopher Kohlhoff (chris_at_[hidden])
Date: 2006-07-21 02:10:30


Hi Scott and Viktor,

After some time spent debugging and trying to figure out the
ssl::stream code, I think have found the problem (actually there
were two):

- A read operation should check the read buffer first to see if
  there's any data present and use that first, before issuing a
  new read from the socket.

- The read buffer is a member of the openssl_operation class,
  and a new openssl_operation object is created for each read or
  write initiated by the application. This means that any
  surplus data from a previous read is lost.

Can you please try the diffs included below and let me know how
it goes. Thanks!

Cheers,
Chris

Index: asio/ssl/detail/openssl_operation.hpp
===================================================================
RCS file: /cvsroot/asio/asio/include/asio/ssl/detail/openssl_operation.hpp,v
retrieving revision 1.9
diff -u -r1.9 openssl_operation.hpp
--- asio/ssl/detail/openssl_operation.hpp 28 May 2006 06:54:42 -0000 1.9
+++ asio/ssl/detail/openssl_operation.hpp 21 Jul 2006 05:31:07 -0000
@@ -82,12 +82,14 @@
   // Constructor for asynchronous operations
   openssl_operation(ssl_primitive_func primitive,
                     Stream& socket,
+ net_buffer& recv_buf,
                     SSL* session,
                     BIO* ssl_bio,
                     user_handler_func handler
                     )
     : primitive_(primitive)
     , user_handler_(handler)
+ , recv_buf_(recv_buf)
     , socket_(socket)
     , ssl_bio_(ssl_bio)
     , session_(session)
@@ -105,9 +107,11 @@
   // Constructor for synchronous operations
   openssl_operation(ssl_primitive_func primitive,
                     Stream& socket,
+ net_buffer& recv_buf,
                     SSL* session,
                     BIO* ssl_bio)
     : primitive_(primitive)
+ , recv_buf_(recv_buf)
     , socket_(socket)
     , ssl_bio_(ssl_bio)
     , session_(session)
@@ -165,6 +169,36 @@
       // not want network communication nor does want to send shutdown out...
       return handler_(asio::error(error_code), rc);
 
+ if (!is_operation_done && !is_write_needed)
+ {
+ // We may have left over data that we can pass to SSL immediately
+ if (recv_buf_.get_data_len() > 0)
+ {
+ // Pass the buffered data to SSL
+ int written = ::BIO_write
+ (
+ ssl_bio_,
+ recv_buf_.get_data_start(),
+ recv_buf_.get_data_len()
+ );
+
+ if (written > 0)
+ {
+ recv_buf_.data_removed(written);
+ }
+ else if (written < 0)
+ {
+ if (!BIO_should_retry(ssl_bio_))
+ {
+ // Some serios error with BIO....
+ return handler_(asio::error(asio::error::no_recovery), 0);
+ }
+ }
+
+ return start();
+ }
+ }
+
     // Continue with operation, flush any SSL data out to network...
     return write_(is_operation_done, rc);
   }
@@ -181,7 +215,12 @@
   int_handler_func handler_;
     
   net_buffer send_buf_; // buffers for network IO
- net_buffer recv_buf_;
+
+ // The recv buffer is owned by the stream, not the operation, since there can
+ // be left over bytes after passing the data up to the application, and these
+ // bytes need to be kept around for the next read operation issued by the
+ // application.
+ net_buffer& recv_buf_;
 
   Stream& socket_;
   BIO* ssl_bio_;
Index: asio/ssl/detail/openssl_stream_service.hpp
===================================================================
RCS file: /cvsroot/asio/asio/include/asio/ssl/detail/openssl_stream_service.hpp,v
retrieving revision 1.11
diff -u -r1.11 openssl_stream_service.hpp
--- asio/ssl/detail/openssl_stream_service.hpp 16 Jun 2006 11:52:28 -0000 1.11
+++ asio/ssl/detail/openssl_stream_service.hpp 21 Jul 2006 05:41:34 -0000
@@ -152,6 +152,7 @@
   {
     ::SSL* ssl;
     ::BIO* ext_bio;
+ net_buffer recv_buf;
   } * impl_type;
 
   // Construct a new stream socket service for the specified io_service.
@@ -179,6 +180,7 @@
     impl = new impl_struct;
     impl->ssl = ::SSL_new(context.impl());
     ::SSL_set_mode(impl->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
+ ::SSL_set_mode(impl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
     ::BIO* int_bio = 0;
     impl->ext_bio = 0;
     ::BIO_new_bio_pair(&int_bio, 8192, &impl->ext_bio, 8192);
@@ -240,6 +242,7 @@
         &ssl_wrap<mutex_type>::SSL_connect:
         &ssl_wrap<mutex_type>::SSL_accept,
       next_layer,
+ impl->recv_buf,
       impl->ssl,
       impl->ext_bio,
       boost::bind
@@ -265,6 +268,7 @@
       openssl_operation<Stream> op(
         &ssl_wrap<mutex_type>::SSL_shutdown,
         next_layer,
+ impl->recv_buf,
         impl->ssl,
         impl->ext_bio);
       op.start();
@@ -292,6 +296,7 @@
     (
       &ssl_wrap<mutex_type>::SSL_shutdown,
       next_layer,
+ impl->recv_buf,
       impl->ssl,
       impl->ext_bio,
       boost::bind
@@ -322,6 +327,7 @@
       openssl_operation<Stream> op(
         send_func,
         next_layer,
+ impl->recv_buf,
         impl->ssl,
         impl->ext_bio
       );
@@ -356,6 +362,7 @@
     (
       send_func,
       next_layer,
+ impl->recv_buf,
       impl->ssl,
       impl->ext_bio,
       boost::bind
@@ -385,6 +392,7 @@
             asio::buffer_size(*buffers.begin()));
       openssl_operation<Stream> op(recv_func,
         next_layer,
+ impl->recv_buf,
         impl->ssl,
         impl->ext_bio
       );
@@ -420,6 +428,7 @@
     (
       recv_func,
       next_layer,
+ impl->recv_buf,
       impl->ssl,
       impl->ext_bio,
       boost::bind


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk