Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
WorldSocketMgr.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
10
11#include "WorldSocketMgr.h"
12
13#include <atomic>
14#include <memory>
15#include <set>
16
17#include "Common.h"
18#include "Config.h"
19#include "DatabaseEnv.h"
20#include "Log.h"
21#include "ScriptMgr.h"
23#include "WorldSocket.h"
24#include "WorldSocketAcceptor.h"
25#include <boost/asio/socket_base.hpp>
26#include <boost/system/error_code.hpp>
27#include <vector>
28
35{
36public:
40 m_Stopped(false)
41 {
42 }
43
45 {
46 Stop();
47 Wait();
48 }
49
50 void Stop()
51 {
52 if (m_Stopped.exchange(true))
53 return;
54
55 std::vector<WorldSocket*> sockets;
56
57 {
58 std::lock_guard<std::mutex> guard(m_SocketsLock);
59 sockets.assign(m_Sockets.begin(), m_Sockets.end());
60 }
61
62 for (WorldSocket* socket : sockets)
63 socket->CloseSocket();
64
65 m_ThreadGroup.Drain();
66 }
67
68 int Start()
69 {
70 return m_ThreadGroup.Start(1,
71 []
72 {
73 SF_LOG_DEBUG("misc", "Network Thread Starting");
74 },
75 []
76 {
77 SF_LOG_DEBUG("misc", "Network Thread exits");
78 });
79 }
80
81 void Wait()
82 {
83 m_ThreadGroup.Join();
84 }
85
87 {
88 return m_Connections.load();
89 }
90
91 boost::asio::io_context& GetIoContext()
92 {
93 return m_ThreadGroup.GetIoContext();
94 }
95
97 {
98 {
99 std::lock_guard<std::mutex> guard(m_SocketsLock);
100
101 if (m_Stopped)
102 return -1;
103
105 sock->AddReference();
106 m_Sockets.insert(sock);
107 }
108
109 sScriptMgr->OnSocketOpen(sock);
110
111 sock->AddReference();
112 sock->Start([this](WorldSocket* socket)
113 {
114 SocketClosed(socket);
115 });
116 sock->RemoveReference();
117
118 return 0;
119 }
120
122 {
123 bool owned = false;
124
125 {
126 std::lock_guard<std::mutex> guard(m_SocketsLock);
127 SocketSet::iterator itr = m_Sockets.find(sock);
128 if (itr != m_Sockets.end())
129 {
130 m_Sockets.erase(itr);
132 owned = true;
133 }
134 }
135
136 if (!owned)
137 return;
138
139 sScriptMgr->OnSocketClose(sock, false);
140 sock->RemoveReference();
141 }
142
143private:
144 typedef std::atomic<long> AtomicInt;
145 typedef std::set<WorldSocket*> SocketSet;
146
149 std::atomic<bool> m_Stopped;
150
152 std::mutex m_SocketsLock;
153};
154
162
164{
165 delete[] m_NetThreads;
166 delete m_Acceptor;
167}
168
169int
170WorldSocketMgr::StartReactiveIO(uint16 port, const char* address)
171{
172 m_UseNoDelay = sConfigMgr->GetBoolDefault("Network.TcpNodelay", true);
173
174 int num_threads = sConfigMgr->GetIntDefault("Network.Threads", 1);
175
176 if (num_threads <= 0)
177 {
178 SF_LOG_ERROR("misc", "Network.Threads is wrong in your config file");
179 return -1;
180 }
181
182 m_NetThreadsCount = static_cast<size_t> (num_threads);
183
185
186 // -1 means use default
187 m_SockOutKBuff = sConfigMgr->GetIntDefault("Network.OutKBuff", -1);
188
189 m_SockOutUBuff = sConfigMgr->GetIntDefault("Network.OutUBuff", 65536);
190
191 if (m_SockOutUBuff <= 0)
192 {
193 SF_LOG_ERROR("misc", "Network.OutUBuff is wrong in your config file");
194 return -1;
195 }
196
197 for (size_t i = 0; i < m_NetThreadsCount; ++i)
198 {
199 if (m_NetThreads[i].Start() == -1)
200 {
201 SF_LOG_ERROR("misc", "Failed to start network thread");
202
203 for (size_t j = 0; j < i; ++j)
204 m_NetThreads[j].Stop();
205
206 for (size_t j = 0; j < i; ++j)
207 m_NetThreads[j].Wait();
208
209 return -1;
210 }
211 }
212
214
215 if (!m_Acceptor->Open(port, address))
216 {
217 SF_LOG_ERROR("misc", "Failed to open acceptor, check if the port is free");
218
219 for (size_t i = 0; i < m_NetThreadsCount; ++i)
220 m_NetThreads[i].Stop();
221
222 for (size_t i = 0; i < m_NetThreadsCount; ++i)
223 m_NetThreads[i].Wait();
224
225 return -1;
226 }
227
228 return 0;
229}
230
231int
232WorldSocketMgr::StartNetwork(uint16 port, const char* address)
233{
234 if (StartReactiveIO(port, address) == -1)
235 return -1;
236
237 sScriptMgr->OnNetworkStart();
238
239 return 0;
240}
241
242void
244{
245 if (m_Acceptor)
246 {
247 m_Acceptor->Close();
248 }
249
250 if (m_NetThreadsCount != 0)
251 {
252 for (size_t i = 0; i < m_NetThreadsCount; ++i)
253 m_NetThreads[i].Stop();
254 }
255
256 Wait();
257
258 sScriptMgr->OnNetworkStop();
259}
260
261void
263{
264 if (m_NetThreadsCount != 0)
265 {
266 for (size_t i = 0; i < m_NetThreadsCount; ++i)
267 m_NetThreads[i].Wait();
268 }
269}
270
271int
273{
274 // set some options here
275 if (m_SockOutKBuff >= 0)
276 {
277 boost::system::error_code error;
278 sock->m_Socket->set_option(boost::asio::socket_base::send_buffer_size(m_SockOutKBuff), error);
279 if (error)
280 {
281 SF_LOG_ERROR("misc", "WorldSocketMgr::OnSocketOpen set_option SO_SNDBUF error = %d", error.value());
282 return -1;
283 }
284 }
285
286 // Set TCP_NODELAY.
287 if (m_UseNoDelay)
288 {
289 boost::system::error_code error;
290 sock->m_Socket->set_option(boost::asio::ip::tcp::no_delay(true), error);
291 if (error)
292 {
293 SF_LOG_ERROR("misc", "WorldSocketMgr::OnSocketOpen: set_option TCP_NODELAY error = %d", error.value());
294 return -1;
295 }
296 }
297
298 sock->m_OutBufferSize = static_cast<size_t> (m_SockOutUBuff);
299
300 if (sock->Initialize() == -1)
301 return -1;
302
303 return reactor->AddSocket(sock);
304}
305
308{
310
311 size_t min = 0;
312
313 for (size_t i = 1; i < m_NetThreadsCount; ++i)
314 if (m_NetThreads[i].Connections() < m_NetThreads[min].Connections())
315 min = i;
316
317 return &m_NetThreads[min];
318}
319
320boost::asio::io_context&
322{
323 return reactor->GetIoContext();
324}
#define sConfigMgr
Definition Config.h:64
std::uint16_t uint16
Definition Define.h:78
#define ASSERT
Definition Errors.h:29
#define SF_LOG_DEBUG(filterType__,...)
Definition Log.h:134
#define SF_LOG_ERROR(filterType__,...)
Definition Log.h:143
#define sScriptMgr
Definition ScriptMgr.h:764
virtual ~ReactorRunnable()
boost::asio::io_context & GetIoContext()
int AddSocket(WorldSocket *sock)
Skyfire::Asio::IoContextThreadGroup m_ThreadGroup
void SocketClosed(WorldSocket *sock)
std::set< WorldSocket * > SocketSet
std::atomic< bool > m_Stopped
std::mutex m_SocketsLock
std::atomic< long > AtomicInt
Handler that can communicate over stream sockets.
Definition WorldSocket.h:51
size_t m_OutBufferSize
Configured output buffer size retained for network option compatibility.
long RemoveReference(void)
Remove reference to this object.
std::unique_ptr< WorldSocketHandle > m_Socket
long AddReference(void)
Add reference to this object.
void Start(std::function< void(WorldSocket *)> closeHandler)
Starts asynchronous socket processing.
int Initialize(void)
Called after socket accept and manager setup.
friend class WorldSocketAcceptor
friend class WorldSocket
int StartNetwork(uint16 port, const char *address)
Start network, listen at address:port .
boost::asio::io_context & GetNetworkIoContext(ReactorRunnable *reactor)
size_t m_NetThreadsCount
int StartReactiveIO(uint16 port, const char *address)
ReactorRunnable * SelectNetworkThread()
int OnSocketOpen(WorldSocket *sock, ReactorRunnable *reactor)
void Wait()
Wait untill all network threads have "joined" .
virtual ~WorldSocketMgr()
ReactorRunnable * m_NetThreads
class WorldSocketAcceptor * m_Acceptor
void StopNetwork()
Stops all network threads, It will wait for all running threads .