PageRenderTime 71ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/src/server/game/Server/WorldSocketMgr.cpp

http://github.com/A-Metaphysical-Drama/BloodyCore
C++ | 365 lines | 250 code | 83 blank | 32 comment | 40 complexity | 9e0bb484b7aeb10f9846cc5da094adcb MD5 | raw file
Possible License(s): GPL-2.0, CC-BY-SA-3.0, BSD-3-Clause
  1. /*
  2. * Copyright (C) 2008-2011 TrinityCore <http://www.trinitycore.org/>
  3. * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the
  7. * Free Software Foundation; either version 2 of the License, or (at your
  8. * option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful, but WITHOUT
  11. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13. * more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /** \file WorldSocketMgr.cpp
  19. * \ingroup u2w
  20. * \author Derex <derex101@gmail.com>
  21. */
  22. #include "WorldSocketMgr.h"
  23. #include <ace/ACE.h>
  24. #include <ace/Log_Msg.h>
  25. #include <ace/Reactor.h>
  26. #include <ace/Reactor_Impl.h>
  27. #include <ace/TP_Reactor.h>
  28. #include <ace/Dev_Poll_Reactor.h>
  29. #include <ace/Guard_T.h>
  30. #include <ace/Atomic_Op.h>
  31. #include <ace/os_include/arpa/os_inet.h>
  32. #include <ace/os_include/netinet/os_tcp.h>
  33. #include <ace/os_include/sys/os_types.h>
  34. #include <ace/os_include/sys/os_socket.h>
  35. #include <set>
  36. #include "Log.h"
  37. #include "Common.h"
  38. #include "Config.h"
  39. #include "DatabaseEnv.h"
  40. #include "WorldSocket.h"
  41. #include "ScriptMgr.h"
  42. /**
  43. * This is a helper class to WorldSocketMgr ,that manages
  44. * network threads, and assigning connections from acceptor thread
  45. * to other network threads
  46. */
  47. class ReactorRunnable : protected ACE_Task_Base
  48. {
  49. public:
  50. ReactorRunnable() :
  51. m_Reactor(0),
  52. m_Connections(0),
  53. m_ThreadId(-1)
  54. {
  55. ACE_Reactor_Impl* imp = 0;
  56. #if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL)
  57. imp = new ACE_Dev_Poll_Reactor();
  58. imp->max_notify_iterations (128);
  59. imp->restart (1);
  60. #else
  61. imp = new ACE_TP_Reactor();
  62. imp->max_notify_iterations (128);
  63. #endif
  64. m_Reactor = new ACE_Reactor (imp, 1);
  65. }
  66. virtual ~ReactorRunnable()
  67. {
  68. Stop();
  69. Wait();
  70. delete m_Reactor;
  71. }
  72. void Stop()
  73. {
  74. m_Reactor->end_reactor_event_loop();
  75. }
  76. int Start()
  77. {
  78. if (m_ThreadId != -1)
  79. return -1;
  80. return (m_ThreadId = activate());
  81. }
  82. void Wait() { ACE_Task_Base::wait(); }
  83. long Connections()
  84. {
  85. return static_cast<long> (m_Connections.value());
  86. }
  87. int AddSocket (WorldSocket* sock)
  88. {
  89. ACE_GUARD_RETURN (ACE_Thread_Mutex, Guard, m_NewSockets_Lock, -1);
  90. ++m_Connections;
  91. sock->AddReference();
  92. sock->reactor (m_Reactor);
  93. m_NewSockets.insert (sock);
  94. sScriptMgr->OnSocketOpen(sock);
  95. return 0;
  96. }
  97. ACE_Reactor* GetReactor()
  98. {
  99. return m_Reactor;
  100. }
  101. protected:
  102. void AddNewSockets()
  103. {
  104. ACE_GUARD (ACE_Thread_Mutex, Guard, m_NewSockets_Lock);
  105. if (m_NewSockets.empty())
  106. return;
  107. for (SocketSet::const_iterator i = m_NewSockets.begin(); i != m_NewSockets.end(); ++i)
  108. {
  109. WorldSocket* sock = (*i);
  110. if (sock->IsClosed())
  111. {
  112. sScriptMgr->OnSocketClose(sock, true);
  113. sock->RemoveReference();
  114. --m_Connections;
  115. }
  116. else
  117. m_Sockets.insert (sock);
  118. }
  119. m_NewSockets.clear();
  120. }
  121. virtual int svc()
  122. {
  123. sLog->outStaticDebug ("Network Thread Starting");
  124. ACE_ASSERT (m_Reactor);
  125. SocketSet::iterator i, t;
  126. while (!m_Reactor->reactor_event_loop_done())
  127. {
  128. // dont be too smart to move this outside the loop
  129. // the run_reactor_event_loop will modify interval
  130. ACE_Time_Value interval (0, 10000);
  131. if (m_Reactor->run_reactor_event_loop (interval) == -1)
  132. break;
  133. AddNewSockets();
  134. for (i = m_Sockets.begin(); i != m_Sockets.end();)
  135. {
  136. if ((*i)->Update() == -1)
  137. {
  138. t = i;
  139. ++i;
  140. (*t)->CloseSocket();
  141. sScriptMgr->OnSocketClose((*t), false);
  142. (*t)->RemoveReference();
  143. --m_Connections;
  144. m_Sockets.erase (t);
  145. }
  146. else
  147. ++i;
  148. }
  149. }
  150. sLog->outStaticDebug ("Network Thread Exitting");
  151. return 0;
  152. }
  153. private:
  154. typedef ACE_Atomic_Op<ACE_SYNCH_MUTEX, long> AtomicInt;
  155. typedef std::set<WorldSocket*> SocketSet;
  156. ACE_Reactor* m_Reactor;
  157. AtomicInt m_Connections;
  158. int m_ThreadId;
  159. SocketSet m_Sockets;
  160. SocketSet m_NewSockets;
  161. ACE_Thread_Mutex m_NewSockets_Lock;
  162. };
  163. WorldSocketMgr::WorldSocketMgr() :
  164. m_NetThreads(0),
  165. m_NetThreadsCount(0),
  166. m_SockOutKBuff(-1),
  167. m_SockOutUBuff(65536),
  168. m_UseNoDelay(true),
  169. m_Acceptor (0)
  170. {
  171. }
  172. WorldSocketMgr::~WorldSocketMgr()
  173. {
  174. delete [] m_NetThreads;
  175. delete m_Acceptor;
  176. }
  177. int
  178. WorldSocketMgr::StartReactiveIO (ACE_UINT16 port, const char* address)
  179. {
  180. m_UseNoDelay = sConfig->GetBoolDefault ("Network.TcpNodelay", true);
  181. int num_threads = sConfig->GetIntDefault ("Network.Threads", 1);
  182. if (num_threads <= 0)
  183. {
  184. sLog->outError ("Network.Threads is wrong in your config file");
  185. return -1;
  186. }
  187. m_NetThreadsCount = static_cast<size_t> (num_threads + 1);
  188. m_NetThreads = new ReactorRunnable[m_NetThreadsCount];
  189. sLog->outBasic ("Max allowed socket connections %d", ACE::max_handles());
  190. // -1 means use default
  191. m_SockOutKBuff = sConfig->GetIntDefault ("Network.OutKBuff", -1);
  192. m_SockOutUBuff = sConfig->GetIntDefault ("Network.OutUBuff", 65536);
  193. if (m_SockOutUBuff <= 0)
  194. {
  195. sLog->outError ("Network.OutUBuff is wrong in your config file");
  196. return -1;
  197. }
  198. WorldSocket::Acceptor *acc = new WorldSocket::Acceptor;
  199. m_Acceptor = acc;
  200. ACE_INET_Addr listen_addr (port, address);
  201. if (acc->open(listen_addr, m_NetThreads[0].GetReactor(), ACE_NONBLOCK) == -1)
  202. {
  203. sLog->outError ("Failed to open acceptor ,check if the port is free");
  204. return -1;
  205. }
  206. for (size_t i = 0; i < m_NetThreadsCount; ++i)
  207. m_NetThreads[i].Start();
  208. return 0;
  209. }
  210. int
  211. WorldSocketMgr::StartNetwork (ACE_UINT16 port, const char* address)
  212. {
  213. if (!sLog->IsOutDebug())
  214. ACE_Log_Msg::instance()->priority_mask (LM_ERROR, ACE_Log_Msg::PROCESS);
  215. if (StartReactiveIO(port, address) == -1)
  216. return -1;
  217. sScriptMgr->OnNetworkStart();
  218. return 0;
  219. }
  220. void
  221. WorldSocketMgr::StopNetwork()
  222. {
  223. if (m_Acceptor)
  224. {
  225. WorldSocket::Acceptor* acc = dynamic_cast<WorldSocket::Acceptor*> (m_Acceptor);
  226. if (acc)
  227. acc->close();
  228. }
  229. if (m_NetThreadsCount != 0)
  230. {
  231. for (size_t i = 0; i < m_NetThreadsCount; ++i)
  232. m_NetThreads[i].Stop();
  233. }
  234. Wait();
  235. sScriptMgr->OnNetworkStop();
  236. }
  237. void
  238. WorldSocketMgr::Wait()
  239. {
  240. if (m_NetThreadsCount != 0)
  241. {
  242. for (size_t i = 0; i < m_NetThreadsCount; ++i)
  243. m_NetThreads[i].Wait();
  244. }
  245. }
  246. int
  247. WorldSocketMgr::OnSocketOpen (WorldSocket* sock)
  248. {
  249. // set some options here
  250. if (m_SockOutKBuff >= 0)
  251. {
  252. if (sock->peer().set_option (SOL_SOCKET,
  253. SO_SNDBUF,
  254. (void*) & m_SockOutKBuff,
  255. sizeof (int)) == -1 && errno != ENOTSUP)
  256. {
  257. sLog->outError ("WorldSocketMgr::OnSocketOpen set_option SO_SNDBUF");
  258. return -1;
  259. }
  260. }
  261. static const int ndoption = 1;
  262. // Set TCP_NODELAY.
  263. if (m_UseNoDelay)
  264. {
  265. if (sock->peer().set_option (ACE_IPPROTO_TCP,
  266. TCP_NODELAY,
  267. (void*)&ndoption,
  268. sizeof (int)) == -1)
  269. {
  270. sLog->outError ("WorldSocketMgr::OnSocketOpen: peer().set_option TCP_NODELAY errno = %s", ACE_OS::strerror (errno));
  271. return -1;
  272. }
  273. }
  274. sock->m_OutBufferSize = static_cast<size_t> (m_SockOutUBuff);
  275. // we skip the Acceptor Thread
  276. size_t min = 1;
  277. ACE_ASSERT (m_NetThreadsCount >= 1);
  278. for (size_t i = 1; i < m_NetThreadsCount; ++i)
  279. if (m_NetThreads[i].Connections() < m_NetThreads[min].Connections())
  280. min = i;
  281. return m_NetThreads[min].AddSocket (sock);
  282. }