Cuberite
A lightweight, fast and extensible game server for Minecraft
NetworkSingleton.cpp
Go to the documentation of this file.
1 
2 // NetworkSingleton.cpp
3 
4 // Implements the cNetworkSingleton class representing the storage for global data pertaining to network API
5 // such as a list of all connections, all listening sockets and the LibEvent dispatch thread.
6 
7 #include "Globals.h"
8 #include "NetworkSingleton.h"
9 #include "Network.h"
10 #include <event2/thread.h>
11 #include <event2/bufferevent.h>
12 #include <event2/listener.h>
13 
14 
15 
16 
17 
19  m_HasTerminated(true)
20 {
21 }
22 
23 
24 
25 
26 
28 {
29  // Check that Terminate has been called already:
31 }
32 
33 
34 
35 
36 
38 {
39  static cNetworkSingleton Instance;
40  return Instance;
41 }
42 
43 
44 
45 
46 
48 {
49  // Start the lookup thread
51 
52  // Windows: initialize networking:
53  #ifdef _WIN32
54  WSADATA wsaData;
55  memset(&wsaData, 0, sizeof(wsaData));
56  int res = WSAStartup (MAKEWORD(2, 2), &wsaData);
57  if (res != 0)
58  {
59  int err = WSAGetLastError();
60  LOGWARNING("WSAStartup failed: %d, WSAGLE = %d (%s)", res, err, evutil_socket_error_to_string(err));
61  exit(1);
62  }
63  #endif // _WIN32
64 
65  // Initialize LibEvent logging:
66  event_set_log_callback(LogCallback);
67 
68  // Initialize threading:
69  #if defined(EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED)
70  evthread_use_windows_threads();
71  #elif defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED)
72  evthread_use_pthreads();
73  #else
74  #error No threading implemented for EVTHREAD
75  #endif
76 
77  // Create the main event_base:
78  event_config * config = event_config_new();
79  event_config_set_flag(config, EVENT_BASE_FLAG_STARTUP_IOCP);
80  m_EventBase = event_base_new_with_config(config);
81  if (m_EventBase == nullptr)
82  {
83  LOGERROR("Failed to initialize LibEvent. The server will now terminate.");
84  abort();
85  }
86  event_config_free(config);
87 
88  // Create the event loop thread:
89  m_HasTerminated = false;
90  m_EventLoopThread = std::thread(RunEventLoop, this);
91  m_StartupEvent.Wait(); // Wait for the LibEvent loop to actually start running (otherwise calling Terminate too soon would hang, see #3228)
92 }
93 
94 
95 
96 
97 
99 {
101 
102  // Wait for the lookup thread to stop
104 
105  // Wait for the LibEvent event loop to terminate:
106  event_base_loopbreak(m_EventBase);
107  m_EventLoopThread.join();
108 
109  // Close all open connections:
110  {
111  cCSLock Lock(m_CS);
112  // Must take copies because Close will modify lists
113  auto Conns = m_Connections;
114  for (auto & Conn : Conns)
115  {
116  Conn->Close();
117  }
118 
119  auto Servers = m_Servers;
120  for (auto & Server : Servers)
121  {
122  Server->Close();
123  }
124 
125  // Closed handles should have removed themself
126  ASSERT(m_Connections.empty());
127  ASSERT(m_Servers.empty());
128  }
129 
130  // Free the underlying LibEvent objects:
131  event_base_free(m_EventBase);
132 
133  libevent_global_shutdown();
134 
135  // Set the HasTerminated flag:
136  // (Only set the flag after everything has been removed, to avoid the random failures in the Google-test, caused by links terminating after this flag was set)
137  m_HasTerminated = true;
138 }
139 
140 
141 
142 
143 
144 void cNetworkSingleton::LogCallback(int a_Severity, const char * a_Msg)
145 {
146  switch (a_Severity)
147  {
148  case _EVENT_LOG_DEBUG: LOGD ("LibEvent: %s", a_Msg); break;
149  case _EVENT_LOG_MSG: LOG ("LibEvent: %s", a_Msg); break;
150  case _EVENT_LOG_WARN: LOGWARNING("LibEvent: %s", a_Msg); break;
151  case _EVENT_LOG_ERR: LOGERROR ("LibEvent: %s", a_Msg); break;
152  default:
153  {
154  LOGWARNING("LibEvent: Unknown log severity (%d): %s", a_Severity, a_Msg);
155  break;
156  }
157  }
158 }
159 
160 
161 
162 
163 
165 {
166  auto timer = evtimer_new(a_Self->m_EventBase, SignalizeStartup, a_Self);
167  timeval timeout{}; // Zero timeout - execute immediately
168  evtimer_add(timer, &timeout);
169  event_base_loop(a_Self->m_EventBase, EVLOOP_NO_EXIT_ON_EMPTY);
170  event_free(timer);
171 }
172 
173 
174 
175 
176 
177 void cNetworkSingleton::SignalizeStartup(evutil_socket_t a_Socket, short a_Events, void * a_Self)
178 {
179  auto self = static_cast<cNetworkSingleton *>(a_Self);
180  ASSERT(self != nullptr);
181  self->m_StartupEvent.Set();
182 }
183 
184 
185 
186 
187 
189 {
191  cCSLock Lock(m_CS);
192  m_Connections.push_back(a_Link);
193 }
194 
195 
196 
197 
198 
200 {
202  cCSLock Lock(m_CS);
203  for (auto itr = m_Connections.begin(), end = m_Connections.end(); itr != end; ++itr)
204  {
205  if (itr->get() == a_Link)
206  {
207  m_Connections.erase(itr);
208  return;
209  }
210  } // for itr - m_Connections[]
211 }
212 
213 
214 
215 
216 
218 {
220  cCSLock Lock(m_CS);
221  m_Servers.push_back(a_Server);
222 }
223 
224 
225 
226 
227 
229 {
231  cCSLock Lock(m_CS);
232  for (auto itr = m_Servers.begin(), end = m_Servers.end(); itr != end; ++itr)
233  {
234  if (itr->get() == a_Server)
235  {
236  m_Servers.erase(itr);
237  return;
238  }
239  } // for itr - m_Servers[]
240 }
241 
242 
243 
244 
#define ASSERT(x)
Definition: Globals.h:276
void LOGERROR(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:73
void LOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:67
void LOG(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:55
#define LOGD
Definition: LoggerSimple.h:83
std::shared_ptr< cTCPLink > cTCPLinkPtr
Definition: Network.h:25
std::shared_ptr< cServerHandle > cServerHandlePtr
Definition: Network.h:28
RAII for cCriticalSection - locks the CS on creation, unlocks on destruction.
void Wait(void)
Waits until the event has been set.
Definition: Event.cpp:23
void Start(void)
Starts the thread; returns without waiting for the actual start.
Definition: IsThread.cpp:35
Interface that provides the methods available on a single TCP connection.
Definition: Network.h:42
Interface that provides the methods available on a listening server socket.
Definition: Network.h:155
void Stop()
Cancels any scheduled lookups and joins the lookup thread.
std::atomic< bool > m_HasTerminated
Set to true if Terminate has been called.
void Terminate(void)
Terminates all network-related threads.
static void SignalizeStartup(evutil_socket_t a_Socket, short a_Events, void *a_Self)
Callback called by LibEvent when the event loop is started.
std::thread m_EventLoopThread
The thread in which the main LibEvent loop runs.
static cNetworkSingleton & Get(void)
Returns the singleton instance of this class.
void Initialise(void)
Initialises all network-related threads.
event_base * m_EventBase
The main LibEvent container for driving the event loop.
cServerHandlePtrs m_Servers
Container for all servers that are currently active.
void AddLink(const cTCPLinkPtr &a_Link)
Adds the specified link to m_Connections.
cEvent m_StartupEvent
Event that is signalled once the startup is finished and the LibEvent loop is running.
void AddServer(const cServerHandlePtr &a_Server)
Adds the specified link to m_Servers.
cCriticalSection m_CS
Mutex protecting all containers against multithreaded access.
static void RunEventLoop(cNetworkSingleton *a_Self)
Implements the thread that runs LibEvent's event dispatcher loop.
void RemoveLink(const cTCPLink *a_Link)
Removes the specified link from m_Connections.
cNetworkLookup m_LookupThread
The thread on which hostname and ip address lookup is performed.
void RemoveServer(const cServerHandle *a_Server)
Removes the specified server from m_Servers.
static void LogCallback(int a_Severity, const char *a_Msg)
Converts LibEvent-generated log events into log messages in MCS log.
~cNetworkSingleton() noexcept(false)
cTCPLinkPtrs m_Connections
Container for all client connections, including ones with pending-connect.