bool CBNETProtocol :: RECEIVE_SID_AUTH_ACCOUNTLOGON( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED SID_AUTH_ACCOUNTLOGON" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // 4 bytes -> Status // if( Status == 0 ) // 32 bytes -> Salt // 32 bytes -> ServerPublicKey if( ValidateLength( data ) && data.size( ) >= 8 ) { BYTEARRAY status = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); if( UTIL_ByteArrayToUInt32( status, false ) == 0 && data.size( ) >= 72 ) { m_Salt = BYTEARRAY( data.begin( ) + 8, data.begin( ) + 40 ); m_ServerPublicKey = BYTEARRAY( data.begin( ) + 40, data.begin( ) + 72 ); return true; } } return false; }
CIncomingGarenaUser *CGCBIProtocol :: RECEIVE_GCBI_INIT( BYTEARRAY data ) { // 2 bytes -> Header // 2 bytes -> Length // 4 bytes -> actual IP address (big endian) // 4 bytes -> Garena user ID (big endian) // 4 bytes -> Garena room ID (big endian) // 4 bytes -> Garena user experience (big endian) // 2 bytes -> country string from Garena if( ValidateLength( data ) && data.size( ) == 22 ) { BYTEARRAY IP = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); BYTEARRAY UserID = BYTEARRAY( data.begin( ) + 8, data.begin( ) + 12 ); BYTEARRAY RoomID = BYTEARRAY( data.begin( ) + 12, data.begin( ) + 16 ); BYTEARRAY UserExp = BYTEARRAY( data.begin( ) + 16, data.begin( ) + 20 ); BYTEARRAY Country = BYTEARRAY( data.begin( ) + 20, data.begin( ) + 22 ); return new CIncomingGarenaUser(UTIL_ByteArrayToUInt32( IP, true ), UTIL_ByteArrayToUInt32( UserID, true ), UTIL_ByteArrayToUInt32( RoomID, true ), UTIL_ByteArrayToUInt32( UserExp, true ), string( Country.begin( ), Country.end( ) ) ); } return NULL; }
void CBNLSClient :: ExtractPackets( ) { string *RecvBuffer = m_Socket->GetBytes( ); BYTEARRAY Bytes = UTIL_CreateByteArray( (unsigned char *)RecvBuffer->c_str( ), RecvBuffer->size( ) ); while( Bytes.size( ) >= 3 ) { uint16_t Length = UTIL_ByteArrayToUInt16( Bytes, false ); if( Length >= 3 ) { if( Bytes.size( ) >= Length ) { m_Packets.push( new CCommandPacket( 0, Bytes[2], BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) ) ); *RecvBuffer = RecvBuffer->substr( Length ); Bytes = BYTEARRAY( Bytes.begin( ) + Length, Bytes.end( ) ); } else return; } else { CONSOLE_Print( "[BNLSC: " + m_Server + ":" + UTIL_ToString( m_Port ) + ":C" + UTIL_ToString( m_WardenCookie ) + "] error - received invalid packet from BNLS server (bad length), disconnecting" ); m_Socket->Disconnect( ); return; } } }
bool CBNETProtocol :: RECEIVE_SID_AUTH_INFO( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED SID_AUTH_INFO" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // 4 bytes -> LogonType // 4 bytes -> ServerToken // 4 bytes -> ??? // 8 bytes -> MPQFileTime // null terminated string -> IX86VerFileName // null terminated string -> ValueStringFormula if( ValidateLength( data ) && data.size( ) >= 25 ) { m_LogonType = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); m_ServerToken = BYTEARRAY( data.begin( ) + 8, data.begin( ) + 12 ); m_MPQFileTime = BYTEARRAY( data.begin( ) + 16, data.begin( ) + 24 ); m_IX86VerFileName = UTIL_ExtractCString( data, 24 ); m_ValueStringFormula = UTIL_ExtractCString( data, m_IX86VerFileName.size( ) + 25 ); return true; } return false; }
BYTEARRAY CBNLSProtocol :: RECEIVE_BNLS_WARDEN( BYTEARRAY data ) { // 2 bytes -> Length // 1 byte -> ID // (BYTE) -> Usage // (DWORD) -> Cookie // (BYTE) -> Result // (WORD) -> Length of data // (VOID) -> Data if( ValidateLength( data ) && data.size( ) >= 11 ) { unsigned char Usage = data[3]; uint32_t Cookie = UTIL_ByteArrayToUInt32( data, false, 4 ); unsigned char Result = data[8]; uint16_t Length = UTIL_ByteArrayToUInt16( data, false, 10 ); if( Result == 0x00 ) return BYTEARRAY( data.begin( ) + 11, data.end( ) ); else CONSOLE_Print( "[BNLSPROTO] received error code " + UTIL_ToString( data[8] ) ); } return BYTEARRAY( ); }
bool CPotentialPlayer :: Update( void *fd ) { if( m_DeleteMe ) return true; if( !m_Socket ) return false; m_Socket->DoRecv( (fd_set *)fd ); // extract as many packets as possible from the socket's receive buffer and process them string *RecvBuffer = m_Socket->GetBytes( ); BYTEARRAY Bytes = UTIL_CreateByteArray( (unsigned char *)RecvBuffer->c_str( ), RecvBuffer->size( ) ); // a packet is at least 4 bytes so loop as long as the buffer contains 4 bytes while( Bytes.size( ) >= 4 ) { if( Bytes[0] == W3GS_HEADER_CONSTANT || Bytes[0] == GPS_HEADER_CONSTANT ) { // bytes 2 and 3 contain the length of the packet uint16_t Length = UTIL_ByteArrayToUInt16( Bytes, false, 2 ); if( Length >= 4 ) { if( Bytes.size( ) >= Length ) { if( Bytes[0] == W3GS_HEADER_CONSTANT && Bytes[1] == CGameProtocol :: W3GS_REQJOIN ) { delete m_IncomingJoinPlayer; m_IncomingJoinPlayer = m_Protocol->RECEIVE_W3GS_REQJOIN( BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) ); if( m_IncomingJoinPlayer ) m_Game->EventPlayerJoined( this, m_IncomingJoinPlayer ); // this is the packet which interests us for now, the remaining is left for CGamePlayer *RecvBuffer = RecvBuffer->substr( Length ); Bytes = BYTEARRAY( Bytes.begin( ) + Length, Bytes.end( ) ); break; } *RecvBuffer = RecvBuffer->substr( Length ); Bytes = BYTEARRAY( Bytes.begin( ) + Length, Bytes.end( ) ); } else break; } } } // don't call DoSend here because some other players may not have updated yet and may generate a packet for this player // also m_Socket may have been set to NULL during ProcessPackets but we're banking on the fact that m_DeleteMe has been set to true as well so it'll short circuit before dereferencing return m_DeleteMe || !m_Socket->GetConnected( ) || m_Socket->HasError( ); }
void CGamePlayer :: ExtractPackets( ) { if( !m_Socket ) return; // extract as many packets as possible from the socket's receive buffer and put them in the m_Packets queue string *RecvBuffer = m_Socket->GetBytes( ); BYTEARRAY Bytes = UTIL_CreateByteArray( (unsigned char *)RecvBuffer->c_str( ), RecvBuffer->size( ) ); // a packet is at least 4 bytes so loop as long as the buffer contains 4 bytes while( Bytes.size( ) >= 4 ) { if( Bytes[0] == W3GS_HEADER_CONSTANT || Bytes[0] == GPS_HEADER_CONSTANT || Bytes[0] == GCBI_HEADER_CONSTANT ) { // bytes 2 and 3 contain the length of the packet uint16_t Length = UTIL_ByteArrayToUInt16( Bytes, false, 2 ); if( Length >= 4 ) { if( Bytes.size( ) >= Length ) { m_Packets.push( new CCommandPacket( Bytes[0], Bytes[1], BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) ) ); if( Bytes[0] == W3GS_HEADER_CONSTANT ) ++m_TotalPacketsReceived; *RecvBuffer = RecvBuffer->substr( Length ); Bytes = BYTEARRAY( Bytes.begin( ) + Length, Bytes.end( ) ); } else return; } else { m_Error = true; m_ErrorString = "received invalid packet from player (bad length)"; return; } } else { m_Error = true; m_ErrorString = "received invalid packet from player (bad header constant)"; return; } } }
BYTEARRAY CBNETProtocol :: RECEIVE_SID_WARDEN( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED SID_WARDEN" ); // DEBUG_PRINT( data ); // 2 bytes -> Header // 2 bytes -> Length // n bytes -> Data if( ValidateLength( data ) && data.size( ) >= 4 ) return BYTEARRAY( data.begin( ) + 4, data.end( ) ); return BYTEARRAY( ); }
BYTEARRAY CBNETProtocol :: RECEIVE_SID_PING( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED SID_PING" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // 4 bytes -> Ping if( ValidateLength( data ) && data.size( ) >= 8 ) return BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); return BYTEARRAY( ); }
CIncomingChatEvent *CBNETProtocol :: RECEIVE_SID_CHATEVENT( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED SID_CHATEVENT" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // 4 bytes -> EventID // 4 bytes -> UserFlags // 4 bytes -> Ping // 12 bytes -> ??? // null terminated string -> User // null terminated string -> Message if( ValidateLength( data ) && data.size( ) >= 29 ) { BYTEARRAY EventID = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); BYTEARRAY UserFlags = BYTEARRAY( data.begin( ) + 8, data.begin( ) + 12 ); BYTEARRAY Ping = BYTEARRAY( data.begin( ) + 12, data.begin( ) + 16 ); BYTEARRAY User = UTIL_ExtractCString( data, 28 ); BYTEARRAY Message = UTIL_ExtractCString( data, User.size( ) + 29 ); switch( UTIL_ByteArrayToUInt32( EventID, false ) ) { case CBNETProtocol :: EID_SHOWUSER: case CBNETProtocol :: EID_JOIN: case CBNETProtocol :: EID_LEAVE: case CBNETProtocol :: EID_WHISPER: case CBNETProtocol :: EID_TALK: case CBNETProtocol :: EID_BROADCAST: case CBNETProtocol :: EID_CHANNEL: case CBNETProtocol :: EID_USERFLAGS: case CBNETProtocol :: EID_WHISPERSENT: case CBNETProtocol :: EID_CHANNELFULL: case CBNETProtocol :: EID_CHANNELDOESNOTEXIST: case CBNETProtocol :: EID_CHANNELRESTRICTED: case CBNETProtocol :: EID_INFO: case CBNETProtocol :: EID_ERROR: case CBNETProtocol :: EID_EMOTE: return new CIncomingChatEvent( (CBNETProtocol :: IncomingChatEvent)UTIL_ByteArrayToUInt32( EventID, false ), UTIL_ByteArrayToUInt32( UserFlags, false ), UTIL_ByteArrayToUInt32( Ping, false ), string( User.begin( ), User.end( ) ), string( Message.begin( ), Message.end( ) ) ); } } return NULL; }
CIncomingJoinPlayer *CGameProtocol :: RECEIVE_W3GS_REQJOIN( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED W3GS_REQJOIN" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // 4 bytes -> Host Counter (Game ID) // 4 bytes -> Entry Key (used in LAN) // 1 byte -> ??? // 2 bytes -> Listen Port // 4 bytes -> Peer Key // null terminated string -> Name // 4 bytes -> ??? // 2 bytes -> InternalPort (???) // 4 bytes -> InternalIP if( ValidateLength( data ) && data.size( ) >= 20 ) { uint32_t HostCounter = UTIL_ByteArrayToUInt32( data, false, 4 ); BYTEARRAY Name = UTIL_ExtractCString( data, 19 ); if( !Name.empty( ) && data.size( ) >= Name.size( ) + 30 ) { BYTEARRAY InternalIP = BYTEARRAY( data.begin( ) + Name.size( ) + 26, data.begin( ) + Name.size( ) + 30 ); return new CIncomingJoinPlayer( HostCounter, string( Name.begin( ), Name.end( ) ), InternalIP ); } } return NULL; }
CIncomingAction *CGameProtocol :: RECEIVE_W3GS_OUTGOING_ACTION( BYTEARRAY data, unsigned char PID ) { // DEBUG_Print( "RECEIVED W3GS_OUTGOING_ACTION" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // 4 bytes -> CRC // remainder of packet -> Action if( PID != 255 && ValidateLength( data ) && data.size( ) >= 8 ) { BYTEARRAY CRC = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); BYTEARRAY Action = BYTEARRAY( data.begin( ) + 8, data.end( ) ); return new CIncomingAction( PID, CRC, Action ); } return NULL; }
CIncomingGameHost *CBNETProtocol :: RECEIVE_SID_GETADVLISTEX( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED SID_GETADVLISTEX" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // 4 bytes -> GamesFound // if( GamesFound > 0 ) // 10 bytes -> ??? // 2 bytes -> Port // 4 bytes -> IP // null term string -> GameName // 2 bytes -> ??? // 8 bytes -> HostCounter if( ValidateLength( data ) && data.size( ) >= 8 ) { BYTEARRAY GamesFound = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); if( UTIL_ByteArrayToUInt32( GamesFound, false ) > 0 && data.size( ) >= 25 ) { BYTEARRAY Port = BYTEARRAY( data.begin( ) + 18, data.begin( ) + 20 ); BYTEARRAY IP = BYTEARRAY( data.begin( ) + 20, data.begin( ) + 24 ); BYTEARRAY GameName = UTIL_ExtractCString( data, 24 ); if( data.size( ) >= GameName.size( ) + 35 ) { BYTEARRAY HostCounter; HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 27, true ) ); HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 29, true ) ); HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 31, true ) ); HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 33, true ) ); return new CIncomingGameHost( IP, UTIL_ByteArrayToUInt16( Port, false ), string( GameName.begin( ), GameName.end( ) ), HostCounter ); } } } return NULL; }
string CBNETProtocol :: RECEIVE_SID_CLANINVITATIONRESPONSE( BYTEARRAY data ) { if( ValidateLength( data ) && data.size( ) >= 12 ) { //skip four bytes cookie m_ClanLastInviteTag = BYTEARRAY( data.begin( ) + 8, data.begin( ) + 12 ); BYTEARRAY ClanName = UTIL_ExtractCString( data, 12 ); m_ClanLastInviteName = UTIL_ExtractCString( data, 12 + ClanName.size( ) ); return string( m_ClanLastInviteName.begin( ), m_ClanLastInviteName.end( ) ); } return NULL; }
void CTCPSocket :: DoSend( fd_set *send_fd ) { if( m_Socket == INVALID_SOCKET || m_HasError || !m_Connected || m_SendBuffer.empty( ) ) return; if( FD_ISSET( m_Socket, send_fd ) ) { // socket is ready, send it int s = send( m_Socket, m_SendBuffer.c_str( ), (int)m_SendBuffer.size( ), MSG_NOSIGNAL ); if( s == SOCKET_ERROR && GetLastError( ) != EWOULDBLOCK ) { // send error m_HasError = true; m_Error = GetLastError( ); if (m_isConsolePrint) CONSOLE_Print( "[TCPSOCKET] error (send) - " + GetErrorString( ) ); return; } else if( s > 0 ) { // success! only some of the data may have been sent, remove it from the buffer if( !m_LogFile.empty( ) ) { ofstream Log; Log.open( m_LogFile.c_str( ), ios :: app ); if( !Log.fail( ) ) { Log << "SEND >>> " << UTIL_ByteArrayToHexString( BYTEARRAY( m_SendBuffer.begin( ), m_SendBuffer.begin( ) + s ) ) << endl; Log.close( ); } } m_SendBuffer = m_SendBuffer.substr( s ); m_LastSend = GetTime( ); } } }
bool CBNETProtocol :: RECEIVE_SID_LOGONRESPONSE( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED SID_LOGONRESPONSE" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // 4 bytes -> Status if( ValidateLength( data ) && data.size( ) >= 8 ) { BYTEARRAY Status = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); if( UTIL_ByteArrayToUInt32( Status, false ) == 1 ) return true; } return false; }
bool CBNETProtocol :: RECEIVE_SID_AUTH_ACCOUNTLOGONPROOF( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED SID_AUTH_ACCOUNTLOGONPROOF" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // 4 bytes -> Status if( ValidateLength( data ) && data.size( ) >= 8 ) { uint32_t Status = UTIL_ByteArrayToUInt32( BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ), false ); if( Status == 0 || Status == 0xE ) return true; } return false; }
bool CBNETProtocol :: RECEIVE_SID_AUTH_CHECK( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED SID_AUTH_CHECK" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // 4 bytes -> KeyState // null terminated string -> KeyStateDescription if( ValidateLength( data ) && data.size( ) >= 9 ) { m_KeyState = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); m_KeyStateDescription = UTIL_ExtractCString( data, 8 ); if( UTIL_ByteArrayToUInt32( m_KeyState, false ) == KR_GOOD ) return true; } return false; }
bool CGamePlayer :: Update( void *fd ) { uint32_t Time = GetTime( ); // wait 4 seconds after joining before sending the /whois or /w // if we send the /whois too early battle.net may not have caught up with where the player is and return erroneous results if( m_WhoisShouldBeSent && !m_Spoofed && !m_WhoisSent && !m_JoinedRealm.empty( ) && Time - m_JoinTime >= 4 ) { // todotodo: we could get kicked from battle.net for sending a command with invalid characters, do some basic checking for( vector<CBNET *> :: iterator i = m_Game->m_Aura->m_BNETs.begin( ); i != m_Game->m_Aura->m_BNETs.end( ); ++i ) { if( (*i)->GetServer( ) == m_JoinedRealm ) { if( m_Game->GetGameState( ) == GAME_PUBLIC || (*i)->GetPasswordHashType( ) == "pvpgn" ) (*i)->QueueChatCommand( "/whois " + m_Name ); else if( m_Game->GetGameState( ) == GAME_PRIVATE ) (*i)->QueueChatCommand( m_Game->m_Aura->m_Language->SpoofCheckByReplying( ), m_Name, true, false ); } } m_WhoisSent = true; } // check for socket timeouts // if we don't receive anything from a player for 35 seconds we can assume they've dropped // this works because in the lobby we send pings every 5 seconds and expect a response to each one // and in the game the Warcraft 3 client sends keepalives frequently (at least once per second it looks like) if( m_Socket && Time - m_Socket->GetLastRecv( ) >= 35 ) m_Game->EventPlayerDisconnectTimedOut( this ); // GProxy++ acks if( m_GProxy && Time - m_LastGProxyAckTime >= 10 ) { if( m_Socket ) m_Socket->PutBytes( m_Game->m_Aura->m_GPSProtocol->SEND_GPSS_ACK( m_TotalPacketsReceived ) ); m_LastGProxyAckTime = Time; } // base class update if( m_Socket->GetConnected( ) ) m_Socket->DoRecv( (fd_set *)fd ); // extract as many packets as possible from the socket's receive buffer and process them string *RecvBuffer = m_Socket->GetBytes( ); BYTEARRAY Bytes = UTIL_CreateByteArray( (unsigned char *)RecvBuffer->c_str( ), RecvBuffer->size( ) ); // a packet is at least 4 bytes so loop as long as the buffer contains 4 bytes CIncomingAction *Action = NULL; CIncomingChatPlayer *ChatPlayer = NULL; CIncomingMapSize *MapSize = NULL; uint32_t CheckSum = 0, Pong = 0; while( Bytes.size( ) >= 4 ) { if( Bytes[0] == W3GS_HEADER_CONSTANT ) { // bytes 2 and 3 contain the length of the packet uint16_t Length = UTIL_ByteArrayToUInt16( Bytes, false, 2 ); if( Length >= 4 ) { if( Bytes.size( ) >= Length ) { // m_Packets.push( new CCommandPacket( Bytes[0], Bytes[1], BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) ) ); switch( Bytes[1] ) { case CGameProtocol :: W3GS_LEAVEGAME: m_Game->EventPlayerLeft( this, m_Protocol->RECEIVE_W3GS_LEAVEGAME( BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) ) ); break; case CGameProtocol :: W3GS_GAMELOADED_SELF: if( m_Protocol->RECEIVE_W3GS_GAMELOADED_SELF( BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) ) ) { if( !m_FinishedLoading ) { m_FinishedLoading = true; m_FinishedLoadingTicks = GetTicks( ); m_Game->EventPlayerLoaded( this ); } } break; case CGameProtocol :: W3GS_OUTGOING_ACTION: Action = m_Protocol->RECEIVE_W3GS_OUTGOING_ACTION( BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ), m_PID ); if( Action ) m_Game->EventPlayerAction( this, Action ); // don't delete Action here because the game is going to store it in a queue and delete it later break; case CGameProtocol :: W3GS_OUTGOING_KEEPALIVE: CheckSum = m_Protocol->RECEIVE_W3GS_OUTGOING_KEEPALIVE( BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) ); m_CheckSums.push( CheckSum ); ++m_SyncCounter; m_Game->EventPlayerKeepAlive( ); break; case CGameProtocol :: W3GS_CHAT_TO_HOST: ChatPlayer = m_Protocol->RECEIVE_W3GS_CHAT_TO_HOST( BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) ); if( ChatPlayer ) m_Game->EventPlayerChatToHost( this, ChatPlayer ); delete ChatPlayer; ChatPlayer = NULL; break; case CGameProtocol :: W3GS_DROPREQ: if( !m_DropVote ) { m_DropVote = true; m_Game->EventPlayerDropRequest( this ); } break; case CGameProtocol :: W3GS_MAPSIZE: MapSize = m_Protocol->RECEIVE_W3GS_MAPSIZE( BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ), m_Game->m_Aura->m_Map->GetMapSize( ) ); if( MapSize ) m_Game->EventPlayerMapSize( this, MapSize ); delete MapSize; MapSize = NULL; break; case CGameProtocol :: W3GS_PONG_TO_HOST: Pong = m_Protocol->RECEIVE_W3GS_PONG_TO_HOST( BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) ); // we discard pong values of 1 // the client sends one of these when connecting plus we return 1 on error to kill two birds with one stone if( Pong != 1 ) { // we also discard pong values when we're downloading because they're almost certainly inaccurate // this statement also gives the player a 5 second grace period after downloading the map to allow queued (i.e. delayed) ping packets to be ignored if( !m_DownloadStarted || ( m_DownloadFinished && GetTime( ) - m_FinishedDownloadingTime >= 5 ) ) { // we also discard pong values when anyone else is downloading if we're configured to if( !m_Game->IsDownloading( ) ) { m_Pings.push_back( GetTicks( ) - Pong ); if( m_Pings.size( ) > 20 ) m_Pings.erase( m_Pings.begin( ) ); } } } m_Game->EventPlayerPongToHost( this, Pong ); break; } *RecvBuffer = RecvBuffer->substr( Length ); Bytes = BYTEARRAY( Bytes.begin( ) + Length, Bytes.end( ) ); } else break; } } else if( Bytes[0] == GPS_HEADER_CONSTANT ) { uint16_t Length = UTIL_ByteArrayToUInt16( Bytes, false, 2 ); if( Length >= 4 ) { if( Bytes.size( ) >= Length ) { BYTEARRAY Data = BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ); if( Bytes[1] == CGPSProtocol :: GPS_ACK && Data.size( ) == 8 ) { uint32_t LastPacket = UTIL_ByteArrayToUInt32( Data, false, 4 ); uint32_t PacketsAlreadyUnqueued = m_TotalPacketsSent - m_GProxyBuffer.size( ); if( LastPacket > PacketsAlreadyUnqueued ) { uint32_t PacketsToUnqueue = LastPacket - PacketsAlreadyUnqueued; if( PacketsToUnqueue > m_GProxyBuffer.size( ) ) PacketsToUnqueue = m_GProxyBuffer.size( ); while( PacketsToUnqueue > 0 ) { m_GProxyBuffer.pop( ); --PacketsToUnqueue; } } } else if( Bytes[1] == CGPSProtocol :: GPS_INIT ) { if( m_Game->m_Aura->m_Reconnect ) { m_GProxy = true; m_Socket->PutBytes( m_Game->m_Aura->m_GPSProtocol->SEND_GPSS_INIT( m_Game->m_Aura->m_ReconnectPort, m_PID, m_GProxyReconnectKey, m_Game->GetGProxyEmptyActions( ) ) ); Print( "[GAME: " + m_Game->GetGameName( ) + "] player [" + m_Name + "] is using GProxy++" ); } } *RecvBuffer = RecvBuffer->substr( Length ); Bytes = BYTEARRAY( Bytes.begin( ) + Length, Bytes.end( ) ); } else break; } } } bool Deleting; if( m_GProxy && m_Game->GetGameLoaded( ) ) Deleting = m_DeleteMe; else Deleting = m_DeleteMe || m_Socket->HasError( ) || !m_Socket->GetConnected( ); // try to find out why we're requesting deletion // in cases other than the ones covered here m_LeftReason should have been set when m_DeleteMe was set if( m_Socket ) { if( m_Socket->HasError( ) ) { m_Game->EventPlayerDisconnectSocketError( this ); m_Socket->Reset( ); } else if( !m_Socket->GetConnected( ) ) { m_Game->EventPlayerDisconnectConnectionClosed( this ); m_Socket->Reset( ); } } return Deleting; }
CIncomingGameHost *CBNETProtocol :: RECEIVE_SID_GETADVLISTEX( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED SID_GETADVLISTEX" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // 4 bytes -> GamesFound // if( GamesFound > 0 ) // 10 bytes -> ??? // 2 bytes -> Port // 4 bytes -> IP // null term string -> GameName // 2 bytes -> ??? // 8 bytes -> HostCounter if( ValidateLength( data ) && data.size( ) >= 8 ) { BYTEARRAY GamesFound = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); /* if (UTIL_ByteArrayToUInt32( GamesFound, false )>1) { string sIP =""; string GN =""; uint32_t PR; uint32_t GF = UTIL_ByteArrayToUInt32( GamesFound, false ); uint32_t Idx = 18; uint32_t Idx2 = 0; for (uint32_t i=0;i<GF;i++) { BYTEARRAY Port = BYTEARRAY( data.begin( ) + Idx, data.begin( ) + 2+Idx ); BYTEARRAY IP = BYTEARRAY( data.begin( ) + 2+Idx, data.begin( ) + 6+Idx ); BYTEARRAY GameName = UTIL_ExtractCString( data, 6+Idx ); Idx2 = GameName.size( ); Idx = Idx + Idx2+ 11; GN = string( GameName.begin( ), GameName.end( ) ); PR = UTIL_ByteArrayToUInt16( Port, false ); CONSOLE_Print("[GHOST] Game "+UTIL_ToString(i)+ " "+ GN + " "+sIP+" "+UTIL_ToString(PR)); } } else */ if( UTIL_ByteArrayToUInt32( GamesFound, false ) > 0 && data.size( ) >= 25 ) { BYTEARRAY Port = BYTEARRAY( data.begin( ) + 18, data.begin( ) + 20 ); BYTEARRAY IP = BYTEARRAY( data.begin( ) + 20, data.begin( ) + 24 ); BYTEARRAY GameName = UTIL_ExtractCString( data, 24 ); if( data.size( ) >= GameName.size( ) + 35 ) { BYTEARRAY HostCounter; HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 27, true ) ); HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 29, true ) ); HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 31, true ) ); HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 33, true ) ); return new CIncomingGameHost( IP, UTIL_ByteArrayToUInt16( Port, false ), string( GameName.begin( ), GameName.end( ) ), HostCounter ); } } } return NULL; }
BYTEARRAY CBNLSProtocol :: SEND_BNLS_WARDEN_RUNMODULE( uint32_t cookie ) { return BYTEARRAY( ); }
CIncomingChatPlayer *CGameProtocol :: RECEIVE_W3GS_CHAT_TO_HOST( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED W3GS_CHAT_TO_HOST" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // 1 byte -> Total // for( 1 .. Total ) // 1 byte -> ToPID // 1 byte -> FromPID // 1 byte -> Flag // if( Flag == 16 ) // null term string -> Message // elseif( Flag == 17 ) // 1 byte -> Team // elseif( Flag == 18 ) // 1 byte -> Colour // elseif( Flag == 19 ) // 1 byte -> Race // elseif( Flag == 20 ) // 1 byte -> Handicap // elseif( Flag == 32 ) // 4 bytes -> ExtraFlags // null term string -> Message if( ValidateLength( data ) ) { unsigned int i = 5; unsigned char Total = data[4]; if( Total > 0 && data.size( ) >= i + Total ) { BYTEARRAY ToPIDs = BYTEARRAY( data.begin( ) + i, data.begin( ) + i + Total ); i += Total; unsigned char FromPID = data[i]; unsigned char Flag = data[i + 1]; i += 2; if( Flag == 16 && data.size( ) >= i + 1 ) { // chat message BYTEARRAY Message = UTIL_ExtractCString( data, i ); return new CIncomingChatPlayer( FromPID, ToPIDs, Flag, string( Message.begin( ), Message.end( ) ) ); } else if( ( Flag >= 17 && Flag <= 20 ) && data.size( ) >= i + 1 ) { // team/colour/race/handicap change request unsigned char Byte = data[i]; return new CIncomingChatPlayer( FromPID, ToPIDs, Flag, Byte ); } else if( Flag == 32 && data.size( ) >= i + 5 ) { // chat message with extra flags BYTEARRAY ExtraFlags = BYTEARRAY( data.begin( ) + i, data.begin( ) + i + 4 ); BYTEARRAY Message = UTIL_ExtractCString( data, i + 4 ); return new CIncomingChatPlayer( FromPID, ToPIDs, Flag, string( Message.begin( ), Message.end( ) ), ExtraFlags ); } } } return NULL; }