1 | /* |
2 | * IXSocketServer.h |
3 | * Author: Benjamin Sergeant |
4 | * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. |
5 | */ |
6 | |
7 | #pragma once |
8 | |
9 | #include "IXConnectionState.h" |
10 | #include "IXNetSystem.h" |
11 | #include "IXSelectInterrupt.h" |
12 | #include "IXSocketTLSOptions.h" |
13 | #include <atomic> |
14 | #include <condition_variable> |
15 | #include <functional> |
16 | #include <list> |
17 | #include <memory> |
18 | #include <mutex> |
19 | #include <set> |
20 | #include <string> |
21 | #include <thread> |
22 | #include <utility> // pair |
23 | |
24 | namespace ix |
25 | { |
26 | class Socket; |
27 | |
28 | class SocketServer |
29 | { |
30 | public: |
31 | using ConnectionStateFactory = std::function<std::shared_ptr<ConnectionState>()>; |
32 | |
33 | // Each connection is handled by its own worker thread. |
34 | // We use a list as we only care about remove and append operations. |
35 | using ConnectionThreads = |
36 | std::list<std::pair<std::shared_ptr<ConnectionState>, std::thread>>; |
37 | |
38 | SocketServer(int port = SocketServer::kDefaultPort, |
39 | const std::string& host = SocketServer::kDefaultHost, |
40 | int backlog = SocketServer::kDefaultTcpBacklog, |
41 | size_t maxConnections = SocketServer::kDefaultMaxConnections, |
42 | int addressFamily = SocketServer::kDefaultAddressFamily); |
43 | virtual ~SocketServer(); |
44 | virtual void stop(); |
45 | |
46 | // It is possible to override ConnectionState through inheritance |
47 | // this method allows user to change the factory by returning an object |
48 | // that inherits from ConnectionState but has its own methods. |
49 | void setConnectionStateFactory(const ConnectionStateFactory& connectionStateFactory); |
50 | |
51 | const static int kDefaultPort; |
52 | const static std::string kDefaultHost; |
53 | const static int kDefaultTcpBacklog; |
54 | const static size_t kDefaultMaxConnections; |
55 | const static int kDefaultAddressFamily; |
56 | |
57 | void start(); |
58 | std::pair<bool, std::string> listen(); |
59 | void wait(); |
60 | |
61 | void setTLSOptions(const SocketTLSOptions& socketTLSOptions); |
62 | |
63 | int getPort(); |
64 | std::string getHost(); |
65 | int getBacklog(); |
66 | std::size_t getMaxConnections(); |
67 | int getAddressFamily(); |
68 | protected: |
69 | // Logging |
70 | void logError(const std::string& str); |
71 | void logInfo(const std::string& str); |
72 | |
73 | void stopAcceptingConnections(); |
74 | |
75 | private: |
76 | // Member variables |
77 | int _port; |
78 | std::string _host; |
79 | int _backlog; |
80 | size_t _maxConnections; |
81 | int _addressFamily; |
82 | |
83 | // socket for accepting connections |
84 | socket_t _serverFd; |
85 | |
86 | std::atomic<bool> _stop; |
87 | |
88 | std::mutex _logMutex; |
89 | |
90 | // background thread to wait for incoming connections |
91 | std::thread _thread; |
92 | void run(); |
93 | void onSetTerminatedCallback(); |
94 | |
95 | // background thread to cleanup (join) terminated threads |
96 | std::atomic<bool> _stopGc; |
97 | std::thread _gcThread; |
98 | void runGC(); |
99 | |
100 | // the list of (connectionState, threads) for each connections |
101 | ConnectionThreads _connectionsThreads; |
102 | std::mutex _connectionsThreadsMutex; |
103 | |
104 | // used to have the main control thread for a server |
105 | // wait for a 'terminate' notification without busy polling |
106 | std::condition_variable _conditionVariable; |
107 | std::mutex _conditionVariableMutex; |
108 | |
109 | // the factory to create ConnectionState objects |
110 | ConnectionStateFactory _connectionStateFactory; |
111 | |
112 | virtual void handleConnection(std::unique_ptr<Socket>, |
113 | std::shared_ptr<ConnectionState> connectionState) = 0; |
114 | virtual size_t getConnectedClientsCount() = 0; |
115 | |
116 | // Returns true if all connection threads are joined |
117 | void closeTerminatedThreads(); |
118 | size_t getConnectionsThreadsCount(); |
119 | |
120 | SocketTLSOptions _socketTLSOptions; |
121 | |
122 | // to wake up from select |
123 | SelectInterruptPtr _acceptSelectInterrupt; |
124 | |
125 | // used by the gc thread, to know that a thread needs to be garbage collected |
126 | // as a connection |
127 | std::condition_variable _conditionVariableGC; |
128 | std::mutex _conditionVariableMutexGC; |
129 | }; |
130 | } // namespace ix |
131 | |