[9581] Fixed apply damage reduction to melee/ranged damage.
[getmangos.git] / src / game / WorldSocket.cpp
blobc181c8d82e890087300fa4b5dba25c337c79d747
1 /*
2 * Copyright (C) 2005-2010 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 "Opcodes.h"
39 #include "Database/DatabaseEnv.h"
40 #include "Auth/BigNumber.h"
41 #include "Auth/Sha1.h"
42 #include "WorldSession.h"
43 #include "WorldSocketMgr.h"
44 #include "Log.h"
45 #include "DBCStores.h"
47 #if defined( __GNUC__ )
48 #pragma pack(1)
49 #else
50 #pragma pack(push,1)
51 #endif
53 struct ServerPktHeader
55 /**
56 * size is the length of the payload _plus_ the length of the opcode
58 ServerPktHeader(uint32 size, uint16 cmd) : size(size)
60 uint8 headerIndex=0;
61 if(isLargePacket())
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);
79 bool isLargePacket()
81 return size > 0x7FFF;
84 const uint32 size;
85 uint8 header[5];
88 struct ClientPktHeader
90 uint16 size;
91 uint32 cmd;
94 #if defined( __GNUC__ )
95 #pragma pack()
96 #else
97 #pragma pack(pop)
98 #endif
100 WorldSocket::WorldSocket (void) :
101 WorldHandler (),
102 m_Session (0),
103 m_RecvWPct (0),
104 m_RecvPct (),
105 m_Header (sizeof (ClientPktHeader)),
106 m_OutBuffer (0),
107 m_OutBufferSize (65536),
108 m_OutActive (false),
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)
121 if (m_RecvWPct)
122 delete m_RecvWPct;
124 if (m_OutBuffer)
125 m_OutBuffer->release ();
127 closing_ = true;
129 peer ().close ();
132 bool WorldSocket::IsClosed (void) const
134 return closing_;
137 void WorldSocket::CloseSocket (void)
140 ACE_GUARD (LockType, Guard, m_OutBufferLock);
142 if (closing_)
143 return;
145 closing_ = true;
146 peer ().close_writer ();
150 ACE_GUARD (LockType, Guard, m_SessionLock);
152 m_Session = NULL;
156 const std::string& WorldSocket::GetRemoteAddress (void) const
158 return m_Address;
161 int WorldSocket::SendPacket (const WorldPacket& pct)
163 ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1);
165 if (closing_)
166 return -1;
168 // Dump outgoing packet.
169 sLog.outWorldPacketDump(uint32(get_handle()), pct.GetOpcode(), LookupOpcodeName(pct.GetOpcode()), &pct, false);
171 ServerPktHeader header(pct.size()+2, pct.GetOpcode());
172 m_Crypt.EncryptSend ((uint8*)header.header, header.getHeaderLength());
174 if (m_OutBuffer->space () >= pct.size () + header.getHeaderLength() && msg_queue()->is_empty())
176 // Put the packet on the buffer.
177 if (m_OutBuffer->copy ((char*) header.header, header.getHeaderLength()) == -1)
178 ACE_ASSERT (false);
180 if (!pct.empty ())
181 if (m_OutBuffer->copy ((char*) pct.contents (), pct.size ()) == -1)
182 ACE_ASSERT (false);
184 else
186 // Enqueue the packet.
187 ACE_Message_Block* mb;
189 ACE_NEW_RETURN(mb, ACE_Message_Block(pct.size () + header.getHeaderLength()), -1);
191 mb->copy((char*) header.header, header.getHeaderLength());
193 if (!pct.empty ())
194 mb->copy((const char*)pct.contents(), pct.size ());
196 if(msg_queue()->enqueue_tail(mb,(ACE_Time_Value*)&ACE_Time_Value::zero) == -1)
198 sLog.outError("WorldSocket::SendPacket enqueue_tail");
199 mb->release();
200 return -1;
204 return 0;
207 long WorldSocket::AddReference (void)
209 return static_cast<long> (add_reference ());
212 long WorldSocket::RemoveReference (void)
214 return static_cast<long> (remove_reference ());
217 int WorldSocket::open (void *a)
219 ACE_UNUSED_ARG (a);
221 // Prevent double call to this func.
222 if (m_OutBuffer)
223 return -1;
225 // This will also prevent the socket from being Updated
226 // while we are initializing it.
227 m_OutActive = true;
229 // Hook for the manager.
230 if (sWorldSocketMgr->OnSocketOpen (this) == -1)
231 return -1;
233 // Allocate the buffer.
234 ACE_NEW_RETURN (m_OutBuffer, ACE_Message_Block (m_OutBufferSize), -1);
236 // Store peer address.
237 ACE_INET_Addr remote_addr;
239 if (peer ().get_remote_addr (remote_addr) == -1)
241 sLog.outError ("WorldSocket::open: peer ().get_remote_addr errno = %s", ACE_OS::strerror (errno));
242 return -1;
245 m_Address = remote_addr.get_host_addr ();
247 // Send startup packet.
248 WorldPacket packet (SMSG_AUTH_CHALLENGE, 24);
249 packet << uint32(1); // 1...31
250 packet << m_Seed;
251 packet << uint32(0xF3539DA3); // random data
252 packet << uint32(0x6E8547B9); // random data
253 packet << uint32(0x9A6AA2F8); // random data
254 packet << uint32(0xA4F170F4); // random data
256 if (SendPacket (packet) == -1)
257 return -1;
259 // Register with ACE Reactor
260 if (reactor ()->register_handler(this, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK) == -1)
262 sLog.outError ("WorldSocket::open: unable to register client handler errno = %s", ACE_OS::strerror (errno));
263 return -1;
266 // reactor takes care of the socket from now on
267 remove_reference ();
269 return 0;
272 int WorldSocket::close (int)
274 shutdown ();
276 closing_ = true;
278 remove_reference ();
280 return 0;
283 int WorldSocket::handle_input (ACE_HANDLE)
285 if (closing_)
286 return -1;
288 switch (handle_input_missing_data ())
290 case -1 :
292 if ((errno == EWOULDBLOCK) ||
293 (errno == EAGAIN))
295 return Update (); // interesting line ,isn't it ?
298 DEBUG_LOG ("WorldSocket::handle_input: Peer error closing connection errno = %s", ACE_OS::strerror (errno));
300 errno = ECONNRESET;
301 return -1;
303 case 0:
305 DEBUG_LOG ("WorldSocket::handle_input: Peer has closed connection");
307 errno = ECONNRESET;
308 return -1;
310 case 1:
311 return 1;
312 default:
313 return Update (); // another interesting line ;)
316 ACE_NOTREACHED(return -1);
319 int WorldSocket::handle_output (ACE_HANDLE)
321 ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1);
323 if (closing_)
324 return -1;
326 const size_t send_len = m_OutBuffer->length ();
328 if (send_len == 0)
329 return handle_output_queue (Guard);
331 #ifdef MSG_NOSIGNAL
332 ssize_t n = peer ().send (m_OutBuffer->rd_ptr (), send_len, MSG_NOSIGNAL);
333 #else
334 ssize_t n = peer ().send (m_OutBuffer->rd_ptr (), send_len);
335 #endif // MSG_NOSIGNAL
337 if (n == 0)
338 return -1;
339 else if (n == -1)
341 if (errno == EWOULDBLOCK || errno == EAGAIN)
342 return schedule_wakeup_output (Guard);
344 return -1;
346 else if (n < (ssize_t)send_len) //now n > 0
348 m_OutBuffer->rd_ptr (static_cast<size_t> (n));
350 // move the data to the base of the buffer
351 m_OutBuffer->crunch ();
353 return schedule_wakeup_output (Guard);
355 else //now n == send_len
357 m_OutBuffer->reset ();
359 return handle_output_queue (Guard);
362 ACE_NOTREACHED (return 0);
365 int WorldSocket::handle_output_queue (GuardType& g)
367 if(msg_queue()->is_empty())
368 return cancel_wakeup_output(g);
370 ACE_Message_Block *mblk;
372 if(msg_queue()->dequeue_head(mblk, (ACE_Time_Value*)&ACE_Time_Value::zero) == -1)
374 sLog.outError("WorldSocket::handle_output_queue dequeue_head");
375 return -1;
378 const size_t send_len = mblk->length ();
380 #ifdef MSG_NOSIGNAL
381 ssize_t n = peer ().send (mblk->rd_ptr (), send_len, MSG_NOSIGNAL);
382 #else
383 ssize_t n = peer ().send (mblk->rd_ptr (), send_len);
384 #endif // MSG_NOSIGNAL
386 if (n == 0)
388 mblk->release();
390 return -1;
392 else if (n == -1)
394 if (errno == EWOULDBLOCK || errno == EAGAIN)
396 msg_queue()->enqueue_head(mblk, (ACE_Time_Value*) &ACE_Time_Value::zero);
397 return schedule_wakeup_output (g);
400 mblk->release();
401 return -1;
403 else if (n < (ssize_t)send_len) //now n > 0
405 mblk->rd_ptr (static_cast<size_t> (n));
407 if (msg_queue()->enqueue_head(mblk, (ACE_Time_Value*) &ACE_Time_Value::zero) == -1)
409 sLog.outError("WorldSocket::handle_output_queue enqueue_head");
410 mblk->release();
411 return -1;
414 return schedule_wakeup_output (g);
416 else //now n == send_len
418 mblk->release();
420 return msg_queue()->is_empty() ? cancel_wakeup_output(g) : ACE_Event_Handler::WRITE_MASK;
423 ACE_NOTREACHED(return -1);
426 int WorldSocket::handle_close (ACE_HANDLE h, ACE_Reactor_Mask)
428 // Critical section
430 ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1);
432 closing_ = true;
434 if (h == ACE_INVALID_HANDLE)
435 peer ().close_writer ();
438 // Critical section
440 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);
442 m_Session = NULL;
445 return 0;
448 int WorldSocket::Update (void)
450 if (closing_)
451 return -1;
453 if (m_OutActive || (m_OutBuffer->length () == 0 && msg_queue()->is_empty()))
454 return 0;
456 int ret;
458 ret = handle_output (get_handle ());
459 while( ret > 0 );
461 return ret;
464 int WorldSocket::handle_input_header (void)
466 ACE_ASSERT (m_RecvWPct == NULL);
468 ACE_ASSERT (m_Header.length () == sizeof (ClientPktHeader));
470 m_Crypt.DecryptRecv ((uint8*) m_Header.rd_ptr (), sizeof (ClientPktHeader));
472 ClientPktHeader& header = *((ClientPktHeader*) m_Header.rd_ptr ());
474 EndianConvertReverse(header.size);
475 EndianConvert(header.cmd);
477 if ((header.size < 4) || (header.size > 10240) || (header.cmd > 10240))
479 sLog.outError ("WorldSocket::handle_input_header: client sent malformed packet size = %d , cmd = %d",
480 header.size, header.cmd);
482 errno = EINVAL;
483 return -1;
486 header.size -= 4;
488 ACE_NEW_RETURN (m_RecvWPct, WorldPacket ((uint16) header.cmd, header.size), -1);
490 if(header.size > 0)
492 m_RecvWPct->resize (header.size);
493 m_RecvPct.base ((char*) m_RecvWPct->contents (), m_RecvWPct->size ());
495 else
497 ACE_ASSERT(m_RecvPct.space() == 0);
500 return 0;
503 int WorldSocket::handle_input_payload (void)
505 // set errno properly here on error !!!
506 // now have a header and payload
508 ACE_ASSERT (m_RecvPct.space () == 0);
509 ACE_ASSERT (m_Header.space () == 0);
510 ACE_ASSERT (m_RecvWPct != NULL);
512 const int ret = ProcessIncoming (m_RecvWPct);
514 m_RecvPct.base (NULL, 0);
515 m_RecvPct.reset ();
516 m_RecvWPct = NULL;
518 m_Header.reset ();
520 if (ret == -1)
521 errno = EINVAL;
523 return ret;
526 int WorldSocket::handle_input_missing_data (void)
528 char buf [4096];
530 ACE_Data_Block db ( sizeof (buf),
531 ACE_Message_Block::MB_DATA,
532 buf,
535 ACE_Message_Block::DONT_DELETE,
538 ACE_Message_Block message_block(&db,
539 ACE_Message_Block::DONT_DELETE,
542 const size_t recv_size = message_block.space ();
544 const ssize_t n = peer ().recv (message_block.wr_ptr (),
545 recv_size);
547 if (n <= 0)
548 return (int)n;
550 message_block.wr_ptr (n);
552 while (message_block.length () > 0)
554 if (m_Header.space () > 0)
556 //need to receive the header
557 const size_t to_header = (message_block.length () > m_Header.space () ? m_Header.space () : message_block.length ());
558 m_Header.copy (message_block.rd_ptr (), to_header);
559 message_block.rd_ptr (to_header);
561 if (m_Header.space () > 0)
563 // Couldn't receive the whole header this time.
564 ACE_ASSERT (message_block.length () == 0);
565 errno = EWOULDBLOCK;
566 return -1;
569 // We just received nice new header
570 if (handle_input_header () == -1)
572 ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN));
573 return -1;
577 // Its possible on some error situations that this happens
578 // for example on closing when epoll receives more chunked data and stuff
579 // hope this is not hack ,as proper m_RecvWPct is asserted around
580 if (!m_RecvWPct)
582 sLog.outError ("Forcing close on input m_RecvWPct = NULL");
583 errno = EINVAL;
584 return -1;
587 // We have full read header, now check the data payload
588 if (m_RecvPct.space () > 0)
590 //need more data in the payload
591 const size_t to_data = (message_block.length () > m_RecvPct.space () ? m_RecvPct.space () : message_block.length ());
592 m_RecvPct.copy (message_block.rd_ptr (), to_data);
593 message_block.rd_ptr (to_data);
595 if (m_RecvPct.space () > 0)
597 // Couldn't receive the whole data this time.
598 ACE_ASSERT (message_block.length () == 0);
599 errno = EWOULDBLOCK;
600 return -1;
604 //just received fresh new payload
605 if (handle_input_payload () == -1)
607 ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN));
608 return -1;
612 return n == recv_size ? 1 : 2;
615 int WorldSocket::cancel_wakeup_output (GuardType& g)
617 if (!m_OutActive)
618 return 0;
620 m_OutActive = false;
622 g.release ();
624 if (reactor ()->cancel_wakeup
625 (this, ACE_Event_Handler::WRITE_MASK) == -1)
627 // would be good to store errno from reactor with errno guard
628 sLog.outError ("WorldSocket::cancel_wakeup_output");
629 return -1;
632 return 0;
635 int WorldSocket::schedule_wakeup_output (GuardType& g)
637 if (m_OutActive)
638 return 0;
640 m_OutActive = true;
642 g.release ();
644 if (reactor ()->schedule_wakeup
645 (this, ACE_Event_Handler::WRITE_MASK) == -1)
647 sLog.outError ("WorldSocket::schedule_wakeup_output");
648 return -1;
651 return 0;
654 int WorldSocket::ProcessIncoming (WorldPacket* new_pct)
656 ACE_ASSERT (new_pct);
658 // manage memory ;)
659 ACE_Auto_Ptr<WorldPacket> aptr (new_pct);
661 const ACE_UINT16 opcode = new_pct->GetOpcode ();
663 if (opcode >= NUM_MSG_TYPES)
665 sLog.outError( "SESSION: received non-existed opcode 0x%.4X", opcode);
666 return -1;
669 if (closing_)
670 return -1;
672 // Dump received packet.
673 sLog.outWorldPacketDump(uint32(get_handle()), new_pct->GetOpcode(), LookupOpcodeName(new_pct->GetOpcode()), new_pct, true);
677 switch(opcode)
679 case CMSG_PING:
680 return HandlePing (*new_pct);
681 case CMSG_AUTH_SESSION:
682 if (m_Session)
684 sLog.outError ("WorldSocket::ProcessIncoming: Player send CMSG_AUTH_SESSION again");
685 return -1;
688 return HandleAuthSession (*new_pct);
689 case CMSG_KEEP_ALIVE:
690 DEBUG_LOG ("CMSG_KEEP_ALIVE ,size: %d", new_pct->size ());
692 return 0;
693 default:
695 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);
697 if (m_Session != NULL)
699 // OK ,give the packet to WorldSession
700 aptr.release ();
701 // WARNINIG here we call it with locks held.
702 // Its possible to cause deadlock if QueuePacket calls back
703 m_Session->QueuePacket (new_pct);
704 return 0;
706 else
708 sLog.outError ("WorldSocket::ProcessIncoming: Client not authed opcode = %u", uint32(opcode));
709 return -1;
714 catch (ByteBufferException &)
716 sLog.outError("WorldSocket::ProcessIncoming ByteBufferException occured while parsing an instant handled packet (opcode: %u) from client %s, accountid=%i.",
717 opcode, GetRemoteAddress().c_str(), m_Session?m_Session->GetAccountId():-1);
718 if(sLog.IsOutDebug())
720 sLog.outDebug("Dumping error-causing packet:");
721 new_pct->hexlike();
724 if (sWorld.getConfig(CONFIG_BOOL_KICK_PLAYER_ON_BAD_PACKET))
726 sLog.outDetail("Disconnecting session [account id %i / address %s] for badly formatted packet.",
727 m_Session?m_Session->GetAccountId():-1, GetRemoteAddress().c_str());
729 return -1;
731 else
732 return 0;
735 ACE_NOTREACHED (return 0);
738 int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
740 // NOTE: ATM the socket is singlethread, have this in mind ...
741 uint8 digest[20];
742 uint32 clientSeed;
743 uint32 unk2, unk3;
744 uint64 unk4;
745 uint32 ClientBuild;
746 uint32 id, security;
747 uint8 expansion = 0;
748 LocaleConstant locale;
749 std::string account;
750 Sha1Hash sha1;
751 BigNumber v, s, g, N;
752 WorldPacket packet, SendAddonPacked;
754 BigNumber K;
756 // Read the content of the packet
757 recvPacket >> ClientBuild;
758 recvPacket >> unk2;
759 recvPacket >> account;
760 recvPacket >> unk3;
761 recvPacket >> clientSeed;
762 recvPacket >> unk4;
763 recvPacket.read (digest, 20);
765 DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, unk3 %u, clientseed %u",
766 ClientBuild,
767 unk2,
768 account.c_str (),
769 unk3,
770 clientSeed);
772 // Check the version of client trying to connect
773 if(!IsAcceptableClientBuild(ClientBuild))
775 packet.Initialize (SMSG_AUTH_RESPONSE, 1);
776 packet << uint8 (AUTH_VERSION_MISMATCH);
778 SendPacket (packet);
780 sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (version mismatch).");
781 return -1;
784 // Get the account information from the realmd database
785 std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below
786 loginDatabase.escape_string (safe_account);
787 // No SQL injection, username escaped.
789 QueryResult *result =
790 loginDatabase.PQuery ("SELECT "
791 "id, " //0
792 "gmlevel, " //1
793 "sessionkey, " //2
794 "last_ip, " //3
795 "locked, " //4
796 "v, " //5
797 "s, " //6
798 "expansion, " //7
799 "mutetime, " //8
800 "locale " //9
801 "FROM account "
802 "WHERE username = '%s'",
803 safe_account.c_str ());
805 // Stop if the account is not found
806 if (!result)
808 packet.Initialize (SMSG_AUTH_RESPONSE, 1);
809 packet << uint8 (AUTH_UNKNOWN_ACCOUNT);
811 SendPacket (packet);
813 sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
814 return -1;
817 Field* fields = result->Fetch ();
819 expansion = ((sWorld.getConfig(CONFIG_UINT32_EXPANSION) > fields[7].GetUInt8()) ? fields[7].GetUInt8() : sWorld.getConfig(CONFIG_UINT32_EXPANSION));
821 N.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
822 g.SetDword (7);
824 v.SetHexStr(fields[5].GetString());
825 s.SetHexStr (fields[6].GetString ());
827 const char* sStr = s.AsHexStr (); //Must be freed by OPENSSL_free()
828 const char* vStr = v.AsHexStr (); //Must be freed by OPENSSL_free()
830 DEBUG_LOG ("WorldSocket::HandleAuthSession: (s,v) check s: %s v: %s",
831 sStr,
832 vStr);
834 OPENSSL_free ((void*) sStr);
835 OPENSSL_free ((void*) vStr);
837 ///- Re-check ip locking (same check as in realmd).
838 if (fields[4].GetUInt8 () == 1) // if ip is locked
840 if (strcmp (fields[3].GetString (), GetRemoteAddress ().c_str ()))
842 packet.Initialize (SMSG_AUTH_RESPONSE, 1);
843 packet << uint8 (AUTH_FAILED);
844 SendPacket (packet);
846 delete result;
847 sLog.outBasic ("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs).");
848 return -1;
852 id = fields[0].GetUInt32 ();
853 security = fields[1].GetUInt16 ();
854 if(security > SEC_ADMINISTRATOR) // prevent invalid security settings in DB
855 security = SEC_ADMINISTRATOR;
857 K.SetHexStr (fields[2].GetString ());
859 time_t mutetime = time_t (fields[8].GetUInt64 ());
861 locale = LocaleConstant (fields[9].GetUInt8 ());
862 if (locale >= MAX_LOCALE)
863 locale = LOCALE_enUS;
865 delete result;
867 // Re-check account ban (same check as in realmd)
868 QueryResult *banresult =
869 loginDatabase.PQuery ("SELECT 1 FROM account_banned WHERE id = %u AND active = 1 AND (unbandate > UNIX_TIMESTAMP() OR unbandate = bandate)"
870 "UNION "
871 "SELECT 1 FROM ip_banned WHERE (unbandate = bandate OR unbandate > UNIX_TIMESTAMP()) AND ip = '%s'",
872 id, GetRemoteAddress().c_str());
874 if (banresult) // if account banned
876 packet.Initialize (SMSG_AUTH_RESPONSE, 1);
877 packet << uint8 (AUTH_BANNED);
878 SendPacket (packet);
880 delete banresult;
882 sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
883 return -1;
886 // Check locked state for server
887 AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit ();
889 if (allowedAccountType > SEC_PLAYER && AccountTypes(security) < allowedAccountType)
891 WorldPacket Packet (SMSG_AUTH_RESPONSE, 1);
892 Packet << uint8 (AUTH_UNAVAILABLE);
894 SendPacket (packet);
896 sLog.outBasic ("WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
897 return -1;
900 // Check that Key and account name are the same on client and server
901 Sha1Hash sha;
903 uint32 t = 0;
904 uint32 seed = m_Seed;
906 sha.UpdateData (account);
907 sha.UpdateData ((uint8 *) & t, 4);
908 sha.UpdateData ((uint8 *) & clientSeed, 4);
909 sha.UpdateData ((uint8 *) & seed, 4);
910 sha.UpdateBigNumbers (&K, NULL);
911 sha.Finalize ();
913 if (memcmp (sha.GetDigest (), digest, 20))
915 packet.Initialize (SMSG_AUTH_RESPONSE, 1);
916 packet << uint8 (AUTH_FAILED);
918 SendPacket (packet);
920 sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed).");
921 return -1;
924 std::string address = GetRemoteAddress ();
926 DEBUG_LOG ("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.",
927 account.c_str (),
928 address.c_str ());
930 // Update the last_ip in the database
931 // No SQL injection, username escaped.
932 loginDatabase.escape_string (address);
934 loginDatabase.PExecute ("UPDATE account "
935 "SET last_ip = '%s' "
936 "WHERE username = '%s'",
937 address.c_str (),
938 safe_account.c_str ());
940 // NOTE ATM the socket is single-threaded, have this in mind ...
941 ACE_NEW_RETURN (m_Session, WorldSession (id, this, AccountTypes(security), expansion, mutetime, locale), -1);
943 m_Crypt.Init(&K);
945 m_Session->LoadGlobalAccountData();
946 m_Session->LoadTutorialsData();
947 m_Session->ReadAddonsInfo(recvPacket);
949 // In case needed sometime the second arg is in microseconds 1 000 000 = 1 sec
950 ACE_OS::sleep (ACE_Time_Value (0, 10000));
952 sWorld.AddSession (m_Session);
954 return 0;
957 int WorldSocket::HandlePing (WorldPacket& recvPacket)
959 uint32 ping;
960 uint32 latency;
962 // Get the ping packet content
963 recvPacket >> ping;
964 recvPacket >> latency;
966 if (m_LastPingTime == ACE_Time_Value::zero)
967 m_LastPingTime = ACE_OS::gettimeofday (); // for 1st ping
968 else
970 ACE_Time_Value cur_time = ACE_OS::gettimeofday ();
971 ACE_Time_Value diff_time (cur_time);
972 diff_time -= m_LastPingTime;
973 m_LastPingTime = cur_time;
975 if (diff_time < ACE_Time_Value (27))
977 ++m_OverSpeedPings;
979 uint32 max_count = sWorld.getConfig (CONFIG_UINT32_MAX_OVERSPEED_PINGS);
981 if (max_count && m_OverSpeedPings > max_count)
983 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);
985 if (m_Session && m_Session->GetSecurity () == SEC_PLAYER)
987 sLog.outError ("WorldSocket::HandlePing: Player kicked for "
988 "over-speed pings address = %s",
989 GetRemoteAddress ().c_str ());
991 return -1;
995 else
996 m_OverSpeedPings = 0;
999 // critical section
1001 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);
1003 if (m_Session)
1004 m_Session->SetLatency (latency);
1005 else
1007 sLog.outError ("WorldSocket::HandlePing: peer sent CMSG_PING, "
1008 "but is not authenticated or got recently kicked,"
1009 " address = %s",
1010 GetRemoteAddress ().c_str ());
1011 return -1;
1015 WorldPacket packet (SMSG_PONG, 4);
1016 packet << ping;
1017 return SendPacket (packet);