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

Generated by: LCOV version 1.14