Line data Source code
1 : /* 2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. 3 : */ 4 : 5 : #ifndef SRC_IO_UDP_SERVER_H_ 6 : #define SRC_IO_UDP_SERVER_H_ 7 : 8 : #include <atomic> 9 : #include <string> 10 : #include <vector> 11 : #include <mutex> 12 : 13 : #include <boost/asio.hpp> 14 : #include <boost/intrusive_ptr.hpp> 15 : #include "io/event_manager.h" 16 : #include "io/server_manager.h" 17 : #include "io/io_utils.h" 18 : 19 : class SocketIOStats; 20 : 21 : class UdpServer { 22 : public: 23 : typedef boost::asio::ip::udp::endpoint Endpoint; 24 : typedef boost::asio::ip::udp::socket Socket; 25 : 26 : enum ServerState { 27 : OK = 42, 28 : Uninitialized, 29 : SocketOpenFailed, 30 : SocketBindFailed, 31 : }; 32 : static const int kDefaultBufferSize = 4 * 1024; 33 : 34 : explicit UdpServer(EventManager *evm, int buffer_size = kDefaultBufferSize); 35 : explicit UdpServer(boost::asio::io_context *io_service, 36 : int buffer_size = kDefaultBufferSize); 37 : virtual ~UdpServer(); 38 : 39 : virtual bool Initialize(unsigned short port); 40 : virtual bool Initialize(const std::string &ipaddress, unsigned short port); 41 : virtual bool Initialize(boost::asio::ip::udp::endpoint local_endpoint); 42 : virtual void Shutdown(); 43 : 44 : // tx-rx 45 : // Assumes mutex is locked or called from the main thread 46 : void StartSend(boost::asio::ip::udp::endpoint ep, std::size_t bytes_to_send, 47 : boost::asio::const_buffer buffer); 48 : // Assumes mutex is locked or called from the main thread 49 : void StartReceive(); 50 : // state 51 21 : ServerState GetServerState() const { return state_; } 52 : boost::asio::ip::udp::endpoint GetLocalEndpoint( 53 : boost::system::error_code *error) const; 54 : std::string GetLocalEndpointAddress() const; 55 : int GetLocalEndpointPort() const; 56 : 57 : // buffers 58 : // Assumes mutex is locked or called from the main thread 59 : boost::asio::mutable_buffer AllocateBuffer(); 60 : boost::asio::mutable_buffer AllocateBuffer(std::size_t s); 61 : // Assumes mutex is locked or called from the main thread 62 : void DeallocateBuffer(const boost::asio::const_buffer &buffer); 63 : 64 : // statistics 65 : const io::SocketStats &GetSocketStats() const { return stats_; } 66 : void GetRxSocketStats(SocketIOStats *socket_stats) const; 67 : void GetTxSocketStats(SocketIOStats *socket_stats) const; 68 : 69 : protected: 70 : EventManager *event_manager() { return evm_; } 71 14 : virtual bool DisableSandeshLogMessages() { return false; } 72 28 : virtual std::string ToString() { return name_; } 73 : 74 : // Assumes mutex is locked, deallocates the buffer 75 : virtual void HandleReceive( 76 : const boost::asio::const_buffer &recv_buffer, 77 : boost::asio::ip::udp::endpoint remote_endpoint, 78 : std::size_t bytes_transferred, 79 : const boost::system::error_code& error); 80 : 81 : virtual void OnRead(const boost::asio::const_buffer &recv_buffer, 82 : const boost::asio::ip::udp::endpoint &remote_endpoint); 83 : 84 2 : virtual int reader_task_id() const { 85 2 : return reader_task_id_; 86 : } 87 : // This function returns the instance to run ReaderTask. 88 : // Returning Task::kTaskInstanceAny would allow multiple reader tasks to 89 : // run in parallel. 90 : // Derived class may override implementation if it expects that all the 91 : // tasks of the reader to run in specific instance 92 : // Note: Two tasks of same task ID and task instance can't run 93 : // at in parallel 94 : // E.g. User can create task per remote endpoint to ensure that 95 : // there is one ReaderTask per remote endpoint 96 : virtual int reader_task_instance( 97 : const boost::asio::ip::udp::endpoint &remote_endpoint) const; 98 : 99 : // Assumes mutex is locked, deallocates the buffer 100 : virtual void HandleSend(boost::asio::const_buffer send_buffer, 101 : boost::asio::ip::udp::endpoint remote_endpoint, 102 : std::size_t bytes_transferred, 103 : const boost::system::error_code& error); 104 : 105 : private: 106 : class Reader; 107 : friend void intrusive_ptr_add_ref(UdpServer *server); 108 : friend void intrusive_ptr_release(UdpServer *server); 109 : void SetName(boost::asio::ip::udp::endpoint ep); 110 : 111 : // Locks the mutex 112 : void HandleReceiveInternal( 113 : boost::asio::const_buffer recv_buffer, 114 : std::size_t bytes_transferred, 115 : const boost::system::error_code& error); 116 : 117 : // Locks the mutex 118 : void HandleSendInternal(boost::asio::const_buffer send_buffer, 119 : boost::asio::ip::udp::endpoint remote_endpoint, 120 : std::size_t bytes_transferred, 121 : const boost::system::error_code& error); 122 : 123 : static int reader_task_id_; 124 : boost::asio::ip::udp::socket socket_; 125 : int buffer_size_; 126 : ServerState state_; 127 : EventManager *evm_; 128 : std::string name_; 129 : boost::asio::ip::udp::endpoint remote_endpoint_; 130 : std::mutex state_guard_; 131 : std::mutex pbuf_guard_; 132 : std::vector<uint8_t *> pbuf_; 133 : std::atomic<int> refcount_; 134 : io::SocketStats stats_; 135 : 136 : DISALLOW_COPY_AND_ASSIGN(UdpServer); 137 : }; 138 : 139 : typedef boost::intrusive_ptr<UdpServer> UdpServerPtr; 140 : 141 107 : inline void intrusive_ptr_add_ref(UdpServer *server) { 142 107 : server->refcount_.fetch_add(1); 143 107 : } 144 : 145 107 : inline void intrusive_ptr_release(UdpServer *server) { 146 107 : int prev = server->refcount_.fetch_sub(1); 147 107 : if (prev == 1) { 148 6 : delete server; 149 : } 150 107 : } 151 : 152 : class UdpServerManager { 153 : public: 154 : static void AddServer(UdpServer *server); 155 : static void DeleteServer(UdpServer *server); 156 : 157 : private: 158 : static ServerManager<UdpServer, UdpServerPtr> impl_; 159 : }; 160 : 161 : #endif // SRC_IO_UDP_SERVER_H_