LCOV - code coverage report
Current view: top level - xmpp - xmpp_server.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 461 499 92.4 %
Date: 2026-11-09 02:10:49 Functions: 64 66 97.0 %
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             : #include "xmpp/xmpp_server.h"
       7             : 
       8             : #include <boost/foreach.hpp>
       9             : #include <boost/tuple/tuple.hpp>
      10             : 
      11             : #include "base/task_annotations.h"
      12             : #include "xmpp/xmpp_connection.h"
      13             : #include "xmpp/xmpp_factory.h"
      14             : #include "xmpp/xmpp_lifetime.h"
      15             : #include "xmpp/xmpp_log.h"
      16             : #include "xmpp/xmpp_sandesh.h"
      17             : #include "xmpp/xmpp_session.h"
      18             : 
      19             : #include "sandesh/request_pipeline.h"
      20             : #include "sandesh/common/vns_types.h"
      21             : #include "sandesh/common/vns_constants.h"
      22             : #include "sandesh/xmpp_server_types.h"
      23             : #include "sandesh/xmpp_trace_sandesh_types.h"
      24             : #include "sandesh/xmpp_client_server_sandesh_types.h"
      25             : 
      26             : using namespace std;
      27             : using namespace boost::asio;
      28             : using boost::tie;
      29             : 
      30             : #define DEFAULT_XMPP_HOLD_TIME 90
      31             : class XmppServer::DeleteActor : public LifetimeActor {
      32             : public:
      33        2158 :     DeleteActor(XmppServer *server)
      34        2158 :         : LifetimeActor(server->lifetime_manager()), server_(server) {
      35        2158 :     }
      36        2156 :     virtual bool MayDelete() const {
      37        2156 :         CHECK_CONCURRENCY("bgp::Config");
      38        2156 :         return server_->MayDelete();
      39             :     }
      40        2156 :     virtual void Shutdown() {
      41        2156 :         CHECK_CONCURRENCY("bgp::Config");
      42        2156 :         server_->SessionShutdown();
      43        2156 :     }
      44        2156 :     virtual void Destroy() {
      45        2156 :         CHECK_CONCURRENCY("bgp::Config");
      46        2156 :         server_->Terminate();
      47        2156 :     }
      48             : 
      49             : private:
      50             :     XmppServer *server_;
      51             : };
      52             : 
      53             : 
      54         414 : XmppServer::XmppServer(EventManager *evm, const string &server_addr,
      55         414 :                        const XmppChannelConfig *config)
      56             :     : XmppConnectionManager(
      57         414 :           evm, ssl::context::sslv23_server, config->auth_enabled, true),
      58         414 :       max_connections_(0),
      59         414 :       lifetime_manager_(XmppStaticObjectFactory::Create<XmppLifetimeManager>(
      60             :           TaskScheduler::GetInstance()->GetTaskId("bgp::Config"))),
      61         414 :       deleter_(new DeleteActor(this)),
      62         414 :       server_addr_(server_addr),
      63         414 :       log_uve_(false),
      64         414 :       auth_enabled_(config->auth_enabled),
      65         414 :       tcp_hold_time_(config->tcp_hold_time),
      66         414 :       gr_helper_disable_(config->gr_helper_disable),
      67         414 :       dscp_value_(0),
      68         414 :       connection_queue_(TaskScheduler::GetInstance()->GetTaskId("bgp::Config"),
      69        1242 :           0, boost::bind(&XmppServer::DequeueConnection, this, _1)) {
      70             : 
      71         414 :     if (config->auth_enabled) {
      72             : 
      73             :         // Get SSL context from base class and update
      74         284 :         boost::asio::ssl::context *ctx = context();
      75         284 :         boost::system::error_code ec;
      76             : 
      77             :         // set mode
      78         284 :         ctx->set_options(ssl::context::default_workarounds |
      79             :                          ssl::context::no_sslv3 | ssl::context::no_sslv2, ec);
      80         284 :         if (ec.value() != 0) {
      81           0 :             LOG(ERROR, "Error : " << ec.message() << ", setting ssl options");
      82           0 :             exit(EINVAL);
      83             :         }
      84             : 
      85             :         // CA certificate, used to verify if the peer certificate
      86             :         // is signed by a trusted CA
      87         284 :         std::string ca_cert_filename = config->path_to_ca_cert;
      88         284 :         if (!ca_cert_filename.empty()) {
      89             : 
      90             :             // Verify peer has CA signed certificate
      91           0 :             ctx->set_verify_mode(boost::asio::ssl::verify_peer, ec);
      92           0 :             if (ec.value() != 0) {
      93           0 :                 LOG(ERROR, "Error : " << ec.message()
      94             :                     << ", while setting ssl verification mode");
      95           0 :                 exit(EINVAL);
      96             :             }
      97             : 
      98           0 :             ctx->load_verify_file(config->path_to_ca_cert, ec);
      99           0 :             if (ec.value() != 0) {
     100           0 :                 LOG(ERROR, "Error : " << ec.message()
     101             :                     << ", while using cacert file : "
     102             :                     << config->path_to_ca_cert);
     103           0 :                 exit(EINVAL);
     104             :             }
     105             :         }
     106             : 
     107             :         // server certificate
     108         284 :         ctx->use_certificate_file(config->path_to_server_cert,
     109             :                                   boost::asio::ssl::context::pem, ec);
     110         284 :         if (ec.value() != 0) {
     111           0 :             LOG(ERROR, "Error : " << ec.message()
     112             :                 << ", while using server cert file : "
     113             :                 << config->path_to_server_cert);
     114           0 :             exit(EINVAL);
     115             :         }
     116             : 
     117             :         // server private key
     118         284 :         ctx->use_private_key_file(config->path_to_server_priv_key,
     119             :                                   boost::asio::ssl::context::pem, ec);
     120         284 :         if (ec.value() != 0) {
     121           0 :             LOG(ERROR, "Error : " << ec.message()
     122             :                 << ", while using privkey file : "
     123             :                 << config->path_to_server_priv_key);
     124           0 :             exit(EINVAL);
     125             :         }
     126         284 :     }
     127         414 : }
     128             : 
     129             : class XmppConfigUpdater {
     130             : public:
     131        2078 :     explicit XmppConfigUpdater(XmppServer *server,
     132        2078 :                                BgpConfigManager *config_manager) :
     133        2078 :             server_(server) {
     134        2078 :         BgpConfigManager::Observers obs;
     135             :         obs.system= boost::bind(&XmppConfigUpdater::ProcessGlobalSystemConfig,
     136        2078 :             this, _1, _2);
     137             :         obs.protocol = boost::bind(&XmppConfigUpdater::ProcessProtocolConfig,
     138        2078 :             this, _1, _2);
     139        2078 :         config_manager->RegisterObservers(obs);
     140        2078 :     }
     141             : 
     142       28650 :     const BgpGlobalSystemConfig &config() const { return config_; }
     143             : 
     144        2686 :     void ProcessProtocolConfig(const BgpProtocolConfig *protocol_config,
     145             :                                BgpConfigManager::EventType event) {
     146             : 
     147        2686 :         if (server_->subcluster_name() != protocol_config->subcluster_name()) {
     148           8 :             server_->set_subcluster_name(protocol_config->subcluster_name());
     149           8 :             server_->ClearAllConnections();
     150             :         }
     151        2686 :     }
     152             : 
     153         467 :     void ProcessGlobalSystemConfig(const BgpGlobalSystemConfig *system,
     154             :             BgpConfigManager::EventType event) {
     155             :         // Clear peers only if GR is or was enabled.
     156         467 :         bool clear_peers = config_.gr_enable() || system->gr_enable();
     157         467 :         bool update_peers = false;
     158         467 :         config_.set_gr_enable(system->gr_enable());
     159         467 :         config_.set_gr_time(system->gr_time());
     160         467 :         config_.set_llgr_time(system->llgr_time());
     161         467 :         config_.set_end_of_rib_timeout(system->end_of_rib_timeout());
     162         467 :         config_.set_gr_xmpp_helper(system->gr_xmpp_helper());
     163             : 
     164             :         // Process any change in xmpp-hold-time
     165         926 :         if (config_.fc_enabled() != system->fc_enabled() ||
     166         459 :             config_.xmpp_hold_time() != system->xmpp_hold_time()) {
     167          16 :             config_.set_xmpp_hold_time(system->xmpp_hold_time());
     168          16 :             config_.set_fc_enabled(system->fc_enabled());
     169             :             // if fc_enabled is not set, use default hold time
     170          16 :             if (!system->fc_enabled())
     171           0 :                 config_.set_xmpp_hold_time(DEFAULT_XMPP_HOLD_TIME);
     172          16 :             update_peers = true;
     173             :         }
     174             : 
     175             :         // Process any change in rd-cluster-seed knob
     176         467 :         if (config_.rd_cluster_seed() != system->rd_cluster_seed()) {
     177          22 :             config_.set_rd_cluster_seed(system->rd_cluster_seed());
     178          22 :             clear_peers = true;
     179             :         }
     180             : 
     181         467 :         if (clear_peers)
     182         447 :             server_->ClearAllConnections();
     183          20 :         else if (update_peers)
     184          16 :             server_->UpdateAllConnections(config_.xmpp_hold_time());
     185         467 :     }
     186             : 
     187             :     const string subcluster_name() const { return server_->subcluster_name(); }
     188             :     void set_subcluster_name(const string& name) {
     189             :         server_->set_subcluster_name(name);
     190             :     }
     191             : 
     192        6531 :     uint8_t xmpp_hold_time() const { return config_.xmpp_hold_time(); }
     193             :     void set_xmpp_hold_time(int hold_time) {
     194             :         config_.set_xmpp_hold_time(hold_time);
     195             :     }
     196             : 
     197             : private:
     198             :     XmppServer *server_;
     199             :     BgpGlobalSystemConfig config_;
     200             : };
     201             : 
     202        1737 : XmppServer::XmppServer(EventManager *evm, const string &server_addr)
     203             :     : XmppConnectionManager(evm, ssl::context::sslv23_server, false, false),
     204        1737 :       max_connections_(0),
     205        1737 :       lifetime_manager_(XmppStaticObjectFactory::Create<XmppLifetimeManager>(
     206             :           TaskScheduler::GetInstance()->GetTaskId("bgp::Config"))),
     207        1737 :       deleter_(new DeleteActor(this)),
     208        1737 :       server_addr_(server_addr),
     209        1737 :       log_uve_(false),
     210        1737 :       auth_enabled_(false),
     211        1737 :       tcp_hold_time_(XmppChannelConfig::kTcpHoldTime),
     212        1737 :       gr_helper_disable_(false),
     213        1737 :       xmpp_config_updater_(NULL),
     214        1737 :       dscp_value_(0),
     215        1737 :       connection_queue_(TaskScheduler::GetInstance()->GetTaskId("bgp::Config"),
     216        5211 :           0, boost::bind(&XmppServer::DequeueConnection, this, _1)) {
     217        1737 : }
     218             : 
     219             : 
     220           7 : XmppServer::XmppServer(EventManager *evm)
     221             :     : XmppConnectionManager(evm, ssl::context::sslv23_server, false, false),
     222           7 :       max_connections_(0),
     223           7 :       lifetime_manager_(new LifetimeManager(
     224          14 :           TaskScheduler::GetInstance()->GetTaskId("bgp::Config"))),
     225           7 :       deleter_(new DeleteActor(this)),
     226           7 :       log_uve_(false),
     227           7 :       auth_enabled_(false),
     228           7 :       tcp_hold_time_(XmppChannelConfig::kTcpHoldTime),
     229           7 :       gr_helper_disable_(false),
     230           7 :       dscp_value_(0),
     231           7 :       connection_queue_(TaskScheduler::GetInstance()->GetTaskId("bgp::Config"),
     232          14 :           0, boost::bind(&XmppServer::DequeueConnection, this, _1)) {
     233           7 : }
     234             : 
     235        2078 : void XmppServer::CreateConfigUpdater(BgpConfigManager *config_manager) {
     236        2078 :     xmpp_config_updater_.reset(new XmppConfigUpdater(this, config_manager));
     237        2078 : }
     238             : 
     239         195 : uint16_t XmppServer::GetGracefulRestartTime() const {
     240             :     // Check if GR is disabled..
     241         195 :     if (!xmpp_config_updater_ || !xmpp_config_updater_->config().gr_enable())
     242           0 :         return 0;
     243         195 :     return xmpp_config_updater_->config().gr_time();
     244             : }
     245             : 
     246          58 : uint32_t XmppServer::GetLongLivedGracefulRestartTime() const {
     247             :     // Check if GR is disabled..
     248          58 :     if (!xmpp_config_updater_ || !xmpp_config_updater_->config().gr_enable())
     249           0 :         return 0;
     250          58 :     return xmpp_config_updater_->config().llgr_time();
     251             : }
     252             : 
     253        6745 : uint32_t XmppServer::GetEndOfRibReceiveTime() const {
     254        6745 :     if (xmpp_config_updater_)
     255        6745 :         return xmpp_config_updater_->config().end_of_rib_timeout();
     256           0 :     return BgpGlobalSystemConfig::kEndOfRibTime;
     257             : }
     258             : 
     259        9599 : uint32_t XmppServer::GetEndOfRibSendTime() const {
     260        9599 :     if (xmpp_config_updater_)
     261        9599 :         xmpp_config_updater_->config().end_of_rib_timeout();
     262        9599 :     return BgpGlobalSystemConfig::kEndOfRibTime;
     263             : }
     264             : 
     265       10604 : bool XmppServer::IsGRHelperModeEnabled() const {
     266             :     // Check if disabled in .conf file.
     267       10604 :     if (gr_helper_disable_)
     268         832 :         return false;
     269             : 
     270             :     // Check from configuration.
     271        9772 :     if (!xmpp_config_updater_)
     272          44 :         return false;
     273             : 
     274             :     // Check if GR is disabled..
     275        9728 :     if (!xmpp_config_updater_->config().gr_enable())
     276        8564 :         return false;
     277             : 
     278        1163 :     return xmpp_config_updater_->config().gr_xmpp_helper();
     279             : }
     280             : 
     281       12087 : bool XmppServer::IsPeerCloseGraceful() const {
     282             : 
     283             :     // If the server is deleted, do not do graceful restart
     284       12087 :     if (deleter()->IsDeleted())
     285        1753 :         return false;
     286             : 
     287             :     // Check if GR helper mode is disabled.
     288       10334 :     if (!IsGRHelperModeEnabled())
     289        9423 :         return false;
     290             : 
     291             :     // Enable GR if either gr-time or llgr-time is configured.
     292         910 :     return (xmpp_config_updater_->config().gr_time() ||
     293         910 :             xmpp_config_updater_->config().llgr_time());
     294             : }
     295             : 
     296        3526 : XmppServer::~XmppServer() {
     297        2158 :     STLDeleteElements(&connection_endpoint_map_);
     298        2158 :     TcpServer::ClearSessions();
     299        3526 : }
     300             : 
     301           0 : bool XmppServer::Initialize(short port) {
     302           0 :     log_uve_ = false;
     303           0 :     return TcpServer::Initialize(port);
     304             : }
     305             : 
     306        2036 : bool XmppServer::Initialize(short port, bool logUVE) {
     307        2036 :     log_uve_ = logUVE;
     308        2036 :     return TcpServer::Initialize(port);
     309             : }
     310             : 
     311         120 : bool XmppServer::Initialize(short port, bool logUVE, const IpAddress& ip) {
     312         120 :     log_uve_ = logUVE;
     313         120 :     return TcpServer::Initialize(port, ip);
     314             : }
     315             : 
     316             : //
     317             : // Can be removed after Shutdown is renamed to ManagedDelete.
     318             : //
     319        2156 : void XmppServer::SessionShutdown() {
     320        2156 :     XmppConnectionManager::Shutdown();
     321        2156 : }
     322             : 
     323             : //
     324             : // Return true if it's possible to delete the XmppServer.
     325             : //
     326             : // No need to check the connection WorkQueue since XmppServerConnections on it
     327             : // are dependents of the XmppServer.
     328             : //
     329        2156 : bool XmppServer::MayDelete() const {
     330        2156 :     return (GetSessionQueueSize() == 0);
     331             : }
     332             : 
     333             : //
     334             : // Trigger deletion of the XmppServer.
     335             : //
     336             : // A mutex is used to ensure that we do not create new XmppServerConnections
     337             : // after this point.  Note that this routine and AcceptSession may be called
     338             : // concurrently from 2 different threads in tests.
     339             : //
     340        2223 : void XmppServer::Shutdown() {
     341        2223 :     std::scoped_lock lock(deletion_mutex_);
     342        2223 :     deleter_->Delete();
     343        2223 : }
     344             : 
     345             : //
     346             : // Called when the XmppServer delete actor is being destroyed.
     347             : //
     348        2156 : void XmppServer::Terminate() {
     349        2156 :     ClearSessions();
     350        2156 :     connection_queue_.Shutdown();
     351        2156 : }
     352             : 
     353        6617 : LifetimeActor *XmppServer::deleter() {
     354        6617 :     return deleter_.get();
     355             : }
     356             : 
     357       12087 : LifetimeActor *XmppServer::deleter() const {
     358       12087 :     return deleter_.get();
     359             : }
     360             : 
     361        8968 : LifetimeManager *XmppServer::lifetime_manager() {
     362        8968 :     return lifetime_manager_.get();
     363             : }
     364             : 
     365          22 : TcpSession *XmppServer::CreateSession() {
     366             :     typedef boost::asio::detail::socket_option::boolean<
     367             :         SOL_SOCKET, SO_REUSEADDR> reuse_addr_t;
     368          22 :     TcpSession *session = TcpServer::CreateSession();
     369          22 :     Socket *socket = session->socket();
     370             : 
     371          22 :     boost::system::error_code err;
     372          22 :     socket->open(ip::tcp::v4(), err);
     373          22 :     if (err) {
     374           0 :         XMPP_WARNING(ServerOpenFail, err.message());
     375             :     }
     376             : 
     377          22 :     socket->set_option(reuse_addr_t(true), err);
     378          22 :     if (err) {
     379           0 :         XMPP_WARNING(SetSockOptFail, "", XMPP_PEER_DIR_OUT, err.message());
     380             :     }
     381             : 
     382          22 :     socket->bind(LocalEndpoint(), err);
     383          22 :     if (err) {
     384          22 :         XMPP_WARNING(ServerBindFailure, err.message());
     385             :     }
     386             : 
     387          22 :     XmppSession *xmpps = static_cast<XmppSession *>(session);
     388          22 :     err = xmpps->EnableTcpKeepalive(tcp_hold_time_);
     389          22 :     if (err) {
     390           0 :         XMPP_WARNING(ServerKeepAliveFailure, session->ToUVEKey(),
     391             :                      XMPP_PEER_DIR_OUT, err.message());
     392             :     }
     393             : 
     394          22 :     return session;
     395             : }
     396             : 
     397           0 : size_t XmppServer::ConnectionEventCount() const {
     398           0 :     return connection_event_map_.size();
     399             : }
     400             : 
     401         854 : size_t XmppServer::ConnectionMapSize() const {
     402         854 :     ReadLock lock(connection_map_mutex_);
     403        1708 :     return connection_map_.size();
     404         854 : }
     405             : 
     406         853 : size_t XmppServer::ConnectionCount() const {
     407         853 :     return ConnectionMapSize() + deleted_connection_set_.size();
     408             : }
     409             : 
     410        6520 : XmppServerConnection *XmppServer::FindConnection(Endpoint remote_endpoint) {
     411        6520 :     ReadLock lock(connection_map_mutex_);
     412        6520 :     ConnectionMap::iterator loc = connection_map_.find(remote_endpoint);
     413        6520 :     if (loc != connection_map_.end()) {
     414           0 :         return loc->second;
     415             :     }
     416        6520 :     return NULL;
     417        6520 : }
     418             : 
     419         658 : XmppServerConnection *XmppServer::FindConnection(const string &address) {
     420         658 :     ReadLock lock(connection_map_mutex_);
     421         669 :     for (auto& value : connection_map_) {
     422          38 :         if (value.second->ToString() == address)
     423          27 :             return value.second;
     424             :     }
     425         631 :     return NULL;
     426         658 : }
     427             : 
     428          56 : bool XmppServer::ClearConnection(const string &hostname) {
     429          56 :     ReadLock lock(connection_map_mutex_);
     430         197 :     for (auto& value : connection_map_) {
     431         157 :         if (value.second->GetComputeHostName() == hostname) {
     432          16 :             value.second->Clear();
     433          16 :             return true;
     434             :         }
     435             :     }
     436          40 :     return false;
     437          56 : }
     438             : 
     439          16 : void XmppServer::UpdateAllConnections(uint8_t time_out) {
     440          16 :     ReadLock lock(connection_map_mutex_);
     441          40 :     for (auto& value : connection_map_) {
     442          24 :         value.second->UpdateKeepAliveTimer(time_out);
     443             :     }
     444          16 : }
     445             : 
     446        5301 : void XmppServer::ClearAllConnections() {
     447        5301 :     ReadLock lock(connection_map_mutex_);
     448        7295 :     for (auto& value : connection_map_) {
     449        1994 :         value.second->Clear();
     450             :     }
     451        5301 : }
     452             : 
     453        2090 : void XmppServer::RegisterConnectionEvent(xmps::PeerId id,
     454             :                                          ConnectionEventCb cb) {
     455        2090 :     connection_event_map_.insert(make_pair(id, cb));
     456        2090 : }
     457             : 
     458        2078 : void XmppServer::UnRegisterConnectionEvent(xmps::PeerId id) {
     459        2078 :     ConnectionEventCbMap::iterator it =  connection_event_map_.find(id);
     460        2078 :     if (it != connection_event_map_.end())
     461        2078 :         connection_event_map_.erase(it);
     462        2078 : }
     463             : 
     464       12897 : void XmppServer::NotifyConnectionEvent(XmppChannelMux *mux,
     465             :                                        xmps::PeerState state) {
     466       12897 :     ConnectionEventCbMap::iterator iter = connection_event_map_.begin();
     467       25770 :     for (; iter != connection_event_map_.end(); ++iter) {
     468       12870 :         ConnectionEventCb cb = iter->second;
     469       12869 :         cb(mux, state);
     470       12873 :     }
     471       12901 : }
     472             : 
     473        6566 : SslSession *XmppServer::AllocSession(SslSocket *socket) {
     474        6566 :     SslSession *session = new XmppSession(this, socket);
     475        6566 :     boost::system::error_code err;
     476        6566 :     XmppSession *xmpp_session = static_cast<XmppSession *>(session);
     477        6566 :     err = xmpp_session->EnableTcpKeepalive(tcp_hold_time_);
     478        6566 :     if (err) {
     479          22 :         XMPP_WARNING(ServerKeepAliveFailure, xmpp_session->ToUVEKey(),
     480             :                      XMPP_PEER_DIR_OUT, err.message());
     481             :     }
     482        6566 :     return session;
     483             : }
     484             : 
     485             : //
     486             : // Accept newly formed passive tcp session by creating necessary xmpp data
     487             : // structures. We do so to make sure that if there is any error reported
     488             : // over this tcp session, it can still be correctly handled, even though
     489             : // the allocated xmpp data structures are not fully processed yet.
     490             : //
     491        6544 : bool XmppServer::AcceptSession(TcpSession *tcp_session) {
     492        6544 :     std::scoped_lock lock(deletion_mutex_);
     493        6544 :     if (deleter_->IsDeleted())
     494           0 :         return false;
     495             : 
     496        6544 :     XmppSession *session = dynamic_cast<XmppSession *>(tcp_session);
     497        6544 :     XmppServerConnection *connection = CreateConnection(session);
     498             : 
     499        6544 :     if (xmpp_config_updater_) {
     500       13062 :         connection->state_machine()->set_hold_time(
     501        6531 :                 xmpp_config_updater_->xmpp_hold_time());
     502             :     }
     503             :     // Register event handler.
     504        6544 :     tcp_session->set_observer(boost::bind(&XmppStateMachine::OnSessionEvent,
     505             :                                           connection->state_machine(), _1, _2));
     506             : 
     507             :     // set async_read_ready as false
     508        6544 :     session->set_read_on_connect(false);
     509        6544 :     connection->set_session(session);
     510        6544 :     connection->state_machine()->set_session(session);
     511        6544 :     connection->set_on_work_queue();
     512        6544 :     connection_queue_.Enqueue(connection);
     513        6544 :     return true;
     514        6544 : }
     515             : 
     516             : //
     517             : // Remove the given XmppServerConnection from the ConnectionMap.
     518             : //
     519        6544 : void XmppServer::RemoveConnection(XmppServerConnection *connection) {
     520        6544 :     CHECK_CONCURRENCY("bgp::Config");
     521             : 
     522        6544 :     assert(connection->IsDeleted());
     523        6544 :     Endpoint endpoint = connection->endpoint();
     524        6544 :     WriteLock lock(connection_map_mutex_);
     525        6544 :     ConnectionMap::iterator loc = connection_map_.find(endpoint);
     526        6544 :     assert(loc != connection_map_.end() && loc->second == connection);
     527        6544 :     connection_map_.erase(loc);
     528        6544 : }
     529             : 
     530         104 : void XmppServer::SwapXmppConnectionMapEntries(
     531             :         XmppConnection *connection1, XmppConnection *connection2) {
     532         104 :     WriteLock lock(connection_map_mutex_);
     533             :     ConnectionMap::iterator loc1 =
     534         104 :         connection_map_.find(connection1->endpoint());
     535         104 :     assert(loc1 != connection_map_.end());
     536             :     ConnectionMap::iterator loc2 =
     537         104 :         connection_map_.find(connection2->endpoint());
     538         104 :     assert(loc2 != connection_map_.end());
     539         104 :     swap(loc1->second, loc2->second);
     540         104 :     swap(loc1->second->endpoint(), loc2->second->endpoint());
     541         104 : }
     542             : 
     543             : //
     544             : // Insert the given XmppServerConnection into the ConnectionMap.
     545             : //
     546        6544 : void XmppServer::InsertConnection(XmppServerConnection *connection) {
     547        6544 :     CHECK_CONCURRENCY("bgp::Config");
     548             : 
     549        6544 :     assert(!connection->IsDeleted());
     550        6544 :     connection->Initialize();
     551        6544 :     Endpoint endpoint = connection->endpoint();
     552        6544 :     ConnectionMap::iterator loc;
     553             :     bool result;
     554        6544 :     WriteLock lock(connection_map_mutex_);
     555        6544 :     tie(loc, result) = connection_map_.insert(make_pair(endpoint, connection));
     556        6544 :     assert(result);
     557        6544 :     max_connections_ = max(max_connections_, connection_map_.size());
     558        6544 : }
     559             : 
     560             : //
     561             : // Create XmppConnnection and its associated data structures. This API is
     562             : // only used to allocate data structures and initialize necessary fields.
     563             : // The data structures are not populated to any maps in the XmppServer at
     564             : // this point.  However, the newly created XmppServerConnection does add
     565             : // itself as a dependent of the XmppServer via LifetimeManager linkage.
     566             : //
     567        6544 : XmppServerConnection *XmppServer::CreateConnection(XmppSession *session) {
     568             :     XmppServerConnection  *connection;
     569             : 
     570        6544 :     XmppChannelConfig cfg(false);
     571        6544 :     cfg.endpoint = session->remote_endpoint();
     572        6544 :     cfg.local_endpoint = session->local_endpoint();
     573        6544 :     cfg.FromAddr = server_addr_;
     574        6544 :     cfg.logUVE = log_uve_;
     575        6544 :     cfg.auth_enabled = auth_enabled_;
     576        6544 :     cfg.dscp_value = dscp_value_;
     577             : 
     578        6544 :     XMPP_DEBUG(XmppCreateConnection, session->ToUVEKey(), XMPP_PEER_DIR_OUT,
     579             :                session->ToString());
     580             :     connection = XmppStaticObjectFactory::Create<XmppServerConnection>
     581        6544 :         (this, static_cast<const XmppChannelConfig*>(&cfg));
     582             : 
     583        6544 :     return connection;
     584        6544 : }
     585             : 
     586           7 : void XmppServer::SetDscpValue(uint8_t value) {
     587           7 :     ReadLock lock(connection_map_mutex_);
     588           7 :     dscp_value_ = value;
     589          18 :     for (auto& value : connection_map_) {
     590          11 :         XmppServerConnection *connection = value.second;
     591          11 :         connection->SetDscpValue(dscp_value_);
     592             :     }
     593           7 : }
     594             : //
     595             : // Handler for XmppServerConnections that are dequeued from the WorkQueue.
     596             : //
     597             : // Since the XmppServerConnections on the WorkQueue are dependents of the
     598             : // XmppServer, we are guaranteed that the XmppServer won't get destroyed
     599             : // before the connection WorkQueue is drained.
     600             : //
     601        6544 : bool XmppServer::DequeueConnection(XmppServerConnection *connection) {
     602        6544 :     CHECK_CONCURRENCY("bgp::Config");
     603        6544 :     connection->clear_on_work_queue();
     604             : 
     605             :     // This happens if the XmppServer got deleted while the XmppConnnection
     606             :     // was on the WorkQueue.
     607        6544 :     if (connection->IsDeleted()) {
     608          24 :         connection->RetryDelete();
     609          24 :         return true;
     610             :     }
     611             : 
     612        6520 :     XmppSession *session = connection->session();
     613        6520 :     connection->clear_session();
     614        6520 :     Endpoint remote_endpoint = session->remote_endpoint();
     615        6520 :     XmppServerConnection *old_connection = FindConnection(remote_endpoint);
     616             : 
     617             :     // Close as duplicate if we have a connection from the same Endpoint.
     618             :     // Otherwise go ahead and insert into the ConnectionMap. We may find
     619             :     // it has a conflicting Endpoint name and decide to terminate it when
     620             :     // we process the Open message.
     621        6520 :     if (old_connection) {
     622           0 :         XMPP_DEBUG(XmppCreateConnection, session->ToUVEKey(), XMPP_PEER_DIR_IN,
     623             :                    "Close duplicate connection " + session->ToString());
     624             :         // Remove reference to the session from StateMachine directly. We don't
     625             :         // go through the entire normal cleanup pipeline for cleaning these
     626             :         // duplicate connections.
     627           0 :         assert(connection->state_machine()->session());
     628           0 :         assert(connection->state_machine()->session() == session);
     629           0 :         connection->state_machine()->RemoveSession();
     630           0 :         DeleteSession(session);
     631           0 :         connection->set_duplicate();
     632           0 :         connection->ManagedDelete();
     633           0 :         InsertDeletedConnection(connection);
     634             :     } else {
     635        6520 :         InsertConnection(connection);
     636        6520 :         connection->AcceptSession(session);
     637             :     }
     638             : 
     639        6520 :     return true;
     640             : }
     641             : 
     642         674 : size_t XmppServer::GetConnectionQueueSize() const {
     643         674 :     return connection_queue_.Length();
     644             : }
     645             : 
     646          48 : void XmppServer::SetConnectionQueueDisable(bool disabled) {
     647          48 :     connection_queue_.set_disable(disabled);
     648          48 : }
     649             : 
     650             : //
     651             : // Connection is marked deleted, add it to the ConnectionSet.
     652             : //
     653        6568 : void XmppServer::InsertDeletedConnection(XmppServerConnection *connection) {
     654        6568 :     CHECK_CONCURRENCY("bgp::Config");
     655             : 
     656        6568 :     assert(connection->IsDeleted());
     657        6568 :     ConnectionSet::iterator it;
     658             :     bool result;
     659        6568 :     tie(it, result) = deleted_connection_set_.insert(connection);
     660        6568 :     assert(result);
     661        6568 : }
     662             : 
     663             : //
     664             : // Connection is being destroyed, remove it from the ConnectionSet.
     665             : //
     666        6568 : void XmppServer::RemoveDeletedConnection(XmppServerConnection *connection) {
     667        6568 :     CHECK_CONCURRENCY("bgp::Config");
     668             : 
     669        6568 :     assert(connection->IsDeleted());
     670        6568 :     ConnectionSet::iterator it = deleted_connection_set_.find(connection);
     671        6568 :     assert(it != deleted_connection_set_.end());
     672        6568 :     deleted_connection_set_.erase(it);
     673        6568 :     ReleaseConnectionEndpoint(connection);
     674        6568 : }
     675             : 
     676       11744 : XmppConnectionEndpoint *XmppServer::FindConnectionEndpoint(
     677             :     const string &endpoint_name) {
     678       11744 :     std::scoped_lock lock(endpoint_map_mutex_);
     679             :     ConnectionEndpointMap::const_iterator loc =
     680       11744 :         connection_endpoint_map_.find(endpoint_name);
     681       23488 :     return (loc != connection_endpoint_map_.end() ? loc->second : NULL);
     682       11744 : }
     683             : 
     684        6305 : XmppConnectionEndpoint *XmppServer::LocateConnectionEndpoint(
     685             :         XmppServerConnection *connection, bool &created) {
     686        6305 :     created = false;
     687        6305 :     if (!connection)
     688           0 :         return NULL;
     689             : 
     690        6305 :     std::scoped_lock lock(endpoint_map_mutex_);
     691             : 
     692             :     ConnectionEndpointMap::const_iterator loc =
     693        6305 :         connection_endpoint_map_.find(connection->ToString());
     694             :     XmppConnectionEndpoint *conn_endpoint;
     695             : 
     696        6304 :     if (loc != connection_endpoint_map_.end()) {
     697        1429 :         conn_endpoint = loc->second;
     698        1429 :         if (!conn_endpoint->connection()) {
     699        1325 :             created = true;
     700        1325 :             conn_endpoint->set_connection(connection);
     701        1325 :             connection->set_conn_endpoint(conn_endpoint);
     702             :         }
     703        1429 :         return conn_endpoint;
     704             :     }
     705             : 
     706        4875 :     created = true;
     707        4875 :     conn_endpoint = new XmppConnectionEndpoint(connection->ToString());
     708             :     bool result;
     709        4875 :     tie(loc, result) = connection_endpoint_map_.insert(
     710        9751 :             make_pair(connection->ToString(), conn_endpoint));
     711        4876 :     assert(result);
     712        4876 :     conn_endpoint->set_connection(connection);
     713        4876 :     connection->set_conn_endpoint(conn_endpoint);
     714        4876 :     return conn_endpoint;
     715        6305 : }
     716             : 
     717             : //
     718             : // Remove association of the given XmppConnectionEndpoint with XmppConnection.
     719             : // This method is provided just to make things symmetrical - the caller could
     720             : // simply have called XmppConnectionEndpoint::reset_connection directly.
     721             : //
     722       13112 : void XmppServer::ReleaseConnectionEndpoint(XmppServerConnection *connection) {
     723       13112 :     std::scoped_lock lock(endpoint_map_mutex_);
     724             : 
     725       13112 :     if (!connection->conn_endpoint())
     726        6911 :         return;
     727        6201 :     assert(connection->conn_endpoint()->connection() == connection);
     728        6201 :     connection->conn_endpoint()->reset_connection();
     729        6201 :     connection->set_conn_endpoint(NULL);
     730       13112 : }
     731             : 
     732          40 : void XmppServer::FillShowConnections(
     733             :     vector<ShowXmppConnection> *show_connection_list) const {
     734          40 :     ReadLock lock(connection_map_mutex_);
     735          88 :     for (const auto& value : connection_map_) {
     736          48 :         const XmppServerConnection *connection = value.second;
     737          48 :         ShowXmppConnection show_connection;
     738          48 :         connection->FillShowInfo(&show_connection);
     739          48 :         show_connection_list->push_back(show_connection);
     740          48 :     }
     741          64 :     for (const auto& connection : deleted_connection_set_) {
     742          24 :         ShowXmppConnection show_connection;
     743          24 :         connection->FillShowInfo(&show_connection);
     744          24 :         show_connection_list->push_back(show_connection);
     745          24 :     }
     746          40 : }
     747             : 
     748           1 : void XmppServer::FillShowServer(ShowXmppServerResp *resp) const {
     749           1 :     SocketIOStats peer_socket_stats;
     750           1 :     GetRxSocketStats(&peer_socket_stats);
     751           1 :     resp->set_rx_socket_stats(peer_socket_stats);
     752           1 :     GetTxSocketStats(&peer_socket_stats);
     753           1 :     resp->set_tx_socket_stats(peer_socket_stats);
     754           1 :     resp->set_current_connections(ConnectionMapSize());
     755           1 :     resp->set_max_connections(max_connections_);
     756           1 : }
     757             : 
     758             : class ShowXmppConnectionHandler {
     759             : public:
     760          40 :     static bool CallbackS1(const Sandesh *sr,
     761             :             const RequestPipeline::PipeSpec ps, int stage, int instNum,
     762             :             RequestPipeline::InstData *data) {
     763             :         const ShowXmppConnectionReq *req =
     764          40 :             static_cast<const ShowXmppConnectionReq *>(ps.snhRequest_.get());
     765             :         XmppSandeshContext *xsc =
     766          40 :             dynamic_cast<XmppSandeshContext *>(req->module_context("XMPP"));
     767             : 
     768          40 :         ShowXmppConnectionResp *resp = new ShowXmppConnectionResp;
     769          40 :         vector<ShowXmppConnection> connections;
     770          40 :         if (xsc)
     771          40 :             xsc->xmpp_server->FillShowConnections(&connections);
     772          40 :         resp->set_connections(connections);
     773          40 :         resp->set_context(req->context());
     774          40 :         resp->Response();
     775          40 :         return true;
     776          40 :     }
     777             : };
     778             : 
     779          40 : void ShowXmppConnectionReq::HandleRequest() const {
     780          40 :     RequestPipeline::PipeSpec ps(this);
     781             : 
     782             :     // Request pipeline has single stage to collect connection info and
     783             :     // respond to the request.
     784          40 :     RequestPipeline::StageSpec s1;
     785          40 :     TaskScheduler *scheduler = TaskScheduler::GetInstance();
     786          40 :     s1.taskId_ = scheduler->GetTaskId("bgp::ShowCommand");
     787          40 :     s1.cbFn_ = ShowXmppConnectionHandler::CallbackS1;
     788          40 :     s1.instances_.push_back(0);
     789          40 :     ps.stages_.push_back(s1);
     790          40 :     RequestPipeline rp(ps);
     791          40 : }
     792             : 
     793             : class ClearXmppConnectionHandler {
     794             : public:
     795          48 :     static bool CallbackS1(const Sandesh *sr,
     796             :         const RequestPipeline::PipeSpec ps, int stage, int instNum,
     797             :         RequestPipeline::InstData *data) {
     798             : 
     799             :         const ClearXmppConnectionReq *req =
     800          48 :             static_cast<const ClearXmppConnectionReq *>(ps.snhRequest_.get());
     801             :         XmppSandeshContext *xsc =
     802          48 :             dynamic_cast<XmppSandeshContext *>(req->module_context("XMPP"));
     803             : 
     804          48 :         ClearXmppConnectionResp *resp = new ClearXmppConnectionResp;
     805          48 :         if (!xsc || !xsc->test_mode) {
     806          24 :             resp->set_success(false);
     807          24 :         } else if (req->get_hostname_or_all() != "all") {
     808          16 :             if (xsc->xmpp_server->ClearConnection(req->get_hostname_or_all())) {
     809           8 :                 resp->set_success(true);
     810             :             } else {
     811           8 :                 resp->set_success(false);
     812             :             }
     813             :         } else {
     814           8 :             if (xsc->xmpp_server->ConnectionCount()) {
     815           8 :                 xsc->xmpp_server->ClearAllConnections();
     816           8 :                 resp->set_success(true);
     817             :             } else {
     818           0 :                 resp->set_success(false);
     819             :             }
     820             :         }
     821             : 
     822          48 :         resp->set_context(req->context());
     823          48 :         resp->Response();
     824          48 :         return true;
     825             :     }
     826             : };
     827             : 
     828          48 : void ClearXmppConnectionReq::HandleRequest() const {
     829             : 
     830             :     // config task is used to create and delete connection objects.
     831             :     // hence use the same task to find the connection
     832          48 :     RequestPipeline::StageSpec s1;
     833          48 :     s1.taskId_ = TaskScheduler::GetInstance()->GetTaskId("bgp::Config");
     834          48 :     s1.instances_.push_back(0);
     835          48 :     s1.cbFn_ = ClearXmppConnectionHandler::CallbackS1;
     836             : 
     837          48 :     RequestPipeline::PipeSpec ps(this);
     838          48 :     ps.stages_.push_back(s1);
     839          48 :     RequestPipeline rp(ps);
     840          48 : }
     841             : 
     842             : class ShowXmppServerHandler {
     843             : public:
     844           1 :     static bool CallbackS1(const Sandesh *sr,
     845             :             const RequestPipeline::PipeSpec ps, int stage, int instNum,
     846             :             RequestPipeline::InstData *data) {
     847             :         const ShowXmppServerReq *req =
     848           1 :             static_cast<const ShowXmppServerReq *>(ps.snhRequest_.get());
     849             :         XmppSandeshContext *xsc =
     850           1 :             dynamic_cast<XmppSandeshContext *>(req->module_context("XMPP"));
     851             : 
     852           1 :         ShowXmppServerResp *resp = new ShowXmppServerResp;
     853           1 :         if (xsc)
     854           1 :             xsc->xmpp_server->FillShowServer(resp);
     855           1 :         resp->set_context(req->context());
     856           1 :         resp->Response();
     857           1 :         return true;
     858             :     }
     859             : };
     860             : 
     861           1 : void ShowXmppServerReq::HandleRequest() const {
     862           1 :     RequestPipeline::PipeSpec ps(this);
     863           1 :     RequestPipeline::StageSpec s1;
     864           1 :     TaskScheduler *scheduler = TaskScheduler::GetInstance();
     865           1 :     s1.taskId_ = scheduler->GetTaskId("bgp::ShowCommand");
     866           1 :     s1.cbFn_ = ShowXmppServerHandler::CallbackS1;
     867           1 :     s1.instances_.push_back(0);
     868           1 :     ps.stages_.push_back(s1);
     869           1 :     RequestPipeline rp(ps);
     870           1 : }

Generated by: LCOV version 1.14