title: boost::asio and async SSL stream: how to detect end of data/connection close?
body: <p>I'm trying to make asio and SSL friends.
  Everything going well, but one thing is causing inconvenience: how to
  detect if peer close connection, and distinguish it from situation
  when peer just take a short break in sending data, aiming to continue
  it few seconds later?</p>
  
  <ul>
  <li>boost 1.48</li>
  <li>OpenSSL 1.0.0e</li>
  <li>Compiled to 32-bit code using VS10</li>
  <li>Working on W7 x64.</li>
  </ul>
  
  <p>My confusion comes from the fact, that asio behaviour is different for
  ordinary socket and SSL-stream.
  If I use tcp::socket - I receive EOF error when peer close connection.
  But for boost::asio::ssl::stream - it is
  not the case. Instead, async_read_some returns 0 as bytes transfered,
  and if I try to continue to read from SSL stream - returns short_error
  ( <a href="http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/overview/core/streams.html" rel="noreferrer">http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/overview/core/streams.html</a> ).</p>
  
  <p>So, the questions is: is it expected behaviour, or I misconfigure anything?</p>
  
  <p>Client code  snippet:</p>
  
  <pre><code>class client
  {
  public:
  
      // bla-bla-bla-bla-bla ....
      //
     void handle_write(const boost::system::error_code&amp; error)
     {
         if (!error)
         {
             socket_.async_read_some(boost::asio::buffer(reply_, max_length),
                 boost::bind(&amp;client::handle_read, this,
                 boost::asio::placeholders::error,
                 boost::asio::placeholders::bytes_transferred));
         }
         else
         {
             std::cout &lt;&lt; "Write failed: " &lt;&lt; error.message() &lt;&lt; "\n";
         }
     }
  
     void handle_read(const boost::system::error_code&amp; error,
                     size_t bytes_transferred)
     {
  
         std::cout &lt;&lt; "Bytes transfered: " &lt;&lt; bytes_transferred &lt;&lt; "\n";
         if (!error)
         {
             std::cout &lt;&lt; "Reply: ";
             std::cout.write(reply_, bytes_transferred);
             std::cout &lt;&lt; "\n";
  
             std::cout &lt;&lt; "Reading...\n";
             socket_.async_read_some(boost::asio::buffer(reply_, max_length),
                 boost::bind(&amp;client::handle_read, this,
                 boost::asio::placeholders::error,
                 boost::asio::placeholders::bytes_transferred));
         }
         else if (0 != bytes_transferred)
         {
             std::cout &lt;&lt; "Read failed: " &lt;&lt; error.message() &lt;&lt; ":" 
                       &lt;&lt; error.value() &lt;&lt;  "\n";
         }
     }
  
  private:
     boost::asio::ssl::stream&lt;boost::asio::ip::tcp::socket&gt; socket_;
     boost::asio::streambuf request_;
     char reply_[max_length];
  };
  </code></pre>
  
  <p>If we remove if (0 != bytes_transferred), we'll get "short read" :(.</p>
  
  <p>If we'll use code as-ai, output will be something like this:</p>
  
  <blockquote>
    <p>Request is:</p>
    
    <p>GET / HTTP/1.0</p>
    
    <p>Cookie: Nama-nama=Vala-vala</p>
    
    <p>Bytes transfered: 1024</p>
    
    <p>Reply: HTTP/1.0 200 ok
    Content-type: text/html</p>
    
    <p>
    ..... bla-bla-bla ....</p>
    
    <p>Reading...
    Bytes transfered: 1024</p>
    
    <p>..... bla-bla-bla ....
    ..... bla-bla-bla ....</p>
    
    <p>Reading...
    Bytes transfered: 482</p>
    
    <p>..... bla-bla-bla ....
    </p>
    
    <p>Reading...</p>
    
    <p>Bytes transfered: 0</p>
  </blockquote>
  
  <p>At the same time, if instead async_read_some  we write code, what for
  ordinary socket will return EOF:</p>
  
  <pre><code>boost::asio::async_read(socket_, response_,
      boost::asio::transfer_at_least(1),
      boost::bind(&amp;client::handle_read_content, this,
      boost::asio::placeholders::error));
  </code></pre>
  
  <p>then for SSL-socket we'll get 0 as bytes transfered, and then short_read.</p>
  
  <p>I know that there is not way to detect disconnect in case if peer, for
  example, was just unplugged from the network.
  But how to detect explicit clean peer disconnect from situation when
  peer just do not send data for a some time, but may be will do it
  little bit later?</p>
  
  <p>Or, may be I do not understant something?</p>
  
  <p>WBR,
  Andrey</p>
  
  <p><em>Some addentum:</em>
  SSL/TLS has notation to inform other party about closing connection.
  It close_notify alert. Also underlying TCP socket can be closed.</p>
  
  <p>So, basically, my question is: why, in the same conditions (TCP socket was closed clearly) I receive EOF in case of tcp::socket, and do not receive anything  for boost::asio::ssl::stream.</p>
  
  <p>Is it bug or asio feature?</p>
  
  <p>Yet another addentum:
  For some reasons asio didn't give me a EOF neither if SSL receive close_notify nor underlying TCP socket was closed.</p>
  
  <p>Yes, I can detect dead connections by timeout.
  But how can I detect properly closed SSL-connections? By receiving short_read? </p>