LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/io - tcp_server.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 287 360 79.7 %
Date: 2026-08-03 02:19:58 Functions: 40 44 90.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include "io/tcp_server.h"
       6             : 
       7             : #include <errno.h>
       8             : 
       9             : #include <boost/asio/connect.hpp>
      10             : #include <boost/asio/placeholders.hpp>
      11             : #include <boost/bind/bind.hpp>
      12             : #include <netinet/tcp.h>
      13             : 
      14             : #include "base/logging.h"
      15             : #include "io/event_manager.h"
      16             : #include "io/tcp_session.h"
      17             : #include "io/io_log.h"
      18             : #include "io/io_utils.h"
      19             : 
      20             : using boost::asio::ip::address;
      21             : using boost::asio::ip::tcp;
      22             : using boost::asio::placeholders::error;
      23             : using boost::asio::socket_base;
      24             : using boost::bind;
      25             : using boost::system::error_code;
      26             : using namespace boost::placeholders;
      27             : 
      28             : using boost::asio::socket_base;
      29             : using std::ostringstream;
      30             : using std::string;
      31             : 
      32       17561 : TcpServer::TcpServer(EventManager *evm)
      33       17561 :     : evm_(evm), socket_open_failure_(false), intf_id_(-1) {
      34       17561 :     refcount_ = 0;
      35       17561 :     TcpServerManager::AddServer(this);
      36       17561 : }
      37             : 
      38             : // TcpServer delete procedure:
      39             : // 1. Shutdown() to stop accepting incoming sessions.
      40             : // 2. Close and terminate current sessions. ASIO callbacks maybe in-flight.
      41             : // 3. Optionally: WaitForEmpty().
      42             : // 4. Destroy TcpServer.
      43       17561 : TcpServer::~TcpServer() {
      44       17561 :     assert(acceptor_ == NULL);
      45       17561 :     assert(session_ref_.empty());
      46       17561 :     assert(session_map_.empty());
      47       17561 : }
      48             : 
      49        8060 : void TcpServer::SetName(Endpoint local_endpoint) {
      50        8060 :     ostringstream out;
      51        8060 :     out << local_endpoint;
      52        8060 :     name_ = out.str();
      53        8060 : }
      54             : 
      55        8193 : void TcpServer::ResetAcceptor() {
      56        8193 :     acceptor_.reset();
      57        8193 :     name_ = "";
      58        8193 : }
      59             : 
      60        2474 : bool TcpServer::Initialize(unsigned short port) {
      61        2474 :     intf_id_ = -1; //this initializer is only for IPv4
      62        2474 :     tcp::endpoint localaddr(tcp::v4(), port);
      63        2474 :     return InitializeInternal(localaddr);
      64             : }
      65             : 
      66        5719 : bool TcpServer::Initialize(unsigned short port,
      67             :     const IpAddress &host_ip,
      68             :     int intf_id) {
      69        5719 :     tcp::endpoint localaddr(host_ip, port);
      70        5719 :     tcp::endpoint serv_ep(host_ip, port);
      71        5719 :     intf_id_ = intf_id;
      72        5719 :     if (host_ip.is_v6()) {
      73           4 :         Ip6Address ipaddr = host_ip.to_v6();
      74           4 :         if (intf_id_ > 0) {
      75           1 :             ipaddr.scope_id(this->intf_id_);
      76           1 :             serv_ep.address(ipaddr);
      77             :         }
      78             :     }
      79        5719 :     return InitializeInternal(serv_ep);
      80             : }
      81             : 
      82        8193 : bool TcpServer::InitializeInternal(tcp::endpoint localaddr) {
      83        8193 :     acceptor_.reset(new tcp::acceptor(*evm_->io_service()));
      84        8193 :     if (!acceptor_) {
      85           0 :         TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "Cannot create acceptor");
      86           0 :         return false;
      87             :     }
      88             : 
      89        8193 :     error_code ec;
      90        8193 :     if (localaddr.address().is_v4())
      91        8189 :         acceptor_->open(tcp::v4(), ec);
      92             :     else
      93           4 :         acceptor_->open(tcp::v6(), ec);
      94             : 
      95        8193 :     if (ec) {
      96           0 :         TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "TCP open: " << ec.message());
      97           0 :         ResetAcceptor();
      98           0 :         return false;
      99             :     }
     100             : 
     101        8193 :     acceptor_->set_option(socket_base::reuse_address(true), ec);
     102        8193 :     if (ec) {
     103           0 :         TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "TCP reuse_address: "
     104             :                                                    << ec.message());
     105           0 :         ResetAcceptor();
     106           0 :         return false;
     107             :     }
     108             : 
     109        8193 :     acceptor_->bind(localaddr, ec);
     110        8193 :     if (ec) {
     111         133 :         TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "TCP bind(" << localaddr.address() <<
     112             :                              ":" << localaddr.port() << "): " << ec.message());
     113         133 :         ResetAcceptor();
     114         133 :         return false;
     115             :     }
     116             : 
     117        8060 :     tcp::endpoint local_endpoint = acceptor_->local_endpoint(ec);
     118        8060 :     if (ec) {
     119           0 :         TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA,
     120             :                              "Cannot retrieve acceptor local-endpont");
     121           0 :         ResetAcceptor();
     122           0 :         return false;
     123             :     }
     124             : 
     125             :     //
     126             :     // Server name can be set after local-endpoint information is available.
     127             :     //
     128        8060 :     SetName(local_endpoint);
     129             : 
     130        8060 :     acceptor_->listen(socket_base::max_connections, ec);
     131        8060 :     if (ec) {
     132           0 :         TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "TCP listen(" << localaddr.port() <<
     133             :                              "): " << ec.message());
     134           0 :         ResetAcceptor();
     135           0 :         return false;
     136             :     }
     137             : 
     138        8096 :     TCP_SERVER_LOG_DEBUG(this, TCP_DIR_NA, "Initialization complete");
     139        8060 :     AsyncAccept();
     140             : 
     141        8060 :     return true;
     142             : }
     143             : 
     144       17373 : void TcpServer::Shutdown() {
     145       17373 :     std::scoped_lock lock(mutex_);
     146       17373 :     error_code ec;
     147             : 
     148       17373 :     if (acceptor_) {
     149        8060 :         acceptor_->close(ec);
     150        8060 :         if (ec) {
     151           0 :             TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "Error during shutdown: "
     152             :                                                        << ec.message());
     153             :         }
     154        8060 :         ResetAcceptor();
     155             :     }
     156       17373 : }
     157             : 
     158             : // Close and remove references from all sessions. The application code must
     159             : // make sure it no longer holds any references to these sessions.
     160       14554 : void TcpServer::ClearSessions() {
     161       14554 :     SessionSet refs;
     162             :     {
     163       14554 :         std::scoped_lock lock(mutex_);
     164       14554 :         refs.swap(session_ref_);
     165       14554 :     }
     166             : 
     167       14554 :     for (SessionSet::iterator iter = refs.begin(), next = iter;
     168       14786 :          iter != refs.end(); iter = next) {
     169         232 :         ++next;
     170         232 :         TcpSession *session = iter->get();
     171         232 :         session->Close();
     172             :     }
     173       14554 :     refs.clear();
     174       14554 :     if (session_ref_.empty() && session_map_.empty()) {
     175       14550 :         cond_var_.notify_all();
     176             :     }
     177       14554 : }
     178             : 
     179           0 : void TcpServer::UpdateSessionsDscp(uint8_t dscp) {
     180           0 :     std::scoped_lock lock(mutex_);
     181             : 
     182           0 :     for (SessionSet::iterator iter = session_ref_.begin(), next = iter;
     183           0 :          iter != session_ref_.end(); iter = next) {
     184           0 :         ++next;
     185           0 :         TcpSession *session = iter->get();
     186           0 :         session->SetDscpSocketOption(dscp);
     187             :     }
     188           0 : }
     189             : 
     190       16373 : TcpSession *TcpServer::CreateSession() {
     191       16373 :     TcpSession *session = AllocSession(false);
     192             :     {
     193       16360 :         std::scoped_lock lock(mutex_);
     194       16374 :         session_ref_.insert(TcpSessionPtr(session));
     195       16374 :     }
     196       16374 :     return session;
     197             : }
     198             : 
     199       30714 : void TcpServer::DeleteSession(TcpSession *session) {
     200             :     // The caller will typically close the socket before deleting the
     201             :     // session.
     202       30714 :     session->Close();
     203             :     {
     204       30713 :         std::scoped_lock lock(mutex_);
     205       30716 :         assert(session->refcount_);
     206       30716 :         session_ref_.erase(TcpSessionPtr(session));
     207       30717 :         if (session_ref_.empty() && session_map_.empty()) {
     208       15818 :             cond_var_.notify_all();
     209             :         }
     210       30719 :     }
     211       30718 : }
     212             : 
     213             : //
     214             : // Insert into SessionMap.
     215             : // Assumes that caller has the mutex.
     216             : //
     217       29242 : void TcpServer::InsertSessionToMap(Endpoint remote, TcpSession *session) {
     218       29242 :     session_map_.insert(make_pair(remote, session));
     219       29242 : }
     220             : 
     221             : //
     222             : // Remove from SessionMap.
     223             : // Assumes that caller has the mutex.
     224             : // Return true if the session is found.
     225             : //
     226       29239 : bool TcpServer::RemoveSessionFromMap(Endpoint remote, TcpSession *session) {
     227       29239 :     for (SessionMap::iterator iter = session_map_.find(remote);
     228       29588 :          iter != session_map_.end() && iter->first == remote; ++iter) {
     229       29588 :         if (iter->second == session) {
     230       29234 :             session_map_.erase(iter);
     231       29237 :             return true;
     232             :         }
     233             :     }
     234           0 :     return false;
     235             : }
     236             : 
     237       29240 : void TcpServer::OnSessionClose(TcpSession *session) {
     238       29240 :     std::scoped_lock lock(mutex_);
     239             : 
     240             :     // CloseSessions closes and removes all the sessions from the map.
     241       29239 :     if (session_map_.empty()) {
     242           0 :         return;
     243             :     }
     244             : 
     245       29239 :     bool found = RemoveSessionFromMap(session->remote_endpoint(), session);
     246       29237 :     if (session_map_.empty() && session_ref_.empty()) {
     247        2904 :         cond_var_.notify_all();
     248             :     }
     249       29235 :     assert(found);
     250       29235 : }
     251             : 
     252             : // This method ensures that the application code requested the session to be
     253             : // deleted (which may be a delayed action). It does not guarantee that the
     254             : // session object has actually been freed yet as ASIO callbacks can be in
     255             : // progress.
     256       22518 : void TcpServer::WaitForEmpty() {
     257       22518 :     std::unique_lock<std::mutex> lock(mutex_);
     258       22522 :     while (!session_ref_.empty() || !session_map_.empty()) {
     259           4 :         cond_var_.wait(lock);
     260             :     }
     261       22518 : }
     262             : 
     263       29679 : void TcpServer::AsyncAccept() {
     264       29679 :     std::scoped_lock lock(mutex_);
     265       29679 :     if (acceptor_ == NULL) {
     266        6996 :         return;
     267             :     }
     268       22683 :     set_accept_socket();
     269       45366 :     acceptor_->async_accept(*accept_socket(),
     270       45366 :         bind(&TcpServer::AcceptHandlerInternal, this,
     271       45366 :             TcpServerPtr(this), error));
     272       29679 : }
     273             : 
     274     5734704 : int TcpServer::GetPort() const {
     275     5734704 :     std::scoped_lock lock(mutex_);
     276     5735228 :     if (acceptor_.get() == NULL) {
     277     1402285 :         return -1;
     278             :     }
     279     4332908 :     error_code ec;
     280     4332908 :     tcp::endpoint ep = acceptor_->local_endpoint(ec);
     281     4332850 :     if (ec) {
     282           0 :         return -1;
     283             :     }
     284     4332835 :     return ep.port();
     285     5735047 : }
     286             : 
     287           4 : bool TcpServer::HasSessions() const {
     288           4 :     std::scoped_lock lock(mutex_);
     289           8 :     return !session_map_.empty();
     290           4 : }
     291             : 
     292           0 : bool TcpServer::HasSessionReadAvailable() const {
     293           0 :     std::scoped_lock lock(mutex_);
     294           0 :     error_code error;
     295           0 :     if (accept_socket()->available(error) > 0) {
     296           0 :         return  true;
     297             :     }
     298           0 :     for (SessionMap::const_iterator iter = session_map_.begin();
     299           0 :          iter != session_map_.end();
     300           0 :          ++iter) {
     301           0 :         if (iter->second->socket()->available(error) > 0) {
     302           0 :             return true;
     303             :         }
     304             :     }
     305           0 :     return false;
     306           0 : }
     307             : 
     308       11452 : TcpServer::Endpoint TcpServer::LocalEndpoint() const {
     309       11452 :     std::scoped_lock lock(mutex_);
     310       11452 :     if (acceptor_.get() == NULL) {
     311        5514 :         return Endpoint();
     312             :     }
     313        5938 :     error_code ec;
     314        5938 :     Endpoint local = acceptor_->local_endpoint(ec);
     315        5938 :     if (ec) {
     316           0 :         return Endpoint();
     317             :     }
     318        5938 :     return local;
     319       11452 : }
     320             : 
     321       16255 : TcpSession *TcpServer::AllocSession(bool server_session) {
     322             :     TcpSession *session;
     323       16255 :     if (server_session) {
     324        8008 :         session = AllocSession(so_accept_.get());
     325             : 
     326             :         // if session allocate succeeds release ownership to so_accept.
     327        8008 :         if (session != NULL) {
     328        8008 :             so_accept_.release();
     329             :         }
     330             :     } else {
     331        8247 :         Socket *socket = new Socket(*evm_->io_service());
     332        8249 :         session = AllocSession(socket);
     333             :     }
     334             : 
     335       16239 :     return session;
     336             : }
     337             : 
     338       21792 : TcpServer::Socket *TcpServer::accept_socket() const {
     339       21792 :     return so_accept_.get();
     340             : }
     341             : 
     342       13784 : void TcpServer::set_accept_socket() {
     343       13784 :     so_accept_.reset(new Socket(*evm_->io_service()));
     344       13784 : }
     345             : 
     346          12 : bool TcpServer::AcceptSession(TcpSession *session) {
     347          12 :     return true;
     348             : }
     349             : 
     350             : //
     351             : // concurrency: called from the event_manager thread.
     352             : //
     353             : // accept() tcp connections. Once done, must register with boost again
     354             : // via AsyncAccept() in order to process future accept calls
     355             : //
     356       21619 : void TcpServer::AcceptHandlerInternal(TcpServerPtr server,
     357             :         const error_code& error) {
     358       21619 :     tcp::endpoint remote;
     359       21619 :     error_code ec;
     360       21619 :     TcpSessionPtr session;
     361       21619 :     bool need_close = false;
     362             : 
     363       21619 :     if (error) {
     364        6996 :         goto done;
     365             :     }
     366             : 
     367       14623 :     remote = accept_socket()->remote_endpoint(ec);
     368       14623 :     if (ec) {
     369           0 :         TCP_SERVER_LOG_ERROR(this, TCP_DIR_IN,
     370             :                              "Accept: No remote endpoint: " << ec.message());
     371           0 :         goto done;
     372             :     }
     373             : 
     374       14623 :     if (acceptor_ == NULL) {
     375           0 :         TCP_SESSION_LOG_DEBUG(session, TCP_DIR_IN,
     376             :                               "Session accepted after server shutdown: "
     377             :                                   << remote.address().to_string()
     378             :                                   << ":" << remote.port());
     379           0 :         accept_socket()->close(ec);
     380           0 :         goto done;
     381             :     }
     382             : 
     383       14623 :     session.reset(AllocSession(true));
     384       14623 :     if (session == NULL) {
     385           0 :         TCP_SERVER_LOG_DEBUG(this, TCP_DIR_IN, "Session not created");
     386           0 :         goto done;
     387             :     }
     388             : 
     389       14623 :     ec = session->SetSocketOptions();
     390       14623 :     if (ec) {
     391           0 :         TCP_SESSION_LOG_ERROR(session, TCP_DIR_IN,
     392             :                               "Accept: Non-blocking error: " << ec.message());
     393           0 :         need_close = true;
     394           0 :         goto done;
     395             :     }
     396             : 
     397       14623 :     session->SessionEstablished(remote, TcpSession::PASSIVE);
     398       14623 :     AcceptHandlerComplete(session);
     399             : 
     400       21619 : done:
     401       21619 :     if (need_close) {
     402           0 :         session->CloseInternal(ec, false, false);
     403             :     }
     404       21619 :     AsyncAccept();
     405       21619 : }
     406             : 
     407       14621 : void TcpServer::AcceptHandlerComplete(TcpSessionPtr session) {
     408       14621 :     tcp::endpoint remote = session->remote_endpoint();
     409             :     {
     410       14621 :         std::scoped_lock lock(mutex_);
     411       14621 :         if (AcceptSession(session.get())) {
     412       14613 :             TCP_SESSION_LOG_UT_DEBUG(session, TCP_DIR_IN,
     413             :                                      "Accepted session from "
     414             :                                          << remote.address().to_string()
     415             :                                          << ":" << remote.port());
     416       14577 :             session_ref_.insert(session);
     417       14577 :             InsertSessionToMap(remote, session.get());
     418             :         } else {
     419          44 :             TCP_SESSION_LOG_UT_DEBUG(session, TCP_DIR_IN,
     420             :                                      "Rejected session from "
     421             :                                          << remote.address().to_string()
     422             :                                          << ":" << remote.port());
     423          44 :             error_code ec;
     424          44 :             session->CloseInternal(ec, false, false);
     425          44 :             return;
     426             :         }
     427       14621 :     }
     428             : 
     429       14577 :     session->Accepted();
     430             : }
     431             : 
     432      242845 : TcpSession *TcpServer::GetSession(Endpoint remote) {
     433      242845 :     std::scoped_lock lock(mutex_);
     434      242845 :     SessionMap::const_iterator iter = session_map_.find(remote);
     435      242845 :     if (iter != session_map_.end()) {
     436      242830 :         return iter->second;
     437             :     }
     438          15 :     return NULL;
     439      242845 : }
     440             : 
     441       16263 : void TcpServer::ConnectHandler(TcpServerPtr server, TcpSessionPtr session,
     442             :                                const error_code &error) {
     443       16263 :     if (error) {
     444        1596 :         TCP_SERVER_LOG_UT_DEBUG(server, TCP_DIR_OUT,
     445             :                                 "Connect failure: " << error.message());
     446        1596 :         session->ConnectFailed();
     447        1596 :         return;
     448             :     }
     449             : 
     450       14667 :     ConnectHandlerComplete(session);
     451             : }
     452             : 
     453       14665 : void TcpServer::ConnectHandlerComplete(TcpSessionPtr session) {
     454       14665 :     error_code ec;
     455       14665 :     Endpoint remote = session->socket()->remote_endpoint(ec);
     456       14665 :     if (ec) {
     457           0 :         TCP_SERVER_LOG_INFO(this, TCP_DIR_OUT,
     458             :                             "Connect getsockaddr: " << ec.message());
     459           0 :         session->ConnectFailed();
     460           0 :         return;
     461             :     }
     462             : 
     463             :     {
     464       14665 :         std::scoped_lock lock(mutex_);
     465       14665 :         InsertSessionToMap(remote, session.get());
     466       14665 :     }
     467             : 
     468             :     // Connected verifies whether the session has been closed or is still
     469             :     // active.
     470       14665 :     if (!session->Connected(remote)) {
     471           0 :         std::scoped_lock lock(mutex_);
     472           0 :         RemoveSessionFromMap(remote, session.get());
     473           0 :     }
     474             : }
     475             : 
     476       16260 : void TcpServer::Connect(TcpSession *session, Endpoint remote) {
     477       16260 :     assert(session->refcount_);
     478       16263 :     Socket *socket = session->socket();
     479       16263 :     socket->async_connect(remote,
     480       32525 :         bind(&TcpServer::ConnectHandler, this, TcpServerPtr(this),
     481       32526 :                     TcpSessionPtr(session), error));
     482       16263 : }
     483             : 
     484        2010 : int TcpServer::SetMd5SocketOption(NativeSocketType fd, uint32_t peer_ip,
     485             :                                   const string &md5_password) {
     486        2010 :     assert(md5_password.size() <= TCP_MD5SIG_MAXKEYLEN);
     487        2010 :     if (!peer_ip) {
     488           0 :         TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "Invalid peer IP");
     489           0 :         return 0;
     490             :     }
     491             : 
     492             :     struct sockaddr_in local_addr;
     493        2010 :     memset(&local_addr, 0, sizeof(local_addr));
     494             : 
     495        2010 :     local_addr.sin_family = AF_INET;
     496        2010 :     local_addr.sin_addr.s_addr = htonl(peer_ip);
     497             : 
     498             :     struct tcp_md5sig md5sig;
     499        2010 :     memset(&md5sig, 0, sizeof (md5sig));
     500             : 
     501        2010 :     memcpy(md5sig.tcpm_key, md5_password.c_str(), md5_password.size());
     502        2010 :     md5sig.tcpm_keylen = md5_password.size();
     503        2010 :     memcpy(&md5sig.tcpm_addr, &local_addr, sizeof(local_addr));
     504        2010 :     int retval = setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, (const char *)&md5sig,
     505             :                             sizeof(md5sig));
     506        2010 :     if (retval < 0) {
     507          12 :         TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA,
     508             :             "Failure in setting md5 key on the socket " +
     509             :             integerToString(fd) + " for peer " + integerToString(peer_ip) +
     510             :             " with errno " + strerror(errno));
     511             :     } else {
     512        1998 :         TCP_SERVER_LOG_DEBUG(this, TCP_DIR_NA,
     513             :             "Success in setting md5 key on the socket " +
     514             :             integerToString(fd) + " for peer " + integerToString(peer_ip));
     515             :     }
     516        2010 :     return retval;
     517             : }
     518             : 
     519         364 : int TcpServer::SetListenSocketMd5Option(uint32_t peer_ip,
     520             :                                         const string &md5_password) {
     521         364 :     int retval = 0;
     522         364 :     if (acceptor_) {
     523         256 :         retval = SetMd5SocketOption(acceptor_->native_handle(), peer_ip,
     524             :                                     md5_password);
     525             :     }
     526         364 :     return retval;
     527             : }
     528             : 
     529           0 : int TcpServer::SetListenSocketDscp(uint8_t value) {
     530           0 :     int retval = 0;
     531           0 :     if (acceptor_) {
     532           0 :         retval = SetDscpSocketOption(acceptor_->native_handle(), value);
     533             :     }
     534           0 :     return retval;
     535             : }
     536             : 
     537        4586 : int TcpServer::SetDscpSocketOption(NativeSocketType fd, uint8_t value) {
     538             :     /* The 'value' argument is expected to have DSCP value between 0 and 63 ie
     539             :      * in the lower order 6 bits of a byte. However, setsockopt expects DSCP
     540             :      * value in upper 6 bits of a byte. Hence left shift the value by 2 digits
     541             :      * before passing it to setsockopt */
     542        4586 :     value = value << 2;
     543        4586 :     int retval = setsockopt(fd, IPPROTO_IP, IP_TOS,
     544             :                             reinterpret_cast<const char *>(&value), sizeof(value));
     545        4586 :     if (retval < 0) {
     546           0 :         TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA,
     547             :             "Failure in setting DSCP value on the socket " +
     548             :             integerToString(fd) + " for value " + integerToString(value) +
     549             :             " with errno " + strerror(errno));
     550             :     }
     551        4586 :     return retval;
     552             : }
     553             : 
     554         968 : uint8_t TcpServer::GetDscpValue(NativeSocketType fd) const {
     555         968 :     uint8_t dscp = 0;
     556         968 :     unsigned int optlen = sizeof(dscp);
     557         968 :     int retval = getsockopt(fd, IPPROTO_IP, IP_TOS,
     558             :                             reinterpret_cast<char *>(&dscp),
     559             :                             reinterpret_cast<socklen_t *>(&optlen));
     560         968 :     if (retval < 0) {
     561           0 :         TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA,
     562             :             "Failure in getting DSCP value on the socket " +
     563             :             integerToString(fd) + " with errno " + strerror(errno));
     564             :     }
     565         968 :     return dscp;
     566             : }
     567             : 
     568          87 : int TcpServer::SetSocketOptions(const SandeshConfig &sandesh_config) {
     569          87 :     int retval = 0;
     570          87 :     if (acceptor_ && sandesh_config.tcp_keepalive_enable) {
     571          87 :         retval = SetKeepAliveSocketOption(acceptor_->native_handle(), sandesh_config);
     572             :     }
     573          87 :     return retval;
     574             : }
     575             : 
     576          87 : int TcpServer::SetKeepAliveSocketOption(int fd, const SandeshConfig &sandesh_config) {
     577          87 :     int tcp_keepalive_enable = 1, retval = 0;
     578          87 :     int tcp_keepalive_idle_time = sandesh_config.tcp_keepalive_idle_time;
     579          87 :     int tcp_keepalive_probes = sandesh_config.tcp_keepalive_probes;
     580          87 :     int tcp_keepalive_interval = sandesh_config.tcp_keepalive_interval;
     581          87 :     retval = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
     582             :                     reinterpret_cast<const char *>(&tcp_keepalive_enable), sizeof(tcp_keepalive_enable));
     583          87 :     if (retval < 0) {
     584           0 :         TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA,
     585             :             "Failure in setting Keepalive enable on the socket " +
     586             :             integerToString(fd) +
     587             :             " with errno " + strerror(errno));
     588           0 :         return retval;
     589             :     }
     590             : 
     591             : #ifdef TCP_KEEPIDLE
     592          87 :     retval = setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,
     593             :                     reinterpret_cast<const char *>(&tcp_keepalive_idle_time), sizeof(tcp_keepalive_idle_time));
     594          87 :     if (retval < 0) {
     595           0 :         TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA,
     596             :             "Failure in setting keepalive idle time on the socket " +
     597             :             integerToString(fd) +
     598             :             " with errno " + strerror(errno));
     599           0 :         return retval;
     600             :     }
     601             : #elif TCP_KEEPALIVE
     602             :     retval = setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE,
     603             :                     reinterpret_cast<const char *>(&tcp_keepalive_idle_time), sizeof(tcp_keepalive_idle_time));
     604             :     if (retval < 0) {
     605             :         TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA,
     606             :             "Failure in setting keepalive time on the socket " +
     607             :             integerToString(fd) +
     608             :             " with errno " + strerror(errno));
     609             :         return retval;
     610             :     }
     611             : #else
     612             : #error No TCP keepalive option defined.
     613             : #endif
     614             : 
     615             : #ifdef TCP_KEEPCNT
     616          87 :     retval = setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,
     617             :                     reinterpret_cast<const char *>(&tcp_keepalive_probes), sizeof(tcp_keepalive_probes));
     618          87 :     if (retval < 0) {
     619           0 :         TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA,
     620             :             "Failure in setting keepalive probes on the socket " +
     621             :             integerToString(fd) +
     622             :             " with errno " + strerror(errno));
     623           0 :         return retval;
     624             :     }
     625             : #endif
     626             : 
     627             : #ifdef TCP_KEEPINTVL
     628          87 :     retval = setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,
     629             :                     reinterpret_cast<const char *>(&tcp_keepalive_interval), sizeof(tcp_keepalive_interval));
     630          87 :     if (retval < 0) {
     631           0 :         TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA,
     632             :             "Failure in setting keepalive interval on the socket " +
     633             :             integerToString(fd) +
     634             :             " with errno " + strerror(errno));
     635           0 :         return retval;
     636             :     }
     637             : #endif
     638          87 :     return retval;
     639             : }
     640             : 
     641         669 : void TcpServer::GetRxSocketStats(SocketIOStats *socket_stats) const {
     642         669 :     stats_.GetRxStats(socket_stats);
     643         669 : }
     644             : 
     645         669 : void TcpServer::GetTxSocketStats(SocketIOStats *socket_stats) const {
     646         669 :     stats_.GetTxStats(socket_stats);
     647         669 : }
     648             : 
     649             : //
     650             : // TcpServerManager class routines
     651             : //
     652             : ServerManager<TcpServer, TcpServerPtr> TcpServerManager::impl_;
     653             : 
     654       17561 : void TcpServerManager::AddServer(TcpServer *server) {
     655       17561 :     impl_.AddServer(server);
     656       17561 : }
     657             : 
     658       17453 : void TcpServerManager::DeleteServer(TcpServer *server) {
     659             :     // Wait for pending writes to be complete
     660       17453 :     server->WaitForEmpty();
     661       17453 :     impl_.DeleteServer(server);
     662       17453 : }
     663             : 
     664        1243 : size_t TcpServerManager::GetServerCount() {
     665        1243 :     return impl_.GetServerCount();
     666             : }

Generated by: LCOV version 1.14