2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <ace/Message_Block.h>
20 #include <ace/OS_NS_string.h>
21 #include <ace/OS_NS_unistd.h>
22 #include <ace/os_include/arpa/os_inet.h>
23 #include <ace/os_include/netinet/os_tcp.h>
24 #include <ace/os_include/sys/os_types.h>
25 #include <ace/os_include/sys/os_socket.h>
26 #include <ace/OS_NS_string.h>
27 #include <ace/Reactor.h>
28 #include <ace/Auto_Ptr.h>
30 #include "WorldSocket.h"
35 #include "WorldPacket.h"
36 #include "SharedDefines.h"
37 #include "ByteBuffer.h"
38 #include "AddonHandler.h"
40 #include "Database/DatabaseEnv.h"
41 #include "Auth/Sha1.h"
42 #include "WorldSession.h"
43 #include "WorldSocketMgr.h"
47 #if defined( __GNUC__ )
53 struct ServerPktHeader
56 * size is the length of the payload _plus_ the length of the opcode
58 ServerPktHeader(uint32 size
, uint16 cmd
) : size(size
)
63 sLog
.outDebug("initializing large server to client packet. Size: %u, cmd: %u", size
, cmd
);
64 header
[headerIndex
++] = 0x80|(0xFF &(size
>>16));
66 header
[headerIndex
++] = 0xFF &(size
>>8);
67 header
[headerIndex
++] = 0xFF &size
;
69 header
[headerIndex
++] = 0xFF & cmd
;
70 header
[headerIndex
++] = 0xFF & (cmd
>>8);
73 uint8
getHeaderLength()
75 // cmd = 2 bytes, size= 2||3bytes
76 return 2+(isLargePacket()?3:2);
88 struct ClientPktHeader
94 #if defined( __GNUC__ )
100 WorldSocket::WorldSocket (void) :
105 m_Header (sizeof (ClientPktHeader
)),
107 m_OutBufferSize (65536),
109 m_Seed (static_cast<uint32
> (rand32 ())),
110 m_OverSpeedPings (0),
111 m_LastPingTime (ACE_Time_Value::zero
)
113 reference_counting_policy ().value (ACE_Event_Handler::Reference_Counting_Policy::ENABLED
);
115 msg_queue()->high_water_mark(8*1024*1024);
116 msg_queue()->low_water_mark(8*1024*1024);
119 WorldSocket::~WorldSocket (void)
125 m_OutBuffer
->release ();
132 bool WorldSocket::IsClosed (void) const
137 void WorldSocket::CloseSocket (void)
140 ACE_GUARD (LockType
, Guard
, m_OutBufferLock
);
146 peer ().close_writer ();
150 ACE_GUARD (LockType
, Guard
, m_SessionLock
);
156 const std::string
& WorldSocket::GetRemoteAddress (void) const
161 int WorldSocket::SendPacket (const WorldPacket
& pct
)
163 ACE_GUARD_RETURN (LockType
, Guard
, m_OutBufferLock
, -1);
168 // Dump outgoing packet.
169 if (sWorldLog
.LogWorld ())
171 sWorldLog
.Log ("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n",
172 (uint32
) get_handle (),
174 LookupOpcodeName (pct
.GetOpcode ()),
178 while (p
< pct
.size ())
180 for (uint32 j
= 0; j
< 16 && p
< pct
.size (); j
++)
181 sWorldLog
.Log ("%.2X ", const_cast<WorldPacket
&>(pct
)[p
++]);
183 sWorldLog
.Log ("\n");
186 sWorldLog
.Log ("\n\n");
189 ServerPktHeader
header(pct
.size()+2, pct
.GetOpcode());
190 m_Crypt
.EncryptSend ( header
.header
, header
.getHeaderLength());
192 if (m_OutBuffer
->space () >= pct
.size () + header
.getHeaderLength() && msg_queue()->is_empty())
194 // Put the packet on the buffer.
195 if (m_OutBuffer
->copy ((char*) header
.header
, header
.getHeaderLength()) == -1)
199 if (m_OutBuffer
->copy ((char*) pct
.contents (), pct
.size ()) == -1)
204 // Enqueue the packet.
205 ACE_Message_Block
* mb
;
207 ACE_NEW_RETURN(mb
, ACE_Message_Block(pct
.size () + header
.getHeaderLength()), -1);
209 mb
->copy((char*) header
.header
, header
.getHeaderLength());
212 mb
->copy((const char*)pct
.contents(), pct
.size ());
214 if(msg_queue()->enqueue_tail(mb
,(ACE_Time_Value
*)&ACE_Time_Value::zero
) == -1)
216 sLog
.outError("WorldSocket::SendPacket enqueue_tail");
225 long WorldSocket::AddReference (void)
227 return static_cast<long> (add_reference ());
230 long WorldSocket::RemoveReference (void)
232 return static_cast<long> (remove_reference ());
235 int WorldSocket::open (void *a
)
239 // Prevent double call to this func.
243 // This will also prevent the socket from being Updated
244 // while we are initializing it.
247 // Hook for the manager.
248 if (sWorldSocketMgr
->OnSocketOpen (this) == -1)
251 // Allocate the buffer.
252 ACE_NEW_RETURN (m_OutBuffer
, ACE_Message_Block (m_OutBufferSize
), -1);
254 // Store peer address.
255 ACE_INET_Addr remote_addr
;
257 if (peer ().get_remote_addr (remote_addr
) == -1)
259 sLog
.outError ("WorldSocket::open: peer ().get_remote_addr errno = %s", ACE_OS::strerror (errno
));
263 m_Address
= remote_addr
.get_host_addr ();
265 // Send startup packet.
266 WorldPacket
packet (SMSG_AUTH_CHALLENGE
, 4);
269 if (SendPacket (packet
) == -1)
272 // Register with ACE Reactor
273 if (reactor ()->register_handler(this, ACE_Event_Handler::READ_MASK
| ACE_Event_Handler::WRITE_MASK
) == -1)
275 sLog
.outError ("WorldSocket::open: unable to register client handler errno = %s", ACE_OS::strerror (errno
));
279 // reactor takes care of the socket from now on
285 int WorldSocket::close (int)
296 int WorldSocket::handle_input (ACE_HANDLE
)
301 switch (handle_input_missing_data ())
305 if ((errno
== EWOULDBLOCK
) ||
308 return Update (); // interesting line ,isn't it ?
311 DEBUG_LOG ("WorldSocket::handle_input: Peer error closing connection errno = %s", ACE_OS::strerror (errno
));
318 DEBUG_LOG ("WorldSocket::handle_input: Peer has closed connection\n");
326 return Update (); // another interesting line ;)
329 ACE_NOTREACHED(return -1);
332 int WorldSocket::handle_output (ACE_HANDLE
)
334 ACE_GUARD_RETURN (LockType
, Guard
, m_OutBufferLock
, -1);
339 const size_t send_len
= m_OutBuffer
->length ();
342 return handle_output_queue (Guard
);
345 ssize_t n
= peer ().send (m_OutBuffer
->rd_ptr (), send_len
, MSG_NOSIGNAL
);
347 ssize_t n
= peer ().send (m_OutBuffer
->rd_ptr (), send_len
);
348 #endif // MSG_NOSIGNAL
354 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
355 return schedule_wakeup_output (Guard
);
359 else if (n
< send_len
) //now n > 0
361 m_OutBuffer
->rd_ptr (static_cast<size_t> (n
));
363 // move the data to the base of the buffer
364 m_OutBuffer
->crunch ();
366 return schedule_wakeup_output (Guard
);
368 else //now n == send_len
370 m_OutBuffer
->reset ();
372 return handle_output_queue (Guard
);
375 ACE_NOTREACHED (return 0);
378 int WorldSocket::handle_output_queue (GuardType
& g
)
380 if(msg_queue()->is_empty())
381 return cancel_wakeup_output(g
);
383 ACE_Message_Block
*mblk
;
385 if(msg_queue()->dequeue_head(mblk
, (ACE_Time_Value
*)&ACE_Time_Value::zero
) == -1)
387 sLog
.outError("WorldSocket::handle_output_queue dequeue_head");
391 const size_t send_len
= mblk
->length ();
394 ssize_t n
= peer ().send (mblk
->rd_ptr (), send_len
, MSG_NOSIGNAL
);
396 ssize_t n
= peer ().send (mblk
->rd_ptr (), send_len
);
397 #endif // MSG_NOSIGNAL
407 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
409 msg_queue()->enqueue_head(mblk
, (ACE_Time_Value
*) &ACE_Time_Value::zero
);
410 return schedule_wakeup_output (g
);
416 else if (n
< send_len
) //now n > 0
418 mblk
->rd_ptr (static_cast<size_t> (n
));
420 if (msg_queue()->enqueue_head(mblk
, (ACE_Time_Value
*) &ACE_Time_Value::zero
) == -1)
422 sLog
.outError("WorldSocket::handle_output_queue enqueue_head");
427 return schedule_wakeup_output (g
);
429 else //now n == send_len
433 return msg_queue()->is_empty() ? cancel_wakeup_output(g
) : ACE_Event_Handler::WRITE_MASK
;
436 ACE_NOTREACHED(return -1);
439 int WorldSocket::handle_close (ACE_HANDLE h
, ACE_Reactor_Mask
)
443 ACE_GUARD_RETURN (LockType
, Guard
, m_OutBufferLock
, -1);
447 if (h
== ACE_INVALID_HANDLE
)
448 peer ().close_writer ();
453 ACE_GUARD_RETURN (LockType
, Guard
, m_SessionLock
, -1);
461 int WorldSocket::Update (void)
466 if (m_OutActive
|| (m_OutBuffer
->length () == 0 && msg_queue()->is_empty()))
471 ret
= handle_output (get_handle ());
477 int WorldSocket::handle_input_header (void)
479 ACE_ASSERT (m_RecvWPct
== NULL
);
481 ACE_ASSERT (m_Header
.length () == sizeof (ClientPktHeader
));
483 m_Crypt
.DecryptRecv ((ACE_UINT8
*) m_Header
.rd_ptr (), sizeof (ClientPktHeader
));
485 ClientPktHeader
& header
= *((ClientPktHeader
*) m_Header
.rd_ptr ());
487 EndianConvertReverse(header
.size
);
488 EndianConvert(header
.cmd
);
490 if ((header
.size
< 4) || (header
.size
> 10240) ||
491 (header
.cmd
< 0) || (header
.cmd
> 10240) )
493 sLog
.outError ("WorldSocket::handle_input_header: client sent mailformed packet size = %d , cmd = %d",
494 header
.size
, header
.cmd
);
502 ACE_NEW_RETURN (m_RecvWPct
, WorldPacket ((uint16
) header
.cmd
, header
.size
), -1);
506 m_RecvWPct
->resize (header
.size
);
507 m_RecvPct
.base ((char*) m_RecvWPct
->contents (), m_RecvWPct
->size ());
511 ACE_ASSERT(m_RecvPct
.space() == 0);
517 int WorldSocket::handle_input_payload (void)
519 // set errno properly here on error !!!
520 // now have a header and payload
522 ACE_ASSERT (m_RecvPct
.space () == 0);
523 ACE_ASSERT (m_Header
.space () == 0);
524 ACE_ASSERT (m_RecvWPct
!= NULL
);
526 const int ret
= ProcessIncoming (m_RecvWPct
);
528 m_RecvPct
.base (NULL
, 0);
540 int WorldSocket::handle_input_missing_data (void)
544 ACE_Data_Block
db ( sizeof (buf
),
545 ACE_Message_Block::MB_DATA
,
549 ACE_Message_Block::DONT_DELETE
,
552 ACE_Message_Block
message_block(&db
,
553 ACE_Message_Block::DONT_DELETE
,
556 const size_t recv_size
= message_block
.space ();
558 const ssize_t n
= peer ().recv (message_block
.wr_ptr (),
564 message_block
.wr_ptr (n
);
566 while (message_block
.length () > 0)
568 if (m_Header
.space () > 0)
570 //need to receive the header
571 const size_t to_header
= (message_block
.length () > m_Header
.space () ? m_Header
.space () : message_block
.length ());
572 m_Header
.copy (message_block
.rd_ptr (), to_header
);
573 message_block
.rd_ptr (to_header
);
575 if (m_Header
.space () > 0)
577 // Couldn't receive the whole header this time.
578 ACE_ASSERT (message_block
.length () == 0);
583 // We just received nice new header
584 if (handle_input_header () == -1)
586 ACE_ASSERT ((errno
!= EWOULDBLOCK
) && (errno
!= EAGAIN
));
591 // Its possible on some error situations that this happens
592 // for example on closing when epoll receives more chunked data and stuff
593 // hope this is not hack ,as proper m_RecvWPct is asserted around
596 sLog
.outError ("Forcing close on input m_RecvWPct = NULL");
601 // We have full read header, now check the data payload
602 if (m_RecvPct
.space () > 0)
604 //need more data in the payload
605 const size_t to_data
= (message_block
.length () > m_RecvPct
.space () ? m_RecvPct
.space () : message_block
.length ());
606 m_RecvPct
.copy (message_block
.rd_ptr (), to_data
);
607 message_block
.rd_ptr (to_data
);
609 if (m_RecvPct
.space () > 0)
611 // Couldn't receive the whole data this time.
612 ACE_ASSERT (message_block
.length () == 0);
618 //just received fresh new payload
619 if (handle_input_payload () == -1)
621 ACE_ASSERT ((errno
!= EWOULDBLOCK
) && (errno
!= EAGAIN
));
626 return n
== recv_size
? 1 : 2;
629 int WorldSocket::cancel_wakeup_output (GuardType
& g
)
638 if (reactor ()->cancel_wakeup
639 (this, ACE_Event_Handler::WRITE_MASK
) == -1)
641 // would be good to store errno from reactor with errno guard
642 sLog
.outError ("WorldSocket::cancel_wakeup_output");
649 int WorldSocket::schedule_wakeup_output (GuardType
& g
)
658 if (reactor ()->schedule_wakeup
659 (this, ACE_Event_Handler::WRITE_MASK
) == -1)
661 sLog
.outError ("WorldSocket::schedule_wakeup_output");
668 int WorldSocket::ProcessIncoming (WorldPacket
* new_pct
)
670 ACE_ASSERT (new_pct
);
673 ACE_Auto_Ptr
<WorldPacket
> aptr (new_pct
);
675 const ACE_UINT16 opcode
= new_pct
->GetOpcode ();
680 // Dump received packet.
681 if (sWorldLog
.LogWorld ())
683 sWorldLog
.Log ("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n",
684 (uint32
) get_handle (),
686 LookupOpcodeName (new_pct
->GetOpcode ()),
687 new_pct
->GetOpcode ());
690 while (p
< new_pct
->size ())
692 for (uint32 j
= 0; j
< 16 && p
< new_pct
->size (); j
++)
693 sWorldLog
.Log ("%.2X ", (*new_pct
)[p
++]);
694 sWorldLog
.Log ("\n");
696 sWorldLog
.Log ("\n\n");
699 // like one switch ;)
700 if (opcode
== CMSG_PING
)
702 return HandlePing (*new_pct
);
704 else if (opcode
== CMSG_AUTH_SESSION
)
708 sLog
.outError ("WorldSocket::ProcessIncoming: Player send CMSG_AUTH_SESSION again");
712 return HandleAuthSession (*new_pct
);
714 else if (opcode
== CMSG_KEEP_ALIVE
)
716 DEBUG_LOG ("CMSG_KEEP_ALIVE ,size: %d", new_pct
->size ());
722 ACE_GUARD_RETURN (LockType
, Guard
, m_SessionLock
, -1);
724 if (m_Session
!= NULL
)
726 // OK ,give the packet to WorldSession
728 // WARNINIG here we call it with locks held.
729 // Its possible to cause deadlock if QueuePacket calls back
730 m_Session
->QueuePacket (new_pct
);
735 sLog
.outError ("WorldSocket::ProcessIncoming: Client not authed opcode = ", opcode
);
740 ACE_NOTREACHED (return 0);
743 int WorldSocket::HandleAuthSession (WorldPacket
& recvPacket
)
745 // NOTE: ATM the socket is singlethread, have this in mind ...
749 uint32 BuiltNumberClient
;
752 LocaleConstant locale
;
755 BigNumber v
, s
, g
, N
, x
, I
;
756 WorldPacket packet
, SendAddonPacked
;
760 if (recvPacket
.size () < (4 + 4 + 1 + 4 + 20))
762 sLog
.outError ("WorldSocket::HandleAuthSession: wrong packet size");
766 // Read the content of the packet
767 recvPacket
>> BuiltNumberClient
; // for now no use
769 recvPacket
>> account
;
772 if (recvPacket
.size () < (4 + 4 + (account
.size () + 1) + 4 + 20))
774 sLog
.outError ("WorldSocket::HandleAuthSession: wrong packet size second check");
778 recvPacket
>> clientSeed
;
779 recvPacket
.read (digest
, 20);
781 DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, clientseed %u",
787 // Get the account information from the realmd database
788 std::string safe_account
= account
; // Duplicate, else will screw the SHA hash verification below
789 loginDatabase
.escape_string (safe_account
);
790 // No SQL injection, username escaped.
792 QueryResult
*result
=
793 loginDatabase
.PQuery ("SELECT "
799 "sha_pass_hash, " //5
806 "WHERE username = '%s'",
807 safe_account
.c_str ());
809 // Stop if the account is not found
812 packet
.Initialize (SMSG_AUTH_RESPONSE
, 1);
813 packet
<< uint8 (AUTH_UNKNOWN_ACCOUNT
);
817 sLog
.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
821 Field
* fields
= result
->Fetch ();
823 expansion
= ((sWorld
.getConfig(CONFIG_EXPANSION
) > fields
[8].GetUInt8()) ? fields
[8].GetUInt8() : sWorld
.getConfig(CONFIG_EXPANSION
));
825 N
.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
827 I
.SetHexStr (fields
[5].GetString ());
829 //In case of leading zeros in the I hash, restore them
830 uint8 mDigest
[SHA_DIGEST_LENGTH
];
831 memset (mDigest
, 0, SHA_DIGEST_LENGTH
);
833 if (I
.GetNumBytes () <= SHA_DIGEST_LENGTH
)
834 memcpy (mDigest
, I
.AsByteArray (), I
.GetNumBytes ());
836 std::reverse (mDigest
, mDigest
+ SHA_DIGEST_LENGTH
);
838 s
.SetHexStr (fields
[7].GetString ());
839 sha1
.UpdateData (s
.AsByteArray (), s
.GetNumBytes ());
840 sha1
.UpdateData (mDigest
, SHA_DIGEST_LENGTH
);
842 x
.SetBinary (sha1
.GetDigest (), sha1
.GetLength ());
845 const char* sStr
= s
.AsHexStr (); //Must be freed by OPENSSL_free()
846 const char* vStr
= v
.AsHexStr (); //Must be freed by OPENSSL_free()
847 const char* vold
= fields
[6].GetString ();
849 DEBUG_LOG ("WorldSocket::HandleAuthSession: (s,v) check s: %s v_old: %s v_new: %s",
854 loginDatabase
.PExecute ("UPDATE account "
858 "WHERE username = '%s'",
859 safe_account
.c_str ());
861 if (!vold
|| strcmp (vStr
, vold
))
863 packet
.Initialize (SMSG_AUTH_RESPONSE
, 1);
864 packet
<< uint8 (AUTH_UNKNOWN_ACCOUNT
);
867 OPENSSL_free ((void*) sStr
);
868 OPENSSL_free ((void*) vStr
);
870 sLog
.outBasic ("WorldSocket::HandleAuthSession: User not logged.");
874 OPENSSL_free ((void*) sStr
);
875 OPENSSL_free ((void*) vStr
);
877 ///- Re-check ip locking (same check as in realmd).
878 if (fields
[4].GetUInt8 () == 1) // if ip is locked
880 if (strcmp (fields
[3].GetString (), GetRemoteAddress ().c_str ()))
882 packet
.Initialize (SMSG_AUTH_RESPONSE
, 1);
883 packet
<< uint8 (AUTH_FAILED
);
887 sLog
.outBasic ("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs).");
892 id
= fields
[0].GetUInt32 ();
893 security
= fields
[1].GetUInt16 ();
894 if(security
> SEC_ADMINISTRATOR
) // prevent invalid security settings in DB
895 security
= SEC_ADMINISTRATOR
;
897 K
.SetHexStr (fields
[2].GetString ());
899 time_t mutetime
= time_t (fields
[9].GetUInt64 ());
901 locale
= LocaleConstant (fields
[10].GetUInt8 ());
902 if (locale
>= MAX_LOCALE
)
903 locale
= LOCALE_enUS
;
907 // Re-check account ban (same check as in realmd)
908 QueryResult
*banresult
=
909 loginDatabase
.PQuery ("SELECT "
912 "FROM account_banned "
917 if (banresult
) // if account banned
919 packet
.Initialize (SMSG_AUTH_RESPONSE
, 1);
920 packet
<< uint8 (AUTH_BANNED
);
925 sLog
.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
929 // Check locked state for server
930 AccountTypes allowedAccountType
= sWorld
.GetPlayerSecurityLimit ();
932 if (allowedAccountType
> SEC_PLAYER
&& security
< allowedAccountType
)
934 WorldPacket
Packet (SMSG_AUTH_RESPONSE
, 1);
935 Packet
<< uint8 (AUTH_UNAVAILABLE
);
939 sLog
.outBasic ("WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
943 // Check that Key and account name are the same on client and server
947 uint32 seed
= m_Seed
;
949 sha
.UpdateData (account
);
950 sha
.UpdateData ((uint8
*) & t
, 4);
951 sha
.UpdateData ((uint8
*) & clientSeed
, 4);
952 sha
.UpdateData ((uint8
*) & seed
, 4);
953 sha
.UpdateBigNumbers (&K
, NULL
);
956 if (memcmp (sha
.GetDigest (), digest
, 20))
958 packet
.Initialize (SMSG_AUTH_RESPONSE
, 1);
959 packet
<< uint8 (AUTH_FAILED
);
963 sLog
.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed).");
967 std::string address
= GetRemoteAddress ();
969 DEBUG_LOG ("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.",
973 // Update the last_ip in the database
974 // No SQL injection, username escaped.
975 loginDatabase
.escape_string (address
);
977 loginDatabase
.PExecute ("UPDATE account "
978 "SET last_ip = '%s' "
979 "WHERE username = '%s'",
981 safe_account
.c_str ());
983 // NOTE ATM the socket is singlethreaded, have this in mind ...
984 ACE_NEW_RETURN (m_Session
, WorldSession (id
, this, security
, expansion
, mutetime
, locale
), -1);
989 m_Session
->LoadAccountData();
991 // In case needed sometime the second arg is in microseconds 1 000 000 = 1 sec
992 ACE_OS::sleep (ACE_Time_Value (0, 10000));
994 sWorld
.AddSession (m_Session
);
996 // Create and send the Addon packet
997 if (sAddOnHandler
.BuildAddonPacket (&recvPacket
, &SendAddonPacked
))
998 SendPacket (SendAddonPacked
);
1003 int WorldSocket::HandlePing (WorldPacket
& recvPacket
)
1008 if (recvPacket
.size () < 8)
1010 sLog
.outError ("WorldSocket::_HandlePing wrong packet size");
1014 // Get the ping packet content
1016 recvPacket
>> latency
;
1018 if (m_LastPingTime
== ACE_Time_Value::zero
)
1019 m_LastPingTime
= ACE_OS::gettimeofday (); // for 1st ping
1022 ACE_Time_Value cur_time
= ACE_OS::gettimeofday ();
1023 ACE_Time_Value
diff_time (cur_time
);
1024 diff_time
-= m_LastPingTime
;
1025 m_LastPingTime
= cur_time
;
1027 if (diff_time
< ACE_Time_Value (27))
1031 uint32 max_count
= sWorld
.getConfig (CONFIG_MAX_OVERSPEED_PINGS
);
1033 if (max_count
&& m_OverSpeedPings
> max_count
)
1035 ACE_GUARD_RETURN (LockType
, Guard
, m_SessionLock
, -1);
1037 if (m_Session
&& m_Session
->GetSecurity () == SEC_PLAYER
)
1039 sLog
.outError ("WorldSocket::HandlePing: Player kicked for "
1040 "over-speed pings address = %s",
1041 GetRemoteAddress ().c_str ());
1048 m_OverSpeedPings
= 0;
1053 ACE_GUARD_RETURN (LockType
, Guard
, m_SessionLock
, -1);
1056 m_Session
->SetLatency (latency
);
1059 sLog
.outError ("WorldSocket::HandlePing: peer sent CMSG_PING, "
1060 "but is not authenticated or got recently kicked,"
1062 GetRemoteAddress ().c_str ());
1067 WorldPacket
packet (SMSG_PONG
, 4);
1069 return SendPacket (packet
);