/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx 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, or (at your option) any later version. ### File Specific: main-programmer: Christoph Renner co-programmer: ... */ #include "connection_monitor.h" #include "network_log.h" #include #include #include /* using namespace std is default, this needs to be here */ ObjectListDefinition(ConnectionMonitor); /** * constructor * @param userId user's id */ ConnectionMonitor::ConnectionMonitor( int userId ) { /* set the class id for the base object and add ist to class list*/ this->registerObject(this, ConnectionMonitor::_objectList); this->userId = userId; this->ping = 0; this->incomingUnzippedBandWidth = 0; this->outgoingUnzippedBandWidth = 0; this->incomingZippedBandWidth = 0; this->outgoingZippedBandWidth = 0; this->nIncomingPackets = 0; this->nOutgoingPackets = 0; this->nZIncomingPackets = 0; this->nZOutgoingPackets = 0; this->lastPacketTick = 0; this->lastPrintTick = 0; } /** * deconstructor */ ConnectionMonitor::~ConnectionMonitor( ) { } /** * process unzipped outgoing packet * @param data pointer to packet data * @param length length of packet * @param stateId packet's state id */ void ConnectionMonitor::processUnzippedOutgoingPacket( int tick, byte * data, int length, int stateId ) { nOutgoingPackets++; // for ping calculation sentStateTicks[stateId] = tick; // calculate bandwidth outgoingUnzippedPacketHistory[tick] = length; outgoingUnzippedBandWidth = calculateBandWidth( outgoingUnzippedPacketHistory, tick ); //NETPRINTF(n)("UNZIPPED UPSTREAM: user: %d bandwidth %f\n", userId, outgoingUnzippedBandWidth ); // count zero bytes //int nZeroBytes = 0; //for ( int i = 0; i < length; i++ ) // if ( data[i] == '\0' ) // nZeroBytes++; //NETPRINTF(n)( "ZEROBYTES: %d (%f%%)\n", nZeroBytes, ((float)100)*nZeroBytes/length ); } /** * process unzipped incoming packet * @param data pointer to packet data * @param length length of packet * @param stateId packet's state id * @param ackedState state which was acked by this packet */ void ConnectionMonitor::processUnzippedIncomingPacket( int tick, byte * data, int length, int stateId, int ackedState ) { nIncomingPackets++; lastPacketTick = tick; // calculate ping if ( sentStateTicks.find( ackedState ) != sentStateTicks.end() ) { ackDelay.push_back( tick - sentStateTicks[ackedState] ); } while ( sentStateTicks.begin() != sentStateTicks.end() && sentStateTicks.begin()->first <= ackedState ) sentStateTicks.erase( sentStateTicks.begin() ); while ( ackDelay.size() > N_PACKETS_FOR_PING ) ackDelay.erase( ackDelay.begin() ); ping = 0; for ( std::list::iterator it = ackDelay.begin(); it != ackDelay.end(); it++ ) ping += *it; if ( ackDelay.size() == 0 ) ping = -1; else ping /= ackDelay.size(); //NETPRINTF(n)("PING: user: %d ping: %d\n", userId, ping ); // calculate bandwidth incomingUnzippedPacketHistory[tick] = length; incomingUnzippedBandWidth = calculateBandWidth( incomingUnzippedPacketHistory, tick ); //NETPRINTF(n)("UNZIPPED DOWNSTREAM: user: %d bandwidth %f\n", userId, incomingUnzippedBandWidth ); } /** * remove old packets * @param packetHistory * @param tick */ void ConnectionMonitor::removeOldPackets( std::map< int, int > & packetHistory, int tick ) { while ( packetHistory.begin()->first < tick - MSECS_TO_CALC_BWIDTH ) packetHistory.erase( packetHistory.begin() ); } /** * calculate bandwidth out of packethistory * @param packetHistory packet history * @param tick current tick from SDL_GetTicks * @return bandwidth in bytes/sec */ float ConnectionMonitor::calculateBandWidth( std::map< int, int > & packetHistory, int tick ) { removeOldPackets( packetHistory, tick ); float res = 0.0f; #if 0 for ( std::map::iterator it = packetHistory.begin(); it != packetHistory.end(); it++ ) { if ( it != packetHistory.begin() ) res += it->second; } if ( packetHistory.size() <= 1 || tick - packetHistory.begin()->first == 0 ) res = 0.0f; else res /= (float)(tick - packetHistory.begin()->first); res *= 1000.0f; #endif for ( std::map::const_iterator it = packetHistory.begin(); it != packetHistory.end(); it++ ) { res += it->second; } if ( packetHistory.size() <= 1 ) res = 0.0f; else res /= (float)(tick - packetHistory.begin()->first); res *= 1000.0f; return res; } /** * process zipped outgoing packet * @param data pointer to packet data * @param length length of packet * @param stateId packet's state id */ void ConnectionMonitor::processZippedOutgoingPacket( int tick, byte * data, int length, int stateId ) { nZOutgoingPackets++; // calculate bandwidth outgoingZippedPacketHistory[tick] = length; outgoingZippedBandWidth = calculateBandWidth( outgoingZippedPacketHistory, tick ); //NETPRINTF(n)("UPSTREAM: user: %d bandwidth %f nOutgoingPackets %d\n", userId, outgoingZippedBandWidth, nOutgoingPackets ); if ( lastPrintTick < tick-1000 ) { printStatis(); lastPrintTick = tick; } } /** * process zipped incoming packet * @param data pointer to packet data * @param length length of packet * @param stateId packet's state id * @param ackedState state which was acked by this packet */ void ConnectionMonitor::processZippedIncomingPacket( int tick, byte * data, int length ) { nZIncomingPackets++; // calculate bandwidth incomingZippedPacketHistory[tick] = length; incomingZippedBandWidth = calculateBandWidth( incomingZippedPacketHistory, tick ); //NETPRINTF(n)("DOWNSTREAM: user: %d bandwidth %f nIncomingPackets %d\n", userId, incomingZippedBandWidth, nIncomingPackets ); } /** * check if client sent no packets for SECS_TO_TIMEOUT * @return true if last packet recieved \< NOW() - SECS_TO_TIMEOUT */ bool ConnectionMonitor::hasTimedOut( ) const { if ( lastPacketTick + SECS_TO_TIMEOUT*1000 < SDL_GetTicks() && nIncomingPackets > 0 ) return true; if ( nIncomingPackets == 0 && nOutgoingPackets >= NETWORK_FREQUENCY*SECS_TO_TIMEOUT ) return true; return false; } /** * prints bandwith usage, ping and other important things to telnet-console */ void ConnectionMonitor::printStatis( ) const { NETPRINT(n)("============NETWORKSTATS FOR USER %d============\n", userId); NETPRINT(n)("PING = %d\n", ping ); NETPRINT(n)("BANDWIDTH: UP: %f (%f) DOWN %f (%f)\n", outgoingZippedBandWidth, outgoingUnzippedBandWidth, incomingZippedBandWidth, incomingUnzippedBandWidth); NETPRINT(n)("PACKETS: RECIEVED %d; SENT %d\n", nIncomingPackets, nOutgoingPackets ); NETPRINT(n)("================================================\n"); }