PageRenderTime 40ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/src/game/WorldSocketMgr.cpp

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