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

Generated by: LCOV version 1.14