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; }
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( ); }
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; }
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; }
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 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; } } }
vector<CIncomingFriendList *> CBNETProtocol :: RECEIVE_SID_FRIENDSLIST( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED SID_FRIENDSLIST" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // 1 byte -> Total // for( 1 .. Total ) // null term string -> Account // 1 byte -> Status // 1 byte -> Area // 4 bytes -> ??? // null term string -> Location vector<CIncomingFriendList *> Friends; if( ValidateLength( data ) && data.size( ) >= 5 ) { unsigned int i = 5; unsigned char Total = data[4]; while( Total > 0 ) { Total--; if( data.size( ) < i + 1 ) break; BYTEARRAY Account = UTIL_ExtractCString( data, i ); i += Account.size( ) + 1; if( data.size( ) < i + 7 ) break; unsigned char Status = data[i]; unsigned char Area = data[i + 1]; i += 6; BYTEARRAY Location = UTIL_ExtractCString( data, i ); i += Location.size( ) + 1; Friends.push_back( new CIncomingFriendList( string( Account.begin( ), Account.end( ) ), Status, Area, string( Location.begin( ), Location.end( ) ) ) ); } } return Friends; }
CIncomingClanList *CBNETProtocol :: RECEIVE_SID_CLANMEMBERSTATUSCHANGE( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED SID_CLANMEMBERSTATUSCHANGE" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // null terminated string -> Name // 1 byte -> Rank // 1 byte -> Status // null terminated string -> Location if( ValidateLength( data ) && data.size( ) >= 5 ) { BYTEARRAY Name = UTIL_ExtractCString( data, 4 ); if( data.size( ) >= Name.size( ) + 7 ) { unsigned char Rank = data[Name.size( ) + 5]; unsigned char Status = data[Name.size( ) + 6]; // in the original VB source the location string is read but discarded, so that's what I do here BYTEARRAY Location = UTIL_ExtractCString( data, Name.size( ) + 7 ); return new CIncomingClanList( string( Name.begin( ), Name.end( ) ), Rank, Status ); } } 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; }
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( ); }
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; }
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 CBNCSUtilInterface :: HELP_SID_AUTH_ACCOUNTLOGONPROOF( BYTEARRAY salt, BYTEARRAY serverKey ) { // set m_M1 char buf[20]; // nls_get_M1( (nls_t *)m_nls, buf, string( serverKey.begin( ), serverKey.end( ) ).c_str( ), string( salt.begin( ), salt.end( ) ).c_str( ) ); ( (NLS *)m_NLS )->getClientSessionKey( buf, string( salt.begin( ), salt.end( ) ).c_str( ), string( serverKey.begin( ), serverKey.end( ) ).c_str( ) ); m_M1 = UTIL_CreateByteArray( (unsigned char *)buf, 20 ); return true; }
void CReplay :: AddLeaveGame( uint32_t reason, unsigned char PID, uint32_t result ) { BYTEARRAY Block; Block.push_back( REPLAY_LEAVEGAME ); UTIL_AppendByteArray( Block, reason, false ); Block.push_back( PID ); UTIL_AppendByteArray( Block, result, false ); UTIL_AppendByteArray( Block, (uint32_t)1, false ); m_CompiledBlocks += string( Block.begin( ), Block.end( ) ); }
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; }
void CBNET :: ExtractPackets( ) { // 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( reinterpret_cast<unsigned char*>( const_cast<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 ) { // byte 0 is always 255 if( Bytes[0] == BNET_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( BNET_HEADER_CONSTANT, Bytes[1], BYTEARRAY(Bytes.begin(), Bytes.begin() + Length) ) ); *RecvBuffer = RecvBuffer->substr( Length ); Bytes = BYTEARRAY( Bytes.begin() + Length, Bytes.end() ); } else return; } else { cout << "[BNET: " << m_ServerAlias << "] error - received invalid packet from battle.net (bad length), disconnecting\n"; m_Socket->Disconnect( ); return; } } else { cout << "[BNET: " << m_ServerAlias << "] error - received invalid packet from battle.net (bad header constant), disconnecting\n"; m_Socket->Disconnect( ); return; } } }
bool CUDPSocket :: SendTo( struct sockaddr_in sin, BYTEARRAY message ) { if( m_Socket == INVALID_SOCKET || m_HasError ) return false; string MessageString = string( message.begin( ), message.end( ) ); if( sendto( m_Socket, MessageString.c_str( ), MessageString.size( ), 0, (struct sockaddr *)&sin, sizeof( sin ) ) == -1 ) return false; return true; }
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 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; }
vector<CIncomingClanList *> CBNETProtocol :: RECEIVE_SID_CLANMEMBERLIST( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED SID_CLANMEMBERLIST" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // 4 bytes -> ??? // 1 byte -> Total // for( 1 .. Total ) // null term string -> Name // 1 byte -> Rank // 1 byte -> Status // null term string -> Location vector<CIncomingClanList *> ClanList; if( ValidateLength( data ) && data.size( ) >= 9 ) { unsigned int i = 9; unsigned char Total = data[8]; while( Total > 0 ) { Total--; if( data.size( ) < i + 1 ) break; BYTEARRAY Name = UTIL_ExtractCString( data, i ); i += Name.size( ) + 1; if( data.size( ) < i + 3 ) break; unsigned char Rank = data[i]; unsigned char Status = data[i + 1]; i += 2; // in the original VB source the location string is read but discarded, so that's what I do here BYTEARRAY Location = UTIL_ExtractCString( data, i ); i += Location.size( ) + 1; ClanList.push_back( new CIncomingClanList( string( Name.begin( ), Name.end( ) ), Rank, Status ) ); } } return ClanList; }
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( ); }
void CSaveGame :: PrepareForSave() { // Custom W3Z file format type header // by freed BYTEARRAY packet; UTIL_AppendByteArray( packet, m_MapPath ); UTIL_AppendByteArray( packet, customMarkFileType, true ); UTIL_AppendByteArray( packet, m_GameName ); UTIL_AppendByteArray( packet, customMarkFileType, true ); UTIL_AppendByteArray( packet, customMarkFileType, true ); UTIL_AppendByteArray( packet, (uint32_t)0, false ); UTIL_AppendByteArray( packet, (uint32_t)0, false ); UTIL_AppendByteArray( packet, (uint16_t)0, false ); packet.push_back ( m_Slots.size() ); for( unsigned char i = 0; i < m_Slots.size(); i++ ) { packet.push_back( m_Slots[i].GetPID() ); packet.push_back( m_Slots[i].GetDownloadStatus() ); packet.push_back( m_Slots[i].GetSlotStatus() ); packet.push_back( m_Slots[i].GetComputer() ); packet.push_back( m_Slots[i].GetTeam() ); packet.push_back( m_Slots[i].GetColour() ); packet.push_back( m_Slots[i].GetRace() ); packet.push_back( m_Slots[i].GetComputerType() ); packet.push_back( m_Slots[i].GetHandicap() ); } UTIL_AppendByteArray( packet, (uint32_t)m_RandomSeed, false ); packet.push_back( 0 ); // GameType packet.push_back( m_PIDs.size() ); // number of player slots (non observer) UTIL_AppendByteArray( packet, m_MagicNumber ); packet.push_back( m_PIDs.size() ); for( vector<CGamePlayer*>::iterator i = m_PIDs.begin(); i != m_PIDs.end(); ++i ) { packet.push_back( (*i)->GetPID() ); UTIL_AppendByteArray( packet, (*i)->GetName(), true ); } m_Decompressed = string( packet.begin( ), packet.end( ) ); }
void CReplay :: AddChatMessage( unsigned char PID, unsigned char flags, uint32_t chatMode, string message ) { BYTEARRAY Block; Block.push_back( REPLAY_CHATMESSAGE ); Block.push_back( PID ); UTIL_AppendByteArray( Block, (uint16_t)0, false ); Block.push_back( flags ); UTIL_AppendByteArray( Block, chatMode, false ); UTIL_AppendByteArrayFast( Block, message ); // assign length BYTEARRAY LengthBytes = UTIL_CreateByteArray( (uint16_t)( Block.size( ) - 4 ), false ); Block[2] = LengthBytes[0]; Block[3] = LengthBytes[1]; m_CompiledBlocks += string( Block.begin( ), Block.end( ) ); }
BYTEARRAY CGameProtocol :: SEND_W3GS_INCOMING_ACTION2( queue<CIncomingAction *> actions ) { BYTEARRAY packet; packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant packet.push_back( W3GS_INCOMING_ACTION2 ); // W3GS_INCOMING_ACTION2 packet.push_back( 0 ); // packet length will be assigned later packet.push_back( 0 ); // packet length will be assigned later packet.push_back( 0 ); // ??? (send interval?) packet.push_back( 0 ); // ??? (send interval?) // create subpacket if( !actions.empty( ) ) { BYTEARRAY subpacket; while( !actions.empty( ) ) { CIncomingAction *Action = actions.front( ); actions.pop( ); subpacket.push_back( Action->GetPID( ) ); UTIL_AppendByteArray( subpacket, (uint16_t)Action->GetAction( )->size( ), false ); UTIL_AppendByteArray( subpacket, *Action->GetAction( ) ); } // calculate crc (we only care about the first 2 bytes though) CCRC32* m_CRC = new CCRC32( ); m_CRC->Initialize(); BYTEARRAY crc32 = UTIL_CreateByteArray( m_CRC->FullCRC( (unsigned char *)string( subpacket.begin( ), subpacket.end( ) ).c_str( ), subpacket.size( ) ), false ); crc32.resize( 2 ); delete m_CRC; // finish subpacket UTIL_AppendByteArray( packet, crc32 ); // crc UTIL_AppendByteArray( packet, subpacket ); // subpacket } AssignLength( packet ); // DEBUG_Print( "SENT W3GS_INCOMING_ACTION2" ); // DEBUG_Print( packet ); return packet; }
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; }
bool CUDPSocket :: Broadcast( uint16_t port, BYTEARRAY message ) { if( m_Socket == INVALID_SOCKET || m_HasError ) return false; struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_addr.s_addr = m_BroadcastTarget.s_addr; sin.sin_port = htons( port ); string MessageString = string( message.begin( ), message.end( ) ); if( sendto( m_Socket, MessageString.c_str( ), MessageString.size( ), 0, (struct sockaddr *)&sin, sizeof( sin ) ) == -1 ) { CONSOLE_Print( "[UDPSOCKET] failed to broadcast packet (port " + UTIL_ToString( port ) + ", size " + UTIL_ToString( MessageString.size( ) ) + " bytes)" ); return false; } return true; }
void CReplay :: AddTimeSlot2( queue<CIncomingAction *> actions ) { BYTEARRAY Block; Block.push_back( REPLAY_TIMESLOT2 ); UTIL_AppendByteArray( Block, (uint16_t)0, false ); UTIL_AppendByteArray( Block, (uint16_t)0, false ); while( !actions.empty( ) ) { CIncomingAction *Action = actions.front( ); actions.pop( ); Block.push_back( Action->GetPID( ) ); UTIL_AppendByteArray( Block, (uint16_t)Action->GetAction( )->size( ), false ); UTIL_AppendByteArrayFast( Block, *Action->GetAction( ) ); } // assign length BYTEARRAY LengthBytes = UTIL_CreateByteArray( (uint16_t)( Block.size( ) - 3 ), false ); Block[1] = LengthBytes[0]; Block[2] = LengthBytes[1]; m_CompiledBlocks += string( Block.begin( ), Block.end( ) ); }
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; }
void CGame::SetStartHead ( BYTEARRAY b ) { m_startHead.assign( b.begin() , b.end() ); m_state = STATUS_STARTED; m_lastUpdateTime = GetTime( ); }