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

Generated by: LCOV version 1.14