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: 258 360 71.7 %
Date: 2026-09-28 02:13:17 Functions: 37 44 84.1 %
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        1016 : TcpServer::TcpServer(EventManager *evm)
      33        1016 :     : evm_(evm), socket_open_failure_(false), intf_id_(-1) {
      34        1016 :     refcount_ = 0;
      35        1016 :     TcpServerManager::AddServer(this);
      36        1016 : }
      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        1015 : TcpServer::~TcpServer() {
      44        1015 :     assert(acceptor_ == NULL);
      45        1015 :     assert(session_ref_.empty());
      46        1015 :     assert(session_map_.empty());
      47        1015 : }
      48             : 
      49         832 : void TcpServer::SetName(Endpoint local_endpoint) {
      50         832 :     ostringstream out;
      51         832 :     out << local_endpoint;
      52         832 :     name_ = out.str();
      53         832 : }
      54             : 
      55         832 : void TcpServer::ResetAcceptor() {
      56         832 :     acceptor_.reset();
      57         832 :     name_ = "";
      58         832 : }
      59             : 
      60         475 : bool TcpServer::Initialize(unsigned short port) {
      61         475 :     intf_id_ = -1; //this initializer is only for IPv4
      62         475 :     tcp::endpoint localaddr(tcp::v4(), port);
      63         475 :     return InitializeInternal(localaddr);
      64             : }
      65             : 
      66         357 : bool TcpServer::Initialize(unsigned short port,
      67             :     const IpAddress &host_ip,
      68             :     int intf_id) {
      69         357 :     tcp::endpoint localaddr(host_ip, port);
      70         357 :     tcp::endpoint serv_ep(host_ip, port);
      71         357 :     intf_id_ = intf_id;
      72         357 :     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         357 :     return InitializeInternal(serv_ep);
      80             : }
      81             : 
      82         832 : bool TcpServer::InitializeInternal(tcp::endpoint localaddr) {
      83         832 :     acceptor_.reset(new tcp::acceptor(*evm_->io_service()));
      84         832 :     if (!acceptor_) {
      85           0 :         TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "Cannot create acceptor");
      86           0 :         return false;
      87             :     }
      88             : 
      89         832 :     error_code ec;
      90         832 :     if (localaddr.address().is_v4())
      91         828 :         acceptor_->open(tcp::v4(), ec);
      92             :     else
      93           4 :         acceptor_->open(tcp::v6(), ec);
      94             : 
      95         832 :     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         832 :     acceptor_->set_option(socket_base::reuse_address(true), ec);
     102         832 :     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         832 :     acceptor_->bind(localaddr, ec);
     110         832 :     if (ec) {
     111           0 :         TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "TCP bind(" << localaddr.address() <<
     112             :                              ":" << localaddr.port() << "): " << ec.message());
     113           0 :         ResetAcceptor();
     114           0 :         return false;
     115             :     }
     116             : 
     117         832 :     tcp::endpoint local_endpoint = acceptor_->local_endpoint(ec);
     118         832 :     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         832 :     SetName(local_endpoint);
     129             : 
     130         832 :     acceptor_->listen(socket_base::max_connections, ec);
     131         832 :     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         832 :     TCP_SERVER_LOG_DEBUG(this, TCP_DIR_NA, "Initialization complete");
     139         832 :     AsyncAccept();
     140             : 
     141         832 :     return true;
     142             : }
     143             : 
     144         971 : void TcpServer::Shutdown() {
     145         971 :     std::scoped_lock lock(mutex_);
     146         971 :     error_code ec;
     147             : 
     148         971 :     if (acceptor_) {
     149         832 :         acceptor_->close(ec);
     150         832 :         if (ec) {
     151           0 :             TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "Error during shutdown: "
     152             :                                                        << ec.message());
     153             :         }
     154         832 :         ResetAcceptor();
     155             :     }
     156         971 : }
     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        1021 : void TcpServer::ClearSessions() {
     161        1021 :     SessionSet refs;
     162             :     {
     163        1021 :         std::scoped_lock lock(mutex_);
     164        1021 :         refs.swap(session_ref_);
     165        1021 :     }
     166             : 
     167        1021 :     for (SessionSet::iterator iter = refs.begin(), next = iter;
     168        1254 :          iter != refs.end(); iter = next) {
     169         233 :         ++next;
     170         233 :         TcpSession *session = iter->get();
     171         233 :         session->Close();
     172             :     }
     173        1021 :     refs.clear();
     174        1021 :     if (session_ref_.empty() && session_map_.empty()) {
     175        1017 :         cond_var_.notify_all();
     176             :     }
     177        1021 : }
     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        1277 : TcpSession *TcpServer::CreateSession() {
     191        1277 :     TcpSession *session = AllocSession(false);
     192             :     {
     193        1262 :         std::scoped_lock lock(mutex_);
     194        1282 :         session_ref_.insert(TcpSessionPtr(session));
     195        1282 :     }
     196        1282 :     return session;
     197             : }
     198             : 
     199        2081 : void TcpServer::DeleteSession(TcpSession *session) {
     200             :     // The caller will typically close the socket before deleting the
     201             :     // session.
     202        2081 :     session->Close();
     203             :     {
     204        2083 :         std::scoped_lock lock(mutex_);
     205        2084 :         assert(session->refcount_);
     206        2084 :         session_ref_.erase(TcpSessionPtr(session));
     207        2084 :         if (session_ref_.empty() && session_map_.empty()) {
     208         731 :             cond_var_.notify_all();
     209             :         }
     210        2084 :     }
     211        2084 : }
     212             : 
     213             : //
     214             : // Insert into SessionMap.
     215             : // Assumes that caller has the mutex.
     216             : //
     217        2157 : void TcpServer::InsertSessionToMap(Endpoint remote, TcpSession *session) {
     218        2157 :     session_map_.insert(make_pair(remote, session));
     219        2157 : }
     220             : 
     221             : //
     222             : // Remove from SessionMap.
     223             : // Assumes that caller has the mutex.
     224             : // Return true if the session is found.
     225             : //
     226        2157 : bool TcpServer::RemoveSessionFromMap(Endpoint remote, TcpSession *session) {
     227        2157 :     for (SessionMap::iterator iter = session_map_.find(remote);
     228        2497 :          iter != session_map_.end() && iter->first == remote; ++iter) {
     229        2496 :         if (iter->second == session) {
     230        2155 :             session_map_.erase(iter);
     231        2157 :             return true;
     232             :         }
     233             :     }
     234           0 :     return false;
     235             : }
     236             : 
     237        2156 : void TcpServer::OnSessionClose(TcpSession *session) {
     238        2156 :     std::scoped_lock lock(mutex_);
     239             : 
     240             :     // CloseSessions closes and removes all the sessions from the map.
     241        2157 :     if (session_map_.empty()) {
     242           0 :         return;
     243             :     }
     244             : 
     245        2157 :     bool found = RemoveSessionFromMap(session->remote_endpoint(), session);
     246        2157 :     if (session_map_.empty() && session_ref_.empty()) {
     247         147 :         cond_var_.notify_all();
     248             :     }
     249        2157 :     assert(found);
     250        2157 : }
     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        1061 : void TcpServer::WaitForEmpty() {
     257        1061 :     std::unique_lock<std::mutex> lock(mutex_);
     258        1065 :     while (!session_ref_.empty() || !session_map_.empty()) {
     259           4 :         cond_var_.wait(lock);
     260             :     }
     261        1061 : }
     262             : 
     263        2617 : void TcpServer::AsyncAccept() {
     264        2617 :     std::scoped_lock lock(mutex_);
     265        2617 :     if (acceptor_ == NULL) {
     266         708 :         return;
     267             :     }
     268        1909 :     set_accept_socket();
     269        3818 :     acceptor_->async_accept(*accept_socket(),
     270        3818 :         bind(&TcpServer::AcceptHandlerInternal, this,
     271        3818 :             TcpServerPtr(this), error));
     272        2617 : }
     273             : 
     274        1957 : int TcpServer::GetPort() const {
     275        1957 :     std::scoped_lock lock(mutex_);
     276        1970 :     if (acceptor_.get() == NULL) {
     277         133 :         return -1;
     278             :     }
     279        1837 :     error_code ec;
     280        1837 :     tcp::endpoint ep = acceptor_->local_endpoint(ec);
     281        1837 :     if (ec) {
     282           0 :         return -1;
     283             :     }
     284        1837 :     return ep.port();
     285        1970 : }
     286             : 
     287           3 : bool TcpServer::HasSessions() const {
     288           3 :     std::scoped_lock lock(mutex_);
     289           6 :     return !session_map_.empty();
     290           3 : }
     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         634 : TcpServer::Endpoint TcpServer::LocalEndpoint() const {
     309         634 :     std::scoped_lock lock(mutex_);
     310         634 :     if (acceptor_.get() == NULL) {
     311         310 :         return Endpoint();
     312             :     }
     313         324 :     error_code ec;
     314         324 :     Endpoint local = acceptor_->local_endpoint(ec);
     315         324 :     if (ec) {
     316           0 :         return Endpoint();
     317             :     }
     318         324 :     return local;
     319         634 : }
     320             : 
     321        2171 : TcpSession *TcpServer::AllocSession(bool server_session) {
     322             :     TcpSession *session;
     323        2171 :     if (server_session) {
     324        1049 :         session = AllocSession(so_accept_.get());
     325             : 
     326             :         // if session allocate succeeds release ownership to so_accept.
     327        1049 :         if (session != NULL) {
     328        1049 :             so_accept_.release();
     329             :         }
     330             :     } else {
     331        1122 :         Socket *socket = new Socket(*evm_->io_service());
     332        1119 :         session = AllocSession(socket);
     333             :     }
     334             : 
     335        2154 :     return session;
     336             : }
     337             : 
     338        2802 : TcpServer::Socket *TcpServer::accept_socket() const {
     339        2802 :     return so_accept_.get();
     340             : }
     341             : 
     342        1753 : void TcpServer::set_accept_socket() {
     343        1753 :     so_accept_.reset(new Socket(*evm_->io_service()));
     344        1753 : }
     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        1785 : void TcpServer::AcceptHandlerInternal(TcpServerPtr server,
     357             :         const error_code& error) {
     358        1785 :     tcp::endpoint remote;
     359        1785 :     error_code ec;
     360        1785 :     TcpSessionPtr session;
     361        1785 :     bool need_close = false;
     362             : 
     363        1785 :     if (error) {
     364         708 :         goto done;
     365             :     }
     366             : 
     367        1077 :     remote = accept_socket()->remote_endpoint(ec);
     368        1077 :     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        1077 :     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        1077 :     session.reset(AllocSession(true));
     384        1077 :     if (session == NULL) {
     385           0 :         TCP_SERVER_LOG_DEBUG(this, TCP_DIR_IN, "Session not created");
     386           0 :         goto done;
     387             :     }
     388             : 
     389        1077 :     ec = session->SetSocketOptions();
     390        1077 :     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        1077 :     session->SessionEstablished(remote, TcpSession::PASSIVE);
     398        1077 :     AcceptHandlerComplete(session);
     399             : 
     400        1785 : done:
     401        1785 :     if (need_close) {
     402           0 :         session->CloseInternal(ec, false, false);
     403             :     }
     404        1785 :     AsyncAccept();
     405        1785 : }
     406             : 
     407        1075 : void TcpServer::AcceptHandlerComplete(TcpSessionPtr session) {
     408        1075 :     tcp::endpoint remote = session->remote_endpoint();
     409             :     {
     410        1075 :         std::scoped_lock lock(mutex_);
     411        1075 :         if (AcceptSession(session.get())) {
     412        1035 :             TCP_SESSION_LOG_UT_DEBUG(session, TCP_DIR_IN,
     413             :                                      "Accepted session from "
     414             :                                          << remote.address().to_string()
     415             :                                          << ":" << remote.port());
     416        1035 :             session_ref_.insert(session);
     417        1035 :             InsertSessionToMap(remote, session.get());
     418             :         } else {
     419          40 :             TCP_SESSION_LOG_UT_DEBUG(session, TCP_DIR_IN,
     420             :                                      "Rejected session from "
     421             :                                          << remote.address().to_string()
     422             :                                          << ":" << remote.port());
     423          40 :             error_code ec;
     424          40 :             session->CloseInternal(ec, false, false);
     425          40 :             return;
     426             :         }
     427        1075 :     }
     428             : 
     429        1035 :     session->Accepted();
     430             : }
     431             : 
     432      160674 : TcpSession *TcpServer::GetSession(Endpoint remote) {
     433      160674 :     std::scoped_lock lock(mutex_);
     434      160674 :     SessionMap::const_iterator iter = session_map_.find(remote);
     435      160674 :     if (iter != session_map_.end()) {
     436      160666 :         return iter->second;
     437             :     }
     438           8 :     return NULL;
     439      160674 : }
     440             : 
     441        1171 : void TcpServer::ConnectHandler(TcpServerPtr server, TcpSessionPtr session,
     442             :                                const error_code &error) {
     443        1171 :     if (error) {
     444          47 :         TCP_SERVER_LOG_UT_DEBUG(server, TCP_DIR_OUT,
     445             :                                 "Connect failure: " << error.message());
     446          47 :         session->ConnectFailed();
     447          47 :         return;
     448             :     }
     449             : 
     450        1124 :     ConnectHandlerComplete(session);
     451             : }
     452             : 
     453        1122 : void TcpServer::ConnectHandlerComplete(TcpSessionPtr session) {
     454        1122 :     error_code ec;
     455        1122 :     Endpoint remote = session->socket()->remote_endpoint(ec);
     456        1122 :     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        1122 :         std::scoped_lock lock(mutex_);
     465        1122 :         InsertSessionToMap(remote, session.get());
     466        1122 :     }
     467             : 
     468             :     // Connected verifies whether the session has been closed or is still
     469             :     // active.
     470        1122 :     if (!session->Connected(remote)) {
     471           0 :         std::scoped_lock lock(mutex_);
     472           0 :         RemoveSessionFromMap(remote, session.get());
     473           0 :     }
     474             : }
     475             : 
     476        1171 : void TcpServer::Connect(TcpSession *session, Endpoint remote) {
     477        1171 :     assert(session->refcount_);
     478        1171 :     Socket *socket = session->socket();
     479        1171 :     socket->async_connect(remote,
     480        2341 :         bind(&TcpServer::ConnectHandler, this, TcpServerPtr(this),
     481        2341 :                     TcpSessionPtr(session), error));
     482        1170 : }
     483             : 
     484           0 : int TcpServer::SetMd5SocketOption(NativeSocketType fd, uint32_t peer_ip,
     485             :                                   const string &md5_password) {
     486           0 :     assert(md5_password.size() <= TCP_MD5SIG_MAXKEYLEN);
     487           0 :     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           0 :     memset(&local_addr, 0, sizeof(local_addr));
     494             : 
     495           0 :     local_addr.sin_family = AF_INET;
     496           0 :     local_addr.sin_addr.s_addr = htonl(peer_ip);
     497             : 
     498             :     struct tcp_md5sig md5sig;
     499           0 :     memset(&md5sig, 0, sizeof (md5sig));
     500             : 
     501           0 :     memcpy(md5sig.tcpm_key, md5_password.c_str(), md5_password.size());
     502           0 :     md5sig.tcpm_keylen = md5_password.size();
     503           0 :     memcpy(&md5sig.tcpm_addr, &local_addr, sizeof(local_addr));
     504           0 :     int retval = setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, (const char *)&md5sig,
     505             :                             sizeof(md5sig));
     506           0 :     if (retval < 0) {
     507           0 :         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           0 :         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           0 :     return retval;
     517             : }
     518             : 
     519           0 : int TcpServer::SetListenSocketMd5Option(uint32_t peer_ip,
     520             :                                         const string &md5_password) {
     521           0 :     int retval = 0;
     522           0 :     if (acceptor_) {
     523           0 :         retval = SetMd5SocketOption(acceptor_->native_handle(), peer_ip,
     524             :                                     md5_password);
     525             :     }
     526           0 :     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         700 : 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         700 :     value = value << 2;
     543         700 :     int retval = setsockopt(fd, IPPROTO_IP, IP_TOS,
     544             :                             reinterpret_cast<const char *>(&value), sizeof(value));
     545         700 :     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         700 :     return retval;
     552             : }
     553             : 
     554           0 : uint8_t TcpServer::GetDscpValue(NativeSocketType fd) const {
     555           0 :     uint8_t dscp = 0;
     556           0 :     unsigned int optlen = sizeof(dscp);
     557           0 :     int retval = getsockopt(fd, IPPROTO_IP, IP_TOS,
     558             :                             reinterpret_cast<char *>(&dscp),
     559             :                             reinterpret_cast<socklen_t *>(&optlen));
     560           0 :     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           0 :     return dscp;
     566             : }
     567             : 
     568          46 : int TcpServer::SetSocketOptions(const SandeshConfig &sandesh_config) {
     569          46 :     int retval = 0;
     570          46 :     if (acceptor_ && sandesh_config.tcp_keepalive_enable) {
     571          46 :         retval = SetKeepAliveSocketOption(acceptor_->native_handle(), sandesh_config);
     572             :     }
     573          46 :     return retval;
     574             : }
     575             : 
     576          46 : int TcpServer::SetKeepAliveSocketOption(int fd, const SandeshConfig &sandesh_config) {
     577          46 :     int tcp_keepalive_enable = 1, retval = 0;
     578          46 :     int tcp_keepalive_idle_time = sandesh_config.tcp_keepalive_idle_time;
     579          46 :     int tcp_keepalive_probes = sandesh_config.tcp_keepalive_probes;
     580          46 :     int tcp_keepalive_interval = sandesh_config.tcp_keepalive_interval;
     581          46 :     retval = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
     582             :                     reinterpret_cast<const char *>(&tcp_keepalive_enable), sizeof(tcp_keepalive_enable));
     583          46 :     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          46 :     retval = setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,
     593             :                     reinterpret_cast<const char *>(&tcp_keepalive_idle_time), sizeof(tcp_keepalive_idle_time));
     594          46 :     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          46 :     retval = setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,
     617             :                     reinterpret_cast<const char *>(&tcp_keepalive_probes), sizeof(tcp_keepalive_probes));
     618          46 :     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          46 :     retval = setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,
     629             :                     reinterpret_cast<const char *>(&tcp_keepalive_interval), sizeof(tcp_keepalive_interval));
     630          46 :     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          46 :     return retval;
     639             : }
     640             : 
     641         399 : void TcpServer::GetRxSocketStats(SocketIOStats *socket_stats) const {
     642         399 :     stats_.GetRxStats(socket_stats);
     643         399 : }
     644             : 
     645         399 : void TcpServer::GetTxSocketStats(SocketIOStats *socket_stats) const {
     646         399 :     stats_.GetTxStats(socket_stats);
     647         399 : }
     648             : 
     649             : //
     650             : // TcpServerManager class routines
     651             : //
     652             : ServerManager<TcpServer, TcpServerPtr> TcpServerManager::impl_;
     653             : 
     654        1016 : void TcpServerManager::AddServer(TcpServer *server) {
     655        1016 :     impl_.AddServer(server);
     656        1016 : }
     657             : 
     658        1015 : void TcpServerManager::DeleteServer(TcpServer *server) {
     659             :     // Wait for pending writes to be complete
     660        1015 :     server->WaitForEmpty();
     661        1015 :     impl_.DeleteServer(server);
     662        1015 : }
     663             : 
     664         126 : size_t TcpServerManager::GetServerCount() {
     665         126 :     return impl_.GetServerCount();
     666             : }

Generated by: LCOV version 1.14