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
24namespace 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