PacketMonitor.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2005-2007 by Peter Dimov.
00004 
00005 This file is part of Calitko (http://www.calitko.org).
00006 
00007 Calitko is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2 of the License, or
00010 (at your option) any later version.
00011 
00012 Calitko is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Calitko; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 
00021 */
00022 #ifdef USE_PACKET_MONITOR
00023 #include "Qt.h"
00024 #include "PacketMonitor.h"
00025 #include "Gnutella/LocalPeer.h"
00026 #include "Protocols/Transports/Properties.h"
00027 
00028 using Gnutella::PacketProcessing::PacketMonitor;
00029 using Gnutella::Packets::Packet;
00030 using Gnutella::Packets::MaximalPayloadLength;
00031 
00032 PacketMonitor::PacketMonitor (LocalPeer *lp)
00033 {
00034     log = 0;
00035     logFile.setFileName (tr ("packets.log"));
00036     /*if (logFile.open (QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
00037         log = new QTextStream (&logFile);
00038         log->setCodec ("ISO 8859-1");
00039     }
00040 */
00041     localPeer = lp;
00042 }
00043 
00044 PacketMonitor::~PacketMonitor()
00045 {
00046 }
00047 
00048 void PacketMonitor::addConnection (ConnectionId id, const NodeInfo &)
00049 {
00050     connectionInputStats.addConnection (id);
00051     connectionInputPacketStats.addConnection (id);
00052     connectionOutputStats.addConnection (id);
00053     connectionOutputPacketStats.addConnection (id);
00054 }
00055 
00056 void PacketMonitor::removeConnection (ConnectionId id)
00057 {
00058     connectionInputStats.removeConnection (id);
00059     connectionInputPacketStats.removeConnection (id);
00060     connectionOutputStats.removeConnection (id);
00061     connectionOutputPacketStats.removeConnection (id);
00062 }
00063 
00064 static QString toHexString (const QByteArray &data)
00065 {
00066     int dataSize = data.size();
00067     QString res;
00068     QTextStream stream (&res);
00069     hex (stream);
00070     stream.setFieldWidth (2);
00071     stream.setPadChar ('0');
00072     for (int i = 0; i < dataSize; i++)
00073         stream << " 0x" << static_cast <uchar> (data[i]);
00074     stream.flush();
00075     return res;
00076 }
00077 
00078 bool PacketMonitor::filter (ConnectionStats *connectionStats, PacketStats *packetStats, const Packet &packet)
00079 {
00080     bool forward = true;
00081     bool isValid = packet.isValid();
00082 
00083     if (isValid && packet.payloadLength() > MaximalPayloadLength)
00084         isValid = false;
00085 
00086     // <pd_todo> if ttl + hops has an excessive value try to reduce the ttl => need a no-const Packet &
00087     // \todo Shareaza may return hits with excessive hops.
00088     //if (isValid && packet.ttl() > MaximalTtl || packet.hops() > MaximalTtl || packet.ttl() + packet.hops() > MaximalTtl)
00089     //  isValid = false;
00090 
00091     if (log)
00092         (*log)  << QTime::currentTime().toString ("hh:mm:ss:zzz") << "\t"
00093                 << packet.name() << "\t"
00094                 << packet.ttl() << "\t"
00095                 << packet.hops() << "\t"
00096                 << packet.descriptorId().toString() << "\t"
00097                 << toHexString (packet.rawPayload()) << endl;
00098 
00099     quint32 packetLength = packet.packetLength();
00100 
00101     connectionStats->totalCount++;
00102     connectionStats->totalBytes += packetLength;
00103 
00104     if (packetStats) {
00105         packetStats->count++;
00106         packetStats->bytes += packetLength;
00107         if (!isValid) {
00108             connectionStats->badCount++;
00109             connectionStats->badBytes += packetLength;
00110             packetStats->badCount++;
00111             packetStats->badBytes += packetLength;
00112             // <pd_todo> If the number / bandwidth of bad packets reaches
00113             // a threshold (percent of total traffic), drop the connection.
00114             // if ()
00115             //  localPeer->disconnectFromPeer (id, TooManyInvalidPackets);
00116             forward = false;
00117         }
00118         forward = isValid;
00119 /*qDebug() << "\tPacket stats: count(" << statsPacket->count
00120          << "), bytes(" << statsPacket->bytes
00121          << "), badCount(" << statsPacket->badCount
00122          << "), badBytes(" << statsPacket->badBytes
00123          << ")";*/
00124     } else {
00125         connectionStats->unknownCount++;
00126         connectionStats->unknownBytes += packet.packetLength();
00127         forward = false;
00128     }
00129 /*qDebug() << "\tConnection stats: totalCount(" << statsConnection->totalCount
00130          << "), totalBytes(" << statsConnection->totalBytes
00131          << "), badCount(" << statsConnection->badCount
00132          << "), badBytes(" << statsConnection->badBytes
00133          << "), unknownCount(" << statsConnection->unknownCount
00134          << "), unknownBytes(" << statsConnection->unknownBytes
00135          << ")";*/
00136     return forward;
00137 }
00138 
00139 bool PacketMonitor::filterInput (ConnectionId connectionId, const Packet &packet)
00140 {
00141     Q_ASSERT (connectionInputStats.contains (connectionId));
00142     Q_ASSERT (connectionInputPacketStats.contains (connectionId));
00143 
00144     ConnectionStats *connectionStats = connectionInputStats [connectionId];
00145     PacketStats *packetStats = connectionInputPacketStats.packetData (connectionId, packet.payloadDescriptor());
00146 
00147     localPeer->packetModel.insertPacket (&packet, PacketModel::Incomming);
00148     return filter (connectionStats, packetStats, packet);
00149 }
00150 
00151 bool PacketMonitor::filterOutput (ConnectionId connectionId, const Packet &packet)
00152 {
00153     Q_ASSERT (connectionOutputStats.contains (connectionId));
00154     Q_ASSERT (connectionOutputPacketStats.contains (connectionId));
00155 
00156     ConnectionStats *connectionStats = connectionOutputStats [connectionId];
00157     PacketStats *packetStats = connectionOutputPacketStats.packetData (connectionId, packet.payloadDescriptor());
00158 
00159     localPeer->packetModel.insertPacket (&packet, PacketModel::Outgoing);
00160     return filter (connectionStats, packetStats, packet);
00161 }
00162 #endif