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 00023 #include "Qt.h" 00024 #include "QrtReader.h" 00025 #include "QueryRoutingTable.h" 00026 #include "Imports.cpp" 00027 00028 using namespace Gnutella::PacketProcessing::QueryRouting; 00029 00030 namespace Gnutella { 00031 namespace PacketProcessing { 00032 namespace QueryRouting { 00033 00034 class QrtReaderPrivate 00035 { 00036 REFERENCE_OBJECT (QrtReaderPrivate) 00037 00038 public: 00039 QueryRoutingTable currentTable; 00040 bool isReset; 00041 bool isUpdating; 00042 quint8 infinity; 00043 quint8 entryBits; 00044 quint32 tableSize; 00045 bool isCompressed; 00046 QByteArray rawUpdateTable; 00047 00048 QrtReaderPrivate() : currentTable(), isReset (false), isUpdating (false), 00049 infinity (0), entryBits (0), tableSize (0), 00050 isCompressed (false), rawUpdateTable() 00051 {} 00052 }; 00053 00054 } // QueryRouting 00055 } // PacketProcessing 00056 } // Gnutella 00057 00058 const QueryRoutingTable & QrtReader::currentTable() const 00059 { return p->currentTable; } 00060 00061 QrtReader::QrtReader() 00062 : p (new QrtReaderPrivate) 00063 { 00064 p->currentTable.reset (8); 00065 p->isUpdating = false; 00066 } 00067 00068 QrtReader::~QrtReader() 00069 { 00070 delete p; 00071 } 00072 00073 bool QrtReader::handlePacket (const Packet &packet) 00074 { 00075 using namespace Gnutella::Packets; 00076 if (packet.payloadDescriptor() != QueryRoutingDescriptor) 00077 return false; 00078 const Packets::QueryRouting &qrp = Packets::QueryRouting::castFrom (packet); 00079 switch (qrp.variant()) 00080 { 00081 case Packets::QueryRouting::ResetVariant: 00082 processReset (QueryRoutingReset::castFrom (packet)); 00083 break; 00084 case Packets::QueryRouting::PatchVariant: 00085 processPatch (QueryRoutingPatch::castFrom (packet)); 00086 break; 00087 case Packets::QueryRouting::UnknownVariant: 00088 default: 00089 break; 00090 } 00091 return true; 00092 } 00093 00094 void QrtReader::processReset (const QueryRoutingReset &reset) 00095 { 00096 p->isReset = true; 00097 p->tableSize = reset.tableLength(); 00098 p->infinity = reset.infinity(); 00099 00101 00108 } 00109 00110 void QrtReader::processPatch (const QueryRoutingPatch &patch) 00111 { 00112 if (patch.seqNo() == 1) { 00113 p->isUpdating = true; 00114 p->rawUpdateTable.resize (0); 00115 p->entryBits = patch.entryBits(); 00116 p->isCompressed = patch.compressor() == QueryRoutingPatch::ZLIB; 00118 00120 } 00121 00123 p->rawUpdateTable.append (patch.data()); 00124 00125 if (patch.seqNo() == patch.seqSize()) 00126 completeTableUpdate(); 00127 } 00128 00129 void QrtReader::completeTableUpdate() 00130 { 00131 if (p->isCompressed) 00132 p->rawUpdateTable = unCompress (p->rawUpdateTable); 00133 00134 // Check whether the received patch matches the expected values. 00135 if (p->rawUpdateTable.size() * 8 != qint32 (p->entryBits * p->tableSize)) { 00137 return; 00138 } 00139 00140 if (p->isReset) { 00141 p->currentTable.reset (p->tableSize); 00142 } 00143 if (p->tableSize != p->currentTable.size()) { 00145 return; 00146 } 00147 p->currentTable.applyPatch (p->rawUpdateTable, p->entryBits); 00148 00149 emit qrtRead(); 00150 00151 p->isReset = false; 00152 p->isUpdating = false; 00153 p->rawUpdateTable.resize (0); 00154 }