LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/sandesh/library/cpp - sandesh_server.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 97 159 61.0 %
Date: 2026-11-09 02:10:49 Functions: 17 22 77.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : //
       7             : // sandesh_server.cc
       8             : //
       9             : // Sandesh server implementation
      10             : //
      11             : 
      12             : #include <boost/bind/bind.hpp>
      13             : #include <boost/assign.hpp>
      14             : 
      15             : #include <base/address_util.h>
      16             : #include <sandesh/protocol/TXMLProtocol.h>
      17             : #include <sandesh/sandesh_types.h>
      18             : #include <sandesh/sandesh.h>
      19             : #include <sandesh/sandesh_ctrl_types.h>
      20             : #include "sandesh_connection.h"
      21             : #include "sandesh_session.h"
      22             : #include "sandesh_server.h"
      23             : 
      24             : using namespace std;
      25             : using namespace boost::asio;
      26             : using namespace boost::placeholders;
      27             : 
      28             : const std::string SandeshServer::kStateMachineTask = "sandesh::SandeshStateMachine";
      29             : const std::string SandeshServer::kLifetimeMgrTask = "sandesh::LifetimeMgr";
      30             : const std::string SandeshServer::kSessionReaderTask = "io::ReaderTask";
      31             : 
      32             : class SandeshServer::DeleteActor : public LifetimeActor {
      33             : public:
      34          37 :     DeleteActor(SandeshServer *server) :
      35          37 :         LifetimeActor(server->lifetime_manager()), server_(server) { }
      36          37 :     virtual bool MayDelete() const {
      37          37 :         return true;
      38             :     }
      39          37 :     virtual void Shutdown() {
      40          37 :         server_->SessionShutdown();
      41          37 :     }
      42          37 :     virtual void Destroy() {
      43          37 :     }
      44             : private:
      45             :     SandeshServer *server_;
      46             : };
      47             : 
      48             : bool SandeshServer::task_policy_set_ = false;
      49             : 
      50          37 : SandeshServer::SandeshServer(EventManager *evm, const SandeshConfig &config)
      51             :     : SslServer(evm, boost::asio::ssl::context::tlsv12_server,
      52          37 :                 config.sandesh_ssl_enable),
      53          37 :       sm_task_id_(TaskScheduler::GetInstance()->GetTaskId(kStateMachineTask)),
      54          37 :       session_reader_task_id_(TaskScheduler::GetInstance()->GetTaskId(kSessionReaderTask)),
      55          37 :       lifetime_mgr_task_id_(TaskScheduler::GetInstance()->GetTaskId(kLifetimeMgrTask)),
      56          37 :       lifetime_manager_(new LifetimeManager(lifetime_mgr_task_id_)),
      57          74 :       deleter_(new DeleteActor(this)) {
      58             :     // Set task policy for exclusion between :
      59             :     // 1. State machine and lifetime mgr since state machine delete happens
      60             :     //    in lifetime mgr task
      61          37 :     if (!task_policy_set_) {
      62             :         TaskPolicy lm_task_policy = boost::assign::list_of
      63           3 :                 (TaskExclusion(sm_task_id_))
      64           3 :                 (TaskExclusion(session_reader_task_id_));
      65           3 :         TaskScheduler::GetInstance()->SetPolicy(lifetime_mgr_task_id_, lm_task_policy);
      66           3 :         task_policy_set_ = true;
      67           3 :     }
      68          37 :     if (config.sandesh_ssl_enable) {
      69           0 :         boost::asio::ssl::context *ctx = context();
      70           0 :         boost::system::error_code ec;
      71           0 :         ctx->set_options(boost::asio::ssl::context::default_workarounds |
      72             :                 boost::asio::ssl::context::no_tlsv1 |
      73             :                 boost::asio::ssl::context::no_sslv3 |
      74             :                 boost::asio::ssl::context::no_sslv2 |
      75             :                 boost::asio::ssl::context::no_tlsv1_1, ec);
      76           0 :         if (ec.value() != 0) {
      77           0 :             SANDESH_LOG(ERROR, "Error setting ssl options: " << ec.message());
      78           0 :             exit(EINVAL);
      79             :         }
      80             :         // CA certificate
      81           0 :         if (!config.ca_cert.empty()) {
      82             :             // Verify that the peer certificate is signed by a trusted CA
      83           0 :             ctx->set_verify_mode(boost::asio::ssl::verify_peer |
      84             :                                  boost::asio::ssl::verify_fail_if_no_peer_cert,
      85             :                                  ec);
      86           0 :             if (ec.value() != 0) {
      87           0 :                 SANDESH_LOG(ERROR, "Error setting verification mode: " <<
      88             :                             ec.message());
      89           0 :                 exit(EINVAL);
      90             :             }
      91           0 :             ctx->load_verify_file(config.ca_cert, ec);
      92           0 :             if (ec.value() != 0) {
      93           0 :                 SANDESH_LOG(ERROR, "Error loading CA certificate: " <<
      94             :                             ec.message());
      95           0 :                 exit(EINVAL);
      96             :             }
      97             :         }
      98             :         // Server certificate
      99           0 :         ctx->use_certificate_chain_file(config.server_certfile, ec);
     100           0 :         if (ec.value() != 0) {
     101           0 :             SANDESH_LOG(ERROR, "Error using server certificate: " <<
     102             :                         ec.message());
     103           0 :             exit(EINVAL);
     104             :         }
     105             :         // Server private key
     106           0 :         ctx->use_private_key_file(config.server_keyfile,
     107             :                                   boost::asio::ssl::context::pem, ec);
     108           0 :         if (ec.value() != 0) {
     109           0 :             SANDESH_LOG(ERROR, "Error using server private key file: " <<
     110             :                         ec.message());
     111           0 :             exit(EINVAL);
     112             :         }
     113             :     }
     114          37 : }
     115             : 
     116          37 : SandeshServer::~SandeshServer() {
     117          37 :     TcpServer::ClearSessions();
     118          37 : }
     119             : 
     120           0 : int SandeshServer::lifetime_mgr_task_id() {
     121           0 :     return lifetime_mgr_task_id_;
     122             : }
     123             : 
     124          37 : void SandeshServer::SessionShutdown() {
     125          37 :     TcpServer::Shutdown();
     126          37 : }
     127             : 
     128          37 : bool SandeshServer::Initialize(short port, const std::string &ip) {
     129          37 :     int count = 0;
     130             : 
     131          37 :     boost::system::error_code ec;
     132          37 :     boost::asio::ip::address ip_addr = AddressFromString(ip, &ec);
     133          37 :     if (ec) {
     134           0 :         SANDESH_LOG(ERROR, __func__ << ": Invalid server address: " <<
     135             :                 ip << " Error: " << ec);
     136           0 :         return false;
     137             :     }
     138          37 :     while (count++ < kMaxInitRetries) {
     139          37 :         if (TcpServer::Initialize(port, ip_addr))
     140          37 :             break;
     141           0 :         sleep(1);
     142             :     }
     143          37 :     if (!(count < kMaxInitRetries)) {
     144           0 :         SANDESH_LOG(ERROR, "Process EXITING: TCP Server initialization failed for port " << port);
     145           0 :         exit(1);
     146             :     }
     147          37 :     return true;
     148             : }
     149             : 
     150          37 : int SandeshServer::AllocConnectionIndex() {
     151          37 :     std::scoped_lock lock(mutex_);
     152          37 :     size_t bit = conn_bmap_.find_first();
     153          37 :     if (bit == conn_bmap_.npos) {
     154          37 :         bit = conn_bmap_.size();
     155          37 :         conn_bmap_.resize(bit + 1, true);
     156             :     }
     157          37 :     conn_bmap_.reset(bit);
     158          37 :     return bit;
     159          37 : }
     160             : 
     161          37 : void SandeshServer::FreeConnectionIndex(int id) {
     162          37 :     std::scoped_lock lock(mutex_);
     163          37 :     conn_bmap_.set(id);
     164             : 
     165          74 :     for (size_t i = conn_bmap_.size(); i != 0; i--) {
     166          37 :         if (conn_bmap_[i-1] != true) {
     167           0 :             if (i != conn_bmap_.size()) {
     168           0 :                 conn_bmap_.resize(i);
     169             :             }
     170           0 :             return;
     171             :         }
     172             :     }
     173          37 :     conn_bmap_.clear();
     174          37 : }
     175             : 
     176           0 : TcpSession *SandeshServer::CreateSession() {
     177             :     typedef boost::asio::detail::socket_option::boolean<
     178             :         SOL_SOCKET, SO_REUSEADDR> reuse_addr_t;
     179           0 :     TcpSession *session = SslServer::CreateSession();
     180           0 :     Socket *socket = session->socket();
     181             : 
     182           0 :     boost::system::error_code err;
     183           0 :     socket->open(ip::tcp::v4(), err);
     184           0 :     if (err) {
     185           0 :         SANDESH_LOG(ERROR, __func__ << " Server Open Fail " << err.message());
     186             :     }
     187             : 
     188           0 :     socket->set_option(reuse_addr_t(true), err);
     189           0 :     if (err) {
     190           0 :         SANDESH_LOG(ERROR, __func__ << " SetSockOpt Fail " << err.message());
     191           0 :         return session;
     192             :     }
     193             : 
     194           0 :     socket->bind(LocalEndpoint(), err);
     195           0 :     if (err) {
     196           0 :         SANDESH_LOG(ERROR, __func__ << " Server Bind Failure " <<  err.message());
     197             :     }
     198             : 
     199           0 :     return session;
     200             : }
     201             : 
     202          37 : void SandeshServer::Shutdown() {
     203          37 :     assert(deleter_.get());
     204          37 :     deleter_->Delete();
     205          37 : }
     206             : 
     207           0 : bool SandeshServer::Compare(const Endpoint &peer_addr,
     208             :                             const SandeshConnectionPair &p) const {
     209           0 :     return (peer_addr == p.second->endpoint() ?  false : true);
     210             : }
     211             : 
     212           0 : SandeshConnection *SandeshServer::FindConnection(const Endpoint &peer_addr) {
     213           0 :     std::scoped_lock lock(mutex_);
     214           0 :     SandeshConnectionMap::iterator loc = find_if(connection_.begin(),
     215             :             connection_.end(), boost::bind(&SandeshServer::Compare, this,
     216             :                                            boost::ref(peer_addr), _1));
     217           0 :     if (loc != connection_.end()) {
     218           0 :         return loc->second;
     219             :     }
     220           0 :     return NULL;
     221           0 : }
     222             : 
     223          37 : SslSession *SandeshServer::AllocSession(SslSocket *socket) {
     224             :     // Use the state machine task to run the session send queue since
     225             :     // they need to be exclusive as session delete happens from state
     226             :     // machine
     227             :     SslSession *session = new SandeshSession(this, socket,
     228          37 :             AllocConnectionIndex(), session_writer_task_id(),
     229          37 :             session_reader_task_id());
     230          37 :     return session;
     231             : }
     232             : 
     233          37 : void SandeshServer::RemoveConnection(SandeshConnection *connection) {
     234          37 :     std::scoped_lock lock(mutex_);
     235          37 :     boost::asio::ip::tcp::endpoint endpoint = connection->endpoint();
     236          37 :     connection_.erase(endpoint);
     237          37 : }
     238             : 
     239          37 : bool SandeshServer::AcceptSession(TcpSession *session) {
     240          37 :     std::scoped_lock lock(mutex_);
     241             :     SandeshConnection *connection;
     242          37 :     SandeshSession *ssession = dynamic_cast<SandeshSession *>(session);
     243          37 :     assert(ssession);
     244          37 :     ip::tcp::endpoint remote = session->remote_endpoint();
     245          37 :     SandeshConnectionMap::iterator loc = connection_.find(remote);
     246             : 
     247          37 :     if (loc == connection_.end()) {
     248          37 :         SANDESH_LOG(INFO, "Server: " << __func__ << " " << "Create Connection");
     249             :         //create a connection_
     250          37 :         connection = new SandeshServerConnection(this, remote,
     251          37 :                          ssession->GetSessionInstance(),
     252          37 :                          sm_task_id_);
     253          37 :         connection->Initialize();
     254          37 :         connection_.insert(remote, connection);
     255             :     } else {
     256           0 :         connection = loc->second;
     257           0 :         if (connection->session() != NULL) {
     258           0 :             return false;
     259             :         }
     260             :     }
     261          37 :     connection->AcceptSession(ssession);
     262          37 :     return true;
     263          37 : }
     264             : 
     265          37 : bool SandeshServer::ReceiveSandeshCtrlMsg(SandeshStateMachine *sm,
     266             :         SandeshSession *session, const Sandesh *sandesh) {
     267             :     const SandeshCtrlClientToServer *snh =
     268          37 :             dynamic_cast<const SandeshCtrlClientToServer *>(sandesh);
     269          37 :     if (!snh) {
     270           0 :         SANDESH_LOG(DEBUG, "Received Ctrl Message with wrong type " << sandesh->Name());
     271           0 :         return false;
     272             :     }
     273          37 :     SANDESH_LOG(DEBUG, "Received Ctrl Message from " << snh->get_module_name());
     274          37 :     std::vector<UVETypeInfo> vu;
     275          37 :     SandeshCtrlServerToClient::Request(vu, true, "ctrl", session->connection());
     276          37 :     return true;
     277          37 : }
     278             : 
     279          37 : LifetimeActor *SandeshServer::deleter() {
     280          37 :     return deleter_.get();
     281             : }
     282             : 
     283          74 : LifetimeManager *SandeshServer::lifetime_manager() {
     284          74 :     return lifetime_manager_.get();
     285             : }

Generated by: LCOV version 1.14