title: Boost asio tcp socket available reports incorrect number of bytes
body: <p>In SSL client server model, I use the code below to read data from the socket on either client or server side.</p>
  
  <p>I only read data when there is data available. To know when there is data available, I check the <code>available()</code> method on the <code>lowest_layer()</code> of the <code>asio::ssl::stream</code>.
  After I send 380 bytes from the client to the server and enter the read method on the server, I see the following.</p>
  
  <p>‘s’   is the buffer I supplied.<br>
  ‘n’   is the size of the buffer I supplied.<br>
  ‘a1’  is the result of available() before the read and will report 458 bytes.<br>
  ‘r’   is the number of bytes actually read. It will report 380, which is correct.<br>
  ‘a2’  is the result of available() after the read and will report 0 bytes. This is what I expect, since my client sent 380 bytes and I have read them all.<br></p>
  
  <p>Why does the first call to <code>available()</code> report too many bytes?</p>
  
  <p>Types: </p>
  
  <pre><code>/**
   * Type used as SSL Socket. Handles SSL and socket functionality.
   */
  typedef boost::asio::ssl::stream&lt;boost::asio::ip::tcp::socket&gt; SslSocket;
  /**
   * A shared pointer version of the SSL Socket type.
   */
  typedef boost::shared_ptr&lt;SslSocket&gt;                           ShpSslSocket;
  </code></pre>
  
  <p>Members:</p>
  
  <pre><code>ShpSslSocket                     m_shpSecureSocket; 
  </code></pre>
  
  <p>Part of the read method:</p>
  
  <pre><code>std::size_t a1 = 0;
  if ((a1 = m_shpSecureSocket-&gt;lowest_layer().available()) &gt; 0)
  {
     r += boost::asio::read(*m_shpSecureSocket,
                            boost::asio::buffer(s, n),
                            boost::asio::transfer_at_least(1));
  }
  
  std::size_t a2 = m_shpSecureSocket-&gt;lowest_layer().available();
  </code></pre>
  
  <hr>
  
  <p>Added info: <br></p>
  
  <p>So I changed my read method to more thoroughly check if there is still data available to be read from the boost::asio::ssl::stream. Not only do I need to check if there is data available on the socket level, but there may also be data stuck in the OpenSSL buffers somewhere. SSL_peek does the trick. Next to checking for available data, it also checks the TCP port status and does all this as long as there is no timeout.</p>
  
  <p>Here is the complete read method of the boost::iostreams::device class that I created.</p>
  
  <pre><code>std::streamsize SslClientSocketDevice::read(char* s, std::streamsize n)
  {
     // Request from the stream/device to receive/read bytes.
     std::streamsize r = 0;
  
     LIB_PROCESS::TcpState eActualState = LIB_PROCESS::TCP_NOT_EXIST;
  
     char chSslPeekBuf; // 1 byte peek buffer
  
     // Check that there is data available. If not, wait for it.
     // Check is on the lowest layer (tcp). In that layer the data is encrypted.
     //  The number of encrypted bytes is most often different than the number
     //  of unencrypted bytes that would be read from the secure socket.
     // Also: Data may be read by OpenSSL from the socket and remain in an
     //  OpenSSL buffer somewhere. We also check that.
     boost::posix_time::ptime start = BOOST_UTC_NOW;
     int         nSslPeek  = 0;
     std::size_t nAvailTcp = 0;
     while ((*m_shpConnected) &amp;&amp;
            (LIB_PROCESS::IpMonitor::CheckPortStatusEquals(GetLocalEndPoint(),
                                                           GetRemoteEndPoint(),
                                                           ms_ciAllowedStates,
                                                           eActualState)) &amp;&amp;
            ((nAvailTcp = m_shpSecureSocket-&gt;lowest_layer().available()) == 0) &amp;&amp;
            ((nSslPeek  = SSL_peek(m_shpSecureSocket-&gt;native_handle(), &amp;chSslPeekBuf, 1)) &lt;= 0) &amp;&amp; // May return error (&lt;0) as well
            ((start + m_oReadTimeout) &gt; BOOST_UTC_NOW))
     {
        boost::this_thread::sleep(boost::posix_time::millisec(10));
     }
  
     // Always read data when there is data available, even if the state is no longer valid.
     // Data may be reported by the TCP socket (num encrypted bytes) or have already been read
     //  by SSL and not yet returned to us.
     // Remote party can have sent data and have closed the socket immediately.
     if ((nAvailTcp &gt; 0) || (nSslPeek &gt; 0))
     {
        r += boost::asio::read(*m_shpSecureSocket,
                               boost::asio::buffer(s, n),
                               boost::asio::transfer_at_least(1));
     }
  
     // Close socket when state is not valid.
     if ((eActualState &amp; ms_ciAllowedStates) == 0x00)
     {
        LOG4CXX_INFO(LOG4CXX_LOGGER, "TCP socket not/no longer connected. State is: " &lt;&lt;
                                      LIB_PROCESS::IpMonitor::TcpStateToString(eActualState));
        LOG4CXX_INFO(LOG4CXX_LOGGER, "Disconnecting socket.");
        Disconnect();
     }
  
     if (! (*m_shpConnected))
     {
        if (r == 0)
        {
           r = -1; // Signal stream is closed if no data was retrieved.
           ThrowExceptionStreamFFL("TCP socket not/no longer connected.");
        }
     }
  
     return r;
  }
  </code></pre>