LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/io - ssl_session.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 77 85 90.6 %
Date: 2026-11-09 02:10:49 Functions: 13 16 81.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #include "io/ssl_session.h"
       7             : 
       8             : #include <string>
       9             : 
      10             : #include <boost/asio.hpp>
      11             : #include <boost/bind/bind.hpp>
      12             : 
      13             : #include "io/event_manager.h"
      14             : #include "io/io_log.h"
      15             : #include "io/io_utils.h"
      16             : 
      17             : using boost::asio::async_write;
      18             : using boost::asio::buffer;
      19             : using boost::asio::buffer_cast;
      20             : using boost::asio::mutable_buffer;
      21             : using boost::asio::mutable_buffers_1;
      22             : using boost::asio::null_buffers;
      23             : using boost::asio::placeholders::error;
      24             : using boost::asio::placeholders::bytes_transferred;
      25             : using boost::asio::ssl::stream_base;
      26             : using boost::bind;
      27             : using boost::function;
      28             : using boost::system::error_code;
      29             : using std::size_t;
      30             : using std::srand;
      31             : using std::string;
      32             : using std::time;
      33             : using namespace boost::placeholders;
      34             : 
      35             : class SslSession::SslReader : public Task {
      36             : public:
      37             :     typedef function<void(Buffer)> ReadHandler;
      38             : 
      39     1174975 :     SslReader(int task_id, SslSessionPtr session, ReadHandler read_fn,
      40             :               Buffer buffer)
      41     2349950 :        : Task(task_id, session->GetSessionInstance()),
      42     1174975 :          session_(session), read_fn_(read_fn), buffer_(buffer) {
      43     1174975 :     }
      44     1174952 :     virtual bool Run() {
      45     1174952 :         if (session_->IsEstablished()) {
      46     1174235 :             session_->ssl_last_read_len_ = BufferSize(buffer_);
      47     1174221 :             read_fn_(buffer_);
      48     1174237 :             if (session_->IsReaderDeferred()) {
      49             :                 // Update socket read block count.
      50           0 :                 session_->stats_.read_block_start_time = UTCTimestampUsec();
      51           0 :                 session_->stats_.read_blocked++;
      52           0 :                 session_->server()->stats_.read_blocked++;
      53             :             } else {
      54     1174230 :                 if (session_->IsSslDisabled()) {
      55      315387 :                      session_->AsyncReadStart();
      56      858840 :                 } else if (!session_->IsSslHandShakeInProgress()) {
      57      855934 :                     session_->AsyncReadStart();
      58             :                 }
      59             :             }
      60             :         }
      61     1174974 :         return true;
      62             :     }
      63           0 :     string Description() const { return "SslSession::SslReader"; }
      64             : 
      65             : private:
      66             :     SslSessionPtr session_;
      67             :     ReadHandler read_fn_;
      68             :     Buffer buffer_;
      69             : };
      70             : 
      71       14475 : SslSession::SslSession(SslServer *server, SslSocket *ssl_socket,
      72       14475 :                        bool async_read_ready)
      73             :     : TcpSession(server, NULL, async_read_ready),
      74       14475 :       ssl_socket_(ssl_socket),
      75       14475 :       ssl_handshake_in_progress_(false),
      76       14475 :       ssl_handshake_success_(false),
      77       14475 :       ssl_enabled_(true),
      78       14475 :       ssl_handshake_delayed_(false),
      79       14475 :       ssl_last_read_len_(0) {
      80             : 
      81       14475 :     if (server) {
      82       14474 :         ssl_enabled_ = server->ssl_enabled_;
      83       14474 :         ssl_handshake_delayed_ = server->ssl_handshake_delayed_;
      84             :     }
      85       14475 : }
      86             : 
      87       14470 : SslSession::~SslSession() {
      88       14470 : }
      89             : 
      90     1174975 : Task* SslSession::CreateReaderTask(mutable_buffer buffer,
      91             :                                    size_t bytes_transferred) {
      92     1174975 :     Buffer rdbuf(buffer_cast<const uint8_t *>(buffer), bytes_transferred);
      93     1174975 :     SslReader *task = new SslReader(this->reader_task_id(),
      94     1174975 :         SslSessionPtr(this), bind(&SslSession::OnRead, this, _1), rdbuf);
      95     1174975 :     return (task);
      96             : }
      97             : 
      98             : 
      99     3235880 : TcpSession::Socket *SslSession::socket() const {
     100     3235880 :     if (ssl_socket_) {
     101             :         // return tcp socket
     102     3235808 :         return &ssl_socket_->next_layer();
     103             :     }
     104           0 :     return NULL;
     105             : }
     106             : 
     107             : // Register for data read notification from the tcp socket or from the ssl
     108             : // socket, as appropriate.
     109     1187468 : void SslSession::AsyncReadSome() {
     110     1187468 :     if (established()) {
     111     1187250 :         if (ssl_last_read_len_ == 0) {
     112             :             // we have drained the read buffer of the socket
     113             :             // register for a read notification from the tcp socket
     114      157374 :             TcpSession::AsyncReadSome();
     115             :         } else {
     116             :             // trigger Async Read Handler for immediate read
     117     1029876 :             TriggerAsyncReadHandler();
     118             :         }
     119             :     }
     120     1187468 : }
     121             : 
     122             : // Tests with large data have consistently shown 16K as the maximum read data
     123             : // size even though when a lot more data was available in the underlying socket.
     124             : // Also, there is no available() api for the ssl socket.
     125     1181523 : size_t SslSession::GetReadBufferSize() const {
     126     1181523 :     return kDefaultBufferSize;
     127             : }
     128             : 
     129             : //
     130             : // Check if a socker error is hard and fatal. Only then should we close the
     131             : // socket. Soft errors like EINTR and EAGAIN should be ignored or properly
     132             : // handled with retries
     133             : //
     134           0 : bool SslSession::IsSocketErrorHard(const error_code &ec) {
     135             : 
     136             :     bool error;
     137           0 :     error = TcpSession::IsSocketErrorHard(ec);
     138             : #if defined(SSL_R_SHORT_READ)  // openssl 1.0
     139             :     if (ec.value() == ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ)) {
     140             :         error = false;
     141             :     }
     142             : #elif defined(BOOST_ASIO_SSL_ERROR_STREAM_TRUNCATED) // new openssl and boost
     143             :     if (ec.value() == boost::asio::ssl::error::stream_truncated) {
     144             :         error = false;
     145             :     }
     146             : #endif
     147             : 
     148           0 :     return error;
     149             : }
     150             : 
     151     1181523 : size_t SslSession::ReadSome(mutable_buffer buffer, error_code *error) {
     152             :     // Read data from the tcp socket or from the ssl socket, as appropriate.
     153     1181523 :     assert(!ssl_handshake_in_progress_);
     154     1181523 :     if (!IsSslHandShakeSuccessLocked())
     155      330305 :         return TcpSession::ReadSome(buffer, error);
     156             : 
     157      851218 :     return ssl_socket_->read_some(mutable_buffers_1(buffer), *error);
     158             : }
     159             : 
     160     1660378 : void SslSession::AsyncWrite(const uint8_t *data, size_t size) {
     161     1660378 :     if (IsSslHandShakeSuccessLocked()) {
     162      807337 :         async_write(*ssl_socket_.get(), buffer(data, size),
     163     1614674 :             bind(&TcpSession::AsyncWriteHandler,
     164     1614674 :                  TcpSessionPtr(this), error, bytes_transferred));
     165             :     } else {
     166      853041 :         return (TcpSession::AsyncWrite(data, size));
     167             :     }
     168             : }
     169             : 
     170        2931 : void SslSession::SslHandShakeCallback(SslHandShakeCallbackHandler cb,
     171             :                                       SslSessionPtr session,
     172             :                                       const error_code &error) {
     173        2931 :     session->ssl_handshake_in_progress_ = false;
     174        2931 :     if (!error) {
     175        2910 :         session->SetSslHandShakeSuccess();
     176             :     } else {
     177          21 :         session->SetSslHandShakeFailure();
     178             :     }
     179             : 
     180        2931 :     if (session->socket() != NULL && !(session->IsClosed())) {
     181        2931 :         cb(session, error);
     182             :     }
     183        2931 : }
     184             : 
     185        2931 : void SslSession::TriggerSslHandShakeInternal(
     186             :         SslSessionPtr session, SslHandShakeCallbackHandler cb) {
     187        2931 :     srand(static_cast<unsigned>(time(0)));
     188        2931 :     error_code ec;
     189        2931 :     session->ssl_handshake_in_progress_ = true;
     190        2931 :     if (session->IsServerSession()) {
     191        2910 :         session->ssl_socket_->async_handshake(stream_base::server,
     192        2910 :             bind(&SslSession::SslHandShakeCallback, cb, session,
     193             :             error));
     194             :     } else {
     195        2952 :         session->ssl_socket_->async_handshake(stream_base::client,
     196        2952 :             bind(&SslSession::SslHandShakeCallback, cb, session,
     197             :                  error));
     198             :     }
     199        2931 : }
     200             : 
     201        2931 : void SslSession::TriggerSslHandShake(SslHandShakeCallbackHandler cb) {
     202        5862 :     server()->event_manager()->io_service()->post(
     203        5862 :         bind(&TriggerSslHandShakeInternal, SslSessionPtr(this), cb));
     204        2931 : }

Generated by: LCOV version 1.14