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 : #ifndef SRC_IO_TCP_SERVER_H_ 7 : #define SRC_IO_TCP_SERVER_H_ 8 : 9 : #include <map> 10 : #include <condition_variable> 11 : #include <mutex> 12 : #include <set> 13 : #include <string> 14 : #include <atomic> 15 : #include <boost/asio/ip/tcp.hpp> 16 : #include <boost/intrusive_ptr.hpp> 17 : #include <boost/scoped_ptr.hpp> 18 : 19 : #include "base/util.h" 20 : #include "base/address.h" 21 : #include "io/server_manager.h" 22 : #include "io/io_utils.h" 23 : #include <sandesh/library/cpp/sandesh_options.h> 24 : 25 : class EventManager; 26 : class TcpSession; 27 : class SocketIOStats; 28 : 29 : class TcpServer { 30 : public: 31 : typedef boost::asio::ip::tcp::endpoint Endpoint; 32 : typedef boost::asio::ip::tcp::socket Socket; 33 : typedef boost::asio::ip::tcp::socket::native_handle_type NativeSocketType; 34 : 35 : explicit TcpServer(EventManager *evm); 36 : virtual ~TcpServer(); 37 : 38 : // Bind a listening socket and register it with the event manager. 39 : virtual bool Initialize(unsigned short port); 40 : virtual bool Initialize(unsigned short port, const IpAddress &host_ip, 41 : int intf_id = -1); 42 : bool InitializeInternal(boost::asio::ip::tcp::endpoint localaddr); 43 : 44 6565 : const std::string ToString() const { return name_; } 45 : void SetAcceptor(); 46 : void ResetAcceptor(); 47 : 48 : // shutdown the listening socket. 49 : void Shutdown(); 50 : 51 : // close all existing sessions and delete them. 52 : void ClearSessions(); 53 : void UpdateSessionsDscp(uint8_t dscp); 54 : 55 : // Helper function that allocates a socket and calls the virtual method 56 : // AllocSession. The session object is owned by the TcpServer and must 57 : // be deallocated via DeleteSession. 58 : virtual TcpSession *CreateSession(); 59 : 60 : // Delete a session object. 61 : virtual void DeleteSession(TcpSession *session); 62 : 63 : virtual void Connect(TcpSession *session, Endpoint remote); 64 : 65 101171 : virtual bool DisableSandeshLogMessages() const { return false; } 66 : 67 : int GetPort() const; 68 : const io::SocketStats &GetSocketStats() const { return stats_; } 69 : 70 : // 71 : // Return the number of tcp sessions in the map 72 : // 73 4 : size_t GetSessionCount() const { 74 4 : return session_ref_.size(); 75 : } 76 : 77 394092 : EventManager *event_manager() { return evm_; } 78 : 79 : // Returns true if any of the sessions on this server has read available 80 : // data. 81 : bool HasSessionReadAvailable() const; 82 : bool HasSessions() const; 83 : 84 : TcpSession *GetSession(Endpoint remote); 85 : 86 : // wait until the server has deleted all sessions. 87 : void WaitForEmpty(); 88 : 89 : void GetRxSocketStats(SocketIOStats *socket_stats) const; 90 : void GetTxSocketStats(SocketIOStats *socket_stats) const; 91 : 92 659 : void GetRxSocketStats(SocketIOStats &socket_stats) const { 93 659 : GetRxSocketStats(&socket_stats); 94 659 : } 95 : 96 659 : void GetTxSocketStats(SocketIOStats &socket_stats) const { 97 659 : GetTxSocketStats(&socket_stats); 98 659 : } 99 : 100 : int SetMd5SocketOption(NativeSocketType fd, uint32_t peer_ip, 101 : const std::string &md5_password); 102 : int SetListenSocketMd5Option(uint32_t peer_ip, 103 : const std::string &md5_password); 104 : int SetDscpSocketOption(NativeSocketType fd, uint8_t value); 105 : uint8_t GetDscpValue(NativeSocketType fd) const; 106 : int SetListenSocketDscp(uint8_t value); 107 : int SetSocketOptions(const SandeshConfig &sandesh_config); 108 : int SetKeepAliveSocketOption(int fd, const SandeshConfig &sandesh_config); 109 : 110 : protected: 111 : typedef boost::intrusive_ptr<TcpServer> TcpServerPtr; 112 : typedef boost::intrusive_ptr<TcpSession> TcpSessionPtr; 113 : 114 : // Create a session object. 115 : virtual TcpSession *AllocSession(Socket *socket) = 0; 116 : 117 : // Only SslServer overrides this method, to manage server with SSL 118 : // socket instead of TCP socket 119 : virtual TcpSession *AllocSession(bool server_session); 120 : 121 : virtual Socket *accept_socket() const; 122 : virtual void set_accept_socket(); 123 : 124 : // 125 : // Passively accepted a new session. Returns true if the session is 126 : // accepted, false otherwise. 127 : // 128 : // If the session is not accepted, tcp_server.cc deletes the newly 129 : // created session. 130 : // 131 : virtual bool AcceptSession(TcpSession *session); 132 : 133 : // For testing - will typically be used by derived class. 134 8 : void set_socket_open_failure(bool flag) { socket_open_failure_ = flag; } 135 6907 : bool socket_open_failure() const { return socket_open_failure_; } 136 : 137 : Endpoint LocalEndpoint() const; 138 : 139 : virtual void AcceptHandlerComplete(TcpSessionPtr session); 140 : virtual void ConnectHandlerComplete(TcpSessionPtr session); 141 : 142 : private: 143 : friend class TcpSession; 144 : friend class SslSession; 145 : friend class TcpMessageWriter; 146 : friend class BgpServerUnitTest; 147 : friend void intrusive_ptr_add_ref(TcpServer *server); 148 : friend void intrusive_ptr_release(TcpServer *server); 149 : 150 : struct TcpSessionPtrCmp { 151 110928 : bool operator()(const TcpSessionPtr &lhs, 152 : const TcpSessionPtr &rhs) const { 153 110928 : return lhs.get() < rhs.get(); 154 : } 155 : }; 156 : typedef std::set<TcpSessionPtr, TcpSessionPtrCmp> SessionSet; 157 : typedef std::multimap<Endpoint, TcpSession *> SessionMap; 158 : 159 : void InsertSessionToMap(Endpoint remote, TcpSession *session); 160 : bool RemoveSessionFromMap(Endpoint remote, TcpSession *session); 161 : 162 : // Called by the asio service. 163 : void AcceptHandlerInternal(TcpServerPtr server, 164 : const boost::system::error_code &error); 165 : 166 : void ConnectHandler(TcpServerPtr server, TcpSessionPtr session, 167 : const boost::system::error_code &error); 168 : 169 : // Trigger the async accept operation. 170 : void AsyncAccept(); 171 : 172 : void OnSessionClose(TcpSession *session); 173 : void SetName(Endpoint local_endpoint); 174 : 175 : io::SocketStats stats_; 176 : EventManager *evm_; 177 : // mutex protects the session maps 178 : mutable std::mutex mutex_; 179 : std::condition_variable cond_var_; 180 : SessionSet session_ref_; 181 : SessionMap session_map_; 182 : std::unique_ptr<Socket> so_accept_; // socket used in async_accept 183 : boost::scoped_ptr<boost::asio::ip::tcp::acceptor> acceptor_; 184 : std::atomic<int> refcount_; 185 : std::string name_; 186 : bool socket_open_failure_; 187 : int intf_id_; 188 : 189 : DISALLOW_COPY_AND_ASSIGN(TcpServer); 190 : }; 191 : 192 : typedef boost::intrusive_ptr<TcpServer> TcpServerPtr; 193 : 194 369268 : inline void intrusive_ptr_add_ref(TcpServer *server) { 195 369268 : server->refcount_.fetch_add(1); 196 369268 : } 197 : 198 369267 : inline void intrusive_ptr_release(TcpServer *server) { 199 369267 : int prev = server->refcount_.fetch_sub(1); 200 369267 : if (prev == 1) { 201 17562 : delete server; 202 : } 203 369267 : } 204 : 205 : class TcpServerManager { 206 : public: 207 : static void AddServer(TcpServer *server); 208 : static void DeleteServer(TcpServer *server); 209 : static size_t GetServerCount(); 210 : 211 : private: 212 : static ServerManager<TcpServer, TcpServerPtr> impl_; 213 : }; 214 : 215 : #endif // SRC_IO_TCP_SERVER_H_