2010-10-07 15:35:36 +02:00
/*
2012-12-31 23:15:50 +01:00
* Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
2010-10-07 15:35:36 +02:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
2010-10-07 14:50:05 +02:00
*/
2009-10-17 15:51:44 -07:00
2008-10-04 06:17:19 -05:00
#include <ace/Message_Block.h>
#include <ace/OS_NS_string.h>
#include <ace/OS_NS_unistd.h>
#include <ace/os_include/arpa/os_inet.h>
#include <ace/os_include/netinet/os_tcp.h>
#include <ace/os_include/sys/os_types.h>
#include <ace/os_include/sys/os_socket.h>
#include <ace/OS_NS_string.h>
#include <ace/Reactor.h>
#include <ace/Auto_Ptr.h>
2009-10-17 15:51:44 -07:00
2008-11-02 16:53:46 -06:00
#include "WorldSocket.h"
#include "Common.h"
2012-11-17 05:18:37 +01:00
#include "Player.h"
2008-10-04 06:17:19 -05:00
#include "Util.h"
#include "World.h"
#include "WorldPacket.h"
#include "SharedDefines.h"
#include "ByteBuffer.h"
2008-10-02 16:23:55 -05:00
#include "Opcodes.h"
2010-06-08 17:01:03 -06:00
#include "DatabaseEnv.h"
2010-06-07 16:21:52 -06:00
#include "BigNumber.h"
#include "SHA1.h"
2008-10-02 16:23:55 -05:00
#include "WorldSession.h"
#include "WorldSocketMgr.h"
2008-10-04 06:17:19 -05:00
#include "Log.h"
2012-08-17 10:36:48 +02:00
#include "PacketLog.h"
2010-08-06 19:23:43 +02:00
#include "ScriptMgr.h"
2011-09-08 15:11:55 +02:00
#include "AccountMgr.h"
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
#if defined(__GNUC__)
2008-10-02 16:23:55 -05:00
#pragma pack(1)
#else
2011-04-29 20:47:02 +02:00
#pragma pack(push, 1)
2008-10-02 16:23:55 -05:00
#endif
2009-10-17 15:51:44 -07:00
2008-10-04 06:17:19 -05:00
struct ServerPktHeader
2008-10-02 16:23:55 -05:00
{
2008-12-24 09:58:26 -06:00
/**
* size is the length of the payload _plus_ the length of the opcode
*/
ServerPktHeader ( uint32 size , uint16 cmd ) : size ( size )
{
uint8 headerIndex = 0 ;
2010-04-07 19:14:10 +02:00
if ( isLargePacket ())
2008-12-24 09:58:26 -06:00
{
2013-05-13 15:07:36 +02:00
TC_LOG_DEBUG ( LOG_FILTER_NETWORKIO , "initializing large server to client packet. Size: %u, cmd: %u" , size , cmd );
2012-08-03 14:20:18 +02:00
header [ headerIndex ++ ] = 0x80 | ( 0xFF & ( size >> 16 ));
2008-12-24 09:58:26 -06:00
}
2012-08-03 14:20:18 +02:00
header [ headerIndex ++ ] = 0xFF & ( size >> 8 );
header [ headerIndex ++ ] = 0xFF & size ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
header [ headerIndex ++ ] = 0xFF & cmd ;
2012-08-03 14:20:18 +02:00
header [ headerIndex ++ ] = 0xFF & ( cmd >> 8 );
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
uint8 getHeaderLength ()
{
// cmd = 2 bytes, size= 2||3bytes
2012-08-03 14:20:18 +02:00
return 2 + ( isLargePacket () ? 3 : 2 );
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2012-06-21 21:05:45 +03:00
bool isLargePacket () const
2008-12-24 09:58:26 -06:00
{
return size > 0x7FFF ;
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
const uint32 size ;
2009-01-04 16:37:14 -06:00
uint8 header [ 5 ];
2008-10-02 16:23:55 -05:00
};
2009-10-17 15:51:44 -07:00
2008-10-04 06:17:19 -05:00
struct ClientPktHeader
2008-10-02 16:23:55 -05:00
{
2008-11-06 16:10:28 -06:00
uint16 size ;
uint32 cmd ;
2008-10-02 16:23:55 -05:00
};
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
#if defined(__GNUC__)
2008-10-02 16:23:55 -05:00
#pragma pack()
#else
#pragma pack(pop)
#endif
2009-10-17 15:51:44 -07:00
2010-08-21 20:08:47 +02:00
WorldSocket :: WorldSocket ( void ) : WorldHandler (),
m_LastPingTime ( ACE_Time_Value :: zero ), m_OverSpeedPings ( 0 ), m_Session ( 0 ),
m_RecvWPct ( 0 ), m_RecvPct (), m_Header ( sizeof ( ClientPktHeader )),
m_OutBuffer ( 0 ), m_OutBufferSize ( 65536 ), m_OutActive ( false ),
m_Seed ( static_cast < uint32 > ( rand32 ()))
2008-10-02 16:23:55 -05:00
{
2010-05-12 22:03:07 +02:00
reference_counting_policy (). value ( ACE_Event_Handler :: Reference_Counting_Policy :: ENABLED );
2010-08-08 19:45:53 +02:00
2012-08-03 14:20:18 +02:00
msg_queue () -> high_water_mark ( 8 * 1024 * 1024 );
msg_queue () -> low_water_mark ( 8 * 1024 * 1024 );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-04 06:17:19 -05:00
WorldSocket ::~ WorldSocket ( void )
2008-10-02 16:23:55 -05:00
{
2010-06-21 23:20:58 +02:00
delete m_RecvWPct ;
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
if ( m_OutBuffer )
2010-05-12 22:03:07 +02:00
m_OutBuffer -> release ();
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
closing_ = true ;
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
peer (). close ();
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
bool WorldSocket :: IsClosed ( void ) const
2008-10-02 16:23:55 -05:00
{
2008-11-06 16:10:28 -06:00
return closing_ ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
void WorldSocket :: CloseSocket ( void )
2008-10-02 16:23:55 -05:00
{
2008-11-06 16:10:28 -06:00
{
ACE_GUARD ( LockType , Guard , m_OutBufferLock );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
if ( closing_ )
2008-12-12 11:21:28 -06:00
return ;
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
closing_ = true ;
2010-05-12 22:03:07 +02:00
peer (). close_writer ();
2008-11-06 16:10:28 -06:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
{
ACE_GUARD ( LockType , Guard , m_SessionLock );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
m_Session = NULL ;
}
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
const std :: string & WorldSocket :: GetRemoteAddress ( void ) const
2008-10-02 16:23:55 -05:00
{
2008-11-06 16:10:28 -06:00
return m_Address ;
2008-10-04 06:17:19 -05:00
}
2009-10-17 15:51:44 -07:00
2012-06-04 08:51:56 +02:00
int WorldSocket :: SendPacket ( WorldPacket const & pct )
2008-10-04 06:17:19 -05:00
{
2008-11-06 16:10:28 -06:00
ACE_GUARD_RETURN ( LockType , Guard , m_OutBufferLock , - 1 );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
if ( closing_ )
return - 1 ;
2009-10-17 15:51:44 -07:00
2013-01-16 11:17:14 +01:00
// Dump outgoing packet
2012-08-17 10:36:48 +02:00
if ( sPacketLog -> CanLogPacket ())
sPacketLog -> LogPacket ( pct , SERVER_TO_CLIENT );
2009-10-17 15:51:44 -07:00
2013-01-16 11:17:14 +01:00
WorldPacket const * pkt = & pct ;
2012-11-23 12:36:18 +01:00
if ( m_Session )
2013-05-13 15:07:36 +02:00
TC_LOG_TRACE ( LOG_FILTER_OPCODES , "S->C: %s %s" , m_Session -> GetPlayerInfo (). c_str (), GetOpcodeNameForLogging ( pkt -> GetOpcode ()). c_str ());
2012-11-23 12:36:18 +01:00
2013-01-16 11:17:14 +01:00
sScriptMgr -> OnPacketSend ( this , * pkt );
2010-08-06 19:23:43 +02:00
2013-01-16 11:17:14 +01:00
ServerPktHeader header ( pkt -> size () + 2 , pkt -> GetOpcode ());
2010-05-12 22:03:07 +02:00
m_Crypt . EncryptSend (( uint8 * ) header . header , header . getHeaderLength ());
2013-01-16 11:17:14 +01:00
if ( m_OutBuffer -> space () >= pkt -> size () + header . getHeaderLength () && msg_queue () -> is_empty ())
2008-10-04 06:17:19 -05:00
{
2010-05-12 22:03:07 +02:00
// Put the packet on the buffer.
if ( m_OutBuffer -> copy (( char * ) header . header , header . getHeaderLength ()) == - 1 )
ACE_ASSERT ( false );
2009-10-17 15:51:44 -07:00
2013-01-16 11:17:14 +01:00
if ( ! pkt -> empty ())
if ( m_OutBuffer -> copy (( char * ) pkt -> contents (), pkt -> size ()) == - 1 )
2010-05-12 22:03:07 +02:00
ACE_ASSERT ( false );
}
else
{
// Enqueue the packet.
ACE_Message_Block * mb ;
2013-01-16 11:17:14 +01:00
ACE_NEW_RETURN ( mb , ACE_Message_Block ( pkt -> size () + header . getHeaderLength ()), - 1 );
2010-05-12 22:03:07 +02:00
mb -> copy (( char * ) header . header , header . getHeaderLength ());
2009-10-17 15:51:44 -07:00
2013-01-16 11:17:14 +01:00
if ( ! pkt -> empty ())
mb -> copy (( const char * ) pkt -> contents (), pkt -> size ());
2010-05-12 22:03:07 +02:00
2011-04-29 20:47:02 +02:00
if ( msg_queue () -> enqueue_tail ( mb , ( ACE_Time_Value * ) & ACE_Time_Value :: zero ) == - 1 )
2008-10-02 16:23:55 -05:00
{
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_NETWORKIO , "WorldSocket::SendPacket enqueue_tail failed" );
2010-05-12 22:03:07 +02:00
mb -> release ();
2008-11-06 16:10:28 -06:00
return - 1 ;
2008-10-02 16:23:55 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
return 0 ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
long WorldSocket :: AddReference ( void )
2008-10-02 16:23:55 -05:00
{
2010-05-12 22:03:07 +02:00
return static_cast < long > ( add_reference ());
2008-10-04 06:17:19 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
long WorldSocket :: RemoveReference ( void )
2008-10-04 06:17:19 -05:00
{
2010-05-12 22:03:07 +02:00
return static_cast < long > ( remove_reference ());
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
int WorldSocket :: open ( void * a )
2008-10-02 16:23:55 -05:00
{
2008-11-06 16:10:28 -06:00
ACE_UNUSED_ARG ( a );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
// Prevent double call to this func.
if ( m_OutBuffer )
return - 1 ;
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
// This will also prevent the socket from being Updated
// while we are initializing it.
m_OutActive = true ;
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
// Hook for the manager.
2010-05-12 22:03:07 +02:00
if ( sWorldSocketMgr -> OnSocketOpen ( this ) == - 1 )
2008-11-06 16:10:28 -06:00
return - 1 ;
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
// Allocate the buffer.
ACE_NEW_RETURN ( m_OutBuffer , ACE_Message_Block ( m_OutBufferSize ), - 1 );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
// Store peer address.
ACE_INET_Addr remote_addr ;
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
if ( peer (). get_remote_addr ( remote_addr ) == - 1 )
2008-10-02 16:23:55 -05:00
{
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_NETWORKIO , "WorldSocket::open: peer().get_remote_addr errno = %s" , ACE_OS :: strerror ( errno ));
2008-11-06 16:10:28 -06:00
return - 1 ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
m_Address = remote_addr . get_host_addr ();
2010-08-08 19:45:53 +02:00
2013-01-16 11:17:14 +01:00
if ( HandleSendAuthSession () == - 1 )
2008-11-06 16:10:28 -06:00
return - 1 ;
2010-08-08 19:45:53 +02:00
2008-11-06 16:10:28 -06:00
// Register with ACE Reactor
2010-05-12 22:03:07 +02:00
if ( reactor () -> register_handler ( this , ACE_Event_Handler :: READ_MASK | ACE_Event_Handler :: WRITE_MASK ) == - 1 )
2008-10-02 16:23:55 -05:00
{
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_NETWORKIO , "WorldSocket::open: unable to register client handler errno = %s" , ACE_OS :: strerror ( errno ));
2008-11-06 16:10:28 -06:00
return - 1 ;
2008-10-02 16:23:55 -05:00
}
2010-08-08 19:45:53 +02:00
2008-11-06 16:10:28 -06:00
// reactor takes care of the socket from now on
2010-05-12 22:03:07 +02:00
remove_reference ();
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
return 0 ;
2008-10-04 06:17:19 -05:00
}
2009-10-17 15:51:44 -07:00
2010-12-14 22:45:23 +01:00
int WorldSocket :: close ( u_long )
2008-10-04 06:17:19 -05:00
{
2010-05-12 22:03:07 +02:00
shutdown ();
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
closing_ = true ;
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
remove_reference ();
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
return 0 ;
2008-10-04 06:17:19 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
int WorldSocket :: handle_input ( ACE_HANDLE )
2008-10-04 06:17:19 -05:00
{
2008-11-06 16:10:28 -06:00
if ( closing_ )
return - 1 ;
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
switch ( handle_input_missing_data ())
2008-10-02 16:23:55 -05:00
{
2008-11-06 16:10:28 -06:00
case - 1 :
{
if (( errno == EWOULDBLOCK ) ||
( errno == EAGAIN ))
{
2011-09-29 12:43:05 +02:00
return Update (); // interesting line, isn't it ?
2008-11-06 16:10:28 -06:00
}
2009-10-17 15:51:44 -07:00
2013-05-13 15:07:36 +02:00
TC_LOG_DEBUG ( LOG_FILTER_NETWORKIO , "WorldSocket::handle_input: Peer error closing connection errno = %s" , ACE_OS :: strerror ( errno ));
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
errno = ECONNRESET ;
return - 1 ;
}
case 0 :
{
2013-05-13 15:07:36 +02:00
TC_LOG_DEBUG ( LOG_FILTER_NETWORKIO , "WorldSocket::handle_input: Peer has closed connection" );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
errno = ECONNRESET ;
return - 1 ;
}
case 1 :
return 1 ;
default :
2010-05-12 22:03:07 +02:00
return Update (); // another interesting line ;)
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
ACE_NOTREACHED ( return - 1 );
2008-10-04 06:17:19 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
int WorldSocket :: handle_output ( ACE_HANDLE )
2008-10-04 06:17:19 -05:00
{
2008-11-06 16:10:28 -06:00
ACE_GUARD_RETURN ( LockType , Guard , m_OutBufferLock , - 1 );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
if ( closing_ )
return - 1 ;
2009-10-17 15:51:44 -07:00
2009-11-10 10:16:26 +01:00
size_t send_len = m_OutBuffer -> length ();
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
if ( send_len == 0 )
2010-05-12 22:03:07 +02:00
return handle_output_queue ( Guard );
2009-10-17 15:51:44 -07:00
2008-10-04 06:17:19 -05:00
#ifdef MSG_NOSIGNAL
2010-05-12 22:03:07 +02:00
ssize_t n = peer (). send ( m_OutBuffer -> rd_ptr (), send_len , MSG_NOSIGNAL );
2008-10-04 06:17:19 -05:00
#else
2010-05-12 22:03:07 +02:00
ssize_t n = peer (). send ( m_OutBuffer -> rd_ptr (), send_len );
2008-10-04 06:17:19 -05:00
#endif // MSG_NOSIGNAL
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
if ( n == 0 )
return - 1 ;
else if ( n == - 1 )
2008-10-02 16:23:55 -05:00
{
2008-11-06 16:10:28 -06:00
if ( errno == EWOULDBLOCK || errno == EAGAIN )
return schedule_wakeup_output ( Guard );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
return - 1 ;
2008-10-02 16:23:55 -05:00
}
2010-05-12 22:03:07 +02:00
else if ( n < ( ssize_t ) send_len ) //now n > 0
2008-10-02 16:23:55 -05:00
{
2008-11-06 16:10:28 -06:00
m_OutBuffer -> rd_ptr ( static_cast < size_t > ( n ));
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
// move the data to the base of the buffer
2010-05-12 22:03:07 +02:00
m_OutBuffer -> crunch ();
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
return schedule_wakeup_output ( Guard );
2008-10-04 06:17:19 -05:00
}
2008-11-06 16:10:28 -06:00
else //now n == send_len
2008-10-02 16:23:55 -05:00
{
2010-05-12 22:03:07 +02:00
m_OutBuffer -> reset ();
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
return handle_output_queue ( Guard );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
ACE_NOTREACHED ( return 0 );
2008-10-04 06:17:19 -05:00
}
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
int WorldSocket :: handle_output_queue ( GuardType & g )
{
if ( msg_queue () -> is_empty ())
return cancel_wakeup_output ( g );
2011-09-15 14:08:17 +02:00
ACE_Message_Block * mblk ;
2010-05-12 22:03:07 +02:00
if ( msg_queue () -> dequeue_head ( mblk , ( ACE_Time_Value * ) & ACE_Time_Value :: zero ) == - 1 )
{
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_NETWORKIO , "WorldSocket::handle_output_queue dequeue_head" );
2010-05-12 22:03:07 +02:00
return - 1 ;
}
const size_t send_len = mblk -> length ();
#ifdef MSG_NOSIGNAL
2013-02-11 02:59:07 +00:00
ssize_t n = peer (). send ( mblk -> rd_ptr (), send_len , MSG_NOSIGNAL );
2010-05-12 22:03:07 +02:00
#else
2013-02-11 02:59:07 +00:00
ssize_t n = peer (). send ( mblk -> rd_ptr (), send_len );
2010-05-12 22:03:07 +02:00
#endif // MSG_NOSIGNAL
if ( n == 0 )
{
mblk -> release ();
return - 1 ;
}
else if ( n == - 1 )
{
if ( errno == EWOULDBLOCK || errno == EAGAIN )
{
msg_queue () -> enqueue_head ( mblk , ( ACE_Time_Value * ) & ACE_Time_Value :: zero );
return schedule_wakeup_output ( g );
}
mblk -> release ();
return - 1 ;
}
else if ( n < ( ssize_t ) send_len ) //now n > 0
{
mblk -> rd_ptr ( static_cast < size_t > ( n ));
if ( msg_queue () -> enqueue_head ( mblk , ( ACE_Time_Value * ) & ACE_Time_Value :: zero ) == - 1 )
{
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_NETWORKIO , "WorldSocket::handle_output_queue enqueue_head" );
2010-05-12 22:03:07 +02:00
mblk -> release ();
return - 1 ;
}
return schedule_wakeup_output ( g );
}
else //now n == send_len
{
mblk -> release ();
return msg_queue () -> is_empty () ? cancel_wakeup_output ( g ) : ACE_Event_Handler :: WRITE_MASK ;
}
ACE_NOTREACHED ( return - 1 );
}
2008-11-06 16:10:28 -06:00
int WorldSocket :: handle_close ( ACE_HANDLE h , ACE_Reactor_Mask )
2008-10-04 06:17:19 -05:00
{
2008-11-06 16:10:28 -06:00
// Critical section
{
ACE_GUARD_RETURN ( LockType , Guard , m_OutBufferLock , - 1 );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
closing_ = true ;
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
if ( h == ACE_INVALID_HANDLE )
2010-05-12 22:03:07 +02:00
peer (). close_writer ();
2008-11-06 16:10:28 -06:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
// Critical section
{
ACE_GUARD_RETURN ( LockType , Guard , m_SessionLock , - 1 );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
m_Session = NULL ;
}
2009-10-17 15:51:44 -07:00
2011-01-09 13:53:25 +01:00
reactor () -> remove_handler ( this , ACE_Event_Handler :: DONT_CALL | ACE_Event_Handler :: ALL_EVENTS_MASK );
2008-11-06 16:10:28 -06:00
return 0 ;
2008-10-04 06:17:19 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
int WorldSocket :: Update ( void )
2008-10-04 06:17:19 -05:00
{
2008-11-06 16:10:28 -06:00
if ( closing_ )
return - 1 ;
2009-10-17 15:51:44 -07:00
2013-09-01 21:29:59 +02:00
if ( m_OutActive )
2008-11-06 16:10:28 -06:00
return 0 ;
2009-10-17 15:51:44 -07:00
2013-09-01 21:29:59 +02:00
{
ACE_GUARD_RETURN ( LockType , Guard , m_OutBufferLock , 0 );
if ( m_OutBuffer -> length () == 0 && msg_queue () -> is_empty ())
return 0 ;
}
2010-05-12 22:03:07 +02:00
int ret ;
do
2013-01-16 11:17:14 +01:00
ret = handle_output ( get_handle ());
2010-05-12 22:03:07 +02:00
while ( ret > 0 );
return ret ;
2008-10-04 06:17:19 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
int WorldSocket :: handle_input_header ( void )
2008-10-04 06:17:19 -05:00
{
2013-01-16 11:17:14 +01:00
ACE_ASSERT ( m_RecvWPct == NULL );
2009-10-17 15:51:44 -07:00
2013-01-16 11:17:14 +01:00
ACE_ASSERT ( m_Header . length () == sizeof ( ClientPktHeader ));
2009-10-17 15:51:44 -07:00
2013-01-16 11:17:14 +01:00
m_Crypt . DecryptRecv (( uint8 * ) m_Header . rd_ptr (), sizeof ( ClientPktHeader ));
2009-10-17 15:51:44 -07:00
2013-01-16 11:17:14 +01:00
ClientPktHeader & header = * (( ClientPktHeader * ) m_Header . rd_ptr ());
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
EndianConvertReverse ( header . size );
EndianConvert ( header . cmd );
2009-10-17 15:51:44 -07:00
2013-01-16 11:17:14 +01:00
if (( header . size < 4 ) || ( header . size > 10240 ) || ( header . cmd > 10240 ))
2008-10-02 16:23:55 -05:00
{
2011-09-15 14:08:17 +02:00
Player * _player = m_Session ? m_Session -> GetPlayer () : NULL ;
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_NETWORKIO , "WorldSocket::handle_input_header(): client (account: %u, char [GUID: %u, name: %s]) sent malformed packet (size: %d, cmd: %d)" ,
2011-02-17 19:47:08 +06:00
m_Session ? m_Session -> GetAccountId () : 0 ,
_player ? _player -> GetGUIDLow () : 0 ,
2012-10-24 13:29:34 +02:00
_player ? _player -> GetName (). c_str () : "<none>" ,
2011-02-17 19:47:08 +06:00
header . size , header . cmd );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
errno = EINVAL ;
return - 1 ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
header . size -= 4 ;
2009-10-17 15:51:44 -07:00
2013-01-16 11:17:14 +01:00
ACE_NEW_RETURN ( m_RecvWPct , WorldPacket (( uint16 ) header . cmd , header . size ), - 1 );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( header . size > 0 )
2008-10-06 04:14:44 -05:00
{
2013-01-16 11:17:14 +01:00
m_RecvWPct -> resize ( header . size );
2010-05-12 22:03:07 +02:00
m_RecvPct . base (( char * ) m_RecvWPct -> contents (), m_RecvWPct -> size ());
2008-10-06 04:14:44 -05:00
}
2008-11-06 16:10:28 -06:00
else
2008-10-06 04:14:44 -05:00
{
2008-11-06 16:10:28 -06:00
ACE_ASSERT ( m_RecvPct . space () == 0 );
2008-10-06 04:14:44 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
return 0 ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
int WorldSocket :: handle_input_payload ( void )
2008-10-02 16:23:55 -05:00
{
2008-11-06 16:10:28 -06:00
// set errno properly here on error !!!
// now have a header and payload
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
ACE_ASSERT ( m_RecvPct . space () == 0 );
ACE_ASSERT ( m_Header . space () == 0 );
2008-11-06 16:10:28 -06:00
ACE_ASSERT ( m_RecvWPct != NULL );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
const int ret = ProcessIncoming ( m_RecvWPct );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
m_RecvPct . base ( NULL , 0 );
2010-05-12 22:03:07 +02:00
m_RecvPct . reset ();
2008-11-06 16:10:28 -06:00
m_RecvWPct = NULL ;
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
m_Header . reset ();
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
if ( ret == - 1 )
errno = EINVAL ;
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
return ret ;
2008-10-04 06:17:19 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
int WorldSocket :: handle_input_missing_data ( void )
2008-10-04 06:17:19 -05:00
{
2009-05-24 11:10:55 -05:00
char buf [ 4096 ];
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
ACE_Data_Block db ( sizeof ( buf ),
2008-11-06 16:10:28 -06:00
ACE_Message_Block :: MB_DATA ,
buf ,
0 ,
0 ,
ACE_Message_Block :: DONT_DELETE ,
0 );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
ACE_Message_Block message_block ( & db ,
ACE_Message_Block :: DONT_DELETE ,
0 );
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
const size_t recv_size = message_block . space ();
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
const ssize_t n = peer (). recv ( message_block . wr_ptr (),
2008-11-06 16:10:28 -06:00
recv_size );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
if ( n <= 0 )
2010-12-11 20:37:38 +06:00
return int ( n );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
message_block . wr_ptr ( n );
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
while ( message_block . length () > 0 )
2008-10-02 16:23:55 -05:00
{
2010-05-12 22:03:07 +02:00
if ( m_Header . space () > 0 )
2008-10-04 06:17:19 -05:00
{
2008-11-14 17:50:48 -06:00
//need to receive the header
2010-05-12 22:03:07 +02:00
const size_t to_header = ( message_block . length () > m_Header . space () ? m_Header . space () : message_block . length ());
m_Header . copy ( message_block . rd_ptr (), to_header );
2008-11-06 16:10:28 -06:00
message_block . rd_ptr ( to_header );
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
if ( m_Header . space () > 0 )
2008-10-04 06:17:19 -05:00
{
2008-12-08 16:34:03 -06:00
// Couldn't receive the whole header this time.
2010-05-12 22:03:07 +02:00
ACE_ASSERT ( message_block . length () == 0 );
2008-11-06 16:10:28 -06:00
errno = EWOULDBLOCK ;
return - 1 ;
2008-10-04 06:17:19 -05:00
}
2009-10-17 15:51:44 -07:00
2008-12-12 11:21:28 -06:00
// We just received nice new header
2010-05-12 22:03:07 +02:00
if ( handle_input_header () == - 1 )
2008-10-04 06:17:19 -05:00
{
2008-11-06 16:10:28 -06:00
ACE_ASSERT (( errno != EWOULDBLOCK ) && ( errno != EAGAIN ));
return - 1 ;
2008-10-04 06:17:19 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
// Its possible on some error situations that this happens
2008-11-14 17:50:48 -06:00
// for example on closing when epoll receives more chunked data and stuff
2011-09-29 12:43:05 +02:00
// hope this is not hack, as proper m_RecvWPct is asserted around
2008-11-06 16:10:28 -06:00
if ( ! m_RecvWPct )
2008-10-04 06:17:19 -05:00
{
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_NETWORKIO , "Forcing close on input m_RecvWPct = NULL" );
2008-11-06 16:10:28 -06:00
errno = EINVAL ;
return - 1 ;
2008-10-04 06:17:19 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-14 17:50:48 -06:00
// We have full read header, now check the data payload
2010-05-12 22:03:07 +02:00
if ( m_RecvPct . space () > 0 )
2008-10-02 16:23:55 -05:00
{
2008-11-06 16:10:28 -06:00
//need more data in the payload
2010-05-12 22:03:07 +02:00
const size_t to_data = ( message_block . length () > m_RecvPct . space () ? m_RecvPct . space () : message_block . length ());
m_RecvPct . copy ( message_block . rd_ptr (), to_data );
2008-11-06 16:10:28 -06:00
message_block . rd_ptr ( to_data );
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
if ( m_RecvPct . space () > 0 )
2008-10-02 16:23:55 -05:00
{
2008-12-08 16:34:03 -06:00
// Couldn't receive the whole data this time.
2010-05-12 22:03:07 +02:00
ACE_ASSERT ( message_block . length () == 0 );
2008-11-06 16:10:28 -06:00
errno = EWOULDBLOCK ;
return - 1 ;
2008-10-02 16:23:55 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-11-14 17:50:48 -06:00
//just received fresh new payload
2010-05-12 22:03:07 +02:00
if ( handle_input_payload () == - 1 )
2008-10-04 06:17:19 -05:00
{
2008-11-06 16:10:28 -06:00
ACE_ASSERT (( errno != EWOULDBLOCK ) && ( errno != EAGAIN ));
return - 1 ;
2008-10-04 06:17:19 -05:00
}
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2010-12-15 10:44:06 +01:00
return size_t ( n ) == recv_size ? 1 : 2 ;
2008-10-04 06:17:19 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
int WorldSocket :: cancel_wakeup_output ( GuardType & g )
2008-10-04 06:17:19 -05:00
{
2008-11-06 16:10:28 -06:00
if ( ! m_OutActive )
return 0 ;
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
m_OutActive = false ;
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
g . release ();
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
if ( reactor () -> cancel_wakeup
2008-11-06 16:10:28 -06:00
( this , ACE_Event_Handler :: WRITE_MASK ) == - 1 )
2008-10-04 06:17:19 -05:00
{
2008-11-06 16:10:28 -06:00
// would be good to store errno from reactor with errno guard
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_NETWORKIO , "WorldSocket::cancel_wakeup_output" );
2008-11-06 16:10:28 -06:00
return - 1 ;
2008-10-04 06:17:19 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
return 0 ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
int WorldSocket :: schedule_wakeup_output ( GuardType & g )
2008-10-02 16:23:55 -05:00
{
2008-11-06 16:10:28 -06:00
if ( m_OutActive )
return 0 ;
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
m_OutActive = true ;
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
g . release ();
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
if ( reactor () -> schedule_wakeup
2008-11-06 16:10:28 -06:00
( this , ACE_Event_Handler :: WRITE_MASK ) == - 1 )
2008-10-02 16:23:55 -05:00
{
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_NETWORKIO , "WorldSocket::schedule_wakeup_output" );
2008-11-06 16:10:28 -06:00
return - 1 ;
2008-10-04 06:17:19 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
return 0 ;
2008-10-04 06:17:19 -05:00
}
2009-10-17 15:51:44 -07:00
2012-06-04 08:51:56 +02:00
int WorldSocket :: ProcessIncoming ( WorldPacket * new_pct )
2008-10-04 06:17:19 -05:00
{
2008-11-06 16:10:28 -06:00
ACE_ASSERT ( new_pct );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
// manage memory ;)
2013-01-16 11:17:14 +01:00
ACE_Auto_Ptr < WorldPacket > aptr ( new_pct );
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
const ACE_UINT16 opcode = new_pct -> GetOpcode ();
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
if ( closing_ )
return - 1 ;
2009-10-17 15:51:44 -07:00
2012-08-17 10:36:48 +02:00
// Dump received packet.
if ( sPacketLog -> CanLogPacket ())
sPacketLog -> LogPacket ( * new_pct , CLIENT_TO_SERVER );
2009-10-17 15:51:44 -07:00
2013-01-16 11:17:14 +01:00
std :: string opcodeName = GetOpcodeNameForLogging ( opcode );
2012-11-23 12:36:18 +01:00
if ( m_Session )
2013-05-13 15:07:36 +02:00
TC_LOG_TRACE ( LOG_FILTER_OPCODES , "C->S: %s %s" , m_Session -> GetPlayerInfo (). c_str (), opcodeName . c_str ());
2012-11-23 12:36:18 +01:00
2010-08-06 19:23:43 +02:00
try
{
2011-09-29 12:43:05 +02:00
switch ( opcode )
2008-10-04 06:17:19 -05:00
{
2009-08-19 16:26:22 -05:00
case CMSG_PING :
2013-01-16 11:17:14 +01:00
return HandlePing ( * new_pct );
2009-08-19 16:26:22 -05:00
case CMSG_AUTH_SESSION :
if ( m_Session )
{
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_NETWORKIO , "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from %s" , m_Session -> GetPlayerInfo (). c_str ());
2009-08-19 16:26:22 -05:00
return - 1 ;
}
2010-08-08 19:45:53 +02:00
2010-12-22 21:25:23 +01:00
sScriptMgr -> OnPacketReceive ( this , WorldPacket ( * new_pct ));
2013-01-16 11:17:14 +01:00
return HandleAuthSession ( * new_pct );
2009-08-19 16:26:22 -05:00
case CMSG_KEEP_ALIVE :
2013-05-13 15:07:36 +02:00
TC_LOG_DEBUG ( LOG_FILTER_NETWORKIO , "%s" , opcodeName . c_str ());
2010-12-22 21:25:23 +01:00
sScriptMgr -> OnPacketReceive ( this , WorldPacket ( * new_pct ));
2009-08-19 16:26:22 -05:00
return 0 ;
default :
{
2013-01-16 11:17:14 +01:00
ACE_GUARD_RETURN ( LockType , Guard , m_SessionLock , - 1 );
2012-08-21 22:12:55 +02:00
if ( ! m_Session )
2009-08-19 16:26:22 -05:00
{
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_OPCODES , "ProcessIncoming: Client not authed opcode = %u" , uint32 ( opcode ));
2009-08-19 16:26:22 -05:00
return - 1 ;
}
2012-08-21 22:12:55 +02:00
// Our Idle timer will reset on any non PING opcodes.
// Catches people idling on the login screen and any lingering ingame connections.
m_Session -> ResetTimeOutTime ();
// OK, give the packet to WorldSession
aptr . release ();
2013-01-16 11:17:14 +01:00
// WARNING here we call it with locks held.
2012-08-21 22:12:55 +02:00
// Its possible to cause deadlock if QueuePacket calls back
m_Session -> QueuePacket ( new_pct );
return 0 ;
2009-08-19 16:26:22 -05:00
}
2008-10-04 06:17:19 -05:00
}
2009-08-19 16:26:22 -05:00
}
2010-08-06 19:23:43 +02:00
catch ( ByteBufferException & )
2009-08-19 16:26:22 -05:00
{
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_NETWORKIO , "WorldSocket::ProcessIncoming ByteBufferException occured while parsing an instant handled packet %s from client %s, accountid=%i. Disconnected client." ,
2013-01-16 11:17:14 +01:00
opcodeName . c_str (), GetRemoteAddress (). c_str (), m_Session ? int32 ( m_Session -> GetAccountId ()) : - 1 );
2012-08-21 22:12:55 +02:00
new_pct -> hexlike ();
2009-08-19 16:26:22 -05:00
return - 1 ;
2008-10-04 06:17:19 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
ACE_NOTREACHED ( return 0 );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2013-01-16 11:17:14 +01:00
int WorldSocket :: HandleSendAuthSession ()
{
WorldPacket packet ( SMSG_AUTH_CHALLENGE , 37 );
packet << uint32 ( 1 ); // 1...31
packet << uint32 ( m_Seed );
BigNumber seed1 ;
seed1 . SetRand ( 16 * 8 );
2013-08-18 16:06:29 +02:00
packet . append ( seed1 . AsByteArray ( 16 ). get (), 16 ); // new encryption seeds
2013-01-16 11:17:14 +01:00
BigNumber seed2 ;
seed2 . SetRand ( 16 * 8 );
2013-08-18 16:06:29 +02:00
packet . append ( seed2 . AsByteArray ( 16 ). get (), 16 ); // new encryption seeds
2013-01-16 11:17:14 +01:00
return SendPacket ( packet );
}
2012-08-03 14:20:18 +02:00
int WorldSocket :: HandleAuthSession ( WorldPacket & recvPacket )
2008-10-02 16:23:55 -05:00
{
2008-11-06 16:10:28 -06:00
uint8 digest [ 20 ];
uint32 clientSeed ;
2013-01-16 11:17:14 +01:00
uint8 security ;
uint32 id ;
2008-11-06 16:10:28 -06:00
LocaleConstant locale ;
std :: string account ;
2012-02-19 13:51:16 +01:00
SHA1Hash sha ;
2013-01-16 11:17:14 +01:00
uint32 clientBuild ;
uint32 unk2 , unk3 , unk5 , unk6 , unk7 ;
uint64 unk4 ;
2008-11-06 16:10:28 -06:00
WorldPacket packet , SendAddonPacked ;
2012-02-19 13:51:16 +01:00
BigNumber k ;
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
if ( sWorld -> IsClosed ())
2009-03-21 13:51:28 +01:00
{
2013-01-16 11:17:14 +01:00
SendAuthResponseError ( AUTH_REJECT );
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_NETWORKIO , "WorldSocket::HandleAuthSession: World closed, denying client (%s)." , GetRemoteAddress (). c_str ());
2009-03-21 13:51:28 +01:00
return - 1 ;
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
// Read the content of the packet
2013-01-16 11:17:14 +01:00
recvPacket >> clientBuild ;
2008-11-06 16:10:28 -06:00
recvPacket >> unk2 ;
recvPacket >> account ;
2008-12-24 09:58:26 -06:00
recvPacket >> unk3 ;
2008-11-06 16:10:28 -06:00
recvPacket >> clientSeed ;
2010-06-30 13:14:23 -06:00
recvPacket >> unk5 >> unk6 >> unk7 ;
2009-12-17 12:36:55 +01:00
recvPacket >> unk4 ;
2011-10-18 14:59:23 +02:00
recvPacket . read ( digest , 20 );
2009-10-17 15:51:44 -07:00
2013-05-13 15:07:36 +02:00
TC_LOG_DEBUG ( LOG_FILTER_NETWORKIO , "WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, unk3 %u, clientseed %u" ,
2013-01-16 11:17:14 +01:00
clientBuild ,
2008-11-06 16:10:28 -06:00
unk2 ,
2010-05-12 22:03:07 +02:00
account . c_str (),
2009-07-31 11:33:48 +08:00
unk3 ,
2008-11-06 16:10:28 -06:00
clientSeed );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
// Get the account information from the realmd database
2013-02-07 16:15:23 +01:00
// 0 1 2 3 4 5 6 7 8
// SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ?
2012-03-24 01:25:08 +01:00
PreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_ACCOUNT_INFO_BY_NAME );
2009-10-17 15:51:44 -07:00
2012-03-24 01:25:08 +01:00
stmt -> setString ( 0 , account );
PreparedQueryResult result = LoginDatabase . Query ( stmt );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
// Stop if the account is not found
if ( ! result )
2008-10-04 06:17:19 -05:00
{
2013-01-16 11:17:14 +01:00
SendAuthResponseError ( AUTH_UNKNOWN_ACCOUNT );
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_NETWORKIO , "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account)." );
2008-11-06 16:10:28 -06:00
return - 1 ;
2008-10-04 06:17:19 -05:00
}
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2013-02-07 16:15:23 +01:00
uint8 expansion = fields [ 4 ]. GetUInt8 ();
2010-12-23 23:25:44 +01:00
uint32 world_expansion = sWorld -> getIntConfig ( CONFIG_EXPANSION );
2010-04-07 19:14:10 +02:00
if ( expansion > world_expansion )
2008-10-20 12:23:56 -05:00
expansion = world_expansion ;
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
///- Re-check ip locking (same check as in realmd).
2010-05-12 22:03:07 +02:00
if ( fields [ 3 ]. GetUInt8 () == 1 ) // if ip is locked
2008-10-04 06:17:19 -05:00
{
2010-09-24 22:16:21 +02:00
if ( strcmp ( fields [ 2 ]. GetCString (), GetRemoteAddress (). c_str ()))
2008-10-04 06:17:19 -05:00
{
2013-01-16 11:17:14 +01:00
SendAuthResponseError ( AUTH_FAILED );
2013-05-13 15:07:36 +02:00
TC_LOG_DEBUG ( LOG_FILTER_NETWORKIO , "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs)." );
2008-11-06 16:10:28 -06:00
return - 1 ;
2008-10-04 06:17:19 -05:00
}
}
2009-10-17 15:51:44 -07:00
2010-05-12 22:03:07 +02:00
id = fields [ 0 ]. GetUInt32 ();
2012-02-19 13:51:16 +01:00
2013-01-16 11:17:14 +01:00
k . SetHexStr ( fields [ 1 ]. GetCString ());
2009-10-17 15:51:44 -07:00
2013-02-07 16:15:23 +01:00
int64 mutetime = fields [ 5 ]. GetInt64 ();
2011-07-27 17:51:57 +02:00
//! Negative mutetime indicates amount of seconds to be muted effective on next login - which is now.
if ( mutetime < 0 )
{
2011-07-28 23:44:39 +02:00
mutetime = time ( NULL ) + llabs ( mutetime );
2011-12-27 00:29:17 +01:00
2013-01-30 13:09:41 +02:00
PreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_UPD_MUTE_TIME_LOGIN );
2011-12-27 00:29:17 +01:00
stmt -> setInt64 ( 0 , mutetime );
stmt -> setUInt32 ( 1 , id );
LoginDatabase . Execute ( stmt );
2011-07-27 17:51:57 +02:00
}
2009-10-17 15:51:44 -07:00
2013-02-07 16:15:23 +01:00
locale = LocaleConstant ( fields [ 6 ]. GetUInt8 ());
2010-09-28 08:21:51 +03:00
if ( locale >= TOTAL_LOCALES )
2008-11-06 16:10:28 -06:00
locale = LOCALE_enUS ;
2009-10-17 15:51:44 -07:00
2013-02-07 16:15:23 +01:00
uint32 recruiter = fields [ 7 ]. GetUInt32 ();
std :: string os = fields [ 8 ]. GetString ();
2010-08-17 19:18:09 -07:00
2012-11-12 00:31:08 +01:00
// Must be done before WorldSession is created
if ( sWorld -> getBoolConfig ( CONFIG_WARDEN_ENABLED ) && os != "Win" && os != "OSX" )
{
2013-01-16 11:17:14 +01:00
SendAuthResponseError ( AUTH_REJECT );
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_NETWORKIO , "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s)." , GetRemoteAddress (). c_str (), os . c_str ());
2012-11-12 00:31:08 +01:00
return - 1 ;
}
2009-12-21 21:21:39 -06:00
// Checks gmlevel per Realm
2012-03-24 01:25:08 +01:00
stmt = LoginDatabase . GetPreparedStatement ( LOGIN_GET_GMLEVEL_BY_REALMID );
stmt -> setUInt32 ( 0 , id );
stmt -> setInt32 ( 1 , int32 ( realmID ));
result = LoginDatabase . Query ( stmt );
2010-04-07 19:14:10 +02:00
if ( ! result )
2010-01-10 02:12:02 +01:00
security = 0 ;
else
{
2010-05-12 22:03:07 +02:00
fields = result -> Fetch ();
2012-03-24 23:05:00 +00:00
security = fields [ 0 ]. GetUInt8 ();
2010-01-10 02:12:02 +01:00
}
2009-12-21 21:08:29 -06:00
2008-11-06 16:10:28 -06:00
// Re-check account ban (same check as in realmd)
2012-03-24 01:25:08 +01:00
stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_BANS );
stmt -> setUInt32 ( 0 , id );
stmt -> setString ( 1 , GetRemoteAddress ());
PreparedQueryResult banresult = LoginDatabase . Query ( stmt );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
if ( banresult ) // if account banned
2008-10-04 06:17:19 -05:00
{
2013-01-16 11:17:14 +01:00
SendAuthResponseError ( AUTH_BANNED );
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_NETWORKIO , "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned)." );
2008-11-06 16:10:28 -06:00
return - 1 ;
2008-10-06 04:14:44 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
// Check locked state for server
2010-12-23 23:25:44 +01:00
AccountTypes allowedAccountType = sWorld -> GetPlayerSecurityLimit ();
2013-05-13 15:07:36 +02:00
TC_LOG_DEBUG ( LOG_FILTER_NETWORKIO , "Allowed Level: %u Player Level %u" , allowedAccountType , AccountTypes ( security ));
2013-01-16 11:17:14 +01:00
if ( allowedAccountType > SEC_PLAYER && AccountTypes ( security ) < allowedAccountType )
2008-10-06 04:14:44 -05:00
{
2013-01-16 11:17:14 +01:00
SendAuthResponseError ( AUTH_UNAVAILABLE );
2013-05-13 15:07:36 +02:00
TC_LOG_INFO ( LOG_FILTER_NETWORKIO , "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough" );
2008-11-06 16:10:28 -06:00
return - 1 ;
2008-10-06 04:14:44 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
// Check that Key and account name are the same on client and server
uint32 t = 0 ;
uint32 seed = m_Seed ;
2009-10-17 15:51:44 -07:00
2013-01-16 11:17:14 +01:00
sha . UpdateData ( account );
sha . UpdateData (( uint8 * ) & t , 4 );
sha . UpdateData (( uint8 * ) & clientSeed , 4 );
sha . UpdateData (( uint8 * ) & seed , 4 );
sha . UpdateBigNumbers ( & k , NULL );
2010-05-12 22:03:07 +02:00
sha . Finalize ();
2009-10-17 15:51:44 -07:00
2012-06-03 23:34:08 +02:00
std :: string address = GetRemoteAddress ();
2013-01-16 11:17:14 +01:00
if ( memcmp ( sha . GetDigest (), digest , 20 ))
2008-10-06 04:14:44 -05:00
{
2013-01-16 11:17:14 +01:00
SendAuthResponseError ( AUTH_FAILED );
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_NETWORKIO , "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s" , id , account . c_str (), address . c_str ());
2008-11-06 16:10:28 -06:00
return - 1 ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2013-05-13 15:07:36 +02:00
TC_LOG_DEBUG ( LOG_FILTER_NETWORKIO , "WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s." ,
2013-01-16 11:17:14 +01:00
account . c_str (),
address . c_str ());
2009-10-17 15:51:44 -07:00
2011-08-03 09:28:12 -07:00
// Check if this user is by any chance a recruiter
2012-03-24 01:25:08 +01:00
stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_ACCOUNT_RECRUITER );
stmt -> setUInt32 ( 0 , id );
result = LoginDatabase . Query ( stmt );
2011-08-03 09:28:12 -07:00
bool isRecruiter = false ;
if ( result )
isRecruiter = true ;
2008-11-06 16:10:28 -06:00
// Update the last_ip in the database
2009-10-17 15:51:44 -07:00
2012-03-24 01:25:08 +01:00
stmt = LoginDatabase . GetPreparedStatement ( LOGIN_UPD_LAST_IP );
2011-12-27 00:29:17 +01:00
stmt -> setString ( 0 , address );
stmt -> setString ( 1 , account );
2011-12-27 16:31:10 +01:00
LoginDatabase . Execute ( stmt );
2009-10-17 15:51:44 -07:00
2009-04-29 00:31:03 -05:00
// NOTE ATM the socket is single-threaded, have this in mind ...
2013-01-16 11:17:14 +01:00
ACE_NEW_RETURN ( m_Session , WorldSession ( id , this , AccountTypes ( security ), expansion , mutetime , locale , recruiter , isRecruiter ), - 1 );
2009-10-17 15:51:44 -07:00
2012-02-19 13:51:16 +01:00
m_Crypt . Init ( & k );
2009-10-17 15:51:44 -07:00
2009-09-01 16:47:49 -05:00
m_Session -> LoadGlobalAccountData ();
2009-06-11 00:45:59 -05:00
m_Session -> LoadTutorialsData ();
2009-03-21 14:39:04 -06:00
m_Session -> ReadAddonsInfo ( recvPacket );
2013-02-04 08:21:25 +01:00
m_Session -> LoadPermissions ();
2009-10-17 15:51:44 -07:00
2012-02-19 13:51:16 +01:00
// Initialize Warden system only if it is enabled by config
if ( sWorld -> getBoolConfig ( CONFIG_WARDEN_ENABLED ))
m_Session -> InitWarden ( & k , os );
2010-08-08 19:45:53 +02:00
// Sleep this Network thread for
2010-12-23 23:25:44 +01:00
uint32 sleepTime = sWorld -> getIntConfig ( CONFIG_SESSION_ADD_DELAY );
2013-01-16 11:17:14 +01:00
ACE_OS :: sleep ( ACE_Time_Value ( 0 , sleepTime ));
2009-10-17 15:51:44 -07:00
2013-01-16 11:17:14 +01:00
sWorld -> AddSession ( m_Session );
2008-11-06 16:10:28 -06:00
return 0 ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
int WorldSocket :: HandlePing ( WorldPacket & recvPacket )
2008-10-02 16:23:55 -05:00
{
2008-11-06 16:10:28 -06:00
uint32 ping ;
uint32 latency ;
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
// Get the ping packet content
recvPacket >> ping ;
recvPacket >> latency ;
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
if ( m_LastPingTime == ACE_Time_Value :: zero )
2010-05-12 22:03:07 +02:00
m_LastPingTime = ACE_OS :: gettimeofday (); // for 1st ping
2008-11-06 16:10:28 -06:00
else
2008-10-04 06:17:19 -05:00
{
2010-05-12 22:03:07 +02:00
ACE_Time_Value cur_time = ACE_OS :: gettimeofday ();
2008-11-06 16:10:28 -06:00
ACE_Time_Value diff_time ( cur_time );
diff_time -= m_LastPingTime ;
m_LastPingTime = cur_time ;
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
if ( diff_time < ACE_Time_Value ( 27 ))
2008-10-04 06:17:19 -05:00
{
2008-11-06 16:10:28 -06:00
++ m_OverSpeedPings ;
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
uint32 max_count = sWorld -> getIntConfig ( CONFIG_MAX_OVERSPEED_PINGS );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
if ( max_count && m_OverSpeedPings > max_count )
2008-10-04 06:17:19 -05:00
{
2008-11-06 16:10:28 -06:00
ACE_GUARD_RETURN ( LockType , Guard , m_SessionLock , - 1 );
2009-10-17 15:51:44 -07:00
2013-02-25 12:50:50 +01:00
if ( m_Session && ! m_Session -> HasPermission ( RBAC_PERM_SKIP_CHECK_OVERSPEED_PING ))
2008-10-04 06:17:19 -05:00
{
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_NETWORKIO , "WorldSocket::HandlePing: %s kicked for over-speed pings (address: %s)" ,
2012-10-24 15:34:23 +02:00
m_Session -> GetPlayerInfo (). c_str (), GetRemoteAddress (). c_str ());
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
return - 1 ;
2008-10-04 06:17:19 -05:00
}
}
}
2008-11-06 16:10:28 -06:00
else
m_OverSpeedPings = 0 ;
2008-10-04 06:17:19 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
// critical section
{
ACE_GUARD_RETURN ( LockType , Guard , m_SessionLock , - 1 );
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06:00
if ( m_Session )
2013-09-26 20:03:39 +02:00
{
2008-12-12 11:21:28 -06:00
m_Session -> SetLatency ( latency );
2013-09-26 20:03:39 +02:00
m_Session -> ResetClientTimeDelay ();
}
2008-11-06 16:10:28 -06:00
else
{
2013-05-13 15:07:36 +02:00
TC_LOG_ERROR ( LOG_FILTER_NETWORKIO , "WorldSocket::HandlePing: peer sent CMSG_PING, "
2011-04-29 20:47:02 +02:00
"but is not authenticated or got recently kicked, "
2008-11-14 17:50:48 -06:00
" address = %s" ,
2010-05-12 22:03:07 +02:00
GetRemoteAddress (). c_str ());
2008-11-06 16:10:28 -06:00
return - 1 ;
}
}
2009-10-17 15:51:44 -07:00
2013-01-16 11:17:14 +01:00
WorldPacket packet ( SMSG_PONG , 4 );
2008-11-06 16:10:28 -06:00
packet << ping ;
2012-03-29 14:43:34 +08:00
return SendPacket ( packet );
2008-10-04 06:17:19 -05:00
}
2013-01-16 11:17:14 +01:00
void WorldSocket :: SendAuthResponseError ( uint8 code )
{
WorldPacket packet ( SMSG_AUTH_RESPONSE , 1 );
packet << uint8 ( code );
SendPacket ( packet );
2013-01-17 17:35:47 +01:00
}