Ggep.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 "Ggep.h"
00025 #include "Ggeps/UnknownGgep.h"
00026 #include "Ggeps/DailyUptime.h"
00027 #include "Ggeps/Ultrapeer.h"
00028 #include "Ggeps/VendorCode.h"
00029 #include "Ggeps/PackedHostCaches.h"
00030 #include "Ggeps/SupportsCachedPongs.h"
00031 #include "Ggeps/UdpHostCache.h"
00032 #include "Ggeps/IpPort.h"
00033 #include "Utils/Encodings/Cobs.h"
00034 #include "Utils/Encodings/Deflate.h"
00035
00036 using namespace Gnutella::Packets::Extensions;
00037
00038 enum Constants
00039 {
00040 MaximalGgepDataLength = 262143
00041 };
00042
00043 Ggep::Ggep (const GgepId &id, int flags, int dataSize)
00044 {
00045 d = new Data;
00046
00047 d->ref.init (1);
00048 d->isValid = true;
00049 d->id = id;
00050
00051 if (flags & LastExtension) d->flags |= LastExtension;
00052 if (flags & Encoding) d->flags |= Encoding;
00053 if (flags & Compression) d->flags |= Compression;
00054 if (flags & Reserved) d->flags |= Reserved;
00055
00056 p.dataLength = dataSize;
00057 }
00058
00059 Ggep::~Ggep()
00060 {
00061 if (!d->ref.deref())
00062 delete d;
00063 }
00064
00065 Ggep & Ggep::operator= (const Ggep &other)
00066 {
00067 Data *x = other.d;
00068 x->ref.ref();
00069 x = qAtomicSetPtr(&d, x);
00070 if (!x->ref.deref())
00071 delete x;
00072
00073 p = other.p;
00074 return *this;
00075 }
00076
00077 void Ggep::invalidateData()
00078 {
00079 if (d->ref != 1) {
00080 Data *x = new Data;
00081 x->ref.init (1);
00082
00083 x->isValid = d->isValid;
00084 x->flags = d->flags;
00085 x->id = d->id;
00086
00087 x = qAtomicSetPtr (&d, x);
00088 if (!x->ref.deref())
00089 delete x;
00090 };
00091 }
00092
00093 Ggep * Ggep::fromId (const GgepId &id, int flags, int dataSize)
00094 {
00095 if (id == Ggeps::Ultrapeer::Id)
00096 return new Ggeps::Ultrapeer (id, flags, dataSize);
00097
00098 if (id == Ggeps::VendorCode::Id)
00099 return new Ggeps::VendorCode (id, flags, dataSize);
00100
00101 if (id == Ggeps::DailyUptime::Id)
00102 return new Ggeps::DailyUptime (id, flags, dataSize);
00103
00104 if (id == Ggeps::PackedHostCaches::Id)
00105 return new Ggeps::PackedHostCaches (id, flags, dataSize);
00106
00107 if (id == Ggeps::SupportsCachedPongs::Id)
00108 return new Ggeps::SupportsCachedPongs (id, flags, dataSize);
00109
00110 if (id == Ggeps::UdpHostCache::Id)
00111 return new Ggeps::UdpHostCache (id, flags, dataSize);
00112
00113 if (id == Ggeps::IpPort::Id)
00114 return new Ggeps::IpPort (id, flags, dataSize);
00115
00116 return new Ggeps::UnknownGgep (id, flags, dataSize);
00117 }
00118
00119 void Ggep::prepareRead (const QByteArray &rawExtensionData)
00120 {
00121 invalidateData();
00133 if (isFlagSet (Compression) || isFlagSet (Encoding))
00134 d->isValid = true;
00135 else {
00136 d->isValid = prepareReadData (rawExtensionData);
00137 }
00138 }
00139
00140 void Ggep::read (QDataStream &in)
00141 {
00142 invalidateData();
00143
00144 uchar temp;
00145 in >> temp;
00146 for (int i = id().size(); i > 0 ; i--)
00147 in >> temp;
00148
00149 do {
00150 in >> temp;
00151 } while ((temp & 0x40) != 0x40);
00152
00153 QByteArray decodedData;
00154
00155 if (isFlagSet (Encoding)) {
00156 QByteArray rawData (p.dataLength, 0);
00157 in.readRawData (rawData.data(), p.dataLength);
00158
00159 decodedData = Utils::Encodings::Cobs::decode (rawData);
00160 }
00161 if (isFlagSet (Compression)) {
00162 QByteArray rawData;
00163 if (decodedData.length() > 0) {
00164 rawData = decodedData;
00165 } else {
00166 rawData.reserve (p.dataLength);
00167 in.readRawData (rawData.data(), p.dataLength);
00168 }
00169 decodedData = Utils::Encodings::Deflate::unCompress (rawData);
00170 }
00171
00172 if (decodedData.size() > 0) {
00173 QDataStream decodedInStream (decodedData);
00174 p.dataLength = decodedData.length();
00175
00176 d->isValid = prepareReadData (decodedData);
00177
00178 if (d->isValid)
00179 readData (decodedInStream);
00180 } else {
00181
00182 if (d->isValid)
00183 readData (in);
00184 else {
00185
00186
00187 QByteArray rawData (p.dataLength, 0);
00188 in.readRawData (rawData.data(), p.dataLength);
00189 }
00190 }
00191 }
00192
00193 int Ggep::prepareWrite() const
00194 {
00195
00196
00197
00198 p.dataLength = prepareWriteData();
00199
00200 if (isFlagSet (Compression)) {
00201 QByteArray rawData (p.dataLength, 0);
00202 QDataStream unencodedOutStream (rawData);
00203 writeData (unencodedOutStream);
00204 p.encodedData = Utils::Encodings::Deflate::compress (rawData);
00205 }
00206 if (isFlagSet (Encoding)) {
00207 QByteArray rawData;
00208 if (p.encodedData.length() > 0) {
00209 rawData = p.encodedData;
00210 } else {
00211 rawData.resize (p.dataLength);
00212 QDataStream unencodedOutStream (rawData);
00213 writeData (unencodedOutStream);
00214 }
00215 p.encodedData = Utils::Encodings::Cobs::encode (rawData);
00216 }
00217 int encodedDataLength = 0;
00218 if (p.encodedData.length() > 0) {
00219 encodedDataLength = p.encodedData.length();
00220 } else {
00221 encodedDataLength = p.dataLength;
00222 }
00223
00224
00225 Q_ASSERT (encodedDataLength >= 0 && encodedDataLength <= MaximalGgepDataLength);
00226
00227 int totalLength = 1 + d->id.length() + encodedDataLength;
00228
00229
00230 do {
00231 totalLength++;
00232 encodedDataLength >>= 6;
00233 } while (encodedDataLength > 0);
00234
00235 return totalLength;
00236 }
00237
00238 void Ggep::write (QDataStream &out) const
00239 {
00240 out << static_cast <uchar> (static_cast <int> (d->flags) | id().size());
00241
00242 for (int i = 0; i < id().size(); i++)
00243 out << static_cast <uchar> (d->id[i]);
00244
00245 int length = p.dataLength;
00246 if (isFlagSet (Compression) || isFlagSet (Encoding)) {
00247 length = p.encodedData.length();
00248 }
00249 do {
00250 uchar byte = length & 0x3F;
00251 length >>= 6;
00252 byte |= (length > 0) ? 0x80 : 0x40;
00253 out << byte;
00254 } while (length > 0);
00255
00256 if (isFlagSet (Compression) || isFlagSet (Encoding)) {
00257 out.writeRawData (p.encodedData.data(), p.encodedData.length());
00258 p.encodedData = QByteArray();
00259 } else {
00260 writeData (out);
00261 }
00262 }
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323