bool CGamePlayer :: Update( void *fd ) { // 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( ) && GetTime( ) - 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_OHBot->m_BNETs.begin( ); i != m_Game->m_OHBot->m_BNETs.end( ); ++i ) { if( (*i)->GetServer( ) == m_JoinedRealm ) { if( m_Game->GetGameState( ) == GAME_PUBLIC ) { if( (*i)->GetPasswordHashType( ) == "pvpgn" ) (*i)->QueueChatCommand( "/whereis " + m_Name ); else (*i)->QueueChatCommand( "/whois " + m_Name ); } else if( m_Game->GetGameState( ) == GAME_PRIVATE ) (*i)->QueueChatCommand( m_Game->m_OHBot->m_Language->SpoofCheckByReplying( ), m_Name, true ); } } m_WhoisSent = true; } // check for socket timeouts // if we don't receive anything from a player for 30 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 && GetTime( ) - m_Socket->GetLastRecv( ) >= 30 ) m_Game->EventPlayerDisconnectTimedOut( this ); // make sure we're not waiting too long for the first MAPSIZE packet /* if( m_ConnectionState == 1 && GetTicks( ) - m_ConnectionTime > 5000 && !m_Game->GetGameLoaded() && !m_Game->GetGameLoading() ) { Log->Info( "[DENY] Kicking player: MAPSIZE not received within five seconds" ); m_DeleteMe = true; SetLeftReason( "MAPSIZE not received within five seconds" ); SetLeftCode( PLAYERLEAVE_LOBBY ); m_Game->OpenSlot( m_Game->GetSIDFromPID( GetPID( ) ), false ); } */ // disconnect if the player is downloading too slowly // make this a bit dynamically, first 10 KB/s is a bit too low, increasing to 100KB/s //decreasing the checktime to 5 seconds // adding an actual playercheck how many players are ingame, if there less than 1 open slots we deny users with a download rate under 500KB/s if( m_DownloadStarted && !m_DownloadFinished && !m_Game->GetGameLoaded() && !m_Game->GetGameLoading() && GetLastMapPartSent( ) > 0 && m_Game->m_OHBot->m_KickSlowDownloader ) { uint32_t downloadingTime = GetTicks( ) - m_StartedDownloadingTicks; if( downloadingTime > 5000 && m_Level < 1) { if( GetLastMapPartAcked( ) / downloadingTime < 500 && m_Game->GetSlotsOccupied( ) <= 1 ) { m_DeleteMe = true; SetLeftReason( "download speed too low" ); SetLeftCode( PLAYERLEAVE_LOBBY ); m_Game->SendAllChat( m_Game->m_OHBot->m_Language->UserWasKickedForSlowDownloadRate( m_Name ) ); m_Game->OpenSlot( m_Game->GetSIDFromPID( GetPID( ) ), false ); } else if( GetLastMapPartAcked( ) / downloadingTime < 100 ) { m_DeleteMe = true; SetLeftReason( "download speed too low" ); SetLeftCode( PLAYERLEAVE_LOBBY ); m_Game->SendAllChat( m_Game->m_OHBot->m_Language->UserWasKickedForSlowDownloadRate( m_Name ) ); m_Game->OpenSlot( m_Game->GetSIDFromPID( GetPID( ) ), false ); } } } // unmute player if( GetMuted( ) && m_MutedAuto && GetTicks( ) - m_MutedTicks > 30000 ) { SetMuted( false ); m_Game->SendChat( m_PID, "["+m_Game->m_OHBot->m_BotManagerName+"] "+m_Game->m_OHBot->m_Language->UserWasAutomaticallyUnmuted( ) ); m_MuteMessages.clear( ); } // GProxy++ acks if( m_Game->m_OHBot->IsMode( BOT_MODE_GPROXY ) && m_GProxy && GetTime( ) - m_LastGProxyAckTime >= 10 ) { if( m_Socket ) m_Socket->PutBytes( m_Game->m_OHBot->m_GPSProtocol->SEND_GPSS_ACK( m_TotalPacketsReceived ) ); m_LastGProxyAckTime = GetTime( ); } // base class update CPotentialPlayer :: Update( fd ); bool Deleting; if( m_GProxy && m_Game->GetGameLoaded( ) ) Deleting = m_DeleteMe || m_Error; else Deleting = m_DeleteMe || m_Error || 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_Error ) { m_Game->EventPlayerDisconnectPlayerError( this ); m_Socket->Reset( ); return Deleting; } 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; }
bool CGamePlayer :: Update( void *fd ) { // 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( ) && GetTime( ) - m_JoinTime >= 4 ) { // todotodo: we could get kicked from battle.net for sending a command with invalid characters, do some basic checking // check if we have this ip in our spoofed cached ip list bool isspoofed = m_Game->m_GHost->IsSpoofedIP(GetName(), GetExternalIPString()); if (isspoofed) { CONSOLE_Print("[OPT] Player "+GetName()+" is in the cached spoof checked list"); m_Game->AddToSpoofed(m_Game->m_Server, GetName(), false); } if (!isspoofed && GetExternalIPString()!="127.0.0.1") for( vector<CBNET *> :: iterator i = m_Game->m_GHost->m_BNETs.begin( ); i != m_Game->m_GHost->m_BNETs.end( ); i++ ) { if( (*i)->GetServer( ) == m_JoinedRealm ) { if( m_Game->GetGameState( ) == GAME_PUBLIC ) { if ((*i)->GetWhereis() || (*i)->GetPasswordHashType( ) == "pvpgn" ) (*i)->QueueChatCommand( "/whereis " + m_Name ); else (*i)->QueueChatCommand( "/whois " + m_Name ); } else if( m_Game->GetGameState( ) == GAME_PRIVATE ) (*i)->QueueChatCommand( m_Game->m_GHost->m_Language->SpoofCheckByReplying( ), m_Name, true ); } } m_WhoisSent = true; } // check for socket timeouts // if we don't receive anything from a player for 30 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 && GetTime( ) - m_Socket->GetLastRecv( ) >= 30 ) m_Game->EventPlayerDisconnectTimedOut( this ); // make sure we're not waiting too long for the first MAPSIZE packet if( m_ConnectionState == 1 && GetTicks( ) - m_ConnectionTime > m_Game->m_GHost->m_DenyMaxMapsizeTime && !m_Game->GetGameLoaded() && !m_Game->GetGameLoading() ) { CONSOLE_Print( "[DENY] Kicking player: MAPSIZE not received within a few seconds" ); m_DeleteMe = true; SetLeftReason( "MAPSIZE not received within a few seconds" ); SetLeftCode( PLAYERLEAVE_LOBBY ); m_Game->OpenSlot( m_Game->GetSIDFromPID( GetPID( ) ), false ); m_Game->m_GHost->DenyIP( GetExternalIPString( ), m_Game->m_GHost->m_DenyMapsizeDuration, "MAPSIZE not received within a few seconds" ); } // disconnect if the player is downloading too slowly if( m_DownloadStarted && !m_DownloadFinished && !m_Game->GetGameLoaded() && !m_Game->GetGameLoading() && GetLastMapPartSent( ) != 0 ) { uint32_t downloadingTime = GetTicks( ) - m_StartedDownloadingTicks; uint32_t Seconds = downloadingTime / 1000; uint32_t Rate = GetLastMapPartSent( ) / 1024; // Rate in miliseconds if (Seconds>0) Rate /= Seconds; if(!(m_Game->IsSafe(GetName()) || m_Game->IsAdmin(GetName()) || m_Game->IsRootAdmin(GetName()) || m_Game->IsOwner(GetName()) )){ // uint32_t iRate = (uint32_t)Rate; if ( m_Game->m_GHost->m_DLRateLimit != 0 ) if ( GetLastMapPartSent( ) <= 102400 ) if ( 0 < Rate && Rate < m_Game->m_GHost->m_DLRateLimit ){ m_Game->DelTempOwner( GetName() ); m_Game->SendAllChat( m_Game->m_GHost->m_Language->KickMsgForSlowDL( GetName( ) , UTIL_ToString( Rate ), UTIL_ToString(m_Game->m_GHost->m_DLRateLimit) ) ); m_Game->m_GHost->m_Callables.push_back( m_Game->m_GHost->m_DB->ThreadedBanAdd( GetJoinedRealm( ), GetName( ), GetExternalIPString(), m_Game->GetGameName( ), "AUTOBAN", "Slow internet", 1, 0 )); if ( m_Game->m_GHost->m_BlacklistSlowDLder && !m_Game->IsBlacklisted(m_Game->GetBannedNames( ),GetName( )) ) m_Game->AddBannedNames(GetName( )); m_DeleteMe = true; SetLeftReason( "kicked for downloading too slowly " + UTIL_ToString( Rate ) + " KB/s" ); SetLeftCode( PLAYERLEAVE_LOBBY ); m_Game->OpenSlot( m_Game->GetSIDFromPID( GetPID( ) ), false ); } if( downloadingTime > m_Game->m_GHost->m_DenyMaxDownloadTime ) { m_Game->DelTempOwner( GetName() ); m_Game->SendAllChat( m_Game->m_GHost->m_Language->KickMsgForSlowDL( GetName( ),"","" ) ); m_DeleteMe = true; SetLeftReason( "download time is too long" ); SetLeftCode( PLAYERLEAVE_LOBBY ); m_Game->OpenSlot( m_Game->GetSIDFromPID( GetPID( ) ), false ); m_Game->m_GHost->DenyIP( GetExternalIPString( ), m_Game->m_GHost->m_DenyDownloadDuration, "("+ GetName( ) +") rejected because download time is too long" ); } } } // unmute player if( GetMuted( ) && ( GetTicks( ) - m_MutedTicks > 60000 || ( m_MutedAuto && GetTicks( ) - m_MutedTicks > 15000 ) ) ) { SetMuted( false ); m_Game->SendAllChat( "[" + m_Name + "] has been automatically unmuted. (Don't spam or you'll be muted again!)" ); m_MuteMessages.clear( ); } // GProxy++ acks if( m_GProxy && GetTime( ) - m_LastGProxyAckTime >= 10 ) { if( m_Socket ) m_Socket->PutBytes( m_Game->m_GHost->m_GPSProtocol->SEND_GPSS_ACK( m_TotalPacketsReceived ) ); m_LastGProxyAckTime = GetTime( ); } // base class update CPotentialPlayer :: Update( fd ); bool Deleting; if( m_GProxy && m_Game->GetGameLoaded( ) ) Deleting = m_DeleteMe || m_Error; else Deleting = m_DeleteMe || m_Error || 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_Error ){ m_Game->m_GHost->DenyIP( GetExternalIPString( ), 180000, "player error" ); m_Game->EventPlayerDisconnectPlayerError( this ); m_Socket->Reset( ); return Deleting; } if( m_Socket ) { if( m_Socket->HasError( ) ){ m_Game->EventPlayerDisconnectSocketError( this ); if( !m_GProxy ) m_Game->m_GHost->DenyIP( GetExternalIPString( ), 20000, "socket error" ); } else if( !m_Socket->GetConnected( ) ){ m_Game->EventPlayerDisconnectConnectionClosed( this ); if( !m_GProxy ) m_Game->m_GHost->DenyIP( GetExternalIPString( ), 30000, "connection closed" ); } } return Deleting; }