Show
Ignore:
Timestamp:
11/19/08 13:22:12 (17 years ago)
Author:
yumileroy
Message:

[svn] * Added ACE for Linux and Windows (Thanks Derex for Linux part and partial Windows part)
* Updated to 6721 and 676
* Fixed TrinityScript? logo
* Version updated to 0.2.6721.676

Original author: Neo2003
Date: 2008-10-04 06:17:19-05:00

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/src/game/WorldSocket.cpp

    r2 r6  
    1 /* 
     1/*  
    22 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> 
    33 * 
     
    1717 */ 
    1818 
    19 /** \file 
    20     \ingroup u2w 
    21 */ 
    22  
    2319#include "Common.h" 
    24 #include "Log.h" 
     20#include "WorldSocket.h"  
     21#include <ace/Message_Block.h> 
     22#include <ace/OS_NS_string.h> 
     23#include <ace/OS_NS_unistd.h> 
     24#include <ace/os_include/arpa/os_inet.h> 
     25#include <ace/os_include/netinet/os_tcp.h> 
     26#include <ace/os_include/sys/os_types.h> 
     27#include <ace/os_include/sys/os_socket.h> 
     28#include <ace/OS_NS_string.h> 
     29#include <ace/Reactor.h> 
     30#include <ace/Auto_Ptr.h> 
     31 
     32#include "Util.h" 
     33#include "World.h" 
     34#include "WorldPacket.h" 
     35#include "SharedDefines.h" 
     36#include "ByteBuffer.h" 
     37#include "AddonHandler.h" 
    2538#include "Opcodes.h" 
    2639#include "Database/DatabaseEnv.h" 
    2740#include "Auth/Sha1.h" 
    28 #include "WorldPacket.h" 
    29 #include "WorldSocket.h" 
    3041#include "WorldSession.h" 
    31 #include "World.h" 
    3242#include "WorldSocketMgr.h" 
    33 #include "Policies/SingletonImp.h" 
     43#include "Log.h" 
    3444#include "WorldLog.h" 
    35 #include "AddonHandler.h" 
    36 #include "sockets/Utility.h" 
    37 #include "Util.h" 
    38  
    39 // GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform 
     45 
    4046#if defined( __GNUC__ ) 
    4147#pragma pack(1) 
     
    4450#endif 
    4551 
    46 /// Client Packet Header 
     52struct ServerPktHeader 
     53{ 
     54  ACE_UINT16 size; 
     55  ACE_UINT16 cmd; 
     56}; 
     57 
    4758struct ClientPktHeader 
    4859{ 
    49     uint16 size; 
    50     uint32 cmd; 
     60  ACE_UINT16 size; 
     61  ACE_UINT32 cmd; 
    5162}; 
    5263 
    53 /// Server Packet Header 
    54 struct ServerPktHeader 
    55 { 
    56     uint16 size; 
    57     uint16 cmd; 
    58 }; 
    59  
    60 // GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform 
    6164#if defined( __GNUC__ ) 
    6265#pragma pack() 
     
    6568#endif 
    6669 
    67 #define SOCKET_CHECK_PACKET_SIZE(P,S) if((P).size() < (S)) return SizeError((P),(S)); 
    68  
    69 /// WorldSocket construction and initialization. 
    70 WorldSocket::WorldSocket(ISocketHandler &sh): TcpSocket(sh), _cmd(0), _remaining(0), _session(NULL) 
    71 { 
    72     _seed = static_cast<uint32>(rand32()); 
    73     m_LastPingMSTime = 0;                                   // first time it will counted as overspeed maybe, but this is not important 
    74     m_OverSpeedPings = 0; 
    75  
    76     if (sWorld.getConfig(CONFIG_TCP_NO_DELAY)) 
    77         SetTcpNodelay(true); 
    78 } 
    79  
    80 /// WorldSocket destructor 
    81 WorldSocket::~WorldSocket() 
    82 { 
    83     if(_session) 
    84         _session->SetSocket(0); 
    85  
    86     WorldPacket *packet; 
    87  
    88     ///- Go through the to-be-sent queue and delete remaining packets 
    89     while(!_sendQueue.empty()) 
    90     { 
    91         packet = _sendQueue.next(); 
    92         delete packet; 
    93     } 
    94 } 
    95  
    96 /// Copy the packet to the to-be-sent queue 
    97 void WorldSocket::SendPacket(WorldPacket const* packet) 
    98 { 
    99     WorldPacket *pck = new WorldPacket(*packet); 
    100     ASSERT(pck); 
    101     _sendQueue.add(pck); 
    102 } 
    103  
    104 /// On client connection 
    105 void WorldSocket::OnAccept() 
    106 { 
    107     ///- Add the current socket to the list of sockets to be managed (WorldSocketMgr) 
    108     sWorldSocketMgr.AddSocket(this); 
    109     Utility::ResolveLocal(); 
    110  
    111     ///- Send a AUTH_CHALLENGE packet 
    112     WorldPacket packet( SMSG_AUTH_CHALLENGE, 4 ); 
    113     packet << _seed; 
    114  
    115     SendPacket(&packet); 
    116 } 
    117  
    118 /// Read the client transmitted data 
    119 void WorldSocket::OnRead() 
    120 { 
    121     TcpSocket::OnRead(); 
    122  
    123     while(1) 
    124     { 
    125         ///- Read the packet header and decipher it (if needed) 
    126         if (!_remaining) 
    127         { 
    128             if (ibuf.GetLength() < 6) 
    129                 break; 
    130  
    131             ClientPktHeader hdr; 
    132  
    133             ibuf.Read((char *)&hdr, 6); 
    134             _crypt.DecryptRecv((uint8 *)&hdr, 6); 
    135  
    136             _remaining = ntohs(hdr.size) - 4; 
    137             _cmd = hdr.cmd; 
    138         } 
    139  
    140         if (ibuf.GetLength() < _remaining) 
    141             break; 
    142  
    143         ///- Read the remaining of the packet 
    144         WorldPacket packet((uint16)_cmd, _remaining); 
    145  
    146         packet.resize(_remaining); 
    147         if(_remaining) ibuf.Read((char*)packet.contents(), _remaining); 
    148         _remaining = 0; 
    149  
    150         ///- If log of world packets is enable, log the incoming packet 
    151         if( sWorldLog.LogWorld() ) 
    152         { 
    153             sWorldLog.Log("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", 
    154                 (uint32)GetSocket(), 
    155                 packet.size(), 
    156                 LookupOpcodeName(packet.GetOpcode()), 
    157                 packet.GetOpcode()); 
    158  
    159             uint32 p = 0; 
    160             while (p < packet.size()) 
     70// used when testing to alow login without password and encryption 
     71// #define _NETCODE_FAKE_AUTH 
     72 
     73WorldSocket::WorldSocket (void) : 
     74WorldHandler (), 
     75m_Session (0), 
     76m_RecvWPct (0), 
     77m_RecvPct (), 
     78m_Header (sizeof (ClientPktHeader)), 
     79m_OutBuffer (0), 
     80m_OutBufferSize (65536), 
     81m_OutActive (false), 
     82m_Seed (static_cast<uint32> (rand32 ())), 
     83m_OverSpeedPings (0), 
     84m_LastPingTime (ACE_Time_Value::zero) 
     85{ 
     86  this->reference_counting_policy ().value (ACE_Event_Handler::Reference_Counting_Policy::ENABLED); 
     87} 
     88 
     89WorldSocket::~WorldSocket (void) 
     90{ 
     91  if (m_RecvWPct) 
     92    delete m_RecvWPct; 
     93 
     94  if (m_OutBuffer) 
     95    m_OutBuffer->release (); 
     96 
     97  this->closing_ = true; 
     98 
     99  this->peer ().close (); 
     100 
     101  WorldPacket* pct; 
     102  while (m_PacketQueue.dequeue_head (pct) == 0) 
     103    delete pct; 
     104} 
     105 
     106bool 
     107WorldSocket::IsClosed (void) const 
     108{ 
     109  return this->closing_; 
     110} 
     111 
     112void 
     113WorldSocket::CloseSocket (void) 
     114{ 
     115  { 
     116    ACE_GUARD (LockType, Guard, m_OutBufferLock); 
     117 
     118    if (this->closing_) 
     119      return; 
     120 
     121    this->closing_ = true; 
     122 
     123    this->peer ().close_writer (); 
     124  } 
     125 
     126  { 
     127    ACE_GUARD (LockType, Guard, m_SessionLock); 
     128 
     129    m_Session = NULL; 
     130  } 
     131 
     132} 
     133 
     134const std::string& 
     135WorldSocket::GetRemoteAddress (void) const 
     136{ 
     137  return m_Address; 
     138} 
     139 
     140int 
     141WorldSocket::SendPacket (const WorldPacket& pct) 
     142{ 
     143  ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); 
     144 
     145  if (this->closing_) 
     146    return -1; 
     147 
     148  // Dump outgoing packet. 
     149  if (sWorldLog.LogWorld ()) 
     150    { 
     151      sWorldLog.Log ("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", 
     152                     (uint32) get_handle (), 
     153                     pct.size (), 
     154                     LookupOpcodeName (pct.GetOpcode ()), 
     155                     pct.GetOpcode ()); 
     156 
     157      uint32 p = 0; 
     158      while (p < pct.size ()) 
     159        { 
     160          for (uint32 j = 0; j < 16 && p < pct.size (); j++) 
     161            sWorldLog.Log ("%.2X ", const_cast<WorldPacket&>(pct)[p++]); 
     162 
     163          sWorldLog.Log ("\n"); 
     164        } 
     165 
     166      sWorldLog.Log ("\n\n"); 
     167    } 
     168 
     169  if (iSendPacket (pct) == -1) 
     170    { 
     171      WorldPacket* npct; 
     172 
     173      ACE_NEW_RETURN (npct, WorldPacket (pct), -1); 
     174 
     175      // NOTE maybe check of the size of the queue can be good ? 
     176      // to make it bounded instead of unbounded 
     177      if (m_PacketQueue.enqueue_tail (npct) == -1) 
     178        { 
     179          delete npct; 
     180          sLog.outError ("WorldSocket::SendPacket: m_PacketQueue.enqueue_tail failed"); 
     181          return -1; 
     182        } 
     183    } 
     184 
     185  return 0; 
     186} 
     187 
     188long 
     189WorldSocket::AddReference (void) 
     190{ 
     191  return static_cast<long> (this->add_reference ()); 
     192} 
     193 
     194long 
     195WorldSocket::RemoveReference (void) 
     196{ 
     197  return static_cast<long> (this->remove_reference ()); 
     198} 
     199 
     200int 
     201WorldSocket::open (void *a) 
     202{ 
     203  ACE_UNUSED_ARG (a); 
     204 
     205  // Prevent double call to this func. 
     206  if (m_OutBuffer) 
     207    return -1; 
     208 
     209  // This will also prevent the socket from being Updated 
     210  // while we are initializing it. 
     211  m_OutActive = true; 
     212 
     213  // Hook for the manager. 
     214  if (sWorldSocketMgr->OnSocketOpen (this) == -1) 
     215    return -1; 
     216 
     217  // Allocate the buffer. 
     218  ACE_NEW_RETURN (m_OutBuffer, ACE_Message_Block (m_OutBufferSize), -1); 
     219 
     220  // Store peer address. 
     221  ACE_INET_Addr remote_addr; 
     222 
     223  if (this->peer ().get_remote_addr (remote_addr) == -1) 
     224    { 
     225      sLog.outError ("WorldSocket::open: peer ().get_remote_addr errno = %s", ACE_OS::strerror (errno)); 
     226      return -1; 
     227    } 
     228 
     229  m_Address = remote_addr.get_host_addr (); 
     230 
     231  // Send startup packet. 
     232  WorldPacket packet (SMSG_AUTH_CHALLENGE, 4); 
     233  packet << m_Seed; 
     234 
     235  if (SendPacket (packet) == -1) 
     236    return -1; 
     237 
     238  // Register with ACE Reactor 
     239  if (this->reactor ()->register_handler 
     240      (this, 
     241       ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK) == -1) 
     242    { 
     243      sLog.outError ("WorldSocket::open: unable to register client handler errno = %s", ACE_OS::strerror (errno)); 
     244      return -1; 
     245    } 
     246 
     247  // reactor takes care of the socket from now on 
     248  this->remove_reference (); 
     249 
     250  return 0; 
     251} 
     252 
     253int 
     254WorldSocket::close (int) 
     255{ 
     256  this->shutdown (); 
     257 
     258  this->closing_ = true; 
     259 
     260  this->remove_reference (); 
     261 
     262  return 0; 
     263} 
     264 
     265int 
     266WorldSocket::handle_input (ACE_HANDLE) 
     267{ 
     268  if (this->closing_) 
     269    return -1; 
     270 
     271  switch (this->handle_input_missing_data ()) 
     272    { 
     273    case -1 : 
     274      { 
     275        if ((errno == EWOULDBLOCK) || 
     276            (errno == EAGAIN)) 
     277          { 
     278            //return 0; 
     279            return this->Update (); // interesting line ,isnt it ? 
     280          } 
     281 
     282        DEBUG_LOG ("WorldSocket::handle_input: Peer error closing connection errno = %s", ACE_OS::strerror (errno)); 
     283 
     284        return -1; 
     285      } 
     286    case 0: 
     287      { 
     288        DEBUG_LOG ("WorldSocket::handle_input: Peer has closed connection\n"); 
     289 
     290        errno = ECONNRESET; 
     291 
     292        return -1; 
     293      } 
     294    case 1: 
     295      return 1; 
     296    } 
     297 
     298  //return 0; 
     299  return this->Update (); // another interesting line ;) 
     300} 
     301 
     302int 
     303WorldSocket::handle_output (ACE_HANDLE) 
     304{ 
     305  ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); 
     306 
     307  if (this->closing_) 
     308    return -1; 
     309 
     310  const size_t send_len = m_OutBuffer->length (); 
     311 
     312  if (send_len == 0) 
     313    return this->cancel_wakeup_output (Guard); 
     314   
     315// TODO SO_NOSIGPIPE on platforms that support it 
     316#ifdef MSG_NOSIGNAL 
     317  ssize_t n = this->peer ().send (m_OutBuffer->rd_ptr (), send_len, MSG_NOSIGNAL); 
     318#else 
     319  ssize_t n = this->peer ().send (m_OutBuffer->rd_ptr (), send_len); 
     320#endif // MSG_NOSIGNAL 
     321           
     322  if (n == 0) 
     323    return -1; 
     324  else if (n == -1) 
     325    { 
     326      if (errno == EWOULDBLOCK || errno == EAGAIN) 
     327        return this->schedule_wakeup_output (Guard); 
     328 
     329      return -1; 
     330    } 
     331  else if (n < send_len) //now n > 0 
     332    { 
     333      m_OutBuffer->rd_ptr (static_cast<size_t> (n)); 
     334 
     335      // move the data to the base of the buffer 
     336      m_OutBuffer->crunch (); 
     337 
     338      return this->schedule_wakeup_output (Guard); 
     339    } 
     340  else //now n == send_len 
     341    { 
     342      m_OutBuffer->reset (); 
     343 
     344      if (!iFlushPacketQueue ()) 
     345        return this->cancel_wakeup_output (Guard); 
     346      else 
     347        return this->schedule_wakeup_output (Guard); 
     348    } 
     349 
     350  ACE_NOTREACHED (return 0); 
     351} 
     352 
     353int 
     354WorldSocket::handle_close (ACE_HANDLE h, ACE_Reactor_Mask) 
     355{ 
     356  // Critical section 
     357  { 
     358    ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); 
     359 
     360    this->closing_ = true; 
     361 
     362    if (h == ACE_INVALID_HANDLE) 
     363      this->peer ().close_writer (); 
     364  } 
     365 
     366  // Critical section 
     367  { 
     368    ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); 
     369 
     370    m_Session = NULL; 
     371  } 
     372 
     373  return 0; 
     374} 
     375 
     376int 
     377WorldSocket::Update (void) 
     378{ 
     379  if (this->closing_) 
     380    return -1; 
     381 
     382  if (m_OutActive || m_OutBuffer->length () == 0) 
     383    return 0; 
     384 
     385  return this->handle_output (this->get_handle ()); 
     386} 
     387 
     388int 
     389WorldSocket::handle_input_header (void) 
     390{ 
     391  ACE_ASSERT (m_RecvWPct == NULL); 
     392 
     393  if (m_Header.length () != sizeof (ClientPktHeader)) 
     394    { 
     395      sLog.outError ("WorldSocket::handle_input_header: internal error: invalid header"); 
     396      errno = EINVAL; 
     397      return -1; 
     398    } 
     399 
     400  m_Crypt.DecryptRecv ((ACE_UINT8*) m_Header.rd_ptr (), sizeof (ClientPktHeader)); 
     401 
     402  ClientPktHeader& header = *((ClientPktHeader*) m_Header.rd_ptr ()); 
     403 
     404  header.size = ACE_NTOHS (header.size); 
     405 
     406#if ACE_BYTE_ORDER == ACE_BIG_ENDIAN 
     407  header.cmd = ACE_SWAP_LONG (header.cmd) 
     408#endif // ACE_BIG_ENDIAN 
     409 
     410  if ((header.size < 4) || 
     411      (header.size > 10240) || 
     412      (header.cmd <= 0) || 
     413      (header.cmd > 10240) 
     414      ) 
     415    { 
     416      sLog.outError ("WorldSocket::handle_input_header: client sent mailformed packet size = %d , cmd = %d", 
     417                     header.size, 
     418                     header.cmd); 
     419 
     420      errno = EINVAL; 
     421      return -1; 
     422    } 
     423 
     424  header.size -= 4; 
     425 
     426  ACE_NEW_RETURN (m_RecvWPct, WorldPacket ((uint16) header.cmd, header.size), -1); 
     427 
     428  if(header.size > 0) 
     429  { 
     430     m_RecvWPct->resize (header.size);   
     431     m_RecvPct.base ((char*) m_RecvWPct->contents (), m_RecvWPct->size ()); 
     432  } 
     433  else 
     434  { 
     435     ACE_ASSERT(m_RecvPct.space() == 0); 
     436  } 
     437 
     438 
     439  return 0; 
     440} 
     441 
     442int 
     443WorldSocket::handle_input_payload (void) 
     444{ 
     445  // set errno properly here on error !!! 
     446  // now have a header and payload 
     447 
     448  ACE_ASSERT (m_RecvPct.space () == 0); 
     449  ACE_ASSERT (m_Header.space () == 0); 
     450  ACE_ASSERT (m_RecvWPct != NULL); 
     451 
     452  const int ret = this->ProcessIncoming (m_RecvWPct); 
     453 
     454  m_RecvPct.base (NULL, 0); 
     455  m_RecvPct.reset (); 
     456  m_RecvWPct = NULL; 
     457 
     458  m_Header.reset (); 
     459 
     460  if (ret == -1) 
     461    errno = EINVAL; 
     462 
     463  return ret; 
     464} 
     465 
     466int 
     467WorldSocket::handle_input_missing_data (void) 
     468{ 
     469  char buf [1024]; 
     470 
     471  ACE_Data_Block db (sizeof (buf), 
     472                     ACE_Message_Block::MB_DATA, 
     473                     buf, 
     474                     0, 
     475                     0, 
     476                     ACE_Message_Block::DONT_DELETE, 
     477                     0); 
     478 
     479  ACE_Message_Block message_block (&db, 
     480                                   ACE_Message_Block::DONT_DELETE, 
     481                                   0); 
     482 
     483  const size_t recv_size = message_block.space (); 
     484 
     485  const ssize_t n = this->peer ().recv (message_block.wr_ptr (), 
     486                                        recv_size); 
     487 
     488  if (n <= 0) 
     489    return n; 
     490 
     491  message_block.wr_ptr (n); 
     492 
     493  while (message_block.length () > 0) 
     494    { 
     495      if (m_Header.space () > 0) 
     496        { 
     497          //need to recieve the header 
     498          const size_t to_header = (message_block.length () > m_Header.space () ? m_Header.space () : message_block.length ()); 
     499          m_Header.copy (message_block.rd_ptr (), to_header); 
     500          message_block.rd_ptr (to_header); 
     501 
     502          if (m_Header.space () > 0) 
    161503            { 
    162                 for (uint32 j = 0; j < 16 && p < packet.size(); j++) 
    163                     sWorldLog.Log("%.2X ", packet[p++]); 
    164                 sWorldLog.Log("\n"); 
     504              //couldnt recieve the whole header this time 
     505              ACE_ASSERT (message_block.length () == 0); 
     506              errno = EWOULDBLOCK; 
     507              return -1; 
    165508            } 
    166             sWorldLog.Log("\n\n"); 
    167         } 
    168  
    169         ///- If the packet is PING, KEEP_ALIVE or AUTH_SESSION, handle immediately 
    170         switch (_cmd) 
    171         { 
    172             case CMSG_KEEP_ALIVE: 
    173                 break;                                      // just ignore, network connectivity timeout preventing 
    174             case CMSG_PING: 
     509 
     510          //we just recieved nice new header 
     511          if (this->handle_input_header () == -1) 
    175512            { 
    176                 _HandlePing(packet); 
    177                 break; 
     513              ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN)); 
     514              return -1; 
    178515            } 
    179             case CMSG_AUTH_SESSION: 
     516        } 
     517 
     518      // Its possible on some error situations that this happens 
     519      // for example on closing when epoll recieves more chunked data and stuff 
     520      // hope this is not hack ,as proper m_RecvWPct is asserted around 
     521      if (!m_RecvWPct) 
     522        { 
     523          sLog.outError ("Forsing close on input m_RecvWPct = NULL"); 
     524          errno = EINVAL; 
     525          return -1; 
     526        } 
     527 
     528      // We have full readed header, now check the data payload 
     529      if (m_RecvPct.space () > 0) 
     530        { 
     531          //need more data in the payload 
     532          const size_t to_data = (message_block.length () > m_RecvPct.space () ? m_RecvPct.space () : message_block.length ()); 
     533          m_RecvPct.copy (message_block.rd_ptr (), to_data); 
     534          message_block.rd_ptr (to_data); 
     535 
     536          if (m_RecvPct.space () > 0) 
    180537            { 
    181                 _HandleAuthSession(packet); 
    182                 break; 
     538              //couldnt recieve the whole data this time 
     539              ACE_ASSERT (message_block.length () == 0); 
     540              errno = EWOULDBLOCK; 
     541              return -1; 
    183542            } 
    184             default: 
     543        } 
     544 
     545      //just recieved fresh new payload 
     546      if (this->handle_input_payload () == -1) 
     547        { 
     548          ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN)); 
     549          return -1; 
     550        } 
     551    } 
     552 
     553  return n == recv_size ? 1 : 2; 
     554} 
     555 
     556int 
     557WorldSocket::cancel_wakeup_output (GuardType& g) 
     558{ 
     559  if (!m_OutActive) 
     560    return 0; 
     561 
     562  m_OutActive = false; 
     563 
     564  g.release (); 
     565 
     566  if (this->reactor ()->cancel_wakeup 
     567      (this, ACE_Event_Handler::WRITE_MASK) == -1) 
     568    { 
     569      // would be good to store errno from reactor with errno guard 
     570      sLog.outError ("WorldSocket::cancel_wakeup_output"); 
     571      return -1; 
     572    } 
     573 
     574  return 0; 
     575} 
     576 
     577int 
     578WorldSocket::schedule_wakeup_output (GuardType& g) 
     579{ 
     580  if (m_OutActive) 
     581    return 0; 
     582 
     583  m_OutActive = true; 
     584 
     585  g.release (); 
     586 
     587  if (this->reactor ()->schedule_wakeup 
     588      (this, ACE_Event_Handler::WRITE_MASK) == -1) 
     589    { 
     590      sLog.outError ("WorldSocket::schedule_wakeup_output"); 
     591      return -1; 
     592    } 
     593 
     594  return 0; 
     595} 
     596 
     597int 
     598WorldSocket::ProcessIncoming (WorldPacket* new_pct) 
     599{ 
     600  ACE_ASSERT (new_pct); 
     601   
     602  // manage memory ;) 
     603  ACE_Auto_Ptr<WorldPacket> aptr (new_pct); 
     604 
     605  const ACE_UINT16 opcode = new_pct->GetOpcode (); 
     606 
     607  if (this->closing_) 
     608    return -1; 
     609 
     610  // dump recieved packet 
     611  if (sWorldLog.LogWorld ()) 
     612    { 
     613      sWorldLog.Log ("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", 
     614                     (uint32) get_handle (), 
     615                     new_pct->size (), 
     616                     LookupOpcodeName (new_pct->GetOpcode ()), 
     617                     new_pct->GetOpcode ()); 
     618 
     619      uint32 p = 0; 
     620      while (p < new_pct->size ()) 
     621        { 
     622          for (uint32 j = 0; j < 16 && p < new_pct->size (); j++) 
     623            sWorldLog.Log ("%.2X ", (*new_pct)[p++]); 
     624          sWorldLog.Log ("\n"); 
     625        } 
     626      sWorldLog.Log ("\n\n"); 
     627    } 
     628 
     629  // like one switch ;) 
     630  if (opcode == CMSG_PING) 
     631    { 
     632      return HandlePing (*new_pct); 
     633    } 
     634  else if (opcode == CMSG_AUTH_SESSION) 
     635    { 
     636      if (m_Session) 
     637        { 
     638          sLog.outError ("WorldSocket::ProcessIncoming: Player send CMSG_AUTH_SESSION again"); 
     639          return -1; 
     640        } 
     641 
     642      return HandleAuthSession (*new_pct); 
     643    } 
     644  else if (opcode == CMSG_KEEP_ALIVE) 
     645    { 
     646      DEBUG_LOG ("CMSG_KEEP_ALIVE ,size: %d", new_pct->size ()); 
     647 
     648      return 0; 
     649    } 
     650  else 
     651    { 
     652      ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); 
     653 
     654      if (m_Session != NULL) 
     655        { 
     656          // OK ,give the packet to WorldSession 
     657          aptr.release (); 
     658          // WARNINIG here we call it with locks held. 
     659          // Its possible to cause deadlock if QueuePacket calls back 
     660          m_Session->QueuePacket (new_pct); 
     661          return 0; 
     662        } 
     663      else 
     664        { 
     665          sLog.outError ("WorldSocket::ProcessIncoming: Client not authed opcode = ", opcode); 
     666          return -1; 
     667        } 
     668    } 
     669 
     670  ACE_NOTREACHED (return 0); 
     671} 
     672 
     673int 
     674WorldSocket::HandleAuthSession (WorldPacket& recvPacket) 
     675{ 
     676  uint8 digest[20]; 
     677  uint32 clientSeed; 
     678  uint32 unk2; 
     679  uint32 BuiltNumberClient; 
     680  uint32 id, security; 
     681  bool tbc = false; 
     682  LocaleConstant locale; 
     683  std::string account; 
     684  Sha1Hash sha1; 
     685  BigNumber v, s, g, N, x, I; 
     686  WorldPacket packet, SendAddonPacked; 
     687 
     688  BigNumber K; 
     689 
     690  if (recvPacket.size () < (4 + 4 + 1 + 4 + 20)) 
     691    { 
     692      sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size"); 
     693      return -1; 
     694    } 
     695 
     696  // Read the content of the packet 
     697  recvPacket >> BuiltNumberClient; // for now no use 
     698  recvPacket >> unk2; 
     699  recvPacket >> account; 
     700 
     701  if (recvPacket.size () < (4 + 4 + (account.size () + 1) + 4 + 20)) 
     702    { 
     703      sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size second check"); 
     704      return -1; 
     705    } 
     706 
     707  recvPacket >> clientSeed; 
     708  recvPacket.read (digest, 20); 
     709 
     710  DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, clientseed %u", 
     711             BuiltNumberClient, 
     712             unk2, 
     713             account.c_str (), 
     714             clientSeed); 
     715 
     716#if defined _NETCODE_FAKE_AUTH 
     717  bool dontchechtheacc = false; 
     718  uint8 digest_fake[sizeof (digest)]; 
     719  memset ((void*) digest_fake, '\0', sizeof (digest_fake)); 
     720  if (memcmp ((void*) digest, (void*) digest_fake, sizeof (digest_fake)) == 0) 
     721    { 
     722      dontchechtheacc = true; 
     723    } 
     724#endif //_NETCODE_FAKE_AUTH 
     725 
     726  // Get the account information from the realmd database 
     727  std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below 
     728  loginDatabase.escape_string (safe_account); 
     729  // No SQL injection, username escaped. 
     730 
     731  QueryResult *result = 
     732          loginDatabase.PQuery ("SELECT " 
     733                                "id, " //0 
     734                                "gmlevel, " //1 
     735                                "sessionkey, " //2 
     736                                "last_ip, " //3 
     737                                "locked, " //4 
     738                                "sha_pass_hash, " //5 
     739                                "v, " //6 
     740                                "s, " //7 
     741                                "tbc, " //8 
     742                                "mutetime, " //9 
     743                                "locale " //10 
     744                                "FROM account " 
     745                                "WHERE username = '%s'", 
     746                                safe_account.c_str ()); 
     747 
     748  // Stop if the account is not found 
     749  if (!result) 
     750    { 
     751      packet.Initialize (SMSG_AUTH_RESPONSE, 1); 
     752      packet << uint8 (AUTH_UNKNOWN_ACCOUNT); 
     753 
     754      SendPacket (packet); 
     755 
     756      sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (unknown account)."); 
     757      return -1; 
     758    } 
     759 
     760  Field* fields = result->Fetch (); 
     761 
     762  tbc = fields[8].GetUInt8 () && sWorld.getConfig (CONFIG_EXPANSION) > 0; 
     763 
     764  N.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); 
     765  g.SetDword (7); 
     766  I.SetHexStr (fields[5].GetString ()); 
     767 
     768  //In case of leading zeros in the I hash, restore them 
     769  uint8 mDigest[SHA_DIGEST_LENGTH]; 
     770  memset (mDigest, 0, SHA_DIGEST_LENGTH); 
     771 
     772  if (I.GetNumBytes () <= SHA_DIGEST_LENGTH) 
     773    memcpy (mDigest, I.AsByteArray (), I.GetNumBytes ()); 
     774 
     775  std::reverse (mDigest, mDigest + SHA_DIGEST_LENGTH); 
     776 
     777  s.SetHexStr (fields[7].GetString ()); 
     778  sha1.UpdateData (s.AsByteArray (), s.GetNumBytes ()); 
     779  sha1.UpdateData (mDigest, SHA_DIGEST_LENGTH); 
     780  sha1.Finalize (); 
     781  x.SetBinary (sha1.GetDigest (), sha1.GetLength ()); 
     782  v = g.ModExp (x, N); 
     783 
     784  const char* sStr = s.AsHexStr (); //Must be freed by OPENSSL_free() 
     785  const char* vStr = v.AsHexStr (); //Must be freed by OPENSSL_free() 
     786  const char* vold = fields[6].GetString (); 
     787 
     788  DEBUG_LOG ("WorldSocket::HandleAuthSession: (s,v) check s: %s v_old: %s v_new: %s", 
     789             sStr, 
     790             vold, 
     791             vStr); 
     792 
     793  loginDatabase.PExecute ("UPDATE account " 
     794                          "SET " 
     795                          "v = '0', " 
     796                          "s = '0' " 
     797                          "WHERE username = '%s'", 
     798                          safe_account.c_str ()); 
     799 
     800#if defined _NETCODE_FAKE_AUTH 
     801  if (!dontchechtheacc) 
     802    { 
     803#endif 
     804      if (!vold || strcmp (vStr, vold)) 
     805        { 
     806          packet.Initialize (SMSG_AUTH_RESPONSE, 1); 
     807          packet << uint8 (AUTH_UNKNOWN_ACCOUNT); 
     808          SendPacket (packet); 
     809          delete result; 
     810          OPENSSL_free ((void*) sStr); 
     811          OPENSSL_free ((void*) vStr); 
     812 
     813          sLog.outError ("WorldSocket::HandleAuthSession: User not logged."); 
     814          return -1; 
     815        } 
     816#if defined _NETCODE_FAKE_AUTH 
     817    } 
     818#endif 
     819 
     820  OPENSSL_free ((void*) sStr); 
     821  OPENSSL_free ((void*) vStr); 
     822 
     823  ///- Re-check ip locking (same check as in realmd). 
     824  if (fields[4].GetUInt8 () == 1) // if ip is locked 
     825    { 
     826      if (strcmp (fields[3].GetString (), GetRemoteAddress ().c_str ())) 
     827        { 
     828          packet.Initialize (SMSG_AUTH_RESPONSE, 1); 
     829          packet << uint8 (AUTH_FAILED); 
     830          SendPacket (packet); 
     831 
     832          delete result; 
     833          sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs)."); 
     834          return -1; 
     835        } 
     836    } 
     837 
     838  id = fields[0].GetUInt32 (); 
     839  security = fields[1].GetUInt16 (); 
     840  K.SetHexStr (fields[2].GetString ()); 
     841 
     842  time_t mutetime = time_t (fields[9].GetUInt64 ()); 
     843 
     844  locale = LocaleConstant (fields[10].GetUInt8 ()); 
     845  if (locale >= MAX_LOCALE) 
     846    locale = LOCALE_enUS; 
     847 
     848  delete result; 
     849 
     850#if defined _NETCODE_FAKE_AUTH 
     851  if (!dontchechtheacc) 
     852    { 
     853#endif 
     854      // Re-check account ban (same check as in realmd)  
     855      QueryResult *banresult = 
     856              loginDatabase.PQuery ("SELECT " 
     857                                    "bandate, " 
     858                                    "unbandate " 
     859                                    "FROM account_banned " 
     860                                    "WHERE id = '%u' " 
     861                                    "AND active = 1", 
     862                                    id); 
     863 
     864      if (banresult) // if account banned 
     865        { 
     866          packet.Initialize (SMSG_AUTH_RESPONSE, 1); 
     867          packet << uint8 (AUTH_BANNED); 
     868          SendPacket (packet); 
     869 
     870          delete banresult; 
     871 
     872          sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account banned)."); 
     873          return -1; 
     874        } 
     875 
     876      // Check locked state for server 
     877      AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit (); 
     878 
     879      if (allowedAccountType > SEC_PLAYER && security < allowedAccountType) 
     880        { 
     881          WorldPacket Packet (SMSG_AUTH_RESPONSE, 1); 
     882          Packet << uint8 (AUTH_UNAVAILABLE); 
     883 
     884          SendPacket (packet); 
     885 
     886          sLog.outBasic ("WorldSocket::HandleAuthSession: User tryes to login but his security level is not enough"); 
     887          return -1; 
     888        } 
     889 
     890      // Check that Key and account name are the same on client and server 
     891      Sha1Hash sha; 
     892 
     893      uint32 t = 0; 
     894      uint32 seed = m_Seed; 
     895 
     896      sha.UpdateData (account); 
     897      sha.UpdateData ((uint8 *) & t, 4); 
     898      sha.UpdateData ((uint8 *) & clientSeed, 4); 
     899      sha.UpdateData ((uint8 *) & seed, 4); 
     900      sha.UpdateBigNumbers (&K, NULL); 
     901      sha.Finalize (); 
     902 
     903      if (memcmp (sha.GetDigest (), digest, 20)) 
     904        { 
     905          packet.Initialize (SMSG_AUTH_RESPONSE, 1); 
     906          packet << uint8 (AUTH_FAILED); 
     907 
     908          SendPacket (packet); 
     909 
     910          sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed)."); 
     911          return -1; 
     912        } 
     913#if defined _NETCODE_FAKE_AUTH 
     914    } 
     915#endif 
     916 
     917  std::string address = this->GetRemoteAddress (); 
     918 
     919  DEBUG_LOG ("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.", 
     920             account.c_str (), 
     921             address.c_str ()); 
     922 
     923  // Update the last_ip in the database 
     924  // No SQL injection, username escaped. 
     925  loginDatabase.escape_string (address); 
     926 
     927  loginDatabase.PExecute ("UPDATE account " 
     928                          "SET last_ip = '%s' " 
     929                          "WHERE username = '%s'", 
     930                          address.c_str (), 
     931                          safe_account.c_str ()); 
     932 
     933  // TODO protect here probably ? 
     934  // Althought atm the socket is singlethreaded 
     935  ACE_NEW_RETURN (m_Session, WorldSession (id, this, security, tbc, mutetime, locale), -1); 
     936 
     937#if defined _NETCODE_FAKE_AUTH 
     938  if (!dontchechtheacc) 
     939    { 
     940#endif 
     941      this->m_Crypt.SetKey (&K); 
     942      this->m_Crypt.Init (); 
     943#if defined _NETCODE_FAKE_AUTH 
     944    } 
     945#endif 
     946 
     947  // In case needed sometime the second arg is in microseconds 1 000 000 = 1 sec 
     948  ACE_OS::sleep (ACE_Time_Value (0, 10000)); 
     949 
     950  // TODO error handling 
     951  sWorld.AddSession (this->m_Session); 
     952 
     953  // Create and send the Addon packet 
     954  if (sAddOnHandler.BuildAddonPacket (&recvPacket, &SendAddonPacked)) 
     955    SendPacket (SendAddonPacked); 
     956 
     957  return 0; 
     958} 
     959 
     960int 
     961WorldSocket::HandlePing (WorldPacket& recvPacket) 
     962{ 
     963  uint32 ping; 
     964  uint32 latency; 
     965 
     966  if (recvPacket.size () < 8) 
     967    { 
     968      sLog.outError ("WorldSocket::_HandlePing wrong packet size"); 
     969      return -1; 
     970    } 
     971 
     972  // Get the ping packet content 
     973  recvPacket >> ping; 
     974  recvPacket >> latency; 
     975 
     976  if (m_LastPingTime == ACE_Time_Value::zero) 
     977    m_LastPingTime = ACE_OS::gettimeofday (); // for 1st ping 
     978  else 
     979    { 
     980      ACE_Time_Value cur_time = ACE_OS::gettimeofday (); 
     981      ACE_Time_Value diff_time (cur_time); 
     982      diff_time -= m_LastPingTime; 
     983      m_LastPingTime = cur_time; 
     984 
     985      if (diff_time < ACE_Time_Value (27)) 
     986        { 
     987          ++m_OverSpeedPings; 
     988 
     989          uint32 max_count = sWorld.getConfig (CONFIG_MAX_OVERSPEED_PINGS); 
     990 
     991          if (max_count && m_OverSpeedPings > max_count) 
    185992            { 
    186                 ///- Else, put it in the world session queue for this user (need to be already authenticated) 
    187                 if (_session) 
    188                     _session->QueuePacket(packet); 
    189                 else 
    190                     sLog.outDetail("Received out of place packet with cmdid 0x%.4X", _cmd); 
    191                 break; 
     993              ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); 
     994 
     995              if (m_Session && m_Session->GetSecurity () == SEC_PLAYER) 
     996                { 
     997                  sLog.outError ("WorldSocket::HandlePing: Player kicked for " 
     998                                 "overspeeded pings adress = %s", 
     999                                 GetRemoteAddress ().c_str ()); 
     1000 
     1001                  return -1; 
     1002                } 
    1921003            } 
    1931004        } 
    194     } 
    195 } 
    196  
    197 /// On socket closing 
    198 void WorldSocket::CloseSocket() 
    199 { 
    200     ///- Set CloseAndDelete flag for TcpSocket class 
    201     SetCloseAndDelete(true); 
    202  
    203     ///- Set _session to NULL. Prevent crashes 
    204     _session = NULL; 
    205 } 
    206  
    207 /// On socket deleting 
    208 void WorldSocket::OnDelete() 
    209 { 
    210     ///- Stop sending remaining data through this socket 
    211     if (_session) 
    212     { 
    213         _session->SetSocket(NULL); 
    214         // Session deleted from World session list at socket==0, This is only back reference from socket to session. 
    215         _session = NULL; 
    216     } 
    217  
    218     ///- Remove the socket from the WorldSocketMgr list 
    219     sWorldSocketMgr.RemoveSocket(this); 
    220  
    221     ///- Removes socket from player queue 
    222     sWorld.RemoveQueuedPlayer(this); 
    223 } 
    224  
    225 /// Handle the client authentication packet 
    226 void WorldSocket::_HandleAuthSession(WorldPacket& recvPacket) 
    227 { 
    228     uint8 digest[20]; 
    229     uint32 clientSeed; 
    230     uint32 unk2; 
    231     uint32 BuiltNumberClient; 
    232     uint32 id, security; 
    233     bool tbc = false; 
    234     std::string account; 
    235     Sha1Hash sha1; 
    236     BigNumber v, s, g, N, x, I; 
    237     WorldPacket packet, SendAddonPacked; 
    238  
    239     BigNumber K; 
    240  
    241     SOCKET_CHECK_PACKET_SIZE(recvPacket,4+4+1+4+20); 
    242  
    243     ///- Read the content of the packet 
    244     recvPacket >> BuiltNumberClient;                        // for now no use 
    245     recvPacket >> unk2; 
    246     recvPacket >> account; 
    247  
    248     // recheck size 
    249     SOCKET_CHECK_PACKET_SIZE(recvPacket,4+4+(account.size()+1)+4+20); 
    250  
    251     recvPacket >> clientSeed; 
    252     recvPacket.read(digest, 20); 
    253  
    254     sLog.outDebug("Auth: client %u, unk2 %u, account %s, clientseed %u", BuiltNumberClient, unk2, account.c_str(), clientSeed); 
    255  
    256     ///- Normalize account name 
    257     //utf8ToUpperOnlyLatin(account); -- client already send account in expected form 
    258  
    259     ///- Get the account information from the realmd database 
    260     std::string safe_account = account;                     // Duplicate, else will screw the SHA hash verification below 
    261     loginDatabase.escape_string(safe_account); 
    262     //No SQL injection, username escaped. 
    263     //                                                 0   1        2           3        4       5              6  7  8    9         10 
    264     QueryResult *result = loginDatabase.PQuery("SELECT id, gmlevel, sessionkey, last_ip, locked, sha_pass_hash, v, s, tbc, mutetime, locale FROM account WHERE username = '%s'", safe_account.c_str()); 
    265  
    266     ///- Stop if the account is not found 
    267     if ( !result ) 
    268     { 
    269         packet.Initialize( SMSG_AUTH_RESPONSE, 1 ); 
    270         packet << uint8( AUTH_UNKNOWN_ACCOUNT ); 
    271         SendPacket( &packet ); 
    272         sLog.outDetail( "SOCKET: Sent Auth Response (unknown account)." ); 
    273         return; 
    274     } 
    275  
    276     Field* fields = result->Fetch(); 
    277  
    278     tbc = fields[8].GetUInt8() && sWorld.getConfig(CONFIG_EXPANSION) > 0; 
    279  
    280     N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); 
    281     g.SetDword(7); 
    282     I.SetHexStr(fields[5].GetString()); 
    283  
    284     //In case of leading zeros in the I hash, restore them 
    285     uint8 mDigest[SHA_DIGEST_LENGTH]; 
    286     memset(mDigest,0,SHA_DIGEST_LENGTH); 
    287     if (I.GetNumBytes() <= SHA_DIGEST_LENGTH) 
    288         memcpy(mDigest,I.AsByteArray(),I.GetNumBytes()); 
    289  
    290     std::reverse(mDigest,mDigest+SHA_DIGEST_LENGTH); 
    291  
    292     s.SetHexStr(fields[7].GetString()); 
    293     sha1.UpdateData(s.AsByteArray(), s.GetNumBytes()); 
    294     sha1.UpdateData(mDigest, SHA_DIGEST_LENGTH); 
    295     sha1.Finalize(); 
    296     x.SetBinary(sha1.GetDigest(), sha1.GetLength()); 
    297     v = g.ModExp(x, N); 
    298  
    299     const char* sStr = s.AsHexStr();                        //Must be freed by OPENSSL_free() 
    300     const char* vStr = v.AsHexStr();                        //Must be freed by OPENSSL_free() 
    301     const char* vold = fields[6].GetString(); 
    302     sLog.outDebug("SOCKET: (s,v) check s: %s v_old: %s v_new: %s", sStr, vold, vStr ); 
    303     loginDatabase.PExecute("UPDATE account SET v = '0', s = '0' WHERE username = '%s'", safe_account.c_str()); 
    304     if ( !vold || strcmp( vStr, vold ) ) 
    305     { 
    306         packet.Initialize( SMSG_AUTH_RESPONSE, 1 ); 
    307         packet << uint8( AUTH_UNKNOWN_ACCOUNT ); 
    308         SendPacket( &packet ); 
    309         sLog.outDetail( "SOCKET: User not logged."); 
    310         delete result; 
    311         OPENSSL_free((void*)sStr); 
    312         OPENSSL_free((void*)vStr); 
    313         return; 
    314     } 
    315     OPENSSL_free((void*)sStr); 
    316     OPENSSL_free((void*)vStr); 
    317  
    318     ///- Re-check ip locking (same check as in realmd). 
    319     if(fields[4].GetUInt8() == 1)                           // if ip is locked 
    320     { 
    321         if ( strcmp(fields[3].GetString(),GetRemoteAddress().c_str()) ) 
    322         { 
    323             packet.Initialize( SMSG_AUTH_RESPONSE, 1 ); 
    324             packet << uint8( AUTH_FAILED ); 
    325             SendPacket( &packet ); 
    326  
    327             sLog.outDetail( "SOCKET: Sent Auth Response (Account IP differs)." ); 
    328             delete result; 
    329             return; 
    330         } 
    331     } 
    332  
    333     id = fields[0].GetUInt32(); 
    334     security = fields[1].GetUInt16(); 
    335     K.SetHexStr(fields[2].GetString()); 
    336     time_t mutetime = time_t(fields[9].GetUInt64()); 
    337  
    338     LocaleConstant locale = LocaleConstant(fields[10].GetUInt8()); 
    339     if (locale>=MAX_LOCALE) 
    340         locale=LOCALE_enUS; 
    341  
    342     delete result; 
    343  
    344     ///- Re-check account ban (same check as in realmd) /// TO DO: why on earth do 2 checks for same thing? 
    345     QueryResult *banresult = loginDatabase.PQuery("SELECT bandate,unbandate FROM account_banned WHERE id = '%u' AND active = 1", id); 
    346     if(banresult)                                           // if account banned 
    347     { 
    348         packet.Initialize( SMSG_AUTH_RESPONSE, 1 ); 
    349         packet << uint8( AUTH_BANNED ); 
    350         SendPacket( &packet ); 
    351  
    352         sLog.outDetail( "SOCKET: Sent Auth Response (Account banned)." ); 
    353         delete banresult; 
    354         return; 
    355     } 
    356  
    357     ///- Check locked state for server 
    358     AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit(); 
    359     if( allowedAccountType > SEC_PLAYER && security < allowedAccountType) 
    360     { 
    361         WorldPacket Packet(SMSG_AUTH_RESPONSE, 1); 
    362         Packet << uint8(AUTH_UNAVAILABLE); 
    363         SendPacket(&Packet); 
    364         return; 
    365     } 
    366  
    367     ///- kick already loaded player with same account (if any) and remove session 
    368     ///- if player is in loading and want to load again, return 
    369     if(!sWorld.RemoveSession(id)) 
    370     { 
    371         return; 
    372     } 
    373  
    374     ///- Check that Key and account name are the same on client and server 
    375     Sha1Hash sha; 
    376  
    377     uint32 t = 0; 
    378     uint32 seed = _seed; 
    379  
    380     sha.UpdateData(account); 
    381     sha.UpdateData((uint8 *)&t, 4); 
    382     sha.UpdateData((uint8 *)&clientSeed, 4); 
    383     sha.UpdateData((uint8 *)&seed, 4); 
    384     sha.UpdateBigNumbers(&K, NULL); 
    385     sha.Finalize(); 
    386  
    387     if (memcmp(sha.GetDigest(), digest, 20)) 
    388     { 
    389         packet.Initialize( SMSG_AUTH_RESPONSE, 1 ); 
    390         packet << uint8( AUTH_FAILED ); 
    391         SendPacket( &packet ); 
    392  
    393         sLog.outDetail( "SOCKET: Sent Auth Response (authentication failed)." ); 
    394         return; 
    395     } 
    396  
    397     ///- Initialize the encryption with the Key 
    398     _crypt.SetKey(&K); 
    399     _crypt.Init(); 
    400  
    401     ///- Send 'Auth is ok' 
    402     packet.Initialize( SMSG_AUTH_RESPONSE, 1+4+1+4+1 ); 
    403     packet << uint8( AUTH_OK ); 
    404     packet << uint32(0);                                    // unknown random value... 
    405     packet << uint8(0);                                     // can be 0 and 2 
    406     packet << uint32(0);                                    // const 0 
    407     packet << uint8(tbc ? 1 : 0);                           // 0 - normal, 1 - TBC, must be set in database manually for each account 
    408     SendPacket(&packet); 
    409  
    410     ///- Create a new WorldSession for the player and add it to the World 
    411     _session = new WorldSession(id, this,security,tbc,mutetime,locale); 
    412     sWorld.AddSession(_session); 
    413  
    414     if(sLog.IsOutDebug())                                   // optimize disabled debug output 
    415     { 
    416         sLog.outDebug( "SOCKET: Client '%s' authenticated successfully.", account.c_str() ); 
    417         sLog.outDebug( "Account: '%s' Logged in from IP %s.", account.c_str(), GetRemoteAddress().c_str()); 
    418     } 
    419  
    420     ///- Update the last_ip in the database 
    421     //No SQL injection, username escaped. 
    422     std::string address = GetRemoteAddress(); 
    423     loginDatabase.escape_string(address); 
    424     loginDatabase.PExecute("UPDATE account SET last_ip = '%s' WHERE username = '%s'",address.c_str(), safe_account.c_str()); 
    425  
    426     // do small delay (10ms) at accepting successful authed connection to prevent dropping packets by client 
    427     // don't must harm anyone (let login ~100 accounts in 1 sec ;) ) 
    428     #ifdef WIN32 
    429     Sleep(10); 
    430     #else 
    431     ZThread::Thread::sleep(10); 
    432     #endif 
    433  
    434     ///- Check that we do not exceed the maximum number of online players in the realm 
    435     uint32 Sessions  = sWorld.GetActiveAndQueuedSessionCount(); 
    436     uint32 pLimit    = sWorld.GetPlayerAmountLimit(); 
    437     uint32 QueueSize = sWorld.GetQueueSize();               //number of players in the queue 
    438     bool   inQueue   = false; 
    439     --Sessions;                                             //so we don't count the user trying to login as a session and queue the socket that we are using 
    440  
    441     if( pLimit >  0 && Sessions >= pLimit && security == SEC_PLAYER ) 
    442     { 
    443         sWorld.AddQueuedPlayer(this); 
    444         SendAuthWaitQue(sWorld.GetQueuePos(this)); 
    445         sWorld.UpdateMaxSessionCounters(); 
    446         sLog.outDetail( "PlayerQueue: %s is in Queue Position (%u).",safe_account.c_str(),++QueueSize); 
    447         inQueue = true; 
    448     } 
    449  
    450     ///- Create and send the Addon packet 
    451     if(sAddOnHandler.BuildAddonPacket(&recvPacket, &SendAddonPacked)) 
    452         SendPacket(&SendAddonPacked); 
    453  
    454     if(inQueue) 
    455         return; 
    456  
    457     sWorld.UpdateMaxSessionCounters(); 
    458  
    459     // Updates the population 
    460     if (pLimit > 0) 
    461     { 
    462         float popu = sWorld.GetActiveSessionCount();        //updated number of users on the server 
    463         popu /= pLimit; 
    464         popu *= 2; 
    465         loginDatabase.PExecute("UPDATE realmlist SET population = '%f' WHERE id = '%d'",popu,realmID); 
    466         sLog.outDetail( "Server Population (%f).",popu); 
    467     } 
    468  
    469     return; 
    470 } 
    471  
    472 /// Handle the Ping packet 
    473 void WorldSocket::_HandlePing(WorldPacket& recvPacket) 
    474 { 
    475     uint32 ping; 
    476     uint32 latency; 
    477  
    478     CHECK_PACKET_SIZE(recvPacket,8); 
    479  
    480     ///- Get the ping packet content 
    481     recvPacket >> ping; 
    482     recvPacket >> latency; 
    483  
    484     if (_session ) 
    485         _session->SetLatency(latency); 
    486  
    487     ///- check ping speed for players 
    488     if(_session && _session->GetSecurity() == SEC_PLAYER) 
    489     { 
    490         uint32 cur_mstime = getMSTime(); 
    491  
    492         // can overflow and start from 0 
    493         uint32 diff_mstime = getMSTimeDiff(m_LastPingMSTime,cur_mstime); 
    494         m_LastPingMSTime = cur_mstime; 
    495         if(diff_mstime < 27000)                             // should be 30000 (=30 secs), add little tolerance 
    496         { 
    497             ++m_OverSpeedPings; 
    498  
    499             uint32 max_count = sWorld.getConfig(CONFIG_MAX_OVERSPEED_PINGS); 
    500             if(max_count && m_OverSpeedPings > max_count) 
     1005      else 
     1006        m_OverSpeedPings = 0; 
     1007    } 
     1008 
     1009  // critical section 
     1010  { 
     1011    ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); 
     1012 
     1013    if (m_Session) 
     1014      m_Session->SetLatency (latency); 
     1015    else 
     1016      { 
     1017        sLog.outError ("WorldSocket::HandlePing: peer sent CMSG_PING, " 
     1018                       "but is not authenticated or got recently kicked," 
     1019                       " adress = %s", 
     1020                       this->GetRemoteAddress ().c_str ()); 
     1021        return -1; 
     1022      } 
     1023  } 
     1024 
     1025  WorldPacket packet (SMSG_PONG, 4); 
     1026  packet << ping; 
     1027  return this->SendPacket (packet); 
     1028} 
     1029 
     1030int 
     1031WorldSocket::iSendPacket (const WorldPacket& pct) 
     1032{ 
     1033  if (m_OutBuffer->space () < pct.size () + sizeof (ServerPktHeader)) 
     1034    { 
     1035      errno = ENOBUFS; 
     1036      return -1; 
     1037    } 
     1038 
     1039  ServerPktHeader header; 
     1040 
     1041  header.cmd = pct.GetOpcode (); 
     1042 
     1043#if ACE_BYTE_ORDER == ACE_BIG_ENDIAN 
     1044  header.cmd = ACE_SWAP_WORD (header.cmd) 
     1045#endif 
     1046           
     1047  header.size = (uint16) pct.size () + 2; 
     1048  header.size = ACE_HTONS (header.size); 
     1049 
     1050  m_Crypt.EncryptSend ((uint8*) & header, sizeof (header)); 
     1051 
     1052  if (m_OutBuffer->copy ((char*) & header, sizeof (header)) == -1) 
     1053    ACE_ASSERT (false); 
     1054 
     1055  if (!pct.empty ()) 
     1056    if (m_OutBuffer->copy ((char*) pct.contents (), pct.size ()) == -1) 
     1057      ACE_ASSERT (false); 
     1058 
     1059  return 0; 
     1060} 
     1061 
     1062bool 
     1063WorldSocket::iFlushPacketQueue () 
     1064{ 
     1065  WorldPacket *pct; 
     1066  bool haveone = false; 
     1067 
     1068  while (m_PacketQueue.dequeue_head (pct) == 0) 
     1069    { 
     1070      if (iSendPacket (*pct) == -1) 
     1071        { 
     1072          if (m_PacketQueue.enqueue_head (pct) == -1) 
    5011073            { 
    502                 sLog.outBasic("Player %s from account id %u kicked for overspeed ping packets from client (non-playable connection lags or cheating) ",_session->GetPlayerName(),_session->GetAccountId()); 
    503                 _session->KickPlayer(); 
    504                 return; 
     1074              delete pct; 
     1075              sLog.outError ("WorldSocket::iFlushPacketQueue m_PacketQueue->enqueue_head"); 
     1076              return false; 
    5051077            } 
    506         } 
    507         else 
    508             m_OverSpeedPings = 0; 
    509  
    510     } 
    511  
    512     ///- And put the pong answer in the to-be-sent queue 
    513     WorldPacket packet( SMSG_PONG, 4 ); 
    514     packet << ping; 
    515     SendPacket(&packet); 
    516  
    517     return; 
    518 } 
    519  
    520 /// Handle the update order for the socket 
    521 void WorldSocket::SendSinglePacket() 
    522 { 
    523     WorldPacket *packet; 
    524     ServerPktHeader hdr; 
    525  
    526     ///- If we have packet to send 
    527     if (!_sendQueue.empty()) 
    528     { 
    529         packet = _sendQueue.next(); 
    530  
    531         hdr.size = ntohs((uint16)packet->size() + 2); 
    532         hdr.cmd = packet->GetOpcode(); 
    533  
    534         if( sWorldLog.LogWorld() ) 
    535         { 
    536             sWorldLog.Log("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", 
    537                 (uint32)GetSocket(), 
    538                 packet->size(), 
    539                 LookupOpcodeName(packet->GetOpcode()), 
    540                 packet->GetOpcode()); 
    541  
    542             uint32 p = 0; 
    543             while (p < packet->size()) 
    544             { 
    545                 for (uint32 j = 0; j < 16 && p < packet->size(); j++) 
    546                     sWorldLog.Log("%.2X ", (*packet)[p++]); 
    547  
    548                 sWorldLog.Log("\n"); 
    549             } 
    550  
    551             sWorldLog.Log("\n\n"); 
    552         } 
    553  
    554         ///- Encrypt (if needed) the header 
    555         _crypt.EncryptSend((uint8*)&hdr, 4); 
    556  
    557         ///- Send the header and body to the client 
    558         TcpSocket::SendBuf((char*)&hdr, 4); 
    559         if(!packet->empty()) TcpSocket::SendBuf((char*)packet->contents(), packet->size()); 
    560  
    561         delete packet; 
    562     } 
    563 } 
    564  
    565 void WorldSocket::Update(time_t diff) 
    566 { 
    567     const uint32 SEND_PACKETS_MAX = 100; 
    568     const uint32 SEND_BUFFER_SIZE = 1024; 
    569  
    570     uint8 sendBuffer[SEND_BUFFER_SIZE]; 
    571  
    572     while (!_sendQueue.empty()) 
    573     { 
    574         bool haveBigPacket = false; 
    575         uint32 bufferSize = 0; 
    576  
    577         ///- While we have packets to send 
    578         for (uint32 packetCount = 0; (packetCount < SEND_PACKETS_MAX) && !_sendQueue.empty(); packetCount++) 
    579         { 
    580             ServerPktHeader *hdr = (ServerPktHeader*)&sendBuffer[bufferSize]; 
    581  
    582             // check merge possibility. 
    583             WorldPacket *front = _sendQueue.front(); 
    584             uint32 packetSize = front->size(); 
    585  
    586             if ((sizeof(*hdr) + packetSize) > SEND_BUFFER_SIZE) 
    587             { 
    588                 haveBigPacket = true; 
    589                 break; 
    590             } 
    591  
    592             if ((bufferSize + sizeof(*hdr) + packetSize) > sizeof(sendBuffer)) 
    593                 break; 
    594  
    595             // can be merged 
    596             WorldPacket *packet = _sendQueue.next(); 
    597  
    598             hdr->size = ntohs((uint16)packetSize + 2); 
    599             hdr->cmd = packet->GetOpcode(); 
    600  
    601             if( sWorldLog.LogWorld() ) 
    602             { 
    603                 sWorldLog.Log("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", 
    604                     (uint32)GetSocket(), 
    605                     packetSize, 
    606                     LookupOpcodeName(packet->GetOpcode()), 
    607                     packet->GetOpcode()); 
    608  
    609                 uint32 p = 0; 
    610                 while (p < packetSize) 
    611                 { 
    612                     for (uint32 j = 0; j < 16 && p < packetSize; j++) 
    613                         sWorldLog.Log("%.2X ", (*packet)[p++]); 
    614  
    615                     sWorldLog.Log("\n"); 
    616                 } 
    617  
    618                 sWorldLog.Log("\n\n"); 
    619             } 
    620  
    621             ///- Encrypt (if needed) the header 
    622             _crypt.EncryptSend((uint8*)hdr, sizeof(*hdr)); 
    623             bufferSize += sizeof(*hdr); 
    624  
    625             if (packetSize) 
    626             { 
    627                 memcpy(&sendBuffer[bufferSize], packet->contents(), packetSize); 
    628                 bufferSize += packetSize; 
    629             } 
    630  
    631             ///- Send the header and body to the client 
    632             delete packet; 
    633         } 
    634  
    635         // send merged packets 
    636         if (bufferSize) TcpSocket::SendBuf((char*)sendBuffer, bufferSize); 
    637         // send too big non-merged packet 
    638         if (haveBigPacket) SendSinglePacket(); 
    639     } 
    640 } 
    641  
    642 /// Handle the authentication waiting queue (to be completed) 
    643 void WorldSocket::SendAuthWaitQue(uint32 position) 
    644 { 
    645     if(position == 0) 
    646     { 
    647         WorldPacket packet( SMSG_AUTH_RESPONSE, 1 ); 
    648         packet << uint8( AUTH_OK ); 
    649         SendPacket(&packet); 
    650     } 
    651     else 
    652     { 
    653         WorldPacket packet( SMSG_AUTH_RESPONSE, 5 ); 
    654         packet << uint8( AUTH_WAIT_QUEUE ); 
    655         packet << uint32 (position);                        //amount of players in queue 
    656         SendPacket(&packet); 
    657     } 
    658 } 
    659  
    660 void WorldSocket::SizeError(WorldPacket const& packet, uint32 size) const 
    661 { 
    662     sLog.outError("Client send packet %s (%u) with size %u but expected %u (attempt crash server?), skipped", 
    663         LookupOpcodeName(packet.GetOpcode()),packet.GetOpcode(),packet.size(),size); 
    664 } 
     1078 
     1079          break; 
     1080        } 
     1081      else 
     1082        { 
     1083          haveone = true; 
     1084          delete pct; 
     1085        } 
     1086    } 
     1087 
     1088  return haveone; 
     1089}