OregonCore  revision 3611e8a-git
Your Favourite TBC server
WorldSocket.cpp
Go to the documentation of this file.
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 
18 #include <ace/Message_Block.h>
19 #include <ace/OS_NS_string.h>
20 #include <ace/OS_NS_unistd.h>
21 #include <ace/os_include/arpa/os_inet.h>
22 #include <ace/os_include/netinet/os_tcp.h>
23 #include <ace/os_include/sys/os_types.h>
24 #include <ace/os_include/sys/os_socket.h>
25 #include <ace/Reactor.h>
26 #include <ace/Auto_Ptr.h>
27 
28 #include "WorldSocket.h"
29 #include "Common.h"
30 
31 #include "Util.h"
32 #include "World.h"
33 #include "WorldPacket.h"
34 #include "SharedDefines.h"
35 #include "ByteBuffer.h"
36 #include "AddonHandler.h"
37 #include "Opcodes.h"
38 #include "Database/DatabaseEnv.h"
39 #include "Auth/Sha1.h"
40 #include "WorldSession.h"
41 #include "WorldSocketMgr.h"
42 #include "Log.h"
43 #include "DBCStores.h"
44 
45 #if defined(__GNUC__)
46 #pragma pack(1)
47 #else
48 #pragma pack(push,1)
49 #endif
50 
52 {
55 };
56 
58 {
61 };
62 
63 #if defined(__GNUC__)
64 #pragma pack()
65 #else
66 #pragma pack(pop)
67 #endif
68 
70  WorldHandler(),
71  m_LastPingTime(ACE_Time_Value::zero),
72  m_OverSpeedPings(0),
73  m_Session(0),
74  m_RecvWPct(0),
75  m_RecvPct(),
76  m_Header(sizeof (ClientPktHeader)),
77  m_OutBuffer(0),
78  m_OutBufferSize(65536),
79  m_OutActive(false),
80  m_Seed(static_cast<uint32> (rand32()))
81 {
82  reference_counting_policy().value (ACE_Event_Handler::Reference_Counting_Policy::ENABLED);
83 }
84 
86 {
87  delete m_RecvWPct;
88 
89  if (m_OutBuffer)
90  m_OutBuffer->release();
91 
92  closing_ = true;
93 
94  peer().close();
95 
96  WorldPacket* pct;
97  while (m_PacketQueue.dequeue_head (pct) == 0)
98  delete pct;
99 }
100 
101 bool WorldSocket::IsClosed (void) const
102 {
103  return closing_;
104 }
105 
107 {
108  {
109  ACE_GUARD (LockType, Guard, m_OutBufferLock);
110 
111  if (closing_)
112  return;
113 
114  closing_ = true;
115  peer().close_writer();
116  }
117 
118  {
119  ACE_GUARD (LockType, Guard, m_SessionLock);
120 
121  m_Session = NULL;
122  }
123 }
124 
125 const std::string& WorldSocket::GetRemoteAddress (void) const
126 {
127  return m_Address;
128 }
129 
131 {
132  ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1);
133 
134  if (closing_)
135  return -1;
136 
137  // Dump outgoing packet.
138  if (sLog.IsLogTypeEnabled(LOG_TYPE_NETWORK))
139  {
140  sLog.outNetwork ("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n",
141  (uint32) get_handle(),
142  pct.size(),
143  LookupOpcodeName (pct.GetOpcode()),
144  pct.GetOpcode());
145 
146  uint32 p = 0;
147  while (p < pct.size())
148  {
149  for (uint32 j = 0; j < 16 && p < pct.size(); j++)
150  sLog.outNetwork("%.2X ", const_cast<WorldPacket&>(pct)[p++]);
151 
152  sLog.outNetwork("");
153  }
154  sLog.outNetwork("");
155  }
156 
157  if (iSendPacket (pct) == -1)
158  {
159  WorldPacket* npct;
160 
161  ACE_NEW_RETURN (npct, WorldPacket (pct), -1);
162 
163  // NOTE maybe check of the size of the queue can be good ?
164  // to make it bounded instead of unbounded
165  if (m_PacketQueue.enqueue_tail (npct) == -1)
166  {
167  delete npct;
168  sLog.outError ("WorldSocket::SendPacket: m_PacketQueue.enqueue_tail failed");
169  return -1;
170  }
171  }
172 
173  return 0;
174 }
175 
177 {
178  return static_cast<long> (add_reference());
179 }
180 
182 {
183  return static_cast<long> (remove_reference());
184 }
185 
186 int WorldSocket::open (void* a)
187 {
188  ACE_UNUSED_ARG (a);
189 
190  // Prevent double call to this func.
191  if (m_OutBuffer)
192  return -1;
193 
194  // This will also prevent the socket from being Updated
195  // while we are initializing it.
196  m_OutActive = true;
197 
198  // Hook for the manager.
199  if (sWorldSocketMgr->OnSocketOpen(this) == -1)
200  return -1;
201 
202  // Allocate the buffer.
203  ACE_NEW_RETURN (m_OutBuffer, ACE_Message_Block (m_OutBufferSize), -1);
204 
205  // Store peer address.
206  ACE_INET_Addr remote_addr;
207 
208  if (peer().get_remote_addr(remote_addr) == -1)
209  {
210  sLog.outError ("WorldSocket::open: peer().get_remote_addr errno = %s", ACE_OS::strerror (errno));
211  return -1;
212  }
213 
214  m_Address = remote_addr.get_host_addr();
215 
216  // Send startup packet.
217  WorldPacket packet (SMSG_AUTH_CHALLENGE, 4);
218  packet << m_Seed;
219 
220  if (SendPacket (packet) == -1)
221  return -1;
222 
223  // Register with ACE Reactor
224  if (reactor()->register_handler(this, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK) == -1)
225  {
226  sLog.outError ("WorldSocket::open: unable to register client handler errno = %s", ACE_OS::strerror (errno));
227  return -1;
228  }
229 
230  // reactor takes care of the socket from now on
231  remove_reference();
232 
233  return 0;
234 }
235 
236 int WorldSocket::close (u_long)
237 {
238  shutdown();
239 
240  closing_ = true;
241 
242  remove_reference();
243 
244  return 0;
245 }
246 
248 {
249  if (closing_)
250  return -1;
251 
252  switch (handle_input_missing_data())
253  {
254  case -1 :
255  {
256  if ((errno == EWOULDBLOCK) ||
257  (errno == EAGAIN))
258  {
259  return Update(); // interesting line ,isn't it ?
260  }
261 
262  DEBUG_LOG("WorldSocket::handle_input: Peer error closing connection errno = %s", ACE_OS::strerror (errno));
263 
264  errno = ECONNRESET;
265  return -1;
266  }
267  case 0:
268  {
269  DEBUG_LOG("WorldSocket::handle_input: Peer has closed connection");
270 
271  errno = ECONNRESET;
272  return -1;
273  }
274  case 1:
275  return 1;
276  default:
277  return Update(); // another interesting line ;)
278  }
279 
280  ACE_NOTREACHED(return -1);
281 }
282 
284 {
285  ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1);
286 
287  if (closing_)
288  return -1;
289 
290  const size_t send_len = m_OutBuffer->length ();
291 
292  if (send_len == 0)
293  return cancel_wakeup_output (Guard);
294 
295  #ifdef MSG_NOSIGNAL
296  ssize_t n = peer().send (m_OutBuffer->rd_ptr(), send_len, MSG_NOSIGNAL);
297  #else
298  ssize_t n = peer().send (m_OutBuffer->rd_ptr(), send_len);
299  #endif // MSG_NOSIGNAL
300 
301  if (n == 0)
302  return -1;
303  else if (n == -1)
304  {
305  if (errno == EWOULDBLOCK || errno == EAGAIN)
306  return schedule_wakeup_output (Guard);
307 
308  return -1;
309  }
310  else if (size_t(n) < send_len) //now n > 0
311  {
312  m_OutBuffer->rd_ptr (static_cast<size_t> (n));
313 
314  // move the data to the base of the buffer
315  m_OutBuffer->crunch();
316 
317  return schedule_wakeup_output (Guard);
318  }
319  else //now n == send_len
320  {
321  m_OutBuffer->reset();
322 
323  if (!iFlushPacketQueue ())
324  return cancel_wakeup_output (Guard);
325  else
326  return schedule_wakeup_output (Guard);
327  }
328 
329  ACE_NOTREACHED (return 0);
330 }
331 
332 int WorldSocket::handle_close (ACE_HANDLE h, ACE_Reactor_Mask)
333 {
334  // Critical section
335  {
336  ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1);
337 
338  closing_ = true;
339 
340  if (h == ACE_INVALID_HANDLE)
341  peer().close_writer();
342  }
343 
344  // Critical section
345  {
346  ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);
347 
348  m_Session = NULL;
349  }
350 
351  reactor()->remove_handler(this, ACE_Event_Handler::DONT_CALL | ACE_Event_Handler::ALL_EVENTS_MASK);
352  return 0;
353 }
354 
356 {
357  if (closing_)
358  return -1;
359 
360  if (m_OutActive || m_OutBuffer->length () == 0)
361  return 0;
362 
363  return handle_output (get_handle ());
364 }
365 
367 {
368  ACE_ASSERT (m_RecvWPct == NULL);
369 
370  ACE_ASSERT (m_Header.length() == sizeof(ClientPktHeader));
371 
372  m_Crypt.DecryptRecv ((ACE_UINT8*) m_Header.rd_ptr (), sizeof (ClientPktHeader));
373 
374  ClientPktHeader& header = *((ClientPktHeader*) m_Header.rd_ptr());
375 
376  EndianConvertReverse(header.size);
377  EndianConvert(header.cmd);
378 
379  if ((header.size < 4) || (header.size > 10240) || (header.cmd > 10240))
380  {
381  sLog.outError ("WorldSocket::handle_input_header: client sent malformed packet size = %d , cmd = %d",
382  header.size, header.cmd);
383 
384  errno = EINVAL;
385  return -1;
386  }
387 
388  header.size -= 4;
389 
390  ACE_NEW_RETURN (m_RecvWPct, WorldPacket ((uint16) header.cmd, header.size), -1);
391 
392  if (header.size > 0)
393  {
394  m_RecvWPct->resize (header.size);
395  m_RecvPct.base ((char*) m_RecvWPct->contents(), m_RecvWPct->size());
396  }
397  else
398  ACE_ASSERT(m_RecvPct.space() == 0);
399 
400  return 0;
401 }
402 
404 {
405  // set errno properly here on error !!!
406  // now have a header and payload
407 
408  ACE_ASSERT (m_RecvPct.space() == 0);
409  ACE_ASSERT (m_Header.space() == 0);
410  ACE_ASSERT (m_RecvWPct != NULL);
411 
412  const int ret = ProcessIncoming (m_RecvWPct);
413 
414  m_RecvPct.base (NULL, 0);
415  m_RecvPct.reset();
416  m_RecvWPct = NULL;
417 
418  m_Header.reset();
419 
420  if (ret == -1)
421  errno = EINVAL;
422 
423  return ret;
424 }
425 
427 {
428  char buf [1024];
429 
430  ACE_Data_Block db (sizeof (buf),
431  ACE_Message_Block::MB_DATA,
432  buf,
433  0,
434  0,
435  ACE_Message_Block::DONT_DELETE,
436  0);
437 
438  ACE_Message_Block message_block(&db,
439  ACE_Message_Block::DONT_DELETE,
440  0);
441 
442  const size_t recv_size = message_block.space();
443 
444  const ssize_t n = peer().recv (message_block.wr_ptr(),
445  recv_size);
446 
447  if (n <= 0)
448  return n;
449 
450  message_block.wr_ptr (n);
451 
452  while (message_block.length() > 0)
453  {
454  if (m_Header.space() > 0)
455  {
456  //need to receive the header
457  const size_t to_header = (message_block.length() > m_Header.space() ? m_Header.space() : message_block.length());
458  m_Header.copy (message_block.rd_ptr(), to_header);
459  message_block.rd_ptr (to_header);
460 
461  if (m_Header.space() > 0)
462  {
463  // Couldn't receive the whole header this time.
464  ACE_ASSERT (message_block.length() == 0);
465  errno = EWOULDBLOCK;
466  return -1;
467  }
468 
469  // We just received nice new header
470  if (handle_input_header() == -1)
471  {
472  ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN));
473  return -1;
474  }
475  }
476 
477  // Its possible on some error situations that this happens
478  // for example on closing when epoll receives more chunked data and stuff
479  // hope this is not hack ,as proper m_RecvWPct is asserted around
480  if (!m_RecvWPct)
481  {
482  sLog.outError ("Forcing close on input m_RecvWPct = NULL");
483  errno = EINVAL;
484  return -1;
485  }
486 
487  // We have full read header, now check the data payload
488  if (m_RecvPct.space() > 0)
489  {
490  //need more data in the payload
491  const size_t to_data = (message_block.length() > m_RecvPct.space() ? m_RecvPct.space() : message_block.length());
492  m_RecvPct.copy (message_block.rd_ptr(), to_data);
493  message_block.rd_ptr (to_data);
494 
495  if (m_RecvPct.space() > 0)
496  {
497  // Couldn't receive the whole data this time.
498  ACE_ASSERT (message_block.length() == 0);
499  errno = EWOULDBLOCK;
500  return -1;
501  }
502  }
503 
504  //just received fresh new payload
505  if (handle_input_payload() == -1)
506  {
507  ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN));
508  return -1;
509  }
510  }
511 
512  return size_t(n) == recv_size ? 1 : 2;
513 }
514 
516 {
517  if (!m_OutActive)
518  return 0;
519 
520  m_OutActive = false;
521 
522  g.release();
523 
524  if (reactor()->cancel_wakeup
525  (this, ACE_Event_Handler::WRITE_MASK) == -1)
526  {
527  // would be good to store errno from reactor with errno guard
528  sLog.outError ("WorldSocket::cancel_wakeup_output");
529  return -1;
530  }
531 
532  return 0;
533 }
534 
536 {
537  if (m_OutActive)
538  return 0;
539 
540  m_OutActive = true;
541 
542  g.release();
543 
544  if (reactor()->schedule_wakeup
545  (this, ACE_Event_Handler::WRITE_MASK) == -1)
546  {
547  sLog.outError ("WorldSocket::schedule_wakeup_output");
548  return -1;
549  }
550 
551  return 0;
552 }
553 
555 {
556  ACE_ASSERT (new_pct);
557 
558  // manage memory ;)
559  ACE_Auto_Ptr<WorldPacket> aptr (new_pct);
560 
561  const ACE_UINT16 opcode = new_pct->GetOpcode();
562 
563  if (closing_)
564  return -1;
565 
566  // Dump received packet.
567  if (sLog.IsLogTypeEnabled(LOG_TYPE_NETWORK))
568  {
569  sLog.outNetwork ("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n",
570  (uint32) get_handle(),
571  new_pct->size(),
572  LookupOpcodeName (new_pct->GetOpcode()),
573  new_pct->GetOpcode());
574 
575  uint32 p = 0;
576  while (p < new_pct->size())
577  {
578  for (uint32 j = 0; j < 16 && p < new_pct->size(); j++)
579  sLog.outNetwork ("%.2X ", (*new_pct)[p++]);
580 
581  sLog.outNetwork ("");
582  }
583  sLog.outNetwork ("");
584  }
585 
586  try
587  {
588  switch (opcode)
589  {
590  case CMSG_PING:
591  return HandlePing (*new_pct);
592  case CMSG_AUTH_SESSION:
593  if (m_Session)
594  {
595  sLog.outError ("WorldSocket::ProcessIncoming: Player send CMSG_AUTH_SESSION again");
596  return -1;
597  }
598 
599  return HandleAuthSession (*new_pct);
600  case CMSG_KEEP_ALIVE:
601  DEBUG_LOG ("CMSG_KEEP_ALIVE ,size: %lu", new_pct->size());
602 
603  return 0;
604  default:
605  {
606  ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);
607 
608  if (m_Session != NULL)
609  {
610  // Our Idle timer will reset on any non PING opcodes.
611  // Catches people idling on the login screen and any lingering ingame connections.
613 
614  // OK ,give the packet to WorldSession
615  aptr.release();
616  // WARNINIG here we call it with locks held.
617  // Its possible to cause deadlock if QueuePacket calls back
618  m_Session->QueuePacket (new_pct);
619  return 0;
620  }
621  else
622  {
623  sLog.outError ("WorldSocket::ProcessIncoming: Client not authed opcode = %u", uint32(opcode));
624  return -1;
625  }
626  }
627  }
628  }
629  catch (ByteBufferException&)
630  {
631  sLog.outError("WorldSocket::ProcessIncoming ByteBufferException occured while parsing an instant handled packet (opcode: %u) from client %s, accountid=%i. Disconnected client.",
632  opcode, GetRemoteAddress().c_str(), m_Session ? m_Session->GetAccountId() : -1);
633  if (sLog.IsOutDebug())
634  {
635  sLog.outDebug("Dumping error causing packet:");
636  new_pct->hexlike();
637  }
638 
639  return -1;
640  }
641 
642  ACE_NOTREACHED (return 0);
643 }
644 
646 {
647  // NOTE: ATM the socket is singlethread, have this in mind ...
648  uint8 digest[20];
649  uint32 clientSeed;
650  uint32 unk2;
651  uint32 BuiltNumberClient;
652  uint32 id, security;
653  //uint8 expansion = 0;
654  LocaleConstant locale;
655  std::string account;
656  Sha1Hash sha1;
657  BigNumber v, s, g, N;
658  WorldPacket packet, SendAddonPacked;
659 
660  BigNumber K;
661 
662  // Read the content of the packet
663  recvPacket >> BuiltNumberClient;
664  recvPacket >> unk2;
665  recvPacket >> account;
666 
667  recvPacket >> clientSeed;
668  recvPacket.read (digest, 20);
669 
670  DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, clientseed %u",
671  BuiltNumberClient,
672  unk2,
673  account.c_str (),
674  clientSeed);
675 
676  // Check the version of client trying to connect
677  if (!IsAcceptableClientBuild(BuiltNumberClient))
678  {
679  packet.Initialize (SMSG_AUTH_RESPONSE, 1);
680  packet << uint8 (AUTH_VERSION_MISMATCH);
681 
682  SendPacket (packet);
683 
684  sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (version mismatch).");
685  return -1;
686  }
687 
688  // Get the account information from the realmd database
689  std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below
690  LoginDatabase.escape_string (safe_account);
691  // No SQL injection, username escaped.
692 
693  QueryResult_AutoPtr result = LoginDatabase.PQuery ("SELECT "
694  "id, " //0
695  "sessionkey, " //1
696  "last_ip, " //2
697  "locked, " //3
698  "v, " //4
699  "s, " //5
700  "expansion, " //6
701  "mutetime, " //7
702  "locale, " //8
703  "os " //9
704  "FROM account "
705  "WHERE username = '%s'",
706  safe_account.c_str ());
707 
708  // Stop if the account is not found
709  if (!result)
710  {
711  packet.Initialize (SMSG_AUTH_RESPONSE, 1);
712  packet << uint8 (AUTH_UNKNOWN_ACCOUNT);
713 
714  SendPacket (packet);
715 
716  sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
717  return -1;
718  }
719 
720  Field* fields = result->Fetch ();
721 
722  uint8 expansion = fields[6].GetUInt8();
723  uint32 world_expansion = sWorld.getConfig(CONFIG_EXPANSION);
724  if (expansion > world_expansion)
725  expansion = world_expansion;
726  //expansion = ((sWorld.getConfig(CONFIG_EXPANSION) > fields[6].GetUInt8()) ? fields[6].GetUInt8() : sWorld.getConfig(CONFIG_EXPANSION));
727 
728  N.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
729  g.SetDword (7);
730 
731  v.SetHexStr(fields[4].GetString());
732  s.SetHexStr (fields[5].GetString ());
733 
734  const char* sStr = s.AsHexStr (); //Must be freed by OPENSSL_free()
735  const char* vStr = v.AsHexStr (); //Must be freed by OPENSSL_free()
736 
737  DEBUG_LOG ("WorldSocket::HandleAuthSession: (s,v) check s: %s v: %s",
738  sStr,
739  vStr);
740 
741  OPENSSL_free ((void*) sStr);
742  OPENSSL_free ((void*) vStr);
743 
744  // Re-check ip locking (same check as in realmd).
745  if (fields[3].GetUInt8 () == 1) // if ip is locked
746  {
747  if (strcmp (fields[2].GetString (), GetRemoteAddress ().c_str ()))
748  {
749  packet.Initialize (SMSG_AUTH_RESPONSE, 1);
750  packet << uint8 (AUTH_FAILED);
751  SendPacket (packet);
752 
753  sLog.outBasic ("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs).");
754  return -1;
755  }
756  }
757 
758  id = fields[0].GetUInt32 ();
759  K.SetHexStr (fields[1].GetString ());
760 
761  time_t mutetime = time_t (fields[7].GetUInt64 ());
762  std::string os = fields[9].GetString();
763 
764  locale = LocaleConstant (fields[8].GetUInt8 ());
765  if (locale >= MAX_LOCALE)
766  locale = LOCALE_enUS;
767 
768  // Checks gmlevel per Realm
769  result =
770  LoginDatabase.PQuery ("SELECT "
771  "RealmID, " //0
772  "gmlevel " //1
773  "FROM account_access "
774  "WHERE id = '%d'"
775  " AND (RealmID = '%d'"
776  " OR RealmID = '-1')",
777  id, realmID);
778  if (!result)
779  security = 0;
780  else
781  {
782  fields = result->Fetch ();
783  security = fields[1].GetInt32();
784  }
785 
786  // Re-check account ban (same check as in realmd)
787  QueryResult_AutoPtr banresult = LoginDatabase.PQuery ("SELECT "
788  "bandate, "
789  "unbandate "
790  "FROM account_banned "
791  "WHERE id = '%u' "
792  "AND active = 1",
793  id);
794 
795  if (banresult) // if account banned
796  {
797  packet.Initialize (SMSG_AUTH_RESPONSE, 1);
798  packet << uint8 (AUTH_BANNED);
799  SendPacket (packet);
800 
801  sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
802  return -1;
803  }
804 
805  // Check locked state for server
806  sWorld.UpdateAllowedSecurity();
807  AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit ();
808  sLog.outDebug("Allowed Level: %u Player Level %u", allowedAccountType, AccountTypes(security));
809  if (allowedAccountType > SEC_PLAYER && security < allowedAccountType)
810  {
811  WorldPacket Packet (SMSG_AUTH_RESPONSE, 1);
812  Packet << uint8 (AUTH_UNAVAILABLE);
813 
814  SendPacket (packet);
815 
816  sLog.outDetail ("WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
817  return -1;
818  }
819 
820  // Check that Key and account name are the same on client and server
821  Sha1Hash sha;
822 
823  uint32 t = 0;
824  uint32 seed = m_Seed;
825 
826  sha.UpdateData (account);
827  sha.UpdateData ((uint8*) & t, 4);
828  sha.UpdateData ((uint8*) & clientSeed, 4);
829  sha.UpdateData ((uint8*) & seed, 4);
830  sha.UpdateBigNumbers (&K, NULL);
831  sha.Finalize ();
832 
833  if (memcmp (sha.GetDigest (), digest, 20))
834  {
835  packet.Initialize (SMSG_AUTH_RESPONSE, 1);
836  packet << uint8 (AUTH_FAILED);
837 
838  SendPacket (packet);
839 
840  sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed).");
841  return -1;
842  }
843 
844  std::string address = GetRemoteAddress();
845 
846  DEBUG_LOG ("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.",
847  account.c_str(),
848  address.c_str());
849 
850  // Update the last_ip in the database
851  // No SQL injection, username escaped.
852  LoginDatabase.escape_string (address);
853 
854  LoginDatabase.PExecute ("UPDATE account "
855  "SET last_ip = '%s' "
856  "WHERE username = '%s'",
857  address.c_str(),
858  safe_account.c_str());
859 
860  // NOTE ATM the socket is single-threaded, have this in mind ...
861  ACE_NEW_RETURN (m_Session, WorldSession (id, this, security, expansion, mutetime, locale), -1);
862 
863  m_Crypt.SetKey(&K);
864  m_Crypt.Init();
865 
866  // Initialize Warden system only if it is enabled by config
867  if (sWorld.getConfig(CONFIG_WARDEN_ENABLED))
868  m_Session->InitWarden(&K, os);
869 
870  // Sleep this Network thread for
871  uint32 sleepTime = sWorld.getConfig(CONFIG_SESSION_ADD_DELAY);
872  ACE_OS::sleep(ACE_Time_Value (0, sleepTime));
873 
874  sWorld.AddSession (m_Session);
875 
876  // Create and send the Addon packet
877  if (sAddOnHandler.BuildAddonPacket (&recvPacket, &SendAddonPacked))
878  SendPacket(SendAddonPacked);
879 
880  return 0;
881 }
882 
884 {
885  uint32 ping;
886  uint32 latency;
887 
888  // Get the ping packet content
889  recvPacket >> ping;
890  recvPacket >> latency;
891 
892  if (m_LastPingTime == ACE_Time_Value::zero)
893  m_LastPingTime = ACE_OS::gettimeofday(); // for 1st ping
894  else
895  {
896  ACE_Time_Value cur_time = ACE_OS::gettimeofday();
897  ACE_Time_Value diff_time (cur_time);
898  diff_time -= m_LastPingTime;
899  m_LastPingTime = cur_time;
900 
901  if (diff_time < ACE_Time_Value (27))
902  {
904 
905  uint32 max_count = sWorld.getConfig (CONFIG_MAX_OVERSPEED_PINGS);
906 
907  if (max_count && m_OverSpeedPings > max_count)
908  {
909  ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);
910 
912  {
913  sLog.outError ("WorldSocket::HandlePing: Player kicked for "
914  "over-speed pings address = %s",
915  GetRemoteAddress().c_str());
916 
917  return -1;
918  }
919  }
920  }
921  else
922  m_OverSpeedPings = 0;
923  }
924 
925  // critical section
926  {
927  ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);
928 
929  if (m_Session)
930  {
931  m_Session->SetLatency (latency);
933  }
934  else
935  {
936  sLog.outError ("WorldSocket::HandlePing: peer sent CMSG_PING, "
937  "but is not authenticated or got recently kicked,"
938  " address = %s",
939  GetRemoteAddress().c_str());
940  return -1;
941  }
942  }
943 
944  WorldPacket packet (SMSG_PONG, 4);
945  packet << ping;
946  return SendPacket (packet);
947 }
948 
950 {
951  if (m_OutBuffer->space () < pct.size () + sizeof (ServerPktHeader))
952  {
953  errno = ENOBUFS;
954  return -1;
955  }
956 
957  ServerPktHeader header;
958 
959  header.cmd = pct.GetOpcode ();
960  EndianConvert(header.cmd);
961 
962  header.size = (uint16) pct.size () + 2;
963  EndianConvertReverse(header.size);
964 
965  m_Crypt.EncryptSend ((uint8*) & header, sizeof (header));
966 
967  if (m_OutBuffer->copy ((char*) & header, sizeof (header)) == -1)
968  ACE_ASSERT (false);
969 
970  if (!pct.empty ())
971  if (m_OutBuffer->copy ((char*) pct.contents (), pct.size ()) == -1)
972  ACE_ASSERT (false);
973 
974  return 0;
975 }
976 
978 {
979  WorldPacket* pct;
980  bool haveone = false;
981 
982  while (m_PacketQueue.dequeue_head (pct) == 0)
983  {
984  if (iSendPacket (*pct) == -1)
985  {
986  if (m_PacketQueue.enqueue_head (pct) == -1)
987  {
988  delete pct;
989  sLog.outError ("WorldSocket::iFlushPacketQueue m_PacketQueue->enqueue_head");
990  return false;
991  }
992 
993  break;
994  }
995  else
996  {
997  haveone = true;
998  delete pct;
999  }
1000  }
1001 
1002  return haveone;
1003 }
1004 
ACE_Message_Block m_Header
Definition: WorldSocket.h:203
long AddReference(void)
uint16 GetOpcode() const
Definition: WorldPacket.h:44
ACE_Time_Value m_LastPingTime
Definition: WorldSocket.h:177
#define sWorldSocketMgr
const uint8 * contents() const
Definition: ByteBuffer.h:331
void EncryptSend(uint8 *, size_t)
Definition: AuthCrypt.cpp:47
void Init()
Definition: AuthCrypt.cpp:26
uint32 m_Seed
Definition: WorldSocket.h:221
virtual int close(u_long)
void DecryptRecv(uint8 *, size_t)
Definition: AuthCrypt.cpp:32
void QueuePacket(WorldPacket *new_packet)
PacketQueueT m_PacketQueue
Definition: WorldSocket.h:216
QueryResult_AutoPtr PQuery(const char *format,...) ATTR_PRINTF(2
Definition: Database.cpp:400
void SetKey(BigNumber *)
Definition: AuthCrypt.cpp:61
AccountTypes
Definition: Common.h:188
void resize(size_t newsize)
Definition: ByteBuffer.h:345
Definition: Field.h:24
ACE_Guard< LockType > GuardType
Definition: WorldSocket.h:95
void EndianConvert(T &val)
Definition: ByteConverter.h:48
ACE_Thread_Mutex LockType
Definition: WorldSocket.h:94
#define sLog
Log class singleton.
Definition: Log.h:187
int SendPacket(const WorldPacket &pct)
unsigned long escape_string(char *to, const char *from, unsigned long length)
Definition: Database.cpp:212
NULL Dbg ErrDB Arena Chat Char Map MMap false
Definition: Log.cpp:556
void Initialize(uint16 opcode, size_t newres=200)
Definition: WorldPacket.h:37
int iSendPacket(const WorldPacket &pct)
void ResetTimeOutTime()
Definition: WorldSession.h:265
uint32 GetAccountId() const
Definition: WorldSession.h:100
WorldSession * m_Session
Definition: WorldSocket.h:192
virtual int handle_input(ACE_HANDLE=ACE_INVALID_HANDLE)
size_t m_OutBufferSize
Definition: WorldSocket.h:212
bool m_OutActive
Definition: WorldSocket.h:219
LockType m_SessionLock
Definition: WorldSocket.h:189
uint8 * GetDigest(void)
Definition: Sha1.h:41
WorldSocket(void)
Definition: WorldSocket.cpp:69
const char * GetString() const
Definition: Field.h:41
LockType m_OutBufferLock
Definition: WorldSocket.h:206
int cancel_wakeup_output(GuardType &g)
ACE_UINT8 uint8
Definition: Define.h:73
void Finalize()
Definition: Sha1.cpp:61
#define sAddOnHandler
Definition: AddonHandler.h:36
ACE_Message_Block m_RecvPct
Definition: WorldSocket.h:200
int handle_input_missing_data(void)
int handle_input_header(void)
const char * AsHexStr()
Definition: BigNumber.cpp:204
const uint8 MAX_LOCALE
Definition: Common.h:224
void SetHexStr(const char *str)
Definition: BigNumber.cpp:66
DatabaseType LoginDatabase
Accessor to the realm/login database.
Definition: Main.cpp:55
void EndianConvertReverse(T &)
Definition: ByteConverter.h:52
std::string m_Address
Definition: WorldSocket.h:183
bool empty() const
Definition: ByteBuffer.h:340
size_t size() const
Definition: ByteBuffer.h:336
void UpdateBigNumbers(BigNumber *bn0,...)
Definition: Sha1.cpp:41
int Update(void)
void Guard(void *)
WorldPacket * m_RecvWPct
Definition: WorldSocket.h:195
#define DEBUG_LOG(...)
Definition: Log.h:194
const char * LookupOpcodeName(uint16 id)
Definition: Opcodes.h:1119
int HandleAuthSession(WorldPacket &recvPacket)
bool IsAcceptableClientBuild(uint32 build)
Definition: DBCStores.cpp:158
bool PExecute(const char *format,...) ATTR_PRINTF(2
Definition: Database.cpp:441
ACE_Message_Block * m_OutBuffer
Definition: WorldSocket.h:209
void hexlike() const
Definition: ByteBuffer.h:451
int HandlePing(WorldPacket &recvPacket)
int handle_input_payload(void)
virtual int handle_output(ACE_HANDLE=ACE_INVALID_HANDLE)
virtual ~WorldSocket(void)
Definition: WorldSocket.cpp:85
void SetDword(uint32)
Definition: BigNumber.cpp:47
bool IsClosed(void) const
void InitWarden(BigNumber *K, std::string os)
int ProcessIncoming(WorldPacket *new_pct)
void SetLatency(uint32 latency)
Definition: WorldSession.h:247
ACE_Refcounted_Auto_Ptr< QueryResult, ACE_Null_Mutex > QueryResult_AutoPtr
Definition: QueryResult.h:113
uint32 realmID
Id of the realm.
Definition: Main.cpp:57
void ResetClientTimeDelay()
Definition: WorldSession.h:251
virtual int open(void *)
int schedule_wakeup_output(GuardType &g)
void UpdateData(const uint8 *dta, int len)
Definition: Sha1.cpp:31
void CloseSocket(void)
#define MSG_NOSIGNAL
LocaleConstant
Definition: Common.h:211
#define sWorld
Definition: World.h:860
void uint32 GetSecurity() const
Definition: WorldSession.h:96
ACE_UINT16 uint16
Definition: Define.h:72
ACE_UINT32 uint32
Definition: Define.h:71
const std::string & GetRemoteAddress(void) const
int32 rand32()
Definition: Util.cpp:81
AuthCrypt m_Crypt
Definition: WorldSocket.h:186
uint32 m_OverSpeedPings
Definition: WorldSocket.h:180
ACE_Svc_Handler< ACE_SOCK_STREAM, ACE_NULL_SYNCH > WorldHandler
Definition: WorldSocket.h:41
long RemoveReference(void)
virtual int handle_close(ACE_HANDLE=ACE_INVALID_HANDLE, ACE_Reactor_Mask=ACE_Event_Handler::ALL_EVENTS_MASK)
bool iFlushPacketQueue()
Definition: Sha1.h:26