2 | | * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> |
3 | | * |
4 | | * Copyright (C) 2008 Trinity <http://www.trinitycore.org/> |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, write to the Free Software |
18 | | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | | */ |
| 2 | * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> |
| 3 | * |
| 4 | * Copyright (C) 2008 Trinity <http://www.trinitycore.org/> |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; either version 2 of the License, or |
| 9 | * (at your option) any later version. |
| 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU General Public License |
| 17 | * along with this program; if not, write to the Free Software |
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 19 | */ |
75 | | m_Reactor = new ACE_Reactor (imp, 1); |
76 | | } |
77 | | |
78 | | virtual |
79 | | ~ReactorRunnable () |
80 | | { |
81 | | this->Stop (); |
82 | | this->Wait (); |
83 | | |
84 | | if (m_Reactor) |
85 | | delete m_Reactor; |
86 | | } |
87 | | |
88 | | void |
89 | | Stop () |
90 | | { |
91 | | m_Reactor->end_reactor_event_loop (); |
92 | | } |
93 | | |
94 | | int |
95 | | Start () |
96 | | { |
97 | | if (m_ThreadId != -1) |
98 | | return -1; |
99 | | |
100 | | return (m_ThreadId = this->activate ()); |
101 | | } |
102 | | |
103 | | void |
104 | | Wait () |
105 | | { |
106 | | ACE_Task_Base::wait (); |
107 | | } |
108 | | |
109 | | long |
110 | | Connections () |
111 | | { |
112 | | return static_cast<long> (m_Connections.value ()); |
113 | | } |
114 | | |
115 | | int |
116 | | AddSocket (WorldSocket* sock) |
117 | | { |
118 | | ACE_GUARD_RETURN (ACE_Thread_Mutex, Guard, m_NewSockets_Lock, -1); |
119 | | |
120 | | ++m_Connections; |
121 | | sock->AddReference(); |
122 | | sock->reactor (m_Reactor); |
123 | | m_NewSockets.insert (sock); |
124 | | |
125 | | return 0; |
126 | | } |
127 | | |
128 | | ACE_Reactor* GetReactor () |
129 | | { |
130 | | return m_Reactor; |
131 | | } |
132 | | |
| 79 | m_Reactor = new ACE_Reactor (imp, 1); |
| 80 | } |
| 81 | |
| 82 | virtual ~ReactorRunnable () |
| 83 | { |
| 84 | this->Stop (); |
| 85 | this->Wait (); |
| 86 | |
| 87 | if (m_Reactor) |
| 88 | delete m_Reactor; |
| 89 | } |
| 90 | |
| 91 | void Stop () |
| 92 | { |
| 93 | m_Reactor->end_reactor_event_loop (); |
| 94 | } |
| 95 | |
| 96 | int Start () |
| 97 | { |
| 98 | if (m_ThreadId != -1) |
| 99 | return -1; |
| 100 | |
| 101 | return (m_ThreadId = this->activate ()); |
| 102 | } |
| 103 | |
| 104 | void Wait () |
| 105 | { |
| 106 | ACE_Task_Base::wait (); |
| 107 | } |
| 108 | |
| 109 | long Connections () |
| 110 | { |
| 111 | return static_cast<long> (m_Connections.value ()); |
| 112 | } |
| 113 | |
| 114 | int AddSocket (WorldSocket* sock) |
| 115 | { |
| 116 | ACE_GUARD_RETURN (ACE_Thread_Mutex, Guard, m_NewSockets_Lock, -1); |
| 117 | |
| 118 | ++m_Connections; |
| 119 | sock->AddReference(); |
| 120 | sock->reactor (m_Reactor); |
| 121 | m_NewSockets.insert (sock); |
| 122 | |
| 123 | return 0; |
| 124 | } |
| 125 | |
| 126 | ACE_Reactor* GetReactor () |
| 127 | { |
| 128 | return m_Reactor; |
| 129 | } |
| 130 | |
134 | | |
135 | | void |
136 | | AddNewSockets () |
137 | | { |
138 | | ACE_GUARD (ACE_Thread_Mutex, Guard, m_NewSockets_Lock); |
139 | | |
140 | | if (m_NewSockets.empty ()) |
141 | | return; |
142 | | |
143 | | for (SocketSet::iterator i = m_NewSockets.begin (); i != m_NewSockets.end (); ++i) |
144 | | { |
145 | | WorldSocket* sock = (*i); |
146 | | |
147 | | if (sock->IsClosed ()) |
148 | | { |
149 | | sock->RemoveReference (); |
150 | | --m_Connections; |
151 | | } |
152 | | else |
153 | | m_Sockets.insert (sock); |
154 | | } |
155 | | |
156 | | m_NewSockets.clear (); |
157 | | } |
158 | | |
159 | | virtual int |
160 | | svc (void) |
161 | | { |
162 | | DEBUG_LOG ("Network Thread Starting"); |
163 | | |
164 | | WorldDatabase.ThreadStart (); |
165 | | |
166 | | ACE_ASSERT (m_Reactor); |
167 | | |
168 | | SocketSet::iterator i, t; |
169 | | |
170 | | while (!m_Reactor->reactor_event_loop_done ()) |
171 | | { |
172 | | // dont be too smart to move this outside the loop |
173 | | // the run_reactor_event_loop will modify interval |
174 | | ACE_Time_Value interval (0, 10000); |
175 | | |
176 | | if (m_Reactor->run_reactor_event_loop (interval) == -1) |
177 | | break; |
178 | | |
179 | | AddNewSockets (); |
180 | | |
181 | | for (i = m_Sockets.begin (); i != m_Sockets.end ();) |
182 | | { |
183 | | if ((*i)->Update () == -1) |
184 | | { |
185 | | t = i; |
186 | | i++; |
187 | | (*t)->CloseSocket (); |
188 | | (*t)->RemoveReference (); |
189 | | --m_Connections; |
190 | | m_Sockets.erase (t); |
191 | | } |
192 | | else |
193 | | i++; |
194 | | } |
195 | | } |
196 | | |
197 | | WorldDatabase.ThreadEnd (); |
198 | | |
199 | | DEBUG_LOG ("Network Thread Exitting"); |
200 | | |
201 | | return 0; |
202 | | } |
| 132 | |
| 133 | void AddNewSockets () |
| 134 | { |
| 135 | ACE_GUARD (ACE_Thread_Mutex, Guard, m_NewSockets_Lock); |
| 136 | |
| 137 | if (m_NewSockets.empty ()) |
| 138 | return; |
| 139 | |
| 140 | for (SocketSet::iterator i = m_NewSockets.begin (); i != m_NewSockets.end (); ++i) |
| 141 | { |
| 142 | WorldSocket* sock = (*i); |
| 143 | |
| 144 | if (sock->IsClosed ()) |
| 145 | { |
| 146 | sock->RemoveReference (); |
| 147 | --m_Connections; |
| 148 | } |
| 149 | else |
| 150 | m_Sockets.insert (sock); |
| 151 | } |
| 152 | |
| 153 | m_NewSockets.clear (); |
| 154 | } |
| 155 | |
| 156 | virtual int svc (void) |
| 157 | { |
| 158 | DEBUG_LOG ("Network Thread Starting"); |
| 159 | |
| 160 | WorldDatabase.ThreadStart (); |
| 161 | |
| 162 | ACE_ASSERT (m_Reactor); |
| 163 | |
| 164 | SocketSet::iterator i, t; |
| 165 | |
| 166 | while (!m_Reactor->reactor_event_loop_done ()) |
| 167 | { |
| 168 | // dont be too smart to move this outside the loop |
| 169 | // the run_reactor_event_loop will modify interval |
| 170 | ACE_Time_Value interval (0, 10000); |
| 171 | |
| 172 | if (m_Reactor->run_reactor_event_loop (interval) == -1) |
| 173 | break; |
| 174 | |
| 175 | AddNewSockets (); |
| 176 | |
| 177 | for (i = m_Sockets.begin (); i != m_Sockets.end ();) |
| 178 | { |
| 179 | if ((*i)->Update () == -1) |
| 180 | { |
| 181 | t = i; |
| 182 | i++; |
| 183 | (*t)->CloseSocket (); |
| 184 | (*t)->RemoveReference (); |
| 185 | --m_Connections; |
| 186 | m_Sockets.erase (t); |
| 187 | } |
| 188 | else |
| 189 | i++; |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | WorldDatabase.ThreadEnd (); |
| 194 | |
| 195 | DEBUG_LOG ("Network Thread Exitting"); |
| 196 | |
| 197 | return 0; |
| 198 | } |
230 | | if (m_NetThreads) |
231 | | delete [] m_NetThreads; |
232 | | |
233 | | if(m_Acceptor) |
234 | | delete m_Acceptor; |
235 | | } |
236 | | |
237 | | int |
238 | | WorldSocketMgr::StartReactiveIO (ACE_UINT16 port, const char* address) |
239 | | { |
240 | | m_UseNoDelay = sConfig.GetBoolDefault ("Network.TcpNodelay", true); |
241 | | |
242 | | int num_threads = sConfig.GetIntDefault ("Network.Threads", 1); |
243 | | |
244 | | if (num_threads <= 0) |
245 | | { |
246 | | sLog.outError ("Network.Threads is wrong in your config file"); |
247 | | return -1; |
248 | | } |
249 | | |
250 | | m_NetThreadsCount = static_cast<size_t> (num_threads + 1); |
251 | | |
252 | | m_NetThreads = new ReactorRunnable[m_NetThreadsCount]; |
253 | | |
254 | | sLog.outBasic ("Max alowed socket connections %d",ACE::max_handles ()); |
255 | | |
256 | | m_SockOutKBuff = sConfig.GetIntDefault ("Network.OutKBuff", -1); // -1 means use default |
257 | | |
258 | | m_SockOutUBuff = sConfig.GetIntDefault ("Network.OutUBuff", 65536); |
259 | | |
260 | | if ( m_SockOutUBuff <= 0 ) |
261 | | { |
262 | | sLog.outError ("Network.OutUBuff is wrong in your config file"); |
263 | | return -1; |
264 | | } |
265 | | |
266 | | WorldSocket::Acceptor *acc = new WorldSocket::Acceptor; |
267 | | m_Acceptor = acc; |
268 | | |
269 | | ACE_INET_Addr listen_addr (port, address); |
270 | | |
271 | | if (acc->open (listen_addr, m_NetThreads[0].GetReactor (), ACE_NONBLOCK) == -1) |
272 | | { |
273 | | sLog.outError ("Failed to open acceptor ,check if the port is free"); |
274 | | return -1; |
275 | | } |
276 | | |
277 | | for (size_t i = 0; i < m_NetThreadsCount; ++i) |
278 | | m_NetThreads[i].Start (); |
279 | | |
280 | | return 0; |
281 | | } |
282 | | |
283 | | int |
284 | | WorldSocketMgr::StartNetwork (ACE_UINT16 port, const char* address) |
285 | | { |
286 | | if (!sLog.IsOutDebug ()) |
287 | | ACE_Log_Msg::instance ()->priority_mask (LM_ERROR, ACE_Log_Msg::PROCESS); |
288 | | |
289 | | if (this->StartReactiveIO (port, address) == -1) |
290 | | return -1; |
291 | | |
292 | | return 0; |
293 | | } |
294 | | |
295 | | void |
296 | | WorldSocketMgr::StopNetwork () |
297 | | { |
298 | | if (m_Acceptor) |
299 | | { |
300 | | WorldSocket::Acceptor* acc = dynamic_cast<WorldSocket::Acceptor*> (m_Acceptor); |
301 | | |
302 | | if (acc) |
303 | | acc->close (); |
304 | | } |
305 | | |
306 | | if (m_NetThreadsCount != 0) |
307 | | { |
308 | | for (size_t i = 0; i < m_NetThreadsCount; ++i) |
309 | | m_NetThreads[i].Stop (); |
310 | | } |
311 | | |
312 | | this->Wait (); |
313 | | } |
314 | | |
315 | | void |
316 | | WorldSocketMgr::Wait () |
317 | | { |
318 | | if (m_NetThreadsCount != 0) |
319 | | { |
320 | | for (size_t i = 0; i < m_NetThreadsCount; ++i) |
321 | | m_NetThreads[i].Wait (); |
322 | | } |
323 | | } |
324 | | |
325 | | int |
326 | | WorldSocketMgr::OnSocketOpen (WorldSocket* sock) |
327 | | { |
328 | | // set some options here |
329 | | if (m_SockOutKBuff >= 0) |
330 | | if (sock->peer ().set_option (SOL_SOCKET, |
331 | | SO_SNDBUF, |
332 | | (void*) & m_SockOutKBuff, |
333 | | sizeof (int)) == -1 && errno != ENOTSUP) |
334 | | { |
335 | | sLog.outError ("WorldSocketMgr::OnSocketOpen set_option SO_SNDBUF"); |
336 | | return -1; |
337 | | } |
338 | | |
339 | | static const int ndoption = 1; |
340 | | |
341 | | // Set TCP_NODELAY. |
342 | | if (m_UseNoDelay) |
343 | | if (sock->peer ().set_option (ACE_IPPROTO_TCP, |
344 | | TCP_NODELAY, |
345 | | (void*) & ndoption, |
346 | | sizeof (int)) == -1) |
347 | | { |
348 | | sLog.outError ("WorldSocketMgr::OnSocketOpen: peer ().set_option TCP_NODELAY errno = %s", ACE_OS::strerror (errno)); |
349 | | return -1; |
350 | | } |
351 | | |
352 | | sock->m_OutBufferSize = static_cast<size_t> (m_SockOutUBuff); |
353 | | |
354 | | // we skip the Acceptor Thread |
355 | | size_t min = 1; |
356 | | |
357 | | ACE_ASSERT (m_NetThreadsCount >= 1); |
358 | | |
359 | | for (size_t i = 1; i < m_NetThreadsCount; ++i) |
360 | | if (m_NetThreads[i].Connections () < m_NetThreads[min].Connections ()) |
361 | | min = i; |
362 | | |
363 | | return m_NetThreads[min].AddSocket (sock); |
364 | | |
365 | | } |
366 | | |
367 | | WorldSocketMgr* |
368 | | WorldSocketMgr::Instance () |
369 | | { |
370 | | return ACE_Singleton<WorldSocketMgr,ACE_Thread_Mutex>::instance(); |
371 | | } |
| 226 | if (m_NetThreads) |
| 227 | delete [] m_NetThreads; |
| 228 | |
| 229 | if(m_Acceptor) |
| 230 | delete m_Acceptor; |
| 231 | } |
| 232 | |
| 233 | int WorldSocketMgr::StartReactiveIO (ACE_UINT16 port, const char* address) |
| 234 | { |
| 235 | m_UseNoDelay = sConfig.GetBoolDefault ("Network.TcpNodelay", true); |
| 236 | |
| 237 | int num_threads = sConfig.GetIntDefault ("Network.Threads", 1); |
| 238 | |
| 239 | if (num_threads <= 0) |
| 240 | { |
| 241 | sLog.outError ("Network.Threads is wrong in your config file"); |
| 242 | return -1; |
| 243 | } |
| 244 | |
| 245 | m_NetThreadsCount = static_cast<size_t> (num_threads + 1); |
| 246 | |
| 247 | m_NetThreads = new ReactorRunnable[m_NetThreadsCount]; |
| 248 | |
| 249 | sLog.outBasic ("Max alowed socket connections %d",ACE::max_handles ()); |
| 250 | |
| 251 | m_SockOutKBuff = sConfig.GetIntDefault ("Network.OutKBuff", -1); // -1 means use default |
| 252 | |
| 253 | m_SockOutUBuff = sConfig.GetIntDefault ("Network.OutUBuff", 65536); |
| 254 | |
| 255 | if ( m_SockOutUBuff <= 0 ) |
| 256 | { |
| 257 | sLog.outError ("Network.OutUBuff is wrong in your config file"); |
| 258 | return -1; |
| 259 | } |
| 260 | |
| 261 | WorldSocket::Acceptor *acc = new WorldSocket::Acceptor; |
| 262 | m_Acceptor = acc; |
| 263 | |
| 264 | ACE_INET_Addr listen_addr (port, address); |
| 265 | |
| 266 | if (acc->open (listen_addr, m_NetThreads[0].GetReactor (), ACE_NONBLOCK) == -1) |
| 267 | { |
| 268 | sLog.outError ("Failed to open acceptor ,check if the port is free"); |
| 269 | return -1; |
| 270 | } |
| 271 | |
| 272 | for (size_t i = 0; i < m_NetThreadsCount; ++i) |
| 273 | m_NetThreads[i].Start (); |
| 274 | |
| 275 | return 0; |
| 276 | } |
| 277 | |
| 278 | int WorldSocketMgr::StartNetwork (ACE_UINT16 port, const char* address) |
| 279 | { |
| 280 | if (!sLog.IsOutDebug ()) |
| 281 | ACE_Log_Msg::instance ()->priority_mask (LM_ERROR, ACE_Log_Msg::PROCESS); |
| 282 | |
| 283 | if (this->StartReactiveIO (port, address) == -1) |
| 284 | return -1; |
| 285 | |
| 286 | return 0; |
| 287 | } |
| 288 | |
| 289 | void WorldSocketMgr::StopNetwork () |
| 290 | { |
| 291 | if (m_Acceptor) |
| 292 | { |
| 293 | WorldSocket::Acceptor* acc = dynamic_cast<WorldSocket::Acceptor*> (m_Acceptor); |
| 294 | |
| 295 | if (acc) |
| 296 | acc->close (); |
| 297 | } |
| 298 | |
| 299 | if (m_NetThreadsCount != 0) |
| 300 | { |
| 301 | for (size_t i = 0; i < m_NetThreadsCount; ++i) |
| 302 | m_NetThreads[i].Stop (); |
| 303 | } |
| 304 | |
| 305 | this->Wait (); |
| 306 | } |
| 307 | |
| 308 | void WorldSocketMgr::Wait () |
| 309 | { |
| 310 | if (m_NetThreadsCount != 0) |
| 311 | { |
| 312 | for (size_t i = 0; i < m_NetThreadsCount; ++i) |
| 313 | m_NetThreads[i].Wait (); |
| 314 | } |
| 315 | } |
| 316 | |
| 317 | int WorldSocketMgr::OnSocketOpen (WorldSocket* sock) |
| 318 | { |
| 319 | // set some options here |
| 320 | if (m_SockOutKBuff >= 0) |
| 321 | if (sock->peer ().set_option (SOL_SOCKET, |
| 322 | SO_SNDBUF, |
| 323 | (void*) & m_SockOutKBuff, |
| 324 | sizeof (int)) == -1 && errno != ENOTSUP) |
| 325 | { |
| 326 | sLog.outError ("WorldSocketMgr::OnSocketOpen set_option SO_SNDBUF"); |
| 327 | return -1; |
| 328 | } |
| 329 | |
| 330 | static const int ndoption = 1; |
| 331 | |
| 332 | // Set TCP_NODELAY. |
| 333 | if (m_UseNoDelay) |
| 334 | if (sock->peer ().set_option (ACE_IPPROTO_TCP, |
| 335 | TCP_NODELAY, |
| 336 | (void*) & ndoption, |
| 337 | sizeof (int)) == -1) |
| 338 | { |
| 339 | sLog.outError ("WorldSocketMgr::OnSocketOpen: peer ().set_option TCP_NODELAY errno = %s", ACE_OS::strerror (errno)); |
| 340 | return -1; |
| 341 | } |
| 342 | |
| 343 | sock->m_OutBufferSize = static_cast<size_t> (m_SockOutUBuff); |
| 344 | |
| 345 | // we skip the Acceptor Thread |
| 346 | size_t min = 1; |
| 347 | |
| 348 | ACE_ASSERT (m_NetThreadsCount >= 1); |
| 349 | |
| 350 | for (size_t i = 1; i < m_NetThreadsCount; ++i) |
| 351 | if (m_NetThreads[i].Connections () < m_NetThreads[min].Connections ()) |
| 352 | min = i; |
| 353 | |
| 354 | return m_NetThreads[min].AddSocket (sock); |
| 355 | } |
| 356 | |
| 357 | WorldSocketMgr* WorldSocketMgr::Instance () |
| 358 | { |
| 359 | return ACE_Singleton<WorldSocketMgr,ACE_Thread_Mutex>::instance(); |
| 360 | } |