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