QueryHits.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "Qt.h"
00024 #include "QueryHits.h"
00025
00026 using namespace Gnutella::Packets;
00027
00028 bool findCString (const QByteArray &rawPayload, int startPos, int* len);
00029
00030 enum QueryHitsDataFlags
00031 {
00032 GgepFlag = 0x20,
00033 UploadSpeedFlag = 0x10,
00034 HaveUploadedFlag = 0x08,
00035 BusyFlag = 0x04,
00036 PushFlag = 0x01
00037 };
00038
00042 QueryHits::QueryHits (const QByteArray &rawHeader, const QByteArray &rawPayload)
00043 : Packet (rawHeader, rawPayload)
00044 {
00045 parse();
00046 }
00047
00048 QueryHits::QueryHits () : Packet (QueryHitsDescriptor)
00049 {
00050 p.numberOfHits = 0;
00051 p.port = 0;
00052 p.ipAddress = QHostAddress ();
00053 p.speed = 0;
00054 p.serventId = QUuid();
00055 }
00056
00057 QueryHits::~QueryHits()
00058 {
00059 }
00060
00061
00062
00063 bool findCString (const QByteArray &rawPayload, int startPos, int* len)
00064 {
00065 int endPos = rawPayload.indexOf ('\0', startPos);
00066 if (endPos == -1)
00067 return false;
00068 *len = endPos - startPos;
00069 return true;
00070 }
00071
00072 bool QueryHits::prepareReadPayload (const QByteArray &rawPayload)
00073 {
00074 int payloadLength = rawPayload.length();
00075 if (payloadLength < 11)
00076 return false;
00077
00078 int currentPos = 11;
00079 int numberOfHits = static_cast <uchar> (rawPayload.at(0));
00080 for (int i = 0; i < numberOfHits; i++) {
00081 p.resultSet.append (Result());
00082
00083 Result& result = p.resultSet [i];
00084
00085 currentPos += 8;
00086
00087 int temp = 0;
00088 if (!findCString (rawPayload, currentPos, &temp))
00089 return false;
00090 result.fileNameSize = temp;
00091 currentPos += result.fileNameSize + 1;
00092
00093 int dataLen = 0;
00094 if (!findCString (rawPayload, currentPos, &dataLen))
00095 return false;
00096 QByteArray rawResultData = QByteArray::fromRawData(
00097 rawPayload.data() + currentPos, dataLen);
00098 result.resultData.prepareRead (rawResultData);
00099 currentPos += dataLen + 1;
00100 }
00101 payloadLength -= 16;
00102 if (currentPos > payloadLength)
00103 return false;
00104
00105 int queryHitsDataSize = payloadLength - currentPos;
00106 QByteArray rawQueryHitsData = QByteArray::fromRawData (rawPayload.data() + currentPos, queryHitsDataSize);
00107 return prepareReadQueryHitsData (rawQueryHitsData);
00108 }
00109
00110 void QueryHits::readPayload (QDataStream &stream)
00111 {
00112 QByteArray fileName;
00113 uchar temp;
00114
00115 stream >> p.numberOfHits;
00116 stream >> p.port;
00117 Gnutella::Packets::operator>> (stream, p.ipAddress);
00118 stream >> p.speed;
00119 if (p.speed & (1<<15)) p.speed = 0;
00120
00121 for (uchar i = 0; i < p.numberOfHits; i++) {
00122 Result &result = p.resultSet[i];
00123 stream >> result.fileIndex;
00124 stream >> result.fileSize;
00125
00126 fileName.resize (result.fileNameSize);
00127 stream.readRawData (fileName.data(), result.fileNameSize);
00128 result.fullFileName = QString::fromLatin1 (fileName);
00129 fileName = QByteArray();
00130
00131 stream >> temp;
00132 result.resultData.read (stream);
00133 stream >> temp;
00134 }
00135 readQueryHitsData (stream);
00136 stream >> p.serventId;
00137 }
00138
00139 int QueryHits::prepareWritePayload() const
00140 {
00141 int payloadLength = 11;
00142
00143 ResultSet::const_iterator it = p.resultSet.begin();
00144 for (uchar i = 0; i < p.numberOfHits && it != p.resultSet.end(); i++, it++) {
00145 const Result &result = *it;
00146
00147 payloadLength += 8;
00148 payloadLength += result.fullFileName.length();
00149 payloadLength ++;
00150 payloadLength += result.resultData.prepareWrite();
00151 payloadLength ++;
00152 }
00153 payloadLength += prepareWriteQueryHitsData ();
00154 payloadLength += 16;
00155
00156 return payloadLength;
00157 }
00158
00159 void QueryHits::writePayload (QDataStream &stream) const
00160 {
00161 stream << p.numberOfHits;
00162 stream << p.port;
00163 Gnutella::Packets::operator<< (stream, p.ipAddress);
00164 stream << p.speed;
00165
00166 ResultSet::const_iterator it = p.resultSet.begin();
00167 for (uchar i = 0; i < p.numberOfHits && it != p.resultSet.end(); i++, it++) {
00168 const Result &result = *it;
00169 stream << result.fileIndex;
00170 stream << result.fileSize;
00171 QByteArray fileName = result.fullFileName.toLatin1();
00172 stream.writeRawData (fileName.data(), fileName.length());
00173 stream << uchar (0);
00174 result.resultData.write (stream);
00175 stream << uchar (0);
00176 }
00177 writeQueryHitsData (stream);
00178 stream << p.serventId;
00179 }
00180
00181 bool QueryHits::prepareReadQueryHitsData (const QByteArray &rawQueryHitsData)
00182 {
00183 int rawDataLength = rawQueryHitsData.length();
00184
00185 p.queryHitsData.xmlLength = rawDataLength;
00186 return true;
00187 int currentPos = 4;
00188
00189 if (currentPos + 1 > rawDataLength)
00190 return false;
00191
00192 int publicDataLength = rawQueryHitsData.at (currentPos++);
00193 if (currentPos + publicDataLength > rawDataLength)
00194 return false;
00195
00196 p.queryHitsData.openAreaFlags1 = rawQueryHitsData.at (currentPos++);
00197 p.queryHitsData.openAreaFlags2 = rawQueryHitsData.at (currentPos++);
00198
00199 if (publicDataLength >= 4) {
00200 p.queryHitsData.xmlLength = static_cast <uchar> (rawQueryHitsData.at (currentPos++));
00201 p.queryHitsData.xmlLength |= static_cast <uchar> (rawQueryHitsData.at (currentPos++)) << 8;
00202 rawDataLength -= p.queryHitsData.xmlLength;
00203
00204
00205 currentPos += publicDataLength - 4;
00206 } else
00207 p.queryHitsData.xmlLength = 0;
00208
00209 currentPos++;
00210
00211 if ((p.queryHitsData.openAreaFlags1 & GgepFlag)
00212 && (p.queryHitsData.openAreaFlags2 & GgepFlag)) {
00213
00214 if (currentPos + 1 > rawDataLength)
00215 return false;
00216
00217 QByteArray ggepData = QByteArray::fromRawData (rawQueryHitsData.data() + currentPos, rawDataLength - currentPos);
00218 if (!p.queryHitsData.ggepBlock.prepareRead (ggepData))
00219 return false;
00220 }
00221 return true;
00222 }
00223
00224 void QueryHits::readQueryHitsData (QDataStream &stream)
00225 {
00226
00227 p.queryHitsData.xmlData.resize (p.queryHitsData.xmlLength);
00228 stream.readRawData (p.queryHitsData.xmlData.data(), p.queryHitsData.xmlLength);
00229 return;
00230 stream >> p.queryHitsData.vendorCode;
00231 stream >> p.queryHitsData.openAreaSize;
00232
00233 stream >> p.queryHitsData.openAreaFlags1;
00234 stream >> p.queryHitsData.openAreaFlags2;
00235
00236 if (p.queryHitsData.xmlLength)
00237 stream >> p.queryHitsData.xmlLength;
00238
00239 stream >> p.queryHitsData.privateVendorFlag;
00240
00241 if ((p.queryHitsData.openAreaFlags1 & GgepFlag)
00242 && (p.queryHitsData.openAreaFlags2 & GgepFlag)) {
00243
00244 p.queryHitsData.ggepBlock.read (stream);
00245 }
00246
00247 if (p.queryHitsData.xmlLength > 0) {
00248 p.queryHitsData.xmlData.resize (p.queryHitsData.xmlLength - 1);
00249 stream.readRawData (p.queryHitsData.xmlData.data(), p.queryHitsData.xmlLength - 1);
00250 uchar tmp;
00251 stream >> tmp;
00252 }
00253 }
00254
00255 int QueryHits::prepareWriteQueryHitsData() const
00256 {
00257 int totalLength = 0;
00258
00259 totalLength += VendorCode::VendorCodeLength;
00260 totalLength += 1;
00261
00262 p.queryHitsData.openAreaSize = 2;
00263 if (p.queryHitsData.xmlData.length()) {
00264 p.queryHitsData.openAreaSize += 2;
00265 p.queryHitsData.xmlLength = p.queryHitsData.xmlData.length();
00266 p.queryHitsData.xmlLength += 1;
00267 } else
00268 p.queryHitsData.xmlLength = 0;
00269
00270 totalLength += p.queryHitsData.openAreaSize;
00271 totalLength += 1;
00272
00273 int ggepLength = p.queryHitsData.ggepBlock.prepareWrite();
00274 if (ggepLength > 0) {
00275 p.queryHitsData.openAreaFlags2 |= GgepFlag;
00276
00277
00278 }
00279
00280 totalLength += ggepLength;
00281 totalLength += p.queryHitsData.xmlLength;
00282
00283 return totalLength;
00284 }
00285
00286 void QueryHits::writeQueryHitsData (QDataStream &stream) const
00287 {
00288 stream << p.queryHitsData.vendorCode;
00289
00290 stream << p.queryHitsData.openAreaSize;
00291 stream << p.queryHitsData.openAreaFlags1;
00292 stream << p.queryHitsData.openAreaFlags2;
00293
00294 if (p.queryHitsData.xmlLength)
00295 stream << p.queryHitsData.xmlLength;
00296
00297 stream << p.queryHitsData.privateVendorFlag;
00298 stream << p.queryHitsData.ggepBlock;
00299
00300 if (p.queryHitsData.xmlLength) {
00301 stream.writeRawData (p.queryHitsData.xmlData.data(), p.queryHitsData.xmlData.length());
00302 stream << uchar (0);
00303 }
00304 }
00305
00306 QueryHits::QueryHitsData::QueryHitsData()
00307 : vendorCode ("LIME")
00308 {
00309 openAreaSize = 2;
00310 openAreaFlags1 = 0x3C;
00311 openAreaFlags2 = 0x19;
00312 xmlLength = 0;
00313 privateVendorFlag = 0;
00314 }
00315
00316 const QueryHits::Result & QueryHits::result (int &index) const
00317 {
00318
00319 if (index < 0 || index >= numberOfHits())
00320 Q_ASSERT (index >= 0 && index < p.resultSet.size());
00321 return p.resultSet.at (index);
00322 }
00323
00324 QString QueryHits::Result::fileExtension() const
00325 {
00326 QString extension = fullFileName;
00327 int startIndex = extension.length() - 9;
00328 startIndex = (startIndex > 0) ? startIndex : 0;
00329 int index = extension.indexOf ('.', startIndex);
00330 if (index > 0)
00331 return extension.remove (0, index+1);
00332 return QString();
00333 }
00334
00335 QString QueryHits::Result::fileName() const
00336 {
00337 QString name = fullFileName;
00338 int startIndex = name.length() - 9;
00339 startIndex = (startIndex > 0) ? startIndex : 0;
00340 int index = name.indexOf ('.', startIndex);
00341 return name.remove (index, name.length());
00342 }
00343
00344 quint32 QueryHits::Result::sizeOfFile() const
00345 {
00346 return fileSize;
00347 }
00348
00349 void QueryHits::setPort (quint16 port)
00350 {
00351 p.port = port;
00352 invalidatePayload();
00353 }
00354
00355 void QueryHits::setIpAddress (const QHostAddress &ipAddress)
00356 {
00357 p.ipAddress = ipAddress;
00358 invalidatePayload();
00359 }
00360
00361 void QueryHits::setSpeed (quint32 speed)
00362 {
00363 p.speed = speed;
00364 invalidatePayload();
00365 }
00366
00367 void QueryHits::setServentId (const QUuid &serventId)
00368 {
00369 p.serventId = serventId;
00370 invalidatePayload();
00371 }
00372
00373
00374
00375
00376
00377
00378
00379 void QueryHits::appendResult (Result &result)
00380 {
00381 p.resultSet.append (result);
00382 p.numberOfHits = p.resultSet.size();
00383 invalidatePayload();
00384 }
00385