[6870] Not output error message at loading empty `db_script_string` table.
[getmangos.git] / src / game / WorldSocket.cpp
blobdf46becc997778226aef3743e3c55cd114c255fc
1 /*
2 * Copyright (C) 2005-2008 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"
31 #include "Common.h"
33 #include "Util.h"
34 #include "World.h"
35 #include "WorldPacket.h"
36 #include "SharedDefines.h"
37 #include "ByteBuffer.h"
38 #include "AddonHandler.h"
39 #include "Opcodes.h"
40 #include "Database/DatabaseEnv.h"
41 #include "Auth/Sha1.h"
42 #include "WorldSession.h"
43 #include "WorldSocketMgr.h"
44 #include "Log.h"
45 #include "WorldLog.h"
47 #if defined( __GNUC__ )
48 #pragma pack(1)
49 #else
50 #pragma pack(push,1)
51 #endif
53 struct ServerPktHeader
55 uint16 size;
56 uint16 cmd;
59 struct ClientPktHeader
61 uint16 size;
62 uint32 cmd;
65 #if defined( __GNUC__ )
66 #pragma pack()
67 #else
68 #pragma pack(pop)
69 #endif
71 WorldSocket::WorldSocket (void) :
72 WorldHandler (),
73 m_Session (0),
74 m_RecvWPct (0),
75 m_RecvPct (),
76 m_Header (sizeof (ClientPktHeader)),
77 m_OutBuffer (0),
78 m_OutBufferSize (65536),
79 m_OutActive (false),
80 m_Seed (static_cast<uint32> (rand32 ())),
81 m_OverSpeedPings (0),
82 m_LastPingTime (ACE_Time_Value::zero)
84 reference_counting_policy ().value (ACE_Event_Handler::Reference_Counting_Policy::ENABLED);
87 WorldSocket::~WorldSocket (void)
89 if (m_RecvWPct)
90 delete m_RecvWPct;
92 if (m_OutBuffer)
93 m_OutBuffer->release ();
95 closing_ = true;
97 peer ().close ();
99 WorldPacket* pct;
100 while (m_PacketQueue.dequeue_head (pct) == 0)
101 delete pct;
104 bool WorldSocket::IsClosed (void) const
106 return closing_;
109 void WorldSocket::CloseSocket (void)
112 ACE_GUARD (LockType, Guard, m_OutBufferLock);
114 if (closing_)
115 return;
117 closing_ = true;
119 peer ().close_writer ();
123 ACE_GUARD (LockType, Guard, m_SessionLock);
125 m_Session = NULL;
129 const std::string& WorldSocket::GetRemoteAddress (void) const
131 return m_Address;
134 int WorldSocket::SendPacket (const WorldPacket& pct)
136 ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1);
138 if (closing_)
139 return -1;
141 // Dump outgoing packet.
142 if (sWorldLog.LogWorld ())
144 sWorldLog.Log ("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n",
145 (uint32) get_handle (),
146 pct.size (),
147 LookupOpcodeName (pct.GetOpcode ()),
148 pct.GetOpcode ());
150 uint32 p = 0;
151 while (p < pct.size ())
153 for (uint32 j = 0; j < 16 && p < pct.size (); j++)
154 sWorldLog.Log ("%.2X ", const_cast<WorldPacket&>(pct)[p++]);
156 sWorldLog.Log ("\n");
159 sWorldLog.Log ("\n\n");
162 if (iSendPacket (pct) == -1)
164 WorldPacket* npct;
166 ACE_NEW_RETURN (npct, WorldPacket (pct), -1);
168 // NOTE maybe check of the size of the queue can be good ?
169 // to make it bounded instead of unbounded
170 if (m_PacketQueue.enqueue_tail (npct) == -1)
172 delete npct;
173 sLog.outError ("WorldSocket::SendPacket: m_PacketQueue.enqueue_tail failed");
174 return -1;
178 return 0;
181 long WorldSocket::AddReference (void)
183 return static_cast<long> (add_reference ());
186 long WorldSocket::RemoveReference (void)
188 return static_cast<long> (remove_reference ());
191 int WorldSocket::open (void *a)
193 ACE_UNUSED_ARG (a);
195 // Prevent double call to this func.
196 if (m_OutBuffer)
197 return -1;
199 // This will also prevent the socket from being Updated
200 // while we are initializing it.
201 m_OutActive = true;
203 // Hook for the manager.
204 if (sWorldSocketMgr->OnSocketOpen (this) == -1)
205 return -1;
207 // Allocate the buffer.
208 ACE_NEW_RETURN (m_OutBuffer, ACE_Message_Block (m_OutBufferSize), -1);
210 // Store peer address.
211 ACE_INET_Addr remote_addr;
213 if (peer ().get_remote_addr (remote_addr) == -1)
215 sLog.outError ("WorldSocket::open: peer ().get_remote_addr errno = %s", ACE_OS::strerror (errno));
216 return -1;
219 m_Address = remote_addr.get_host_addr ();
221 // Send startup packet.
222 WorldPacket packet (SMSG_AUTH_CHALLENGE, 4);
223 packet << m_Seed;
225 if (SendPacket (packet) == -1)
226 return -1;
228 // Register with ACE Reactor
229 if (reactor ()->register_handler(this, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK) == -1)
231 sLog.outError ("WorldSocket::open: unable to register client handler errno = %s", ACE_OS::strerror (errno));
232 return -1;
235 // reactor takes care of the socket from now on
236 remove_reference ();
238 return 0;
241 int WorldSocket::close (int)
243 shutdown ();
245 closing_ = true;
247 remove_reference ();
249 return 0;
252 int WorldSocket::handle_input (ACE_HANDLE)
254 if (closing_)
255 return -1;
257 switch (handle_input_missing_data ())
259 case -1 :
261 if ((errno == EWOULDBLOCK) ||
262 (errno == EAGAIN))
264 return Update (); // interesting line ,isn't it ?
267 DEBUG_LOG ("WorldSocket::handle_input: Peer error closing connection errno = %s", ACE_OS::strerror (errno));
269 errno = ECONNRESET;
270 return -1;
272 case 0:
274 DEBUG_LOG ("WorldSocket::handle_input: Peer has closed connection\n");
276 errno = ECONNRESET;
277 return -1;
279 case 1:
280 return 1;
281 default:
282 return Update (); // another interesting line ;)
285 ACE_NOTREACHED(return -1);
288 int WorldSocket::handle_output (ACE_HANDLE)
290 ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1);
292 if (closing_)
293 return -1;
295 const size_t send_len = m_OutBuffer->length ();
297 if (send_len == 0)
298 return cancel_wakeup_output (Guard);
300 #ifdef MSG_NOSIGNAL
301 ssize_t n = peer ().send (m_OutBuffer->rd_ptr (), send_len, MSG_NOSIGNAL);
302 #else
303 ssize_t n = peer ().send (m_OutBuffer->rd_ptr (), send_len);
304 #endif // MSG_NOSIGNAL
306 if (n == 0)
307 return -1;
308 else if (n == -1)
310 if (errno == EWOULDBLOCK || errno == EAGAIN)
311 return schedule_wakeup_output (Guard);
313 return -1;
315 else if (n < send_len) //now n > 0
317 m_OutBuffer->rd_ptr (static_cast<size_t> (n));
319 // move the data to the base of the buffer
320 m_OutBuffer->crunch ();
322 return schedule_wakeup_output (Guard);
324 else //now n == send_len
326 m_OutBuffer->reset ();
328 if (!iFlushPacketQueue ())
329 return cancel_wakeup_output (Guard);
330 else
331 return schedule_wakeup_output (Guard);
334 ACE_NOTREACHED (return 0);
337 int WorldSocket::handle_close (ACE_HANDLE h, ACE_Reactor_Mask)
339 // Critical section
341 ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1);
343 closing_ = true;
345 if (h == ACE_INVALID_HANDLE)
346 peer ().close_writer ();
349 // Critical section
351 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);
353 m_Session = NULL;
356 return 0;
359 int WorldSocket::Update (void)
361 if (closing_)
362 return -1;
364 if (m_OutActive || m_OutBuffer->length () == 0)
365 return 0;
367 return handle_output (get_handle ());
370 int WorldSocket::handle_input_header (void)
372 ACE_ASSERT (m_RecvWPct == NULL);
374 ACE_ASSERT (m_Header.length () == sizeof (ClientPktHeader));
376 m_Crypt.DecryptRecv ((ACE_UINT8*) m_Header.rd_ptr (), sizeof (ClientPktHeader));
378 ClientPktHeader& header = *((ClientPktHeader*) m_Header.rd_ptr ());
380 EndianConvertReverse(header.size);
381 EndianConvert(header.cmd);
383 if ((header.size < 4) || (header.size > 10240) ||
384 (header.cmd < 0) || (header.cmd > 10240) )
386 sLog.outError ("WorldSocket::handle_input_header: client sent mailformed packet size = %d , cmd = %d",
387 header.size, header.cmd);
389 errno = EINVAL;
390 return -1;
393 header.size -= 4;
395 ACE_NEW_RETURN (m_RecvWPct, WorldPacket ((uint16) header.cmd, header.size), -1);
397 if(header.size > 0)
399 m_RecvWPct->resize (header.size);
400 m_RecvPct.base ((char*) m_RecvWPct->contents (), m_RecvWPct->size ());
402 else
404 ACE_ASSERT(m_RecvPct.space() == 0);
407 return 0;
410 int WorldSocket::handle_input_payload (void)
412 // set errno properly here on error !!!
413 // now have a header and payload
415 ACE_ASSERT (m_RecvPct.space () == 0);
416 ACE_ASSERT (m_Header.space () == 0);
417 ACE_ASSERT (m_RecvWPct != NULL);
419 const int ret = ProcessIncoming (m_RecvWPct);
421 m_RecvPct.base (NULL, 0);
422 m_RecvPct.reset ();
423 m_RecvWPct = NULL;
425 m_Header.reset ();
427 if (ret == -1)
428 errno = EINVAL;
430 return ret;
433 int WorldSocket::handle_input_missing_data (void)
435 char buf [1024];
437 ACE_Data_Block db ( sizeof (buf),
438 ACE_Message_Block::MB_DATA,
439 buf,
442 ACE_Message_Block::DONT_DELETE,
445 ACE_Message_Block message_block(&db,
446 ACE_Message_Block::DONT_DELETE,
449 const size_t recv_size = message_block.space ();
451 const ssize_t n = peer ().recv (message_block.wr_ptr (),
452 recv_size);
454 if (n <= 0)
455 return n;
457 message_block.wr_ptr (n);
459 while (message_block.length () > 0)
461 if (m_Header.space () > 0)
463 //need to receive the header
464 const size_t to_header = (message_block.length () > m_Header.space () ? m_Header.space () : message_block.length ());
465 m_Header.copy (message_block.rd_ptr (), to_header);
466 message_block.rd_ptr (to_header);
468 if (m_Header.space () > 0)
470 // Couldn't receive the whole header this time.
471 ACE_ASSERT (message_block.length () == 0);
472 errno = EWOULDBLOCK;
473 return -1;
476 // We just received nice new header
477 if (handle_input_header () == -1)
479 ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN));
480 return -1;
484 // Its possible on some error situations that this happens
485 // for example on closing when epoll receives more chunked data and stuff
486 // hope this is not hack ,as proper m_RecvWPct is asserted around
487 if (!m_RecvWPct)
489 sLog.outError ("Forcing close on input m_RecvWPct = NULL");
490 errno = EINVAL;
491 return -1;
494 // We have full read header, now check the data payload
495 if (m_RecvPct.space () > 0)
497 //need more data in the payload
498 const size_t to_data = (message_block.length () > m_RecvPct.space () ? m_RecvPct.space () : message_block.length ());
499 m_RecvPct.copy (message_block.rd_ptr (), to_data);
500 message_block.rd_ptr (to_data);
502 if (m_RecvPct.space () > 0)
504 // Couldn't receive the whole data this time.
505 ACE_ASSERT (message_block.length () == 0);
506 errno = EWOULDBLOCK;
507 return -1;
511 //just received fresh new payload
512 if (handle_input_payload () == -1)
514 ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN));
515 return -1;
519 return n == recv_size ? 1 : 2;
522 int WorldSocket::cancel_wakeup_output (GuardType& g)
524 if (!m_OutActive)
525 return 0;
527 m_OutActive = false;
529 g.release ();
531 if (reactor ()->cancel_wakeup
532 (this, ACE_Event_Handler::WRITE_MASK) == -1)
534 // would be good to store errno from reactor with errno guard
535 sLog.outError ("WorldSocket::cancel_wakeup_output");
536 return -1;
539 return 0;
542 int WorldSocket::schedule_wakeup_output (GuardType& g)
544 if (m_OutActive)
545 return 0;
547 m_OutActive = true;
549 g.release ();
551 if (reactor ()->schedule_wakeup
552 (this, ACE_Event_Handler::WRITE_MASK) == -1)
554 sLog.outError ("WorldSocket::schedule_wakeup_output");
555 return -1;
558 return 0;
561 int WorldSocket::ProcessIncoming (WorldPacket* new_pct)
563 ACE_ASSERT (new_pct);
565 // manage memory ;)
566 ACE_Auto_Ptr<WorldPacket> aptr (new_pct);
568 const ACE_UINT16 opcode = new_pct->GetOpcode ();
570 if (closing_)
571 return -1;
573 // Dump received packet.
574 if (sWorldLog.LogWorld ())
576 sWorldLog.Log ("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n",
577 (uint32) get_handle (),
578 new_pct->size (),
579 LookupOpcodeName (new_pct->GetOpcode ()),
580 new_pct->GetOpcode ());
582 uint32 p = 0;
583 while (p < new_pct->size ())
585 for (uint32 j = 0; j < 16 && p < new_pct->size (); j++)
586 sWorldLog.Log ("%.2X ", (*new_pct)[p++]);
587 sWorldLog.Log ("\n");
589 sWorldLog.Log ("\n\n");
592 // like one switch ;)
593 if (opcode == CMSG_PING)
595 return HandlePing (*new_pct);
597 else if (opcode == CMSG_AUTH_SESSION)
599 if (m_Session)
601 sLog.outError ("WorldSocket::ProcessIncoming: Player send CMSG_AUTH_SESSION again");
602 return -1;
605 return HandleAuthSession (*new_pct);
607 else if (opcode == CMSG_KEEP_ALIVE)
609 DEBUG_LOG ("CMSG_KEEP_ALIVE ,size: %d", new_pct->size ());
611 return 0;
613 else
615 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);
617 if (m_Session != NULL)
619 // OK ,give the packet to WorldSession
620 aptr.release ();
621 // WARNINIG here we call it with locks held.
622 // Its possible to cause deadlock if QueuePacket calls back
623 m_Session->QueuePacket (new_pct);
624 return 0;
626 else
628 sLog.outError ("WorldSocket::ProcessIncoming: Client not authed opcode = ", opcode);
629 return -1;
633 ACE_NOTREACHED (return 0);
636 int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
638 // NOTE: ATM the socket is singlethread, have this in mind ...
639 uint8 digest[20];
640 uint32 clientSeed;
641 uint32 unk2;
642 uint32 BuiltNumberClient;
643 uint32 id, security;
644 uint8 expansion = 0;
645 LocaleConstant locale;
646 std::string account;
647 Sha1Hash sha1;
648 BigNumber v, s, g, N, x, I;
649 WorldPacket packet, SendAddonPacked;
651 BigNumber K;
653 if (recvPacket.size () < (4 + 4 + 1 + 4 + 20))
655 sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size");
656 return -1;
659 // Read the content of the packet
660 recvPacket >> BuiltNumberClient; // for now no use
661 recvPacket >> unk2;
662 recvPacket >> account;
664 if (recvPacket.size () < (4 + 4 + (account.size () + 1) + 4 + 20))
666 sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size second check");
667 return -1;
670 recvPacket >> clientSeed;
671 recvPacket.read (digest, 20);
673 DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, clientseed %u",
674 BuiltNumberClient,
675 unk2,
676 account.c_str (),
677 clientSeed);
679 // Get the account information from the realmd database
680 std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below
681 loginDatabase.escape_string (safe_account);
682 // No SQL injection, username escaped.
684 QueryResult *result =
685 loginDatabase.PQuery ("SELECT "
686 "id, " //0
687 "gmlevel, " //1
688 "sessionkey, " //2
689 "last_ip, " //3
690 "locked, " //4
691 "sha_pass_hash, " //5
692 "v, " //6
693 "s, " //7
694 "expansion, " //8
695 "mutetime, " //9
696 "locale " //10
697 "FROM account "
698 "WHERE username = '%s'",
699 safe_account.c_str ());
701 // Stop if the account is not found
702 if (!result)
704 packet.Initialize (SMSG_AUTH_RESPONSE, 1);
705 packet << uint8 (AUTH_UNKNOWN_ACCOUNT);
707 SendPacket (packet);
709 sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
710 return -1;
713 Field* fields = result->Fetch ();
715 expansion = fields[8].GetUInt8 () && sWorld.getConfig (CONFIG_EXPANSION) > 0;
717 N.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
718 g.SetDword (7);
719 I.SetHexStr (fields[5].GetString ());
721 //In case of leading zeros in the I hash, restore them
722 uint8 mDigest[SHA_DIGEST_LENGTH];
723 memset (mDigest, 0, SHA_DIGEST_LENGTH);
725 if (I.GetNumBytes () <= SHA_DIGEST_LENGTH)
726 memcpy (mDigest, I.AsByteArray (), I.GetNumBytes ());
728 std::reverse (mDigest, mDigest + SHA_DIGEST_LENGTH);
730 s.SetHexStr (fields[7].GetString ());
731 sha1.UpdateData (s.AsByteArray (), s.GetNumBytes ());
732 sha1.UpdateData (mDigest, SHA_DIGEST_LENGTH);
733 sha1.Finalize ();
734 x.SetBinary (sha1.GetDigest (), sha1.GetLength ());
735 v = g.ModExp (x, N);
737 const char* sStr = s.AsHexStr (); //Must be freed by OPENSSL_free()
738 const char* vStr = v.AsHexStr (); //Must be freed by OPENSSL_free()
739 const char* vold = fields[6].GetString ();
741 DEBUG_LOG ("WorldSocket::HandleAuthSession: (s,v) check s: %s v_old: %s v_new: %s",
742 sStr,
743 vold,
744 vStr);
746 loginDatabase.PExecute ("UPDATE account "
747 "SET "
748 "v = '0', "
749 "s = '0' "
750 "WHERE username = '%s'",
751 safe_account.c_str ());
753 if (!vold || strcmp (vStr, vold))
755 packet.Initialize (SMSG_AUTH_RESPONSE, 1);
756 packet << uint8 (AUTH_UNKNOWN_ACCOUNT);
757 SendPacket (packet);
758 delete result;
759 OPENSSL_free ((void*) sStr);
760 OPENSSL_free ((void*) vStr);
762 sLog.outBasic ("WorldSocket::HandleAuthSession: User not logged.");
763 return -1;
766 OPENSSL_free ((void*) sStr);
767 OPENSSL_free ((void*) vStr);
769 ///- Re-check ip locking (same check as in realmd).
770 if (fields[4].GetUInt8 () == 1) // if ip is locked
772 if (strcmp (fields[3].GetString (), GetRemoteAddress ().c_str ()))
774 packet.Initialize (SMSG_AUTH_RESPONSE, 1);
775 packet << uint8 (AUTH_FAILED);
776 SendPacket (packet);
778 delete result;
779 sLog.outBasic ("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs).");
780 return -1;
784 id = fields[0].GetUInt32 ();
785 security = fields[1].GetUInt16 ();
786 K.SetHexStr (fields[2].GetString ());
788 time_t mutetime = time_t (fields[9].GetUInt64 ());
790 locale = LocaleConstant (fields[10].GetUInt8 ());
791 if (locale >= MAX_LOCALE)
792 locale = LOCALE_enUS;
794 delete result;
796 // Re-check account ban (same check as in realmd)
797 QueryResult *banresult =
798 loginDatabase.PQuery ("SELECT "
799 "bandate, "
800 "unbandate "
801 "FROM account_banned "
802 "WHERE id = '%u' "
803 "AND active = 1",
804 id);
806 if (banresult) // if account banned
808 packet.Initialize (SMSG_AUTH_RESPONSE, 1);
809 packet << uint8 (AUTH_BANNED);
810 SendPacket (packet);
812 delete banresult;
814 sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
815 return -1;
818 // Check locked state for server
819 AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit ();
821 if (allowedAccountType > SEC_PLAYER && security < allowedAccountType)
823 WorldPacket Packet (SMSG_AUTH_RESPONSE, 1);
824 Packet << uint8 (AUTH_UNAVAILABLE);
826 SendPacket (packet);
828 sLog.outBasic ("WorldSocket::HandleAuthSession: User tryes to login but his security level is not enough");
829 return -1;
832 // Check that Key and account name are the same on client and server
833 Sha1Hash sha;
835 uint32 t = 0;
836 uint32 seed = m_Seed;
838 sha.UpdateData (account);
839 sha.UpdateData ((uint8 *) & t, 4);
840 sha.UpdateData ((uint8 *) & clientSeed, 4);
841 sha.UpdateData ((uint8 *) & seed, 4);
842 sha.UpdateBigNumbers (&K, NULL);
843 sha.Finalize ();
845 if (memcmp (sha.GetDigest (), digest, 20))
847 packet.Initialize (SMSG_AUTH_RESPONSE, 1);
848 packet << uint8 (AUTH_FAILED);
850 SendPacket (packet);
852 sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed).");
853 return -1;
856 std::string address = GetRemoteAddress ();
858 DEBUG_LOG ("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.",
859 account.c_str (),
860 address.c_str ());
862 // Update the last_ip in the database
863 // No SQL injection, username escaped.
864 loginDatabase.escape_string (address);
866 loginDatabase.PExecute ("UPDATE account "
867 "SET last_ip = '%s' "
868 "WHERE username = '%s'",
869 address.c_str (),
870 safe_account.c_str ());
872 // NOTE ATM the socket is singlethreaded, have this in mind ...
873 ACE_NEW_RETURN (m_Session, WorldSession (id, this, security, expansion, mutetime, locale), -1);
875 m_Crypt.SetKey (&K);
876 m_Crypt.Init ();
878 // In case needed sometime the second arg is in microseconds 1 000 000 = 1 sec
879 ACE_OS::sleep (ACE_Time_Value (0, 10000));
881 sWorld.AddSession (m_Session);
883 // Create and send the Addon packet
884 if (sAddOnHandler.BuildAddonPacket (&recvPacket, &SendAddonPacked))
885 SendPacket (SendAddonPacked);
887 return 0;
890 int WorldSocket::HandlePing (WorldPacket& recvPacket)
892 uint32 ping;
893 uint32 latency;
895 if (recvPacket.size () < 8)
897 sLog.outError ("WorldSocket::_HandlePing wrong packet size");
898 return -1;
901 // Get the ping packet content
902 recvPacket >> ping;
903 recvPacket >> latency;
905 if (m_LastPingTime == ACE_Time_Value::zero)
906 m_LastPingTime = ACE_OS::gettimeofday (); // for 1st ping
907 else
909 ACE_Time_Value cur_time = ACE_OS::gettimeofday ();
910 ACE_Time_Value diff_time (cur_time);
911 diff_time -= m_LastPingTime;
912 m_LastPingTime = cur_time;
914 if (diff_time < ACE_Time_Value (27))
916 ++m_OverSpeedPings;
918 uint32 max_count = sWorld.getConfig (CONFIG_MAX_OVERSPEED_PINGS);
920 if (max_count && m_OverSpeedPings > max_count)
922 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);
924 if (m_Session && m_Session->GetSecurity () == SEC_PLAYER)
926 sLog.outError ("WorldSocket::HandlePing: Player kicked for "
927 "over-speed pings address = %s",
928 GetRemoteAddress ().c_str ());
930 return -1;
934 else
935 m_OverSpeedPings = 0;
938 // critical section
940 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);
942 if (m_Session)
943 m_Session->SetLatency (latency);
944 else
946 sLog.outError ("WorldSocket::HandlePing: peer sent CMSG_PING, "
947 "but is not authenticated or got recently kicked,"
948 " address = %s",
949 GetRemoteAddress ().c_str ());
950 return -1;
954 WorldPacket packet (SMSG_PONG, 4);
955 packet << ping;
956 return SendPacket (packet);
959 int WorldSocket::iSendPacket (const WorldPacket& pct)
961 if (m_OutBuffer->space () < pct.size () + sizeof (ServerPktHeader))
963 errno = ENOBUFS;
964 return -1;
967 ServerPktHeader header;
969 header.cmd = pct.GetOpcode ();
970 EndianConvert(header.cmd);
972 header.size = (uint16) pct.size () + 2;
973 EndianConvertReverse(header.size);
975 m_Crypt.EncryptSend ((uint8*) & header, sizeof (header));
977 if (m_OutBuffer->copy ((char*) & header, sizeof (header)) == -1)
978 ACE_ASSERT (false);
980 if (!pct.empty ())
981 if (m_OutBuffer->copy ((char*) pct.contents (), pct.size ()) == -1)
982 ACE_ASSERT (false);
984 return 0;
987 bool WorldSocket::iFlushPacketQueue ()
989 WorldPacket *pct;
990 bool haveone = false;
992 while (m_PacketQueue.dequeue_head (pct) == 0)
994 if (iSendPacket (*pct) == -1)
996 if (m_PacketQueue.enqueue_head (pct) == -1)
998 delete pct;
999 sLog.outError ("WorldSocket::iFlushPacketQueue m_PacketQueue->enqueue_head");
1000 return false;
1003 break;
1005 else
1007 haveone = true;
1008 delete pct;
1012 return haveone;