root/trunk/src/game/WorldSocket.cpp @ 181

Revision 181, 26.4 kB (checked in by yumileroy, 17 years ago)

[svn] Merge from Mangos:
3c7ac5bd3e20c33a22ac57c5c3bac23a0798dc9e 2008-10-23 19:06:27
Some endianess related fixes and cleanups. By VladimirMangos?.

Original author: megamage
Date: 2008-11-06 16:10:28-06:00

Line 
1/*
2* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3*
4* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
5*
6* This program is free software; you can redistribute it and/or modify
7* it under the terms of the GNU General Public License as published by
8* the Free Software Foundation; either version 2 of the License, or
9* (at your option) any later version.
10*
11* This program is distributed in the hope that it will be useful,
12* but WITHOUT ANY WARRANTY; without even the implied warranty of
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14* GNU General Public License for more details.
15*
16* You should have received a copy of the GNU General Public License
17* along with this program; if not, write to the Free Software
18* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
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 "WorldSocket.h"
33#include "Common.h"
34
35#include "Util.h"
36#include "World.h"
37#include "WorldPacket.h"
38#include "SharedDefines.h"
39#include "ByteBuffer.h"
40#include "AddonHandler.h"
41#include "Opcodes.h"
42#include "Database/DatabaseEnv.h"
43#include "Auth/Sha1.h"
44#include "WorldSession.h"
45#include "WorldSocketMgr.h"
46#include "Log.h"
47#include "WorldLog.h"
48
49#if defined( __GNUC__ )
50#pragma pack(1)
51#else
52#pragma pack(push,1)
53#endif
54
55struct ServerPktHeader
56{
57    uint16 size;
58    uint16 cmd;
59};
60
61struct ClientPktHeader
62{
63    uint16 size;
64    uint32 cmd;
65};
66
67#if defined( __GNUC__ )
68#pragma pack()
69#else
70#pragma pack(pop)
71#endif
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    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    closing_ = true;
98
99    peer ().close ();
100
101    WorldPacket* pct;
102    while (m_PacketQueue.dequeue_head (pct) == 0)
103        delete pct;
104}
105
106bool WorldSocket::IsClosed (void) const
107{
108    return closing_;
109}
110
111void WorldSocket::CloseSocket (void)
112{
113    {
114        ACE_GUARD (LockType, Guard, m_OutBufferLock);
115
116        if (closing_)
117        return;
118
119        closing_ = true;
120
121        peer ().close_writer ();
122    }
123
124    {
125        ACE_GUARD (LockType, Guard, m_SessionLock);
126
127        m_Session = NULL;
128    }
129}
130
131const std::string& WorldSocket::GetRemoteAddress (void) const
132{
133    return m_Address;
134}
135
136int WorldSocket::SendPacket (const WorldPacket& pct)
137{
138    ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1);
139
140    if (closing_)
141        return -1;
142
143    // Dump outgoing packet.
144    if (sWorldLog.LogWorld ())
145    {
146        sWorldLog.Log ("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n",
147                     (uint32) get_handle (),
148                     pct.size (),
149                     LookupOpcodeName (pct.GetOpcode ()),
150                     pct.GetOpcode ());
151
152        uint32 p = 0;
153        while (p < pct.size ())
154        {
155            for (uint32 j = 0; j < 16 && p < pct.size (); j++)
156                sWorldLog.Log ("%.2X ", const_cast<WorldPacket&>(pct)[p++]);
157
158            sWorldLog.Log ("\n");
159        }
160
161        sWorldLog.Log ("\n\n");
162    }
163
164    if (iSendPacket (pct) == -1)
165    {
166        WorldPacket* npct;
167
168        ACE_NEW_RETURN (npct, WorldPacket (pct), -1);
169
170        // NOTE maybe check of the size of the queue can be good ?
171        // to make it bounded instead of unbounded
172        if (m_PacketQueue.enqueue_tail (npct) == -1)
173        {
174            delete npct;
175            sLog.outError ("WorldSocket::SendPacket: m_PacketQueue.enqueue_tail failed");
176            return -1;
177        }
178    }
179
180    return 0;
181}
182
183long WorldSocket::AddReference (void)
184{
185    return static_cast<long> (add_reference ());
186}
187
188long WorldSocket::RemoveReference (void)
189{
190    return static_cast<long> (remove_reference ());
191}
192
193int WorldSocket::open (void *a)
194{
195    ACE_UNUSED_ARG (a);
196
197    // Prevent double call to this func.
198    if (m_OutBuffer)
199        return -1;
200
201    // This will also prevent the socket from being Updated
202    // while we are initializing it.
203    m_OutActive = true;
204
205    // Hook for the manager.
206    if (sWorldSocketMgr->OnSocketOpen (this) == -1)
207        return -1;
208
209    // Allocate the buffer.
210    ACE_NEW_RETURN (m_OutBuffer, ACE_Message_Block (m_OutBufferSize), -1);
211
212    // Store peer address.
213    ACE_INET_Addr remote_addr;
214
215    if (peer ().get_remote_addr (remote_addr) == -1)
216    {
217        sLog.outError ("WorldSocket::open: peer ().get_remote_addr errno = %s", ACE_OS::strerror (errno));
218        return -1;
219    }
220
221    m_Address = remote_addr.get_host_addr ();
222
223    // Send startup packet.
224    WorldPacket packet (SMSG_AUTH_CHALLENGE, 4);
225    packet << m_Seed;
226
227    if (SendPacket (packet) == -1)
228        return -1;
229
230    // Register with ACE Reactor
231    if (reactor ()->register_handler(this, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK) == -1)
232    {
233        sLog.outError ("WorldSocket::open: unable to register client handler errno = %s", ACE_OS::strerror (errno));
234        return -1;
235    }
236
237    // reactor takes care of the socket from now on
238    remove_reference ();
239
240    return 0;
241}
242
243int WorldSocket::close (int)
244{
245    shutdown ();
246
247    closing_ = true;
248
249    remove_reference ();
250
251    return 0;
252}
253
254int WorldSocket::handle_input (ACE_HANDLE)
255{
256    if (closing_)
257        return -1;
258
259    switch (handle_input_missing_data ())
260    {
261        case -1 :
262        {
263            if ((errno == EWOULDBLOCK) ||
264                (errno == EAGAIN))
265            {
266                return Update (); // interesting line ,isnt it ?
267            }
268
269            DEBUG_LOG ("WorldSocket::handle_input: Peer error closing connection errno = %s", ACE_OS::strerror (errno));
270
271            errno = ECONNRESET;
272            return -1;
273        }
274        case 0:
275        {
276            DEBUG_LOG ("WorldSocket::handle_input: Peer has closed connection\n");
277
278            errno = ECONNRESET;
279            return -1;
280        }
281        case 1:
282            return 1;
283        default:
284            return Update (); // another interesting line ;)
285    }
286
287    ACE_NOTREACHED(return -1);
288}
289
290int WorldSocket::handle_output (ACE_HANDLE)
291{
292    ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1);
293
294    if (closing_)
295        return -1;
296
297    const size_t send_len = m_OutBuffer->length ();
298
299    if (send_len == 0)
300        return cancel_wakeup_output (Guard);
301
302#ifdef MSG_NOSIGNAL
303    ssize_t n = peer ().send (m_OutBuffer->rd_ptr (), send_len, MSG_NOSIGNAL);
304#else
305    ssize_t n = peer ().send (m_OutBuffer->rd_ptr (), send_len);
306#endif // MSG_NOSIGNAL
307
308    if (n == 0)
309        return -1;
310    else if (n == -1)
311    {
312        if (errno == EWOULDBLOCK || errno == EAGAIN)
313            return schedule_wakeup_output (Guard);
314
315        return -1;
316    }
317    else if (n < send_len) //now n > 0
318    {
319        m_OutBuffer->rd_ptr (static_cast<size_t> (n));
320
321        // move the data to the base of the buffer
322        m_OutBuffer->crunch ();
323
324        return schedule_wakeup_output (Guard);
325    }
326    else //now n == send_len
327    {
328        m_OutBuffer->reset ();
329
330        if (!iFlushPacketQueue ())
331            return cancel_wakeup_output (Guard);
332        else
333            return schedule_wakeup_output (Guard);
334    }
335
336    ACE_NOTREACHED (return 0);
337}
338
339int WorldSocket::handle_close (ACE_HANDLE h, ACE_Reactor_Mask)
340{
341    // Critical section
342    {
343        ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1);
344
345        closing_ = true;
346
347        if (h == ACE_INVALID_HANDLE)
348            peer ().close_writer ();
349    }
350
351    // Critical section
352    {
353        ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);
354
355        m_Session = NULL;
356    }
357
358    return 0;
359}
360
361int WorldSocket::Update (void)
362{
363    if (closing_)
364        return -1;
365
366    if (m_OutActive || m_OutBuffer->length () == 0)
367        return 0;
368
369    return handle_output (get_handle ());
370}
371
372int WorldSocket::handle_input_header (void)
373{
374    ACE_ASSERT (m_RecvWPct == NULL);
375
376    ACE_ASSERT (m_Header.length () == sizeof (ClientPktHeader));
377
378    m_Crypt.DecryptRecv ((ACE_UINT8*) m_Header.rd_ptr (), sizeof (ClientPktHeader));
379
380    ClientPktHeader& header = *((ClientPktHeader*) m_Header.rd_ptr ());
381
382    EndianConvertReverse(header.size);
383    EndianConvert(header.cmd);
384
385    if ((header.size < 4) || (header.size > 10240) ||
386        (header.cmd  < 0) || (header.cmd  > 10240) )
387    {
388        sLog.outError ("WorldSocket::handle_input_header: client sent mailformed packet size = %d , cmd = %d",
389                       header.size, header.cmd);
390
391        errno = EINVAL;
392        return -1;
393    }
394
395    header.size -= 4;
396
397    ACE_NEW_RETURN (m_RecvWPct, WorldPacket ((uint16) header.cmd, header.size), -1);
398
399    if(header.size > 0)
400    {
401        m_RecvWPct->resize (header.size);
402        m_RecvPct.base ((char*) m_RecvWPct->contents (), m_RecvWPct->size ());
403    }
404    else
405    {
406        ACE_ASSERT(m_RecvPct.space() == 0);
407    }
408
409    return 0;
410}
411
412int WorldSocket::handle_input_payload (void)
413{
414    // set errno properly here on error !!!
415    // now have a header and payload
416
417    ACE_ASSERT (m_RecvPct.space () == 0);
418    ACE_ASSERT (m_Header.space () == 0);
419    ACE_ASSERT (m_RecvWPct != NULL);
420
421    const int ret = ProcessIncoming (m_RecvWPct);
422
423    m_RecvPct.base (NULL, 0);
424    m_RecvPct.reset ();
425    m_RecvWPct = NULL;
426
427    m_Header.reset ();
428
429    if (ret == -1)
430        errno = EINVAL;
431
432    return ret;
433}
434
435int WorldSocket::handle_input_missing_data (void)
436{
437    char buf [1024];
438
439    ACE_Data_Block db ( sizeof (buf),
440                        ACE_Message_Block::MB_DATA,
441                        buf,
442                        0,
443                        0,
444                        ACE_Message_Block::DONT_DELETE,
445                        0);
446
447    ACE_Message_Block message_block(&db,
448                                    ACE_Message_Block::DONT_DELETE,
449                                    0);
450
451    const size_t recv_size = message_block.space ();
452
453    const ssize_t n = peer ().recv (message_block.wr_ptr (),
454                                          recv_size);
455
456    if (n <= 0)
457        return n;
458
459    message_block.wr_ptr (n);
460
461    while (message_block.length () > 0)
462    {
463        if (m_Header.space () > 0)
464        {
465            //need to recieve the header
466            const size_t to_header = (message_block.length () > m_Header.space () ? m_Header.space () : message_block.length ());
467            m_Header.copy (message_block.rd_ptr (), to_header);
468            message_block.rd_ptr (to_header);
469
470            if (m_Header.space () > 0)
471            {
472                //couldnt recieve the whole header this time
473                ACE_ASSERT (message_block.length () == 0);
474                errno = EWOULDBLOCK;
475                return -1;
476            }
477
478          //we just recieved nice new header
479            if (handle_input_header () == -1)
480            {
481                ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN));
482                return -1;
483            }
484        }
485
486        // Its possible on some error situations that this happens
487        // for example on closing when epoll recieves more chunked data and stuff
488        // hope this is not hack ,as proper m_RecvWPct is asserted around
489        if (!m_RecvWPct)
490        {
491            sLog.outError ("Forsing close on input m_RecvWPct = NULL");
492            errno = EINVAL;
493            return -1;
494        }
495
496        // We have full readed header, now check the data payload
497        if (m_RecvPct.space () > 0)
498        {
499            //need more data in the payload
500            const size_t to_data = (message_block.length () > m_RecvPct.space () ? m_RecvPct.space () : message_block.length ());
501            m_RecvPct.copy (message_block.rd_ptr (), to_data);
502            message_block.rd_ptr (to_data);
503
504            if (m_RecvPct.space () > 0)
505            {
506                //couldnt recieve the whole data this time
507                ACE_ASSERT (message_block.length () == 0);
508                errno = EWOULDBLOCK;
509                return -1;
510            }
511        }
512
513        //just recieved fresh new payload
514        if (handle_input_payload () == -1)
515        {
516            ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN));
517            return -1;
518        }
519    }
520
521    return n == recv_size ? 1 : 2;
522}
523
524int WorldSocket::cancel_wakeup_output (GuardType& g)
525{
526    if (!m_OutActive)
527        return 0;
528
529    m_OutActive = false;
530
531    g.release ();
532
533    if (reactor ()->cancel_wakeup
534        (this, ACE_Event_Handler::WRITE_MASK) == -1)
535    {
536        // would be good to store errno from reactor with errno guard
537        sLog.outError ("WorldSocket::cancel_wakeup_output");
538        return -1;
539    }
540
541    return 0;
542}
543
544int WorldSocket::schedule_wakeup_output (GuardType& g)
545{
546    if (m_OutActive)
547        return 0;
548
549    m_OutActive = true;
550
551    g.release ();
552
553    if (reactor ()->schedule_wakeup
554        (this, ACE_Event_Handler::WRITE_MASK) == -1)
555    {
556        sLog.outError ("WorldSocket::schedule_wakeup_output");
557        return -1;
558    }
559
560    return 0;
561}
562
563int WorldSocket::ProcessIncoming (WorldPacket* new_pct)
564{
565    ACE_ASSERT (new_pct);
566
567    // manage memory ;)
568    ACE_Auto_Ptr<WorldPacket> aptr (new_pct);
569
570    const ACE_UINT16 opcode = new_pct->GetOpcode ();
571
572    if (closing_)
573        return -1;
574
575    // dump recieved packet
576    if (sWorldLog.LogWorld ())
577    {
578        sWorldLog.Log ("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n",
579                     (uint32) get_handle (),
580                     new_pct->size (),
581                     LookupOpcodeName (new_pct->GetOpcode ()),
582                     new_pct->GetOpcode ());
583
584        uint32 p = 0;
585        while (p < new_pct->size ())
586        {
587            for (uint32 j = 0; j < 16 && p < new_pct->size (); j++)
588                sWorldLog.Log ("%.2X ", (*new_pct)[p++]);
589            sWorldLog.Log ("\n");
590        }
591        sWorldLog.Log ("\n\n");
592    }
593
594    // like one switch ;)
595    if (opcode == CMSG_PING)
596    {
597        return HandlePing (*new_pct);
598    }
599    else if (opcode == CMSG_AUTH_SESSION)
600    {
601        if (m_Session)
602        {
603            sLog.outError ("WorldSocket::ProcessIncoming: Player send CMSG_AUTH_SESSION again");
604            return -1;
605        }
606
607        return HandleAuthSession (*new_pct);
608    }
609    else if (opcode == CMSG_KEEP_ALIVE)
610    {
611        DEBUG_LOG ("CMSG_KEEP_ALIVE ,size: %d", new_pct->size ());
612
613        return 0;
614    }
615    else
616    {
617        ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);
618
619        if (m_Session != NULL)
620        {
621            // OK ,give the packet to WorldSession
622            aptr.release ();
623            // WARNINIG here we call it with locks held.
624            // Its possible to cause deadlock if QueuePacket calls back
625            m_Session->QueuePacket (new_pct);
626            return 0;
627        }
628        else
629        {
630            sLog.outError ("WorldSocket::ProcessIncoming: Client not authed opcode = ", opcode);
631            return -1;
632        }
633    }
634
635    ACE_NOTREACHED (return 0);
636}
637
638int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
639{
640    // NOTE: ATM the socket is singlethreaded, have this in mind ...
641    uint8 digest[20];
642    uint32 clientSeed;
643    uint32 unk2;
644    uint32 BuiltNumberClient;
645    uint32 id, security;
646    //uint8 expansion = 0;
647    LocaleConstant locale;
648    std::string account;
649    Sha1Hash sha1;
650    BigNumber v, s, g, N, x, I;
651    WorldPacket packet, SendAddonPacked;
652
653    BigNumber K;
654
655    if (recvPacket.size () < (4 + 4 + 1 + 4 + 20))
656    {
657        sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size");
658        return -1;
659    }
660
661    // Read the content of the packet
662    recvPacket >> BuiltNumberClient;                        // for now no use
663    recvPacket >> unk2;
664    recvPacket >> account;
665
666    if (recvPacket.size () < (4 + 4 + (account.size () + 1) + 4 + 20))
667    {
668        sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size second check");
669        return -1;
670    }
671
672    recvPacket >> clientSeed;
673    recvPacket.read (digest, 20);
674
675    DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, clientseed %u",
676                BuiltNumberClient,
677                unk2,
678                account.c_str (),
679                clientSeed);
680
681    // Get the account information from the realmd database
682    std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below
683    loginDatabase.escape_string (safe_account);
684    // No SQL injection, username escaped.
685
686    QueryResult *result =
687          loginDatabase.PQuery ("SELECT "
688                                "id, " //0
689                                "gmlevel, " //1
690                                "sessionkey, " //2
691                                "last_ip, " //3
692                                "locked, " //4
693                                "sha_pass_hash, " //5
694                                "v, " //6
695                                "s, " //7
696                                "expansion, " //8
697                                "mutetime, " //9
698                                "locale " //10
699                                "FROM account "
700                                "WHERE username = '%s'",
701                                safe_account.c_str ());
702
703    // Stop if the account is not found
704    if (!result)
705    {
706        packet.Initialize (SMSG_AUTH_RESPONSE, 1);
707        packet << uint8 (AUTH_UNKNOWN_ACCOUNT);
708
709        SendPacket (packet);
710
711        sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
712        return -1;
713    }
714
715    Field* fields = result->Fetch ();
716
717    uint8 expansion = fields[8].GetUInt8();
718    uint32 world_expansion = sWorld.getConfig(CONFIG_EXPANSION);
719    if(expansion > world_expansion)
720        expansion = world_expansion;
721
722    N.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
723    g.SetDword (7);
724    I.SetHexStr (fields[5].GetString ());
725
726    //In case of leading zeros in the I hash, restore them
727    uint8 mDigest[SHA_DIGEST_LENGTH];
728    memset (mDigest, 0, SHA_DIGEST_LENGTH);
729
730    if (I.GetNumBytes () <= SHA_DIGEST_LENGTH)
731        memcpy (mDigest, I.AsByteArray (), I.GetNumBytes ());
732
733    std::reverse (mDigest, mDigest + SHA_DIGEST_LENGTH);
734
735    s.SetHexStr (fields[7].GetString ());
736    sha1.UpdateData (s.AsByteArray (), s.GetNumBytes ());
737    sha1.UpdateData (mDigest, SHA_DIGEST_LENGTH);
738    sha1.Finalize ();
739    x.SetBinary (sha1.GetDigest (), sha1.GetLength ());
740    v = g.ModExp (x, N);
741
742    const char* sStr = s.AsHexStr (); //Must be freed by OPENSSL_free()
743    const char* vStr = v.AsHexStr (); //Must be freed by OPENSSL_free()
744    const char* vold = fields[6].GetString ();
745
746    DEBUG_LOG ("WorldSocket::HandleAuthSession: (s,v) check s: %s v_old: %s v_new: %s",
747                sStr,
748                vold,
749                vStr);
750
751    loginDatabase.PExecute ("UPDATE account "
752                            "SET "
753                            "v = '0', "
754                            "s = '0' "
755                            "WHERE username = '%s'",
756                            safe_account.c_str ());
757
758    if (!vold || strcmp (vStr, vold))
759    {
760        packet.Initialize (SMSG_AUTH_RESPONSE, 1);
761        packet << uint8 (AUTH_UNKNOWN_ACCOUNT);
762        SendPacket (packet);
763        delete result;
764        OPENSSL_free ((void*) sStr);
765        OPENSSL_free ((void*) vStr);
766
767        sLog.outBasic ("WorldSocket::HandleAuthSession: User not logged.");
768        return -1;
769    }
770
771    OPENSSL_free ((void*) sStr);
772    OPENSSL_free ((void*) vStr);
773
774    ///- Re-check ip locking (same check as in realmd).
775    if (fields[4].GetUInt8 () == 1) // if ip is locked
776    {
777        if (strcmp (fields[3].GetString (), GetRemoteAddress ().c_str ()))
778        {
779            packet.Initialize (SMSG_AUTH_RESPONSE, 1);
780            packet << uint8 (AUTH_FAILED);
781            SendPacket (packet);
782
783            delete result;
784            sLog.outBasic ("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs).");
785            return -1;
786        }
787    }
788
789    id = fields[0].GetUInt32 ();
790    security = fields[1].GetUInt16 ();
791    K.SetHexStr (fields[2].GetString ());
792
793    time_t mutetime = time_t (fields[9].GetUInt64 ());
794
795    locale = LocaleConstant (fields[10].GetUInt8 ());
796    if (locale >= MAX_LOCALE)
797        locale = LOCALE_enUS;
798
799    delete result;
800
801    // Re-check account ban (same check as in realmd)
802    QueryResult *banresult =
803          loginDatabase.PQuery ("SELECT "
804                                "bandate, "
805                                "unbandate "
806                                "FROM account_banned "
807                                "WHERE id = '%u' "
808                                "AND active = 1",
809                                id);
810
811    if (banresult) // if account banned
812    {
813        packet.Initialize (SMSG_AUTH_RESPONSE, 1);
814        packet << uint8 (AUTH_BANNED);
815        SendPacket (packet);
816
817        delete banresult;
818
819        sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
820        return -1;
821    }
822
823    // Check locked state for server
824    AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit ();
825
826    if (allowedAccountType > SEC_PLAYER && security < allowedAccountType)
827    {
828        WorldPacket Packet (SMSG_AUTH_RESPONSE, 1);
829        Packet << uint8 (AUTH_UNAVAILABLE);
830
831        SendPacket (packet);
832
833        sLog.outBasic ("WorldSocket::HandleAuthSession: User tryes to login but his security level is not enough");
834        return -1;
835    }
836
837    // Check that Key and account name are the same on client and server
838    Sha1Hash sha;
839
840    uint32 t = 0;
841    uint32 seed = m_Seed;
842
843    sha.UpdateData (account);
844    sha.UpdateData ((uint8 *) & t, 4);
845    sha.UpdateData ((uint8 *) & clientSeed, 4);
846    sha.UpdateData ((uint8 *) & seed, 4);
847    sha.UpdateBigNumbers (&K, NULL);
848    sha.Finalize ();
849
850    if (memcmp (sha.GetDigest (), digest, 20))
851    {
852        packet.Initialize (SMSG_AUTH_RESPONSE, 1);
853        packet << uint8 (AUTH_FAILED);
854
855        SendPacket (packet);
856
857        sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed).");
858        return -1;
859    }
860
861    std::string address = GetRemoteAddress ();
862
863    DEBUG_LOG ("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.",
864                account.c_str (),
865                address.c_str ());
866
867    // Update the last_ip in the database
868    // No SQL injection, username escaped.
869    loginDatabase.escape_string (address);
870
871    loginDatabase.PExecute ("UPDATE account "
872                            "SET last_ip = '%s' "
873                            "WHERE username = '%s'",
874                            address.c_str (),
875                            safe_account.c_str ());
876
877    // NOTE ATM the socket is singlethreaded, have this in mind ...
878    ACE_NEW_RETURN (m_Session, WorldSession (id, this, security, expansion, mutetime, locale), -1);
879
880    m_Crypt.SetKey (&K);
881    m_Crypt.Init ();
882
883    // In case needed sometime the second arg is in microseconds 1 000 000 = 1 sec
884    ACE_OS::sleep (ACE_Time_Value (0, 10000));
885
886    sWorld.AddSession (m_Session);
887
888    // Create and send the Addon packet
889    if (sAddOnHandler.BuildAddonPacket (&recvPacket, &SendAddonPacked))
890        SendPacket (SendAddonPacked);
891
892    return 0;
893}
894
895int WorldSocket::HandlePing (WorldPacket& recvPacket)
896{
897    uint32 ping;
898    uint32 latency;
899
900    if (recvPacket.size () < 8)
901    {
902        sLog.outError ("WorldSocket::_HandlePing wrong packet size");
903        return -1;
904    }
905
906    // Get the ping packet content
907    recvPacket >> ping;
908    recvPacket >> latency;
909
910    if (m_LastPingTime == ACE_Time_Value::zero)
911        m_LastPingTime = ACE_OS::gettimeofday (); // for 1st ping
912    else
913    {
914        ACE_Time_Value cur_time = ACE_OS::gettimeofday ();
915        ACE_Time_Value diff_time (cur_time);
916        diff_time -= m_LastPingTime;
917        m_LastPingTime = cur_time;
918
919        if (diff_time < ACE_Time_Value (27))
920        {
921            ++m_OverSpeedPings;
922
923            uint32 max_count = sWorld.getConfig (CONFIG_MAX_OVERSPEED_PINGS);
924
925            if (max_count && m_OverSpeedPings > max_count)
926            {
927                ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);
928
929                if (m_Session && m_Session->GetSecurity () == SEC_PLAYER)
930                {
931                    sLog.outError  ("WorldSocket::HandlePing: Player kicked for "
932                                    "overspeeded pings adress = %s",
933                                    GetRemoteAddress ().c_str ());
934
935                    return -1;
936                }
937            }
938        }
939        else
940            m_OverSpeedPings = 0;
941    }
942
943    // critical section
944    {
945        ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);
946
947        if (m_Session)
948        m_Session->SetLatency (latency);
949        else
950        {
951            sLog.outError ("WorldSocket::HandlePing: peer sent CMSG_PING, "
952                            "but is not authenticated or got recently kicked,"
953                            " adress = %s",
954                            GetRemoteAddress ().c_str ());
955             return -1;
956        }
957    }
958
959    WorldPacket packet (SMSG_PONG, 4);
960    packet << ping;
961    return SendPacket (packet);
962}
963
964int WorldSocket::iSendPacket (const WorldPacket& pct)
965{
966    if (m_OutBuffer->space () < pct.size () + sizeof (ServerPktHeader))
967    {
968        errno = ENOBUFS;
969        return -1;
970    }
971
972    ServerPktHeader header;
973
974    header.cmd = pct.GetOpcode ();
975    EndianConvert(header.cmd);
976
977    header.size = (uint16) pct.size () + 2;
978    EndianConvertReverse(header.size);
979
980    m_Crypt.EncryptSend ((uint8*) & header, sizeof (header));
981
982    if (m_OutBuffer->copy ((char*) & header, sizeof (header)) == -1)
983        ACE_ASSERT (false);
984
985    if (!pct.empty ())
986        if (m_OutBuffer->copy ((char*) pct.contents (), pct.size ()) == -1)
987            ACE_ASSERT (false);
988
989    return 0;
990}
991
992bool WorldSocket::iFlushPacketQueue ()
993{
994    WorldPacket *pct;
995    bool haveone = false;
996
997    while (m_PacketQueue.dequeue_head (pct) == 0)
998    {
999        if (iSendPacket (*pct) == -1)
1000        {
1001            if (m_PacketQueue.enqueue_head (pct) == -1)
1002            {
1003                delete pct;
1004                sLog.outError ("WorldSocket::iFlushPacketQueue m_PacketQueue->enqueue_head");
1005                return false;
1006            }
1007
1008            break;
1009        }
1010        else
1011        {
1012            haveone = true;
1013            delete pct;
1014        }
1015    }
1016
1017    return haveone;
1018}
Note: See TracBrowser for help on using the browser.