LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/io - udp_server.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 166 206 80.6 %
Date: 2026-08-03 02:19:58 Functions: 25 30 83.3 %
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/udp_server.h"
       6             : 
       7             : #include <boost/bind/bind.hpp>
       8             : 
       9             : #include "base/logging.h"
      10             : #include "base/address_util.h"
      11             : #include "io/io_log.h"
      12             : #include "io/io_utils.h"
      13             : 
      14             : using boost::asio::buffer_cast;
      15             : using boost::asio::mutable_buffer;
      16             : using boost::asio::mutable_buffers_1;
      17             : using boost::asio::const_buffer;
      18             : using boost::asio::ip::udp;
      19             : using namespace boost::placeholders;
      20             : 
      21             : int UdpServer::reader_task_id_ = -1;
      22             : 
      23             : class UdpServer::Reader : public Task {
      24             : public:
      25           2 :     Reader(UdpServerPtr server, const udp::endpoint &remote_endpoint,
      26             :         const const_buffer &buffer)
      27           6 :         : Task(server->reader_task_id(),
      28           4 :                server->reader_task_instance(remote_endpoint)),
      29           2 :         server_(server),
      30           2 :         remote_endpoint_(remote_endpoint),
      31           2 :         buffer_(buffer) {
      32           2 :     }
      33             : 
      34           2 :     virtual bool Run() {
      35           2 :         std::scoped_lock lock(server_->state_guard_);
      36           2 :         if (server_->state_ == OK) {
      37           2 :             server_->OnRead(buffer_, remote_endpoint_);
      38           2 :             server_->DeallocateBuffer(buffer_);
      39             :         }
      40           2 :         return true;
      41           2 :     }
      42           0 :     std::string Description() const { return "UdpServer::Reader"; }
      43             : 
      44             : private:
      45             :     UdpServerPtr server_;
      46             :     udp::endpoint remote_endpoint_;
      47             :     const_buffer buffer_;
      48             : };
      49             : 
      50           3 : UdpServer::UdpServer(boost::asio::io_context *io_service, int buffer_size):
      51           3 :     socket_(*io_service),
      52           3 :     buffer_size_(buffer_size),
      53           3 :     state_(Uninitialized),
      54           3 :     evm_(NULL) {
      55           3 :     if (reader_task_id_ == -1) {
      56           0 :         TaskScheduler *scheduler = TaskScheduler::GetInstance();
      57           0 :         reader_task_id_ = scheduler->GetTaskId("io::udp::ReaderTask");
      58             :     }
      59           3 :     refcount_ = 0;
      60           3 :     UdpServerManager::AddServer(this);
      61           3 : }
      62             : 
      63           3 : UdpServer::UdpServer(EventManager *evm, int buffer_size):
      64           3 :     socket_(*(evm->io_service())),
      65           3 :     buffer_size_(buffer_size),
      66           3 :     state_(Uninitialized),
      67           6 :     evm_(evm) {
      68           3 :     if (reader_task_id_ == -1) {
      69           2 :         TaskScheduler *scheduler = TaskScheduler::GetInstance();
      70           2 :         reader_task_id_ = scheduler->GetTaskId("io::udp::ReaderTask");
      71             :     }
      72           3 :     refcount_ = 0;
      73           3 :     UdpServerManager::AddServer(this);
      74           3 : }
      75             : 
      76           2 : int UdpServer::reader_task_instance(const udp::endpoint &rep) const {
      77           2 :     return Task::kTaskInstanceAny;
      78             : }
      79             : 
      80           6 : void UdpServer::SetName(udp::endpoint ep) {
      81           6 :     std::ostringstream s;
      82           6 :     boost::system::error_code ec;
      83           6 :     s << "Udpsocket@" << ep;
      84           6 :     name_ = s.str();
      85           6 : }
      86             : 
      87           7 : UdpServer::~UdpServer() {
      88             :     {
      89           6 :         std::scoped_lock lock(state_guard_);
      90           6 :         assert(state_ == Uninitialized || state_ == SocketOpenFailed ||
      91             :             state_ == SocketBindFailed);
      92           6 :     }
      93             :     {
      94           6 :         std::scoped_lock lock(pbuf_guard_);
      95           6 :         assert(pbuf_.empty());
      96           6 :     }
      97           7 : }
      98             : 
      99           6 : void UdpServer::Shutdown() {
     100           6 :     std::scoped_lock lock(state_guard_);
     101             :     {
     102           6 :         std::scoped_lock lock_pbuf(pbuf_guard_);
     103          10 :         while (!pbuf_.empty()) {
     104           4 :             delete[] pbuf_.back();
     105           4 :             pbuf_.pop_back();
     106             :         }
     107           6 :     }
     108           6 :     if (socket_.is_open()) {
     109           6 :         boost::system::error_code ec;
     110           6 :         socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
     111           6 :         if (ec) {
     112           6 :             UDP_SERVER_LOG_ERROR(this, UDP_DIR_NA,
     113             :                 "ERROR shutdown UDP socket: " << ec);
     114             :         }
     115           6 :         socket_.close(ec);
     116           6 :         if (ec) {
     117           0 :             UDP_SERVER_LOG_ERROR(this, UDP_DIR_NA,
     118             :                 "ERROR closing UDP socket: " << ec);
     119             :         }
     120             :     }
     121           6 :     state_ = Uninitialized;
     122           6 : }
     123             : 
     124           1 : bool UdpServer::Initialize(const std::string &ipaddress, unsigned short port) {
     125           1 :     boost::system::error_code error;
     126           1 :     boost::asio::ip::address ip = AddressFromString(ipaddress, &error);
     127           1 :     if (!error) {
     128           1 :         udp::endpoint local_endpoint = udp::endpoint(ip, port);
     129           1 :         return Initialize(local_endpoint);
     130             :     } else {
     131           0 :         UDP_SERVER_LOG_ERROR(this, UDP_DIR_NA, "IP address conversion: "
     132             :             << ipaddress << ": " << error);
     133           0 :         return false;
     134             :     }
     135             : }
     136             : 
     137           6 : bool UdpServer::Initialize(unsigned short port) {
     138           6 :     udp::endpoint local_endpoint = udp::endpoint(udp::v4(), port);
     139           6 :     return Initialize(local_endpoint);
     140             : }
     141             : 
     142           7 : bool UdpServer::Initialize(udp::endpoint local_endpoint) {
     143           7 :     if (GetServerState() != Uninitialized) {
     144           1 :         UDP_SERVER_LOG_ERROR(this, UDP_DIR_NA,
     145             :             "Initialize UDP server in WRONG state: " << state_);
     146           1 :         return false;
     147             :     }
     148           6 :     boost::system::error_code error;
     149           6 :     socket_.open(udp::v4(), error);
     150           6 :     if (error) {
     151           0 :         UDP_SERVER_LOG_ERROR(this, UDP_DIR_NA, "UDP socket open FAILED: " <<
     152             :             error.message());
     153           0 :         state_ = SocketOpenFailed;
     154           0 :         return false;
     155             :     }
     156           6 :     socket_.bind(local_endpoint, error);
     157           6 :     if (error) {
     158           0 :         boost::system::error_code ec;
     159           0 :         UDP_SERVER_LOG_ERROR(this, UDP_DIR_NA, "UDP socket bind FAILED: "
     160             :             << error.message() << ":" << socket_.local_endpoint(ec));
     161           0 :         state_ = SocketBindFailed;
     162           0 :         socket_.close(ec);
     163           0 :         return false;
     164             :     }
     165           6 :     SetName(local_endpoint);
     166           6 :     state_ = OK;
     167           6 :     return true;
     168             : }
     169             : 
     170          12 : mutable_buffer UdpServer::AllocateBuffer(std::size_t s) {
     171          12 :     uint8_t *p = new uint8_t[s];
     172             :     {
     173          12 :         std::scoped_lock lock(pbuf_guard_);
     174          12 :         pbuf_.push_back(p);
     175          12 :     }
     176          12 :     return mutable_buffer(p, s);
     177             : }
     178             : 
     179           9 : mutable_buffer UdpServer::AllocateBuffer() {
     180           9 :     return AllocateBuffer(buffer_size_);
     181             : }
     182             : 
     183           8 : void UdpServer::DeallocateBuffer(const const_buffer &buffer) {
     184           8 :     const uint8_t *p = buffer_cast<const uint8_t *>(buffer);
     185             :     {
     186           8 :         std::scoped_lock lock(pbuf_guard_);
     187           8 :         std::vector<uint8_t *>::iterator f = std::find(pbuf_.begin(),
     188             :             pbuf_.end(), p);
     189           8 :         if (f != pbuf_.end())
     190           8 :             pbuf_.erase(f);
     191           8 :     }
     192           8 :     delete[] p;
     193           8 : }
     194             : 
     195           4 : void UdpServer::StartSend(udp::endpoint ep, std::size_t bytes_to_send,
     196             :         const_buffer buffer) {
     197           4 :     if (state_ == OK) {
     198           3 :         socket_.async_send_to(boost::asio::buffer(buffer), ep,
     199           6 :             boost::bind(&UdpServer::HandleSendInternal, UdpServerPtr(this),
     200             :             buffer, ep,
     201             :             boost::asio::placeholders::bytes_transferred,
     202             :             boost::asio::placeholders::error));
     203             :     } else {
     204           1 :         stats_.write_errors++;
     205           1 :         UDP_SERVER_LOG_ERROR(this, UDP_DIR_NA,
     206             :             "StartSend UDP server in WRONG state: " << state_);
     207           1 :         DeallocateBuffer(buffer);
     208             :     }
     209           4 : }
     210             : 
     211           3 : void UdpServer::HandleSendInternal(const const_buffer send_buffer,
     212             :         udp::endpoint remote_endpoint, std::size_t bytes_transferred,
     213             :         const boost::system::error_code& error) {
     214           3 :     std::scoped_lock lock(state_guard_);
     215           3 :     if (state_ != OK) {
     216           0 :         stats_.write_errors++;
     217           0 :         UDP_SERVER_LOG_ERROR(this, UDP_DIR_OUT,
     218             :             "Send UDP server in WRONG state: " << state_);
     219           0 :         return;
     220             :     }
     221           3 :     if (error) {
     222           0 :         stats_.write_errors++;
     223           0 :         UDP_SERVER_LOG_ERROR(this, UDP_DIR_OUT,
     224             :             "Send to " << remote_endpoint << " FAILED due to error: " <<
     225             :             error.value() << " : " << error.message());
     226           0 :         DeallocateBuffer(send_buffer);
     227           0 :         return;
     228             :     }
     229             :     // Update write statistics.
     230           3 :     stats_.write_calls++;
     231           3 :     stats_.write_bytes += bytes_transferred;
     232             :     // Call the handler
     233           3 :     HandleSend(send_buffer, remote_endpoint, bytes_transferred, error);
     234           3 : }
     235             : 
     236           9 : void UdpServer::StartReceive() {
     237           9 :     if (state_ == OK) {
     238           8 :         mutable_buffer b(AllocateBuffer());
     239           8 :         const_buffer buffer(buffer_cast<const uint8_t*>(b), buffer_size(b));
     240           8 :         socket_.async_receive_from(mutable_buffers_1(b),
     241          16 :             remote_endpoint_, boost::bind(&UdpServer::HandleReceiveInternal,
     242          16 :             UdpServerPtr(this), buffer,
     243             :             boost::asio::placeholders::bytes_transferred,
     244             :             boost::asio::placeholders::error));
     245             :     } else {
     246           1 :         stats_.read_errors++;
     247           1 :         UDP_SERVER_LOG_ERROR(this, UDP_DIR_NA,
     248             :             "StartReceive UDP server in WRONG state: " << state_);
     249             :     }
     250           9 : }
     251             : 
     252           5 : void UdpServer::HandleReceiveInternal(const_buffer recv_buffer,
     253             :     std::size_t bytes_transferred, const boost::system::error_code& error) {
     254           5 :     std::scoped_lock lock(state_guard_);
     255           5 :     if (state_ != OK) {
     256           1 :         stats_.read_errors++;
     257           1 :         UDP_SERVER_LOG_ERROR(this, UDP_DIR_IN,
     258             :             "Receive UDP server in WRONG state: " << state_);
     259           1 :         return;
     260             :     }
     261           4 :     if (error) {
     262           0 :         stats_.read_errors++;
     263           0 :         UDP_SERVER_LOG_ERROR(this, UDP_DIR_IN,
     264             :             "Read FAILED due to error: " << error.value() << " : " <<
     265             :             error.message());
     266           0 :         DeallocateBuffer(recv_buffer);
     267             :     } else {
     268             :         // Update read statistics.
     269           4 :         stats_.read_calls++;
     270           4 :         stats_.read_bytes += bytes_transferred;
     271             :         // Call the handler
     272           4 :         HandleReceive(recv_buffer, remote_endpoint_, bytes_transferred, error);
     273             :     }
     274           4 :     StartReceive();
     275           5 : }
     276             : 
     277           2 : void UdpServer::HandleReceive(const const_buffer &recv_buffer,
     278             :     udp::endpoint remote_endpoint, std::size_t bytes_transferred,
     279             :     const boost::system::error_code& error) {
     280           2 :     const_buffer rdbuf(buffer_cast<const uint8_t *>(recv_buffer),
     281           2 :                        bytes_transferred);
     282           2 :     Reader *task = new Reader(UdpServerPtr(this), remote_endpoint,
     283           2 :                               rdbuf);
     284             :     // Starting a new task for the session
     285           2 :     TaskScheduler *scheduler = TaskScheduler::GetInstance();
     286           2 :     scheduler->Enqueue(task);
     287           2 : }
     288             : 
     289           0 : void UdpServer::OnRead(const const_buffer &recv_buffer,
     290             :     const udp::endpoint &remote_endpoint) {
     291           0 :     UDP_SERVER_LOG_ERROR(this, UDP_DIR_IN, "Receive UDP: " <<
     292             :         "Default implementation of OnRead does NOT process received message");
     293           0 : }
     294             : 
     295           0 : void UdpServer::HandleSend(boost::asio::const_buffer send_buffer,
     296             :     udp::endpoint remote_endpoint, std::size_t bytes_transferred,
     297             :     const boost::system::error_code& error) {
     298           0 :     DeallocateBuffer(send_buffer);
     299           0 : }
     300             : 
     301           4 : udp::endpoint UdpServer::GetLocalEndpoint(boost::system::error_code *error)
     302             :         const {
     303           4 :     return socket_.local_endpoint(*error);
     304             : }
     305             : 
     306           0 : std::string UdpServer::GetLocalEndpointAddress() const {
     307           0 :     boost::system::error_code error;
     308           0 :     udp::endpoint ep = GetLocalEndpoint(&error);
     309           0 :     if (error.value())
     310           0 :         return "";
     311           0 :     return ep.address().to_string();
     312             : }
     313             : 
     314           1 : int UdpServer::GetLocalEndpointPort() const {
     315           1 :     boost::system::error_code error;
     316           1 :     udp::endpoint ep = GetLocalEndpoint(&error);
     317           1 :     if (error.value())
     318           1 :         return -1;
     319           0 :     return ep.port();
     320             : }
     321             : 
     322           1 : void UdpServer::GetRxSocketStats(SocketIOStats *socket_stats) const {
     323           1 :     stats_.GetRxStats(socket_stats);
     324           1 : }
     325             : 
     326           0 : void UdpServer::GetTxSocketStats(SocketIOStats *socket_stats) const {
     327           0 :     stats_.GetTxStats(socket_stats);
     328           0 : }
     329             : 
     330             : //
     331             : // UdpServerManager class routines
     332             : //
     333             : ServerManager<UdpServer, UdpServerPtr> UdpServerManager::impl_;
     334             : 
     335           6 : void UdpServerManager::AddServer(UdpServer *server) {
     336           6 :     impl_.AddServer(server);
     337           6 : }
     338             : 
     339           6 : void UdpServerManager::DeleteServer(UdpServer *server) {
     340           6 :     impl_.DeleteServer(server);
     341           6 : }

Generated by: LCOV version 1.14