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"
39 #include "Database/DatabaseEnv.h"
40 #include "Auth/Sha1.h"
41 #include "WorldSession.h"
42 #include "WorldSocketMgr.h"
46 #if defined( __GNUC__ )
52 struct ServerPktHeader
55 * size is the length of the payload _plus_ the length of the opcode
57 ServerPktHeader(uint32 size
, uint16 cmd
) : size(size
)
62 sLog
.outDebug("initializing large server to client packet. Size: %u, cmd: %u", size
, cmd
);
63 header
[headerIndex
++] = 0x80|(0xFF &(size
>>16));
65 header
[headerIndex
++] = 0xFF &(size
>>8);
66 header
[headerIndex
++] = 0xFF &size
;
68 header
[headerIndex
++] = 0xFF & cmd
;
69 header
[headerIndex
++] = 0xFF & (cmd
>>8);
72 uint8
getHeaderLength()
74 // cmd = 2 bytes, size= 2||3bytes
75 return 2+(isLargePacket()?3:2);
87 struct ClientPktHeader
93 #if defined( __GNUC__ )
99 WorldSocket::WorldSocket (void) :
104 m_Header (sizeof (ClientPktHeader
)),
106 m_OutBufferSize (65536),
108 m_Seed (static_cast<uint32
> (rand32 ())),
109 m_OverSpeedPings (0),
110 m_LastPingTime (ACE_Time_Value::zero
)
112 reference_counting_policy ().value (ACE_Event_Handler::Reference_Counting_Policy::ENABLED
);
114 msg_queue()->high_water_mark(8*1024*1024);
115 msg_queue()->low_water_mark(8*1024*1024);
118 WorldSocket::~WorldSocket (void)
124 m_OutBuffer
->release ();
131 bool WorldSocket::IsClosed (void) const
136 void WorldSocket::CloseSocket (void)
139 ACE_GUARD (LockType
, Guard
, m_OutBufferLock
);
145 peer ().close_writer ();
149 ACE_GUARD (LockType
, Guard
, m_SessionLock
);
155 const std::string
& WorldSocket::GetRemoteAddress (void) const
160 int WorldSocket::SendPacket (const WorldPacket
& pct
)
162 ACE_GUARD_RETURN (LockType
, Guard
, m_OutBufferLock
, -1);
167 // Dump outgoing packet.
168 if (sWorldLog
.LogWorld ())
170 sWorldLog
.Log ("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n",
171 (uint32
) get_handle (),
173 LookupOpcodeName (pct
.GetOpcode ()),
177 while (p
< pct
.size ())
179 for (uint32 j
= 0; j
< 16 && p
< pct
.size (); j
++)
180 sWorldLog
.Log ("%.2X ", const_cast<WorldPacket
&>(pct
)[p
++]);
182 sWorldLog
.Log ("\n");
185 sWorldLog
.Log ("\n\n");
188 ServerPktHeader
header(pct
.size()+2, pct
.GetOpcode());
189 m_Crypt
.EncryptSend ((uint8
*)header
.header
, header
.getHeaderLength());
191 if (m_OutBuffer
->space () >= pct
.size () + header
.getHeaderLength() && msg_queue()->is_empty())
193 // Put the packet on the buffer.
194 if (m_OutBuffer
->copy ((char*) header
.header
, header
.getHeaderLength()) == -1)
198 if (m_OutBuffer
->copy ((char*) pct
.contents (), pct
.size ()) == -1)
203 // Enqueue the packet.
204 ACE_Message_Block
* mb
;
206 ACE_NEW_RETURN(mb
, ACE_Message_Block(pct
.size () + header
.getHeaderLength()), -1);
208 mb
->copy((char*) header
.header
, header
.getHeaderLength());
211 mb
->copy((const char*)pct
.contents(), pct
.size ());
213 if(msg_queue()->enqueue_tail(mb
,(ACE_Time_Value
*)&ACE_Time_Value::zero
) == -1)
215 sLog
.outError("WorldSocket::SendPacket enqueue_tail");
224 long WorldSocket::AddReference (void)
226 return static_cast<long> (add_reference ());
229 long WorldSocket::RemoveReference (void)
231 return static_cast<long> (remove_reference ());
234 int WorldSocket::open (void *a
)
238 // Prevent double call to this func.
242 // This will also prevent the socket from being Updated
243 // while we are initializing it.
246 // Hook for the manager.
247 if (sWorldSocketMgr
->OnSocketOpen (this) == -1)
250 // Allocate the buffer.
251 ACE_NEW_RETURN (m_OutBuffer
, ACE_Message_Block (m_OutBufferSize
), -1);
253 // Store peer address.
254 ACE_INET_Addr remote_addr
;
256 if (peer ().get_remote_addr (remote_addr
) == -1)
258 sLog
.outError ("WorldSocket::open: peer ().get_remote_addr errno = %s", ACE_OS::strerror (errno
));
262 m_Address
= remote_addr
.get_host_addr ();
264 // Send startup packet.
265 WorldPacket
packet (SMSG_AUTH_CHALLENGE
, 4);
268 if (SendPacket (packet
) == -1)
271 // Register with ACE Reactor
272 if (reactor ()->register_handler(this, ACE_Event_Handler::READ_MASK
| ACE_Event_Handler::WRITE_MASK
) == -1)
274 sLog
.outError ("WorldSocket::open: unable to register client handler errno = %s", ACE_OS::strerror (errno
));
278 // reactor takes care of the socket from now on
284 int WorldSocket::close (int)
295 int WorldSocket::handle_input (ACE_HANDLE
)
300 switch (handle_input_missing_data ())
304 if ((errno
== EWOULDBLOCK
) ||
307 return Update (); // interesting line ,isn't it ?
310 DEBUG_LOG ("WorldSocket::handle_input: Peer error closing connection errno = %s", ACE_OS::strerror (errno
));
317 DEBUG_LOG ("WorldSocket::handle_input: Peer has closed connection");
325 return Update (); // another interesting line ;)
328 ACE_NOTREACHED(return -1);
331 int WorldSocket::handle_output (ACE_HANDLE
)
333 ACE_GUARD_RETURN (LockType
, Guard
, m_OutBufferLock
, -1);
338 const size_t send_len
= m_OutBuffer
->length ();
341 return handle_output_queue (Guard
);
344 ssize_t n
= peer ().send (m_OutBuffer
->rd_ptr (), send_len
, MSG_NOSIGNAL
);
346 ssize_t n
= peer ().send (m_OutBuffer
->rd_ptr (), send_len
);
347 #endif // MSG_NOSIGNAL
353 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
354 return schedule_wakeup_output (Guard
);
358 else if (n
< send_len
) //now n > 0
360 m_OutBuffer
->rd_ptr (static_cast<size_t> (n
));
362 // move the data to the base of the buffer
363 m_OutBuffer
->crunch ();
365 return schedule_wakeup_output (Guard
);
367 else //now n == send_len
369 m_OutBuffer
->reset ();
371 return handle_output_queue (Guard
);
374 ACE_NOTREACHED (return 0);
377 int WorldSocket::handle_output_queue (GuardType
& g
)
379 if(msg_queue()->is_empty())
380 return cancel_wakeup_output(g
);
382 ACE_Message_Block
*mblk
;
384 if(msg_queue()->dequeue_head(mblk
, (ACE_Time_Value
*)&ACE_Time_Value::zero
) == -1)
386 sLog
.outError("WorldSocket::handle_output_queue dequeue_head");
390 const size_t send_len
= mblk
->length ();
393 ssize_t n
= peer ().send (mblk
->rd_ptr (), send_len
, MSG_NOSIGNAL
);
395 ssize_t n
= peer ().send (mblk
->rd_ptr (), send_len
);
396 #endif // MSG_NOSIGNAL
406 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
408 msg_queue()->enqueue_head(mblk
, (ACE_Time_Value
*) &ACE_Time_Value::zero
);
409 return schedule_wakeup_output (g
);
415 else if (n
< send_len
) //now n > 0
417 mblk
->rd_ptr (static_cast<size_t> (n
));
419 if (msg_queue()->enqueue_head(mblk
, (ACE_Time_Value
*) &ACE_Time_Value::zero
) == -1)
421 sLog
.outError("WorldSocket::handle_output_queue enqueue_head");
426 return schedule_wakeup_output (g
);
428 else //now n == send_len
432 return msg_queue()->is_empty() ? cancel_wakeup_output(g
) : ACE_Event_Handler::WRITE_MASK
;
435 ACE_NOTREACHED(return -1);
438 int WorldSocket::handle_close (ACE_HANDLE h
, ACE_Reactor_Mask
)
442 ACE_GUARD_RETURN (LockType
, Guard
, m_OutBufferLock
, -1);
446 if (h
== ACE_INVALID_HANDLE
)
447 peer ().close_writer ();
452 ACE_GUARD_RETURN (LockType
, Guard
, m_SessionLock
, -1);
460 int WorldSocket::Update (void)
465 if (m_OutActive
|| (m_OutBuffer
->length () == 0 && msg_queue()->is_empty()))
470 ret
= handle_output (get_handle ());
476 int WorldSocket::handle_input_header (void)
478 ACE_ASSERT (m_RecvWPct
== NULL
);
480 ACE_ASSERT (m_Header
.length () == sizeof (ClientPktHeader
));
482 m_Crypt
.DecryptRecv ((uint8
*) m_Header
.rd_ptr (), sizeof (ClientPktHeader
));
484 ClientPktHeader
& header
= *((ClientPktHeader
*) m_Header
.rd_ptr ());
486 EndianConvertReverse(header
.size
);
487 EndianConvert(header
.cmd
);
489 if ((header
.size
< 4) || (header
.size
> 10240) || (header
.cmd
> 10240))
491 sLog
.outError ("WorldSocket::handle_input_header: client sent mailformed packet size = %d , cmd = %d",
492 header
.size
, header
.cmd
);
500 ACE_NEW_RETURN (m_RecvWPct
, WorldPacket ((uint16
) header
.cmd
, header
.size
), -1);
504 m_RecvWPct
->resize (header
.size
);
505 m_RecvPct
.base ((char*) m_RecvWPct
->contents (), m_RecvWPct
->size ());
509 ACE_ASSERT(m_RecvPct
.space() == 0);
515 int WorldSocket::handle_input_payload (void)
517 // set errno properly here on error !!!
518 // now have a header and payload
520 ACE_ASSERT (m_RecvPct
.space () == 0);
521 ACE_ASSERT (m_Header
.space () == 0);
522 ACE_ASSERT (m_RecvWPct
!= NULL
);
524 const int ret
= ProcessIncoming (m_RecvWPct
);
526 m_RecvPct
.base (NULL
, 0);
538 int WorldSocket::handle_input_missing_data (void)
542 ACE_Data_Block
db ( sizeof (buf
),
543 ACE_Message_Block::MB_DATA
,
547 ACE_Message_Block::DONT_DELETE
,
550 ACE_Message_Block
message_block(&db
,
551 ACE_Message_Block::DONT_DELETE
,
554 const size_t recv_size
= message_block
.space ();
556 const ssize_t n
= peer ().recv (message_block
.wr_ptr (),
562 message_block
.wr_ptr (n
);
564 while (message_block
.length () > 0)
566 if (m_Header
.space () > 0)
568 //need to receive the header
569 const size_t to_header
= (message_block
.length () > m_Header
.space () ? m_Header
.space () : message_block
.length ());
570 m_Header
.copy (message_block
.rd_ptr (), to_header
);
571 message_block
.rd_ptr (to_header
);
573 if (m_Header
.space () > 0)
575 // Couldn't receive the whole header this time.
576 ACE_ASSERT (message_block
.length () == 0);
581 // We just received nice new header
582 if (handle_input_header () == -1)
584 ACE_ASSERT ((errno
!= EWOULDBLOCK
) && (errno
!= EAGAIN
));
589 // Its possible on some error situations that this happens
590 // for example on closing when epoll receives more chunked data and stuff
591 // hope this is not hack ,as proper m_RecvWPct is asserted around
594 sLog
.outError ("Forcing close on input m_RecvWPct = NULL");
599 // We have full read header, now check the data payload
600 if (m_RecvPct
.space () > 0)
602 //need more data in the payload
603 const size_t to_data
= (message_block
.length () > m_RecvPct
.space () ? m_RecvPct
.space () : message_block
.length ());
604 m_RecvPct
.copy (message_block
.rd_ptr (), to_data
);
605 message_block
.rd_ptr (to_data
);
607 if (m_RecvPct
.space () > 0)
609 // Couldn't receive the whole data this time.
610 ACE_ASSERT (message_block
.length () == 0);
616 //just received fresh new payload
617 if (handle_input_payload () == -1)
619 ACE_ASSERT ((errno
!= EWOULDBLOCK
) && (errno
!= EAGAIN
));
624 return n
== recv_size
? 1 : 2;
627 int WorldSocket::cancel_wakeup_output (GuardType
& g
)
636 if (reactor ()->cancel_wakeup
637 (this, ACE_Event_Handler::WRITE_MASK
) == -1)
639 // would be good to store errno from reactor with errno guard
640 sLog
.outError ("WorldSocket::cancel_wakeup_output");
647 int WorldSocket::schedule_wakeup_output (GuardType
& g
)
656 if (reactor ()->schedule_wakeup
657 (this, ACE_Event_Handler::WRITE_MASK
) == -1)
659 sLog
.outError ("WorldSocket::schedule_wakeup_output");
666 int WorldSocket::ProcessIncoming (WorldPacket
* new_pct
)
668 ACE_ASSERT (new_pct
);
671 ACE_Auto_Ptr
<WorldPacket
> aptr (new_pct
);
673 const ACE_UINT16 opcode
= new_pct
->GetOpcode ();
678 // Dump received packet.
679 if (sWorldLog
.LogWorld ())
681 sWorldLog
.Log ("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n",
682 (uint32
) get_handle (),
684 LookupOpcodeName (new_pct
->GetOpcode ()),
685 new_pct
->GetOpcode ());
688 while (p
< new_pct
->size ())
690 for (uint32 j
= 0; j
< 16 && p
< new_pct
->size (); j
++)
691 sWorldLog
.Log ("%.2X ", (*new_pct
)[p
++]);
692 sWorldLog
.Log ("\n");
694 sWorldLog
.Log ("\n\n");
697 // like one switch ;)
698 if (opcode
== CMSG_PING
)
700 return HandlePing (*new_pct
);
702 else if (opcode
== CMSG_AUTH_SESSION
)
706 sLog
.outError ("WorldSocket::ProcessIncoming: Player send CMSG_AUTH_SESSION again");
710 return HandleAuthSession (*new_pct
);
712 else if (opcode
== CMSG_KEEP_ALIVE
)
714 DEBUG_LOG ("CMSG_KEEP_ALIVE ,size: %d", new_pct
->size ());
720 ACE_GUARD_RETURN (LockType
, Guard
, m_SessionLock
, -1);
722 if (m_Session
!= NULL
)
724 // OK ,give the packet to WorldSession
726 // WARNINIG here we call it with locks held.
727 // Its possible to cause deadlock if QueuePacket calls back
728 m_Session
->QueuePacket (new_pct
);
733 sLog
.outError ("WorldSocket::ProcessIncoming: Client not authed opcode = %u", uint32(opcode
));
738 ACE_NOTREACHED (return 0);
741 int WorldSocket::HandleAuthSession (WorldPacket
& recvPacket
)
743 // NOTE: ATM the socket is singlethread, have this in mind ...
747 uint32 BuiltNumberClient
;
750 LocaleConstant locale
;
753 BigNumber v
, s
, g
, N
, x
, I
;
754 WorldPacket packet
, SendAddonPacked
;
758 if (recvPacket
.size () < (4 + 4 + 1 + 4 + 20))
760 sLog
.outError ("WorldSocket::HandleAuthSession: wrong packet size");
764 // Read the content of the packet
765 recvPacket
>> BuiltNumberClient
; // for now no use
767 recvPacket
>> account
;
770 if (recvPacket
.size () < (4 + 4 + (account
.size () + 1) + 4 + 20))
772 sLog
.outError ("WorldSocket::HandleAuthSession: wrong packet size second check");
776 recvPacket
>> clientSeed
;
777 recvPacket
.read (digest
, 20);
779 DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, clientseed %u",
785 // Get the account information from the realmd database
786 std::string safe_account
= account
; // Duplicate, else will screw the SHA hash verification below
787 loginDatabase
.escape_string (safe_account
);
788 // No SQL injection, username escaped.
790 QueryResult
*result
=
791 loginDatabase
.PQuery ("SELECT "
797 "sha_pass_hash, " //5
804 "WHERE username = '%s'",
805 safe_account
.c_str ());
807 // Stop if the account is not found
810 packet
.Initialize (SMSG_AUTH_RESPONSE
, 1);
811 packet
<< uint8 (AUTH_UNKNOWN_ACCOUNT
);
815 sLog
.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
819 Field
* fields
= result
->Fetch ();
821 expansion
= ((sWorld
.getConfig(CONFIG_EXPANSION
) > fields
[8].GetUInt8()) ? fields
[8].GetUInt8() : sWorld
.getConfig(CONFIG_EXPANSION
));
823 N
.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
825 I
.SetHexStr (fields
[5].GetString ());
827 //In case of leading zeros in the I hash, restore them
828 uint8 mDigest
[SHA_DIGEST_LENGTH
];
829 memset (mDigest
, 0, SHA_DIGEST_LENGTH
);
831 if (I
.GetNumBytes () <= SHA_DIGEST_LENGTH
)
832 memcpy (mDigest
, I
.AsByteArray (), I
.GetNumBytes ());
834 std::reverse (mDigest
, mDigest
+ SHA_DIGEST_LENGTH
);
836 s
.SetHexStr (fields
[7].GetString ());
837 sha1
.UpdateData (s
.AsByteArray (), s
.GetNumBytes ());
838 sha1
.UpdateData (mDigest
, SHA_DIGEST_LENGTH
);
840 x
.SetBinary (sha1
.GetDigest (), sha1
.GetLength ());
843 const char* sStr
= s
.AsHexStr (); //Must be freed by OPENSSL_free()
844 const char* vStr
= v
.AsHexStr (); //Must be freed by OPENSSL_free()
845 const char* vold
= fields
[6].GetString ();
847 DEBUG_LOG ("WorldSocket::HandleAuthSession: (s,v) check s: %s v_old: %s v_new: %s",
852 loginDatabase
.PExecute ("UPDATE account "
856 "WHERE username = '%s'",
857 safe_account
.c_str ());
859 if (!vold
|| strcmp (vStr
, vold
))
861 packet
.Initialize (SMSG_AUTH_RESPONSE
, 1);
862 packet
<< uint8 (AUTH_UNKNOWN_ACCOUNT
);
865 OPENSSL_free ((void*) sStr
);
866 OPENSSL_free ((void*) vStr
);
868 sLog
.outBasic ("WorldSocket::HandleAuthSession: User not logged.");
872 OPENSSL_free ((void*) sStr
);
873 OPENSSL_free ((void*) vStr
);
875 ///- Re-check ip locking (same check as in realmd).
876 if (fields
[4].GetUInt8 () == 1) // if ip is locked
878 if (strcmp (fields
[3].GetString (), GetRemoteAddress ().c_str ()))
880 packet
.Initialize (SMSG_AUTH_RESPONSE
, 1);
881 packet
<< uint8 (AUTH_FAILED
);
885 sLog
.outBasic ("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs).");
890 id
= fields
[0].GetUInt32 ();
891 security
= fields
[1].GetUInt16 ();
892 if(security
> SEC_ADMINISTRATOR
) // prevent invalid security settings in DB
893 security
= SEC_ADMINISTRATOR
;
895 K
.SetHexStr (fields
[2].GetString ());
897 time_t mutetime
= time_t (fields
[9].GetUInt64 ());
899 locale
= LocaleConstant (fields
[10].GetUInt8 ());
900 if (locale
>= MAX_LOCALE
)
901 locale
= LOCALE_enUS
;
905 // Re-check account ban (same check as in realmd)
906 QueryResult
*banresult
=
907 loginDatabase
.PQuery ("SELECT "
910 "FROM account_banned "
915 if (banresult
) // if account banned
917 packet
.Initialize (SMSG_AUTH_RESPONSE
, 1);
918 packet
<< uint8 (AUTH_BANNED
);
923 sLog
.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
927 // Check locked state for server
928 AccountTypes allowedAccountType
= sWorld
.GetPlayerSecurityLimit ();
930 if (allowedAccountType
> SEC_PLAYER
&& AccountTypes(security
) < allowedAccountType
)
932 WorldPacket
Packet (SMSG_AUTH_RESPONSE
, 1);
933 Packet
<< uint8 (AUTH_UNAVAILABLE
);
937 sLog
.outBasic ("WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
941 // Check that Key and account name are the same on client and server
945 uint32 seed
= m_Seed
;
947 sha
.UpdateData (account
);
948 sha
.UpdateData ((uint8
*) & t
, 4);
949 sha
.UpdateData ((uint8
*) & clientSeed
, 4);
950 sha
.UpdateData ((uint8
*) & seed
, 4);
951 sha
.UpdateBigNumbers (&K
, NULL
);
954 if (memcmp (sha
.GetDigest (), digest
, 20))
956 packet
.Initialize (SMSG_AUTH_RESPONSE
, 1);
957 packet
<< uint8 (AUTH_FAILED
);
961 sLog
.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed).");
965 std::string address
= GetRemoteAddress ();
967 DEBUG_LOG ("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.",
971 // Update the last_ip in the database
972 // No SQL injection, username escaped.
973 loginDatabase
.escape_string (address
);
975 loginDatabase
.PExecute ("UPDATE account "
976 "SET last_ip = '%s' "
977 "WHERE username = '%s'",
979 safe_account
.c_str ());
981 // NOTE ATM the socket is single-threaded, have this in mind ...
982 ACE_NEW_RETURN (m_Session
, WorldSession (id
, this, AccountTypes(security
), expansion
, mutetime
, locale
), -1);
987 m_Session
->LoadAccountData();
988 m_Session
->ReadAddonsInfo(recvPacket
);
990 // In case needed sometime the second arg is in microseconds 1 000 000 = 1 sec
991 ACE_OS::sleep (ACE_Time_Value (0, 10000));
993 sWorld
.AddSession (m_Session
);
998 int WorldSocket::HandlePing (WorldPacket
& recvPacket
)
1003 if (recvPacket
.size () < 8)
1005 sLog
.outError ("WorldSocket::_HandlePing wrong packet size");
1009 // Get the ping packet content
1011 recvPacket
>> latency
;
1013 if (m_LastPingTime
== ACE_Time_Value::zero
)
1014 m_LastPingTime
= ACE_OS::gettimeofday (); // for 1st ping
1017 ACE_Time_Value cur_time
= ACE_OS::gettimeofday ();
1018 ACE_Time_Value
diff_time (cur_time
);
1019 diff_time
-= m_LastPingTime
;
1020 m_LastPingTime
= cur_time
;
1022 if (diff_time
< ACE_Time_Value (27))
1026 uint32 max_count
= sWorld
.getConfig (CONFIG_MAX_OVERSPEED_PINGS
);
1028 if (max_count
&& m_OverSpeedPings
> max_count
)
1030 ACE_GUARD_RETURN (LockType
, Guard
, m_SessionLock
, -1);
1032 if (m_Session
&& m_Session
->GetSecurity () == SEC_PLAYER
)
1034 sLog
.outError ("WorldSocket::HandlePing: Player kicked for "
1035 "over-speed pings address = %s",
1036 GetRemoteAddress ().c_str ());
1043 m_OverSpeedPings
= 0;
1048 ACE_GUARD_RETURN (LockType
, Guard
, m_SessionLock
, -1);
1051 m_Session
->SetLatency (latency
);
1054 sLog
.outError ("WorldSocket::HandlePing: peer sent CMSG_PING, "
1055 "but is not authenticated or got recently kicked,"
1057 GetRemoteAddress ().c_str ());
1062 WorldPacket
packet (SMSG_PONG
, 4);
1064 return SendPacket (packet
);