packets.cpp

Go to the documentation of this file.
00001 /**
00002  *  Copyright (C) 2004-2005 Alo Sarv <madcat_@users.sourceforge.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 
00019 /**
00020  * @file packets.cpp Implementation of Packet objects input/output
00021  *
00022  * This file basically includes the entire eDonkey2000 protocol packets reading
00023  * writing. As such, this file grows rather big over time. In addition to that,
00024  * this file also needs to include large amount of ed2k module headers, since
00025  * we want the packet objects to be as self-contained as possible, requiring
00026  * minimum amount of construction arguments for easier usage. If this file
00027  * grows beyond our management capabilities, it could be broken up into
00028  * several smaller files, based on some criteria.
00029  */
00030 
00031 #include <hn/hnprec.h>
00032 #include <hn/osdep.h>
00033 #include <hn/partdata.h>
00034 #include <boost/tuple/tuple.hpp>
00035 #include <boost/random/mersenne_twister.hpp> // random number generator
00036 #include "packets.h"
00037 #include "ed2k.h"
00038 #include "serverlist.h"
00039 #include "tag.h"
00040 #include "ed2kfile.h"
00041 #include "zutils.h"
00042 #include <bitset>
00043 
00044 // All packets are declared in ED2KPacket namespace to avoid name clashes
00045 namespace ED2KPacket {
00046 
00047 // Utility functions
00048 // -----------------
00049 
00050 // random number generator functor
00051 boost::mt19937 getRandom;
00052 
00053 uint64_t s_overheadUpSize = 0;
00054 uint64_t s_overheadDnSize = 0;
00055 uint64_t getOverheadUp() { return s_overheadUpSize; }
00056 uint64_t getOverheadDn() { return s_overheadDnSize; }
00057 void addOverheadDn(uint32_t amount) { s_overheadDnSize += amount; }
00058 
00059 /**
00060  * Generates chunk map, as specified by eDonkey2000 protocol. This means
00061  * the vector is filled with bitfields, where each 'true' bit indicates
00062  * we have the 9.28MB part, and each 'false' bit indicates we do not
00063  * have that part. Empty partmap indicates the entire file is available.
00064  * Leftover bits are padded with zeros.
00065  *
00066  * Note that PartData API now supports this internally, so when possible, we
00067  * attempt to aquire this data from PartData. However, if that fails, we still
00068  * generate it ourselves here.
00069  */
00070 std::vector<bool> makePartMap(const PartData *pd) {
00071         if (!pd) {
00072                 return std::vector<bool>();
00073         }
00074         try {
00075                 return pd->getPartStatus(ED2K_PARTSIZE);
00076         } catch (std::exception &) {}
00077 
00078         std::vector<bool> partMap;
00079         for (uint32_t i = 0; i < pd->getSize(); i += ED2K_PARTSIZE + 1) {
00080                 if (i + ED2K_PARTSIZE > pd->getSize()) {
00081                         partMap.push_back(pd->isComplete(i, pd->getSize()));
00082                 } else {
00083                         partMap.push_back(pd->isComplete(i, i + ED2K_PARTSIZE));
00084                 }
00085         }
00086         return partMap;
00087 }
00088 
00089 // Write part map into stream
00090 void writePartMap(std::ostream &o, const std::vector<bool> &partMap) {
00091         Utils::putVal<uint16_t>(o, partMap.size());
00092         std::vector<bool>::const_iterator iter = partMap.begin();
00093         while (iter != partMap.end()) {
00094                 uint8_t tmp = 0;
00095                 for (uint8_t i = 0; i < 8; ++i, ++iter) {
00096                         if (iter == partMap.end()) {
00097                                 Utils::putVal<uint8_t>(o, tmp);
00098                                 break;
00099                         } else {
00100                                 tmp |= *iter << i;
00101                         }
00102                 }
00103                 Utils::putVal<uint8_t>(o, tmp);
00104         }
00105 }
00106 
00107 // Read part map from stream and store in passed container
00108 void readPartMap(std::istream &i, std::vector<bool> *partMap) {
00109         CHECK_THROW(partMap);
00110         uint16_t cnt = Utils::getVal<uint16_t>(i);
00111         while (cnt && i) {
00112                 std::bitset<8> tmp(Utils::getVal<uint8_t>(i));
00113                 for (uint8_t i = 0; i < (cnt >= 8 ? 8 : cnt); ++i) {
00114                         partMap->push_back(tmp[i]);
00115                 }
00116                 cnt -= cnt > 8 ? 8 : cnt;
00117         }
00118 }
00119 
00120 // Exception class
00121 // ---------------
00122 InvalidPacket::InvalidPacket(const std::string &what) :
00123 std::runtime_error(what) {}
00124 
00125 // Packet class
00126 // ------------
00127 Packet::Packet(uint8_t proto) : m_proto(proto) {}
00128 Packet::~Packet() {}
00129 
00130 // Construct the final packet. This method is called during every outgoing
00131 // packet sending, thus should be as fast as possible.
00132 //
00133 // If we are required to build a compressed packet, we attempt to compress the
00134 // packet data using zlib. If we end up with more data than originally after
00135 // compression, we drop the compressed data.
00136 //
00137 // Note: We do NOT compress the opcode of the packet - that is left outside
00138 //       compressed area.
00139 //
00140 // The packet length is the total amount of data in the packet (including
00141 // opcode. When sending compressed packet, the packet length is the amount
00142 // of compressed data (not uncompressed size).
00143 std::string Packet::makePacket(const std::string &data, bool hexDump) {
00144         using namespace Zlib;
00145 
00146         std::string packet(data);
00147         if (m_proto == PR_ZLIB) {
00148                 std::string ret = compress(data.substr(1));
00149                 if (ret.size() >= data.size()) {
00150                         m_proto = PR_ED2K; // revert to non-compressed
00151                 } else {
00152 #ifndef NDEBUG // Verify compressiong/decompression
00153                         std::string check(decompress(ret));
00154                         assert(check == data.substr(1));
00155 #endif
00156                         ret.insert(ret.begin(), data.at(0));
00157                         packet = ret;
00158                 }
00159         }
00160         std::ostringstream tmp;
00161         Utils::putVal<uint8_t>(tmp, m_proto);
00162         Utils::putVal<uint32_t>(tmp, packet.size());
00163         Utils::putVal(tmp, packet, packet.size());
00164         if (hexDump) {
00165                 logDebug(boost::format(
00166                         COL_SEND
00167                         "Sending packet: protocol=%s opcode=%s size=%s %s %s"
00168                         COL_NONE
00169                         ) % Utils::hexDump(m_proto) % Utils::hexDump(data.at(0))
00170                         % Utils::hexDump(data.size())
00171                         % (m_proto == PR_ZLIB ?
00172                                 COL_COMP "(compressed)" COL_SEND
00173                                 : ""
00174                         ) % (data.size() > 1024
00175                                 ? "Data size > 1024 - omitted."
00176                                 : Utils::hexDump(data.substr(1))
00177                         )
00178                 );
00179         }
00180 
00181         if (tmp.str()[5] == OP_SENDINGCHUNK || tmp.str()[5] == OP_PACKEDCHUNK) {
00182                 s_overheadUpSize += 30;
00183         } else {
00184                 s_overheadUpSize += tmp.str().size();
00185         }
00186 
00187         return tmp.str();
00188 }
00189 
00190                         /***********************/
00191                         /*  Client <-> Server  */
00192                         /***********************/
00193 
00194 // LoginRequest class
00195 // ------------------
00196 LoginRequest::LoginRequest(uint8_t proto) : Packet(proto) {}
00197 LoginRequest::operator std::string() {
00198         std::ostringstream tmp;
00199         Utils::putVal<uint8_t>(tmp, OP_LOGINREQUEST);
00200         Utils::putVal(tmp, ED2K::instance().getHash().getData(), 16);
00201         Utils::putVal<uint32_t>(tmp, 0); // clientid
00202         Utils::putVal<uint16_t>(tmp, ED2K::instance().getTcpPort());
00203         Utils::putVal<uint32_t>(tmp, 5); // tagcount
00204         tmp << Tag(CT_NICK, ED2K::instance().getNick());
00205         tmp << Tag(CT_VERSION, VER_EDONKEY);
00206         tmp << Tag(CT_PORT, ED2K::instance().getTcpPort());
00207         tmp << Tag(CT_MULEVERSION, VER_OWN);
00208         tmp << Tag(CT_FLAGS, FL_ZLIB|FL_NEWTAGS);
00209         return makePacket(tmp.str());
00210 }
00211 
00212 // ServerMessage class
00213 // -------------------
00214 ServerMessage::ServerMessage(std::istream &i) {
00215         uint16_t len = Utils::getVal<uint16_t>(i);
00216         m_msg = Utils::getVal<std::string>(i, len);
00217 }
00218 
00219 // ServerStatus class
00220 // ------------------
00221 ServerStatus::ServerStatus(std::istream &i) {
00222         m_users = Utils::getVal<uint32_t>(i);
00223         m_files = Utils::getVal<uint32_t>(i);
00224 }
00225 
00226 // IdChange class
00227 // --------------
00228 IdChange::IdChange(std::istream &i) : m_id(Utils::getVal<uint32_t>(i)),
00229 m_flags() {
00230         // Peek at next byte to see if we have TCP flags that newer servers send
00231         try {
00232                 m_flags = Utils::getVal<uint32_t>(i);
00233         } catch (Utils::ReadError &) {
00234                 // No worries - probably server doesn't support it
00235         }
00236 }
00237 
00238 // GetServerList class
00239 // -------------------
00240 GetServerList::GetServerList(uint8_t proto) : Packet(proto) {}
00241 GetServerList::operator std::string() {
00242         std::ostringstream tmp;
00243         Utils::putVal<uint8_t>(tmp, OP_GETSERVERLIST);
00244         return makePacket(tmp.str());
00245 }
00246 
00247 // ServerIdent class
00248 // -----------------
00249 ServerIdent::ServerIdent(std::istream &i) {
00250         m_hash = Utils::getVal<std::string>(i, 16);
00251         m_addr.setAddr(Utils::getVal<uint32_t>(i));
00252         m_addr.setPort(Utils::getVal<uint16_t>(i));
00253         uint32_t tagcount = Utils::getVal<uint32_t>(i);
00254         while (tagcount-- && i) {
00255                 Tag t(i);
00256                 switch (t.getOpcode()) {
00257                         case CT_SERVERNAME:
00258                                 m_name = t.getStr();
00259                                 break;
00260                         case CT_SERVERDESC:
00261                                 m_desc = t.getStr();
00262                                 break;
00263                         default:
00264                                 warnUnHandled("ServerIdent packet", t);
00265                                 break;
00266                 }
00267         }
00268 }
00269 
00270 ServerList::ServerList(std::istream &i) {
00271         uint8_t count = Utils::getVal<uint8_t>(i);
00272         while (count--) {
00273                 IPV4Address addr;
00274                 addr.setAddr(Utils::getVal<uint32_t>(i));
00275                 addr.setPort(Utils::getVal<uint16_t>(i));
00276                 m_servers.push_back(addr);
00277         }
00278 }
00279 
00280 // OfferFiles class
00281 // ----------------
00282 OfferFiles::OfferFiles(uint8_t proto) : Packet(proto) {}
00283 OfferFiles::OfferFiles(boost::shared_ptr<ED2KFile> f, uint8_t proto)
00284 : Packet(proto) {
00285         push(f);
00286 }
00287 
00288 // Construct the OFFERFILES packet.
00289 OfferFiles::operator std::string() {
00290         std::ostringstream tmp;
00291         Utils::putVal<uint8_t>(tmp, OP_OFFERFILES);
00292         Utils::putVal<uint32_t>(tmp, m_toOffer.size());
00293         for (Iter i = m_toOffer.begin(); i != m_toOffer.end(); ++i) {
00294                 logDebug(
00295                         boost::format("Offering file %s to server.")
00296                         % (*i)->getName()
00297                 );
00298                 tmp << *(*i);
00299         }
00300         return makePacket(tmp.str());
00301 }
00302 
00303 // Search class
00304 // ------------
00305 /*
00306 Search request data:
00307 00000000  00 00 01 04 00 62 6c 61  68 02 03 00 41 6e 79 01  |.....blah...Any.|
00308 00000010  00 03                                             |..|
00309 */
00310 /*
00311 Search request data:
00312 00000000  00 00 00 00 01 17 00 6f  6e 65 20 74 77 6f 20 74  |.......one.two.t|
00313 00000010  68 72 65 65 20 66 6f 75  72 20 66 69 76 65 02 09  |hree.four.five..|
00314 00000020  00 43 44 2d 49 6d 61 67  65 73 01 00 03 03 00 00  |.CD-Images......|
00315 00000030  10 00 01 01 00 02                                 |......|
00316 */
00317 Search::Search(SearchPtr data, uint8_t proto) : Packet(proto), m_data(data) {}
00318 // Generate search packet
00319 Search::operator std::string() {
00320         // Static data used in search packet creation
00321         static const uint8_t  stringParameter   = 0x01;
00322         static const uint8_t  typeParameter     = 0x02;
00323         static const uint8_t  numericParameter  = 0x03;
00324         static const uint16_t andParameter      = 0x0000;
00325         static const uint32_t typeNemonic       = 0x030001;    // !! 24-bit !!
00326 //      static const uint32_t extensionNemonic  = 0x040001;    // !! 24-bit !!
00327         static const uint32_t minNemonic        = 0x02000101;
00328         static const uint32_t maxNemonic        = 0x02000102;
00329 //      static const uint32_t avaibilityNemonic = 0x15000101;
00330 
00331         std::ostringstream tmp;
00332         uint32_t paramCount = 0;
00333         // First - search terms. in ed2k, we just send a big string containing
00334         // all search terms, separated by spaces (is this right?)
00335         std::string terms;
00336         for (uint32_t i = 0; i < m_data->getTermCount(); ++i) {
00337                 terms += m_data->getTerm(i) + " ";
00338         }
00339         terms.erase(--terms.end());
00340         Utils::putVal<uint16_t>(tmp, andParameter);
00341         Utils::putVal<uint8_t>(tmp, stringParameter);
00342         Utils::putVal<uint16_t>(tmp, terms.size());
00343         Utils::putVal(tmp, terms, terms.size());
00344         ++paramCount;
00345 
00346         // Type is always required
00347         std::string type(ED2KFile::HNType2ED2KType(m_data->getType()));
00348         if (!type.size()) {
00349                 type = "Any";
00350         }
00351         Utils::putVal<uint8_t>(tmp, typeParameter);
00352         Utils::putVal<uint16_t>(tmp, type.size());
00353         Utils::putVal(tmp, type, type.size());
00354         // Who on earth came up with the idea of a 3-byte field ? *DOH*
00355         uint32_t _tmp(typeNemonic);
00356         _tmp = SWAP32_ON_BE(_tmp);
00357         tmp.write(reinterpret_cast<const char*>(&_tmp), 3);
00358         ++paramCount;
00359 
00360         // Next check additional things we might have.
00361         if (m_data->getMinSize() > 0) {
00362                 Utils::putVal<uint16_t>(tmp, andParameter);
00363                 Utils::putVal<uint8_t>(tmp, numericParameter);
00364                 Utils::putVal<uint32_t>(tmp, m_data->getMinSize());
00365                 Utils::putVal<uint32_t>(tmp, minNemonic);
00366                 ++paramCount;
00367         }
00368         if (m_data->getMaxSize() < std::numeric_limits<uint32_t>::max()) {
00369                 Utils::putVal<uint16_t>(tmp, andParameter);
00370                 Utils::putVal<uint8_t>(tmp, numericParameter);
00371                 Utils::putVal<uint32_t>(tmp, m_data->getMaxSize());
00372                 Utils::putVal<uint32_t>(tmp, maxNemonic);
00373                 ++paramCount;
00374         }
00375 
00376         // TODO: More search parameters support
00377         // Finalize the packet
00378         std::ostringstream packet;
00379         Utils::putVal<uint8_t>(packet, OP_SEARCH);
00380         Utils::putVal(packet, tmp.str(), tmp.str().size());
00381         return makePacket(packet.str());
00382 }
00383 
00384 // SearchResult class
00385 //! TODO: Actually, the ID and Port here contain some useful
00386 //! TODO: information, but there were some problems with that...
00387 //! TODO: Look into it.
00388 SearchResult::SearchResult(std::istream &i) {
00389         uint32_t count = Utils::getVal<uint32_t>(i);
00390         Utils::StopWatch stopwatch;
00391         uint32_t cnt2 = count; // used for later debug msg
00392         while (count-- && i) {
00393                 Hash<ED2KHash> h(Utils::getVal<std::string>(i, 16));
00394                 Utils::getVal<uint32_t>(i); // id - ignored
00395                 Utils::getVal<uint16_t>(i); // port - ignored
00396                 uint32_t tagCount = Utils::getVal<uint32_t>(i);
00397                 std::string name;
00398                 uint32_t size = 0;
00399                 uint32_t sources = 0;
00400                 uint32_t completesrc = 0;
00401                 std::string codec;
00402                 uint32_t bitrate = 0;
00403                 uint32_t len = 0;
00404                 uint32_t lastSeen = 0;
00405                 while (tagCount-- && i) {
00406                         Tag t(i);
00407                         switch (t.getOpcode()) {
00408                                 case CT_FILENAME:
00409                                         name = t.getStr();
00410                                         break;
00411                                 case CT_FILESIZE:
00412                                         size = t.getInt();
00413                                         break;
00414                                 case CT_SOURCES:
00415                                         sources = t.getInt();
00416                                         break;
00417                                 case CT_COMPLSRC:
00418                                         completesrc = t.getInt();
00419                                         break;
00420                                 case CT_MEDIA_CODEC:
00421                                         codec = t.getStr();
00422                                         break;
00423                                 case CT_MEDIA_BITRATE:
00424                                         bitrate = t.getInt();
00425                                         break;
00426                                 case CT_MEDIA_LENGTH:
00427                                         len = t.getInt();
00428                                         break;
00429                                 case CT_LASTSEENCOMPL:
00430                                         lastSeen = t.getInt();
00431                                         break;
00432                                 default:
00433                                         warnUnHandled("SearchResult", t);
00434                                         break;
00435                         }
00436                 }
00437                 boost::shared_ptr<ED2KSearchResult> f;
00438 
00439                 // Note - ignoring ID/Port values.
00440                 f.reset(new ED2KSearchResult(h, name, size));
00441                 f->addSources(sources);
00442                 f->addComplete(completesrc);
00443 
00444                 if (codec.empty() || bitrate || len) {
00445                         f->getStrd().reset(new StreamData(codec, bitrate, len));
00446                 }
00447 
00448                 m_results.push_back(f);
00449         }
00450 
00451         logDebug(
00452                 boost::format(
00453                         "Parsing " COL_BCYAN "%d"COL_NONE" search results took "
00454                         COL_BGREEN "%dms" COL_NONE "."
00455                 ) % cnt2 % stopwatch
00456         );
00457 }
00458 
00459 // ReqCallback class
00460 // -----------------
00461 ReqCallback::ReqCallback(uint32_t id) : m_id(id) {}
00462 ReqCallback::operator std::string() {
00463         std::ostringstream tmp;
00464         Utils::putVal<uint8_t>(tmp, OP_REQCALLBACK);
00465         Utils::putVal<uint32_t>(tmp, m_id);
00466         return makePacket(tmp.str());
00467 }
00468 
00469 // CallbackReq class
00470 // -----------------
00471 CallbackReq::CallbackReq(std::istream &i) {
00472         m_addr.setAddr(Utils::getVal<uint32_t>(i));
00473         m_addr.setPort(Utils::getVal<uint16_t>(i));
00474 }
00475 
00476 // ReqSources class
00477 // ----------------
00478 ReqSources::ReqSources(const Hash<ED2KHash> &h) : m_hash(h) {}
00479 ReqSources::operator std::string() {
00480         std::ostringstream tmp;
00481         Utils::putVal<uint8_t>(tmp, OP_GETSOURCES);
00482         Utils::putVal(tmp, m_hash.getData(), 16);
00483         return makePacket(tmp.str());
00484 }
00485 
00486 // FoundSources class
00487 // ------------------
00488 FoundSources::FoundSources(std::istream &i) : m_lowCount() {
00489         m_hash = Utils::getVal<std::string>(i, 16);
00490         uint8_t cnt = Utils::getVal<uint8_t>(i);
00491         while (cnt--) {
00492                 IPV4Address addr;
00493                 addr.setAddr(Utils::getVal<uint32_t>(i));
00494                 addr.setPort(Utils::getVal<uint16_t>(i));
00495                 addr.setAddr(SWAP32_ON_BE(addr.getAddr()));
00496                 m_sources.push_back(addr);
00497                 m_lowCount += isLowId(addr.getIp());
00498         }
00499 }
00500 
00501 // GlobGetSources class
00502 // --------------------
00503 GlobGetSources::GlobGetSources(bool sendSize) : m_sendSize(sendSize) {}
00504 GlobGetSources::operator std::string() {
00505         std::ostringstream tmp;
00506         Utils::putVal<uint8_t>(tmp, PR_ED2K);
00507         Utils::putVal<uint8_t>(tmp, OP_GLOBGETSOURCES);
00508         for (uint32_t i = 0; i < m_hashList.size(); ++i) {
00509                 Utils::putVal(tmp, m_hashList[i].first.getData(), 16);
00510                 if (m_sendSize) {
00511                         Utils::putVal<uint32_t>(tmp, m_hashList[i].second);
00512                 }
00513         }
00514         return tmp.str();
00515 }
00516 
00517 // GlobFoundSources class
00518 // ----------------------
00519 GlobFoundSources::GlobFoundSources(std::istream &i) {
00520         m_hash = Utils::getVal<std::string>(i, 16);
00521         uint8_t cnt = Utils::getVal<uint8_t>(i);
00522         while (i && cnt--) {
00523                 uint32_t id = Utils::getVal<uint32_t>(i);
00524                 uint16_t port = Utils::getVal<uint16_t>(i);
00525                 id = SWAP32_ON_BE(id);
00526                 m_sources.push_back(IPV4Address(id, port));
00527         }
00528 }
00529 
00530 // GlobStatReq class
00531 // -----------------
00532 GlobStatReq::GlobStatReq() {
00533         m_challenge = 0x55aa0000 + static_cast<uint16_t>(getRandom());
00534 }
00535 GlobStatReq::operator std::string() {
00536         std::ostringstream tmp;
00537         Utils::putVal<uint8_t>(tmp, PR_ED2K);
00538         Utils::putVal<uint8_t>(tmp, OP_GLOBSTATREQ);
00539         Utils::putVal<uint32_t>(tmp, m_challenge);
00540         return tmp.str();
00541 }
00542 
00543 // GlobStatRes class
00544 // -----------------
00545 GlobStatRes::GlobStatRes(std::istream &i) : m_challenge(), m_users(), m_files(),
00546 m_maxUsers(), m_softLimit(), m_hardLimit(), m_udpFlags(), m_lowIdUsers() {
00547         try {
00548                 m_challenge  = Utils::getVal<uint32_t>(i);
00549                 m_users      = Utils::getVal<uint32_t>(i);
00550                 m_files      = Utils::getVal<uint32_t>(i);
00551                 m_maxUsers   = Utils::getVal<uint32_t>(i);
00552                 m_softLimit  = Utils::getVal<uint32_t>(i);
00553                 m_hardLimit  = Utils::getVal<uint32_t>(i);
00554                 m_udpFlags   = Utils::getVal<uint32_t>(i);
00555                 m_lowIdUsers = Utils::getVal<uint32_t>(i);
00556         } catch (std::exception &) {} // safe to ignore
00557 }
00558 
00559                       /*************************/
00560                       /*  Client <-> Client    */
00561                       /*************************/
00562 
00563 // Hello class
00564 // -----------
00565 Hello::Hello(uint8_t proto , const std::string &modStr /* = "" */)
00566 : Packet(proto), m_modStr(modStr) {}
00567 
00568 Hello::Hello(std::istream &i, bool hashLen /* = true */)
00569 : m_version(), m_muleVer(), m_udpPort(), m_features() {
00570         load(i, hashLen);
00571 }
00572 void Hello::load(std::istream &i, bool hashLen) {
00573         if (hashLen) {
00574                 uint8_t hashSize = Utils::getVal<uint8_t>(i);
00575                 if (hashSize != 16) {
00576                         // Sanity checking
00577                         throw InvalidPacket("Hello: hashSize != 16");
00578                 }
00579         }
00580         m_hash = Utils::getVal<std::string>(i, 16);
00581         m_clientAddr.setAddr(Utils::getVal<uint32_t>(i));
00582         m_clientAddr.setPort(Utils::getVal<uint16_t>(i));
00583         uint32_t tagcount = Utils::getVal<uint32_t>(i);
00584         while (tagcount--) {
00585                 Tag t(i);
00586                 try {
00587                         switch (t.getOpcode()) {
00588                         case CT_NICK:         m_nick = t.getStr();     break;
00589                         case CT_VERSION:      m_version = t.getInt();  break;
00590                         case CT_PORT:         /* ignored */            break;
00591                         case CT_MODSTR:       m_modStr = t.getStr();   break;
00592                         case CT_MULEVERSION:  m_muleVer = t.getInt();  break;
00593                         case CT_UDPPORTS:     m_udpPort = t.getInt();  break;
00594                         case CT_MISCFEATURES: m_features = t.getInt(); break;
00595                         default:
00596                                 break; // ignore unknown/useless tags
00597                         }
00598                 } catch (boost::bad_any_cast &) {
00599                         logWarning(
00600                                 boost::format(
00601                                         "Invalid Hello Packet tag: %s"
00602                                 ) % t.dump()
00603                         );
00604                 }
00605         }
00606         // Now comes server ip/port. NB: Servers don't send ip/port!
00607         try {
00608                 m_serverAddr.setAddr(Utils::getVal<uint32_t>(i));
00609                 m_serverAddr.setPort(Utils::getVal<uint16_t>(i));
00610         } catch (Utils::ReadError&) {}
00611 
00612         // Post-parsing checks
00613         CHECK_THROW(m_clientAddr.getPort() != 0);
00614 }
00615 Hello::operator std::string() {
00616         return save(OP_HELLO, true);
00617 }
00618 std::string Hello::save(uint8_t opcode, bool hashLen /* = true */) {
00619         std::ostringstream tmp;
00620         Utils::putVal<uint8_t>(tmp, opcode);                // opcode
00621         if (hashLen) {
00622                 Utils::putVal<uint8_t>(tmp, 16);            // hash size
00623         }
00624 
00625         // Get our own userhash from ED2K class
00626         Utils::putVal(tmp, ED2K::instance().getHash().getData(), 16);
00627         // Get our own ip/port from ED2K class
00628         Utils::putVal<uint32_t>(tmp, ED2K::instance().getId());
00629         Utils::putVal<uint16_t>(tmp, ED2K::instance().getTcpPort());
00630 
00631         uint32_t tagcount = 5;
00632 
00633         // Note: We omit PORT tag since it is not required by ed2k specification
00634 
00635         // Only write modVersion if it was passed to constructor
00636         if (m_modStr.size()) {
00637                 tagcount++;                                 // add modversion
00638         }
00639 
00640         Utils::putVal<uint32_t>(tmp, tagcount);             // tagcount
00641 
00642         if (m_modStr.size()) {
00643                 tmp << Tag(CT_MODSTR, m_modStr);
00644         }
00645 
00646         tmp << Tag(CT_NICK, ED2K::instance().getNick());    // username
00647         // Mules send 0x3c, edonkey2000 clients send smth like 1000+ ...
00648         // and then there are some guys who send 53? Old edonkeys? anyway.
00649         // we pretend we are a pure-hearted mule.
00650         tmp << Tag(CT_VERSION, 0x3c);
00651         tmp << Tag(CT_MULEVERSION, VER_OWN);                // client version
00652         tmp << Tag(CT_UDPPORTS, ED2K::instance().getUdpPort()); // UDP port
00653 
00654         // Miscellanous features set
00655         static struct Features {
00656                 uint8_t m_preview     :1;        // Preview, implies viewshared
00657                 uint8_t m_multiPacket :1;        // MultiPacket support
00658                 uint8_t m_noViewShared:1;        // No view shared allowed
00659                 uint8_t m_peerCache   :1;        // PeerCache supported
00660                 uint8_t m_commentVer  :4;        // Comment version
00661                 uint8_t m_extReqVer   :4;        // Extended Request version
00662                 uint8_t m_srcExchVer  :4;        // Source Exchange version
00663                 uint8_t m_secIdentVer :4;        // SecIdent version
00664                 uint8_t m_comprVer    :4;        // Compression version
00665                 uint8_t m_udpVer      :4;        // UDP version
00666                 uint8_t m_unicode     :1;        // Unicode supported
00667                 uint8_t m_aichVer     :3;        // AICH support
00668         } options;
00669 
00670         options.m_aichVer      = 0;
00671         options.m_unicode      = 0;
00672         options.m_udpVer       = 4;
00673         // This is disabled because while we do support compressed downloads,
00674         // we unpack data once all data is received, but some clients pack
00675         // multiple 180kb chunks into same zlib pack, which means we stop doing
00676         // chunk-requests, and hence all download-sessions end at 3*180kb.
00677         // Do NOT enable this before implementing dynamic de-comression using
00678         // ZStream in Detail::DownloadClient class.
00679         options.m_comprVer     = 0;
00680         options.m_secIdentVer  = 3; // eMule 0.45b seems to use 3
00681         options.m_srcExchVer   = 3;
00682         options.m_extReqVer    = 2;
00683         options.m_commentVer   = 1;
00684         options.m_peerCache    = 0;
00685         options.m_noViewShared = 1;
00686         options.m_multiPacket  = 0;
00687         options.m_preview      = 0;
00688 
00689         tmp << Tag(CT_MISCFEATURES, *reinterpret_cast<uint32_t*>(&options));
00690 
00691         IPV4Address addr;
00692         try {
00693                 addr = ::ServerList::instance().getCurServerAddr();
00694         } catch (...) {
00695                 // Nothing to do - we are probably not connected. Send 0/0
00696                 // TODO: Is it allowed to sent 0/0 as server addr in Hello
00697                 // TODO: packet if we are not connected?
00698         }
00699         Utils::putVal<uint32_t>(tmp, addr.getAddr());   // server ip
00700         Utils::putVal<uint16_t>(tmp, addr.getPort());   // server port
00701 
00702         return makePacket(tmp.str());
00703 }
00704 
00705 // HelloAnswer class
00706 // -----------------
00707 HelloAnswer::HelloAnswer(uint8_t proto , const std::string &modStr /* = "" */)
00708 : Hello(proto, modStr) {}
00709 HelloAnswer::HelloAnswer(std::istream &i) : Hello(i, false) {}
00710 HelloAnswer::operator std::string() { return save(OP_HELLOANSWER, false); }
00711 
00712 // MuleInfo class
00713 // --------------
00714 MuleInfo::MuleInfo(std::istream &i) : Packet(PR_EMULE), m_protocol(),
00715 m_version(), m_comprVer(), m_udpVer(), m_commentVer(), m_extReqVer(),
00716 m_srcExchVer(), m_compatCliID(), m_udpPort(), m_features(), m_opcode() {
00717         m_version = Utils::getVal<uint8_t>(i);
00718         m_protocol = Utils::getVal<uint8_t>(i);
00719         uint32_t tagCount = Utils::getVal<uint32_t>(i);
00720         while (i && tagCount--) {
00721                 Tag t(i);
00722                 switch (t.getOpcode()) {
00723                         case CT_COMPRESSION:  m_comprVer    = t.getInt(); break;
00724                         case CT_UDPVER:       m_udpVer      = t.getInt(); break;
00725                         case CT_UDPPORT:      m_udpPort     = t.getInt(); break;
00726                         case CT_SOURCEEXCH:   m_srcExchVer  = t.getInt(); break;
00727                         case CT_COMMENTS:     m_commentVer  = t.getInt(); break;
00728                         case CT_EXTREQ:       m_extReqVer   = t.getInt(); break;
00729                         case CT_FEATURES:     m_features    = t.getInt(); break;
00730                         case CT_COMPATCLIENT: m_compatCliID = t.getInt(); break;
00731                         case CT_MODVERSION: {
00732                                 try {
00733                                         m_modStr = t.getStr();
00734                                         break;
00735                                 } catch (boost::bad_any_cast&) {
00736                                         try {
00737                                                 boost::format fmt("ModID: %s");
00738                                                 fmt % t.getInt();
00739                                                 m_modStr = fmt.str();
00740                                                 break;
00741                                         } catch (boost::bad_any_cast&) {
00742                                                 m_modStr = "ModID: <unknown>";
00743                                                 break;
00744                                         }
00745                                 }
00746                         }
00747                         default: break; // suppress warnings
00748                 }
00749         }
00750 }
00751 MuleInfo::MuleInfo() : Packet(PR_EMULE), m_opcode(OP_MULEINFO) {}
00752 MuleInfo::operator std::string() {
00753         std::ostringstream tmp;
00754         Utils::putVal<uint8_t>(tmp, m_opcode);
00755         Utils::putVal<uint8_t>(tmp, 0x44);                   // Software version
00756         Utils::putVal<uint8_t>(tmp, 0x01);                   // Protocol version
00757         Utils::putVal<uint32_t>(tmp, 8);                     // Tagcount
00758         tmp << Tag(CT_COMPRESSION, 0x00);                    // compression
00759         tmp << Tag(CT_UDPVER,      0x04);                    // udp version
00760         tmp << Tag(CT_UDPPORT, ED2K::instance().getUdpPort()); // UDP port
00761         tmp << Tag(CT_SOURCEEXCH,  0x03);                    // src exchannge
00762         tmp << Tag(CT_COMMENTS,    0x01);                    // mh ?
00763         tmp << Tag(CT_EXTREQ,      0x02);                    // Extended request
00764         tmp << Tag(CT_FEATURES,    0x03);                    // secident only
00765         tmp << Tag(CT_COMPATCLIENT, CS_HYDRANODE);           // compat client
00766         return makePacket(tmp.str());
00767 }
00768 
00769 
00770 // MuleInfoAnswer class
00771 // --------------------
00772 MuleInfoAnswer::MuleInfoAnswer() {}
00773 MuleInfoAnswer::MuleInfoAnswer(std::istream &i) : MuleInfo(i) {}
00774 MuleInfoAnswer::operator std::string() {
00775         m_opcode = OP_MULEINFOANSWER;
00776         return *dynamic_cast<MuleInfo*>(this);
00777 }
00778 
00779 // ReqFile class
00780 // -----------------
00781 ReqFile::ReqFile(const Hash<ED2KHash> &h, const PartData *pd, uint16_t srcCnt)
00782 : m_hash(h), m_srcCnt(srcCnt) {
00783         CHECK_THROW(!h.isEmpty());
00784         CHECK_THROW(pd);
00785         m_partMap = makePartMap(pd);
00786 }
00787 ReqFile::ReqFile(std::istream &i) {
00788         try {
00789                 m_hash = Utils::getVal<std::string>(i, 16);
00790                 readPartMap(i, &m_partMap);
00791                 m_srcCnt = Utils::getVal<uint16_t>(i);
00792         } catch (Utils::ReadError&) {}
00793 }
00794 
00795 ReqFile::operator std::string() {
00796         std::ostringstream tmp;
00797         Utils::putVal<uint8_t>(tmp, OP_REQFILE);
00798         Utils::putVal(tmp, m_hash.getData(), 16);
00799         writePartMap(tmp, m_partMap);
00800         Utils::putVal<uint16_t>(tmp, m_srcCnt);
00801         return makePacket(tmp.str());
00802 }
00803 
00804 // FileName class
00805 // -----------------------
00806 FileName::FileName(const Hash<ED2KHash> &h, const std::string &filename)
00807 : m_hash(h), m_name(filename) {}
00808 FileName::FileName(std::istream &i) {
00809         m_hash = Utils::getVal<std::string>(i, 16);
00810         uint16_t len = Utils::getVal<uint16_t>(i);
00811         m_name = Utils::getVal<std::string>(i, len);
00812 }
00813 FileName::operator std::string() {
00814         std::ostringstream tmp;
00815         Utils::putVal<uint8_t>(tmp, OP_FILENAME);
00816         Utils::putVal(tmp, m_hash.getData(), 16);
00817         Utils::putVal<uint16_t>(tmp, m_name.size());
00818         Utils::putVal(tmp, m_name, m_name.size());
00819         return makePacket(tmp.str());
00820 }
00821 
00822 // FileDesc class
00823 // --------------
00824 FileDesc::FileDesc(ED2KFile::Rating rating, const std::string &comment)
00825 : m_rating(rating), m_comment(comment) {}
00826 FileDesc::FileDesc(std::istream &i) {
00827         m_rating = static_cast<ED2KFile::Rating>(Utils::getVal<uint8_t>(i));
00828         uint32_t len = Utils::getVal<uint32_t>(i);
00829         m_comment = Utils::getVal<std::string>(i, len);
00830 }
00831 FileDesc::operator std::string() {
00832         std::ostringstream tmp;
00833         Utils::putVal<uint8_t>(tmp, OP_FILEDESC);
00834         Utils::putVal<uint8_t>(tmp, m_rating);
00835         Utils::putVal<uint32_t>(tmp, m_comment.size());
00836         Utils::putVal(tmp, m_comment, m_comment.size());
00837         return makePacket(tmp.str());
00838 }
00839 
00840 // SetReqFileId class
00841 // ------------------
00842 SetReqFileId::SetReqFileId(const Hash<ED2KHash> &hash) : m_hash(hash) {}
00843 SetReqFileId::SetReqFileId(std::istream &i) {
00844          m_hash = Utils::getVal<std::string>(i, 16);
00845 }
00846 SetReqFileId::operator std::string() {
00847         std::ostringstream tmp;
00848         Utils::putVal<uint8_t>(tmp, OP_SETREQFILEID);
00849         Utils::putVal(tmp, m_hash.getData(), 16);
00850         return makePacket(tmp.str());
00851 }
00852 
00853 // NoFile class
00854 // ------------
00855 NoFile::NoFile(const Hash<ED2KHash> &hash) : m_hash(hash) {}
00856 NoFile::NoFile(std::istream &i) {
00857         m_hash = Utils::getVal<std::string>(i, 16);
00858 }
00859 NoFile::operator std::string() {
00860         std::ostringstream tmp;
00861         Utils::putVal<uint8_t>(tmp, OP_REQFILE_NOFILE);
00862         Utils::putVal(tmp, m_hash.getData(), 16);
00863         return makePacket(tmp.str());
00864 }
00865 
00866 // FileStatus class
00867 // -------------------------
00868 // Note - we can be passed 0 pointer in pd if there is no partdata - e.g.
00869 // the file is full.
00870 FileStatus::FileStatus(const Hash<ED2KHash> &hash, const PartData *pd)
00871 : m_hash(hash), m_partMap(makePartMap(pd)) {
00872         CHECK_THROW(!hash.isEmpty());
00873 }
00874 FileStatus::operator std::string() {
00875         std::ostringstream tmp;
00876         Utils::putVal<uint8_t>(tmp, OP_REQFILE_STATUS);
00877         Utils::putVal(tmp, m_hash.getData(), 16);
00878         writePartMap(tmp, m_partMap);
00879         return makePacket(tmp.str());
00880 }
00881 
00882 FileStatus::FileStatus(std::istream &i) {
00883         m_hash = Utils::getVal<std::string>(i, 16);
00884         readPartMap(i, &m_partMap);
00885 }
00886 
00887 // ReqHashSet class
00888 // ----------------
00889 ReqHashSet::ReqHashSet(const Hash<ED2KHash> &hash) : m_hash(hash) {}
00890 ReqHashSet::ReqHashSet(std::istream &i)
00891 : m_hash(Utils::getVal<std::string>(i, 16)) {}
00892 ReqHashSet::operator std::string() {
00893         std::ostringstream tmp;
00894         Utils::putVal<uint8_t>(tmp, OP_REQHASHSET);
00895         Utils::putVal(tmp, m_hash.getData(), 16);
00896         return makePacket(tmp.str());
00897 }
00898 
00899 // HashSet class
00900 // -------------
00901 HashSet::HashSet(ED2KHashSet *hashset) : m_tmpSet(hashset) {}
00902 HashSet::HashSet(std::istream &i) {
00903         m_hashSet.reset(new ED2KHashSet());
00904         m_hashSet->setFileHash(Utils::getVal<std::string>(i, 16));
00905         uint16_t count = Utils::getVal<uint16_t>(i);
00906         while (count--) {
00907                 m_hashSet->addChunkHash(Utils::getVal<std::string>(i, 16));
00908         }
00909 }
00910 HashSet::operator std::string() {
00911         CHECK_THROW(m_tmpSet);
00912         std::ostringstream tmp;
00913         Utils::putVal<uint8_t>(tmp, OP_HASHSET);
00914         Utils::putVal(tmp, m_tmpSet->getFileHash().getData(), 16);
00915         Utils::putVal<uint16_t>(tmp, m_tmpSet->getChunkCnt());
00916         for (uint32_t i = 0; i < m_tmpSet->getChunkCnt(); ++i) {
00917                 Utils::putVal(tmp, (*m_tmpSet)[i].getData(), 16);
00918         }
00919         return makePacket(tmp.str());
00920 }
00921 
00922 // StartUploadReq class
00923 // --------------------
00924 StartUploadReq::StartUploadReq() {}
00925 StartUploadReq::StartUploadReq(const Hash<ED2KHash> &h) : m_hash(h) {}
00926 StartUploadReq::StartUploadReq(std::istream &i) {
00927         // Optional
00928         try {
00929                 m_hash = Utils::getVal<std::string>(i, 16);
00930         } catch (Utils::ReadError&) {}
00931 }
00932 StartUploadReq::operator std::string() {
00933         std::ostringstream tmp;
00934         Utils::putVal<uint8_t>(tmp, OP_STARTUPLOADREQ);
00935         if (!m_hash.isEmpty()) {
00936                 Utils::putVal(tmp, m_hash.getData(), 16);
00937         }
00938         return makePacket(tmp.str());
00939 }
00940 
00941 // AcceptUploadReq class
00942 // ---------------------
00943 AcceptUploadReq::AcceptUploadReq() {}
00944 AcceptUploadReq::AcceptUploadReq(std::istream &) {}
00945 AcceptUploadReq::operator std::string() {
00946         std::ostringstream tmp;
00947         Utils::putVal<uint8_t>(tmp, OP_ACCEPTUPLOADREQ);
00948         return makePacket(tmp.str());
00949 }
00950 
00951 // QueueRanking class
00952 // ------------------
00953 QueueRanking::QueueRanking(uint16_t rank) : m_qr(rank) {}
00954 QueueRanking::QueueRanking(std::istream &i) {
00955         m_qr = Utils::getVal<uint32_t>(i);
00956 }
00957 QueueRanking::operator std::string() {
00958         std::ostringstream tmp;
00959         Utils::putVal<uint8_t>(tmp, OP_QUEUERANKING);
00960         Utils::putVal<uint32_t>(tmp, m_qr);
00961         return makePacket(tmp.str());
00962 }
00963 
00964 // MuleQueueRank class
00965 // -------------------
00966 MuleQueueRank::MuleQueueRank(uint16_t rank) : Packet(PR_EMULE), m_qr(rank) {}
00967 MuleQueueRank::MuleQueueRank(std::istream &i) {
00968         m_qr = Utils::getVal<uint16_t>(i);
00969 }
00970 MuleQueueRank::operator std::string() {
00971         std::ostringstream tmp;
00972         Utils::putVal<uint8_t>(tmp, OP_MULEQUEUERANK);
00973         Utils::putVal<uint16_t>(tmp, m_qr);
00974         Utils::putVal<uint16_t>(tmp, 0); // Yes, these are needed
00975         Utils::putVal<uint32_t>(tmp, 0);
00976         Utils::putVal<uint32_t>(tmp, 0);
00977         return makePacket(tmp.str());
00978 }
00979 
00980 // ReqChunks class
00981 // --------------
00982 ReqChunks::ReqChunks(
00983         const Hash<ED2KHash> &h, const std::list<Range32> &reqparts
00984 ) : m_hash(h) {
00985         CHECK_THROW(!m_hash.isEmpty());
00986         CHECK_THROW(reqparts.size());
00987         CHECK_THROW(reqparts.size() < 4);
00988         copy(reqparts.begin(), reqparts.end(), std::back_inserter(m_reqChunks));
00989 }
00990 ReqChunks::ReqChunks(std::istream &i) {
00991         m_hash = Utils::getVal<std::string>(i, 16);
00992         boost::tuple<uint32_t, uint32_t, uint32_t> begins;
00993         boost::tuple<uint32_t, uint32_t, uint32_t> ends;
00994         begins.get<0>() = Utils::getVal<uint32_t>(i);
00995         begins.get<1>() = Utils::getVal<uint32_t>(i);
00996         begins.get<2>() = Utils::getVal<uint32_t>(i);
00997         ends.get<0>()   = Utils::getVal<uint32_t>(i);
00998         ends.get<1>()   = Utils::getVal<uint32_t>(i);
00999         ends.get<2>()   = Utils::getVal<uint32_t>(i);
01000         if (ends.get<0>()) {
01001                 Range32 r(begins.get<0>(), ends.get<0>() - 1);
01002                 m_reqChunks.push_back(r);
01003         }
01004         if (ends.get<1>()) {
01005                 Range32 r(begins.get<1>(), ends.get<1>() - 1);
01006                 m_reqChunks.push_back(r);
01007         }
01008         if (ends.get<2>()) {
01009                 Range32 r(begins.get<2>(), ends.get<2>() - 1);
01010                 m_reqChunks.push_back(r);
01011         }
01012 }
01013 ReqChunks::operator std::string() {
01014         std::ostringstream tmp;
01015         Utils::putVal<uint8_t>(tmp, OP_REQCHUNKS);
01016         Utils::putVal(tmp, m_hash.getData(), 16);
01017         CHECK_THROW(m_reqChunks.size());
01018         Utils::putVal<uint32_t>(tmp, m_reqChunks.at(0).begin());
01019         if (m_reqChunks.size() > 1) {
01020                 Utils::putVal<uint32_t>(tmp, m_reqChunks.at(1).begin());
01021         } else {
01022                 Utils::putVal<uint32_t>(tmp, 0);
01023         }
01024         if (m_reqChunks.size() > 2) {
01025                 Utils::putVal<uint32_t>(tmp, m_reqChunks.at(2).begin());
01026         } else {
01027                 Utils::putVal<uint32_t>(tmp, 0);
01028         }
01029         Utils::putVal<uint32_t>(tmp, m_reqChunks.at(0).end() + 1);
01030         if (m_reqChunks.size() > 1) {
01031                 Utils::putVal<uint32_t>(tmp, m_reqChunks.at(1).end() + 1);
01032         } else {
01033                 Utils::putVal<uint32_t>(tmp, 0);
01034         }
01035         if (m_reqChunks.size() > 2) {
01036                 Utils::putVal<uint32_t>(tmp, m_reqChunks.at(2).end() + 1);
01037         } else {
01038                 Utils::putVal<uint32_t>(tmp, 0);
01039         }
01040         return makePacket(tmp.str());
01041 }
01042 
01043 // DataChunk class
01044 // ---------------
01045 DataChunk::DataChunk(
01046         Hash<ED2KHash> hash, uint32_t begin, uint32_t end,
01047         const std::string &data
01048 ) : m_hash(hash), m_begin(begin), m_end(end), m_data(data) {
01049         CHECK_THROW(m_end > m_begin);
01050         CHECK_THROW(m_data.size() == m_end - m_begin);
01051         CHECK_THROW(!hash.isEmpty());
01052 }
01053 DataChunk::DataChunk(std::istream &i) {
01054         m_hash  = Utils::getVal<std::string>(i, 16);
01055         m_begin = Utils::getVal<uint32_t>(i);
01056         m_end   = Utils::getVal<uint32_t>(i);
01057         m_data  = Utils::getVal<std::string>(i, m_end - m_begin);
01058 }
01059 DataChunk::operator std::string() {
01060         std::ostringstream tmp;
01061         Utils::putVal<uint8_t>(tmp, OP_SENDINGCHUNK);
01062         Utils::putVal(tmp, m_hash.getData(), 16);
01063         Utils::putVal<uint32_t>(tmp, m_begin);
01064         Utils::putVal<uint32_t>(tmp, m_end);
01065         Utils::putVal(tmp, m_data, m_data.size());
01066         return makePacket(tmp.str());
01067 }
01068 
01069 // PackedChunk class
01070 // -----------------
01071 PackedChunk::PackedChunk(
01072         Hash<ED2KHash> hash, uint32_t begin, uint32_t size,
01073         const std::string &data
01074 ) : Packet(PR_EMULE), m_hash(hash), m_begin(begin), m_size(size), m_data(data){}
01075 // Ok, here we have a problem. Due to the packet structure implemention, we have
01076 // no way of knowing the length of the packet at this point, and thus no way of
01077 // knowing how much data to read. Thing is, the usual 'end' offset as used in
01078 // DataChunk packet is used as 'total length' of the packed data, and this
01079 // packet usually contains a roughly 10k chunk of the larger packed data part.
01080 // So, the only way we can safely find out how much data to read from the stream
01081 // at this point is to do some evilness. This goes against everything I believe
01082 // in, but I see no other way - blame the protocol :(
01083 PackedChunk::PackedChunk(std::istream &i) : Packet(PR_EMULE) {
01084         m_hash  = Utils::getVal<std::string>(i, 16);
01085         m_begin = Utils::getVal<uint32_t>(i);
01086         m_size  = Utils::getVal<uint32_t>(i);
01087         std::istringstream &is = dynamic_cast<std::istringstream&>(i);
01088         m_data  = is.str().substr(24);
01089 }
01090 PackedChunk::operator std::string() {
01091         std::ostringstream tmp;
01092         Utils::putVal<uint8_t>(tmp, OP_PACKEDCHUNK);
01093         Utils::putVal(tmp, m_hash.getData(), 16);
01094         Utils::putVal<uint32_t>(tmp, m_begin);
01095         Utils::putVal<uint32_t>(tmp, m_size);
01096         Utils::putVal(tmp, m_data, m_data.size());
01097         return makePacket(tmp.str());
01098 }
01099 
01100 // CancelTransfer class
01101 // --------------------
01102 CancelTransfer::CancelTransfer() {}
01103 CancelTransfer::CancelTransfer(std::istream &) {}
01104 CancelTransfer::operator std::string() {
01105         std::ostringstream tmp;
01106         Utils::putVal<uint8_t>(tmp, OP_CANCELTRANSFER);
01107         return makePacket(tmp.str());
01108 }
01109 
01110 // SourceExchReq class
01111 // -------------------
01112 SourceExchReq::SourceExchReq(const Hash<ED2KHash> &hash)
01113 : Packet(PR_EMULE), m_hash(hash) {
01114         CHECK_THROW(m_hash);
01115 }
01116 SourceExchReq::SourceExchReq(std::istream &i) {
01117         m_hash = Utils::getVal<std::string>(i, 16);
01118 }
01119 SourceExchReq::operator std::string() {
01120         std::ostringstream tmp;
01121         Utils::putVal<uint8_t>(tmp, OP_REQSOURCES);
01122         Utils::putVal(tmp, m_hash.getData(), 16);
01123         return makePacket(tmp.str());
01124 }
01125 
01126 // AnswerSources class
01127 // -------------------
01128 AnswerSources::AnswerSources(const Hash<ED2KHash> &hash, const SourceList &srcs)
01129 : Packet(PR_EMULE), m_hash(hash), m_srcList(srcs), m_swapIds() {
01130         CHECK_THROW(m_hash);
01131 }
01132 AnswerSources::AnswerSources(std::istringstream &i) {
01133         m_hash = Utils::getVal<std::string>(i, 16);
01134         uint16_t cnt = Utils::getVal<uint16_t>(i);
01135         bool hashes = true;
01136 
01137         if (i.str().size() - 18u == cnt * 12u) {
01138                 hashes = false;
01139         } else if (i.str().size() - 18u == cnt * (12u + 16u)) {
01140                 hashes = true;
01141         } else {
01142                 logDebug(
01143                         boost::format(
01144                                 "%s: Shouldn't get here; cnt=%d size=%d data:%s"
01145                         ) % __PRETTY_FUNCTION__ % cnt % i.str().size()
01146                         % Utils::hexDump(i.str())
01147                 );
01148         }
01149 
01150         while (i && cnt--) {
01151                 Source tmp;
01152                 tmp.get<0>() = Utils::getVal<uint32_t>(i);
01153                 tmp.get<1>() = Utils::getVal<uint16_t>(i);
01154                 tmp.get<2>() = Utils::getVal<uint32_t>(i);
01155                 tmp.get<3>() = Utils::getVal<uint16_t>(i);
01156                 if (hashes) {
01157                         // SrcExchv2 adds hash16 here
01158                         i.seekg(16, std::ios::cur);
01159                 }
01160                 m_srcList.push_back(tmp);
01161         }
01162 }
01163 
01164 AnswerSources::operator std::string() {
01165         std::ostringstream tmp;
01166         Utils::putVal<uint8_t>(tmp, OP_ANSWERSOURCES);
01167         Utils::putVal<uint16_t>(tmp, m_srcList.size());
01168         for (CIter i = begin(); i != end(); ++i) {
01169                 if (m_swapIds) {
01170                         SWAP32_ON_LE((*i).get<0>());
01171                 }
01172                 Utils::putVal<uint32_t>(tmp, (*i).get<0>());
01173                 Utils::putVal<uint16_t>(tmp, (*i).get<1>());
01174                 Utils::putVal<uint32_t>(tmp, (*i).get<2>());
01175                 Utils::putVal<uint16_t>(tmp, (*i).get<3>());
01176         }
01177         return makePacket(tmp.str());
01178 }
01179 
01180 // Message class
01181 // -------------
01182 Message::Message(const std::string &msg) : m_message(msg) {}
01183 Message::Message(std::istream &i) {
01184         uint16_t len = Utils::getVal<uint16_t>(i);
01185         m_message = Utils::getVal<std::string>(i, len);
01186 }
01187 Message::operator std::string() {
01188         std::ostringstream tmp;
01189         Utils::putVal<uint16_t>(tmp, m_message.size());
01190         Utils::putVal(tmp, m_message, m_message.size());
01191         return makePacket(tmp.str());
01192 }
01193 
01194 // ChangeId class
01195 // --------------
01196 ChangeId::ChangeId(uint32_t oldId, uint32_t newId)
01197 : m_oldId(oldId), m_newId(newId) {
01198         CHECK_THROW(m_oldId);
01199         CHECK_THROW(m_newId);
01200 }
01201 ChangeId::ChangeId(std::istream &i) {
01202         m_oldId = Utils::getVal<uint32_t>(i);
01203         m_newId = Utils::getVal<uint32_t>(i);
01204 
01205         CHECK_THROW(m_oldId);
01206         CHECK_THROW(m_newId);
01207 }
01208 ChangeId::operator std::string() {
01209         std::ostringstream tmp;
01210         Utils::putVal<uint8_t>(tmp, OP_CHANGEID);
01211         Utils::putVal<uint32_t>(tmp, m_oldId);
01212         Utils::putVal<uint32_t>(tmp, m_newId);
01213         return makePacket(tmp.str());
01214 }
01215 
01216 // SecIdentState class
01217 // -------------------
01218 SecIdentState::SecIdentState(::SecIdentState s)
01219 : Packet(PR_EMULE), m_state(s), m_challenge() {
01220         m_challenge = getRandom();
01221 }
01222 SecIdentState::SecIdentState(std::istream &i) {
01223         m_state = Utils::getVal<uint8_t>(i);
01224         m_challenge = Utils::getVal<uint32_t>(i);
01225 }
01226 SecIdentState::operator std::string() {
01227         std::ostringstream tmp;
01228         Utils::putVal<uint8_t>(tmp, OP_SECIDENTSTATE);
01229         Utils::putVal<uint8_t>(tmp, m_state);
01230         Utils::putVal<uint32_t>(tmp, m_challenge);
01231         return makePacket(tmp.str());
01232 }
01233 
01234 // PublicKey class
01235 // ---------------
01236 PublicKey::PublicKey(const ::PublicKey &pubKey)
01237 : Packet(PR_EMULE), m_pubKey(pubKey) {}
01238 PublicKey::PublicKey(std::istream &i) {
01239         uint8_t keyLen = Utils::getVal<uint8_t>(i);
01240         m_pubKey = ::PublicKey(Utils::getVal<std::string>(i, keyLen));
01241 }
01242 PublicKey::operator std::string() {
01243         std::ostringstream tmp;
01244         Utils::putVal<uint8_t>(tmp, OP_PUBLICKEY);
01245         Utils::putVal<uint8_t>(tmp, m_pubKey.size());
01246         Utils::putVal(tmp, m_pubKey.c_str(), m_pubKey.size());
01247         return makePacket(tmp.str());
01248 }
01249 
01250 // Signature class
01251 // ---------------
01252 Signature::Signature(const std::string &sign, IpType ipType)
01253 : Packet(PR_EMULE), m_signature(sign), m_ipType(ipType) {}
01254 Signature::Signature(std::istream &i) : m_ipType() {
01255         std::istringstream &is = dynamic_cast<std::istringstream&>(i);
01256         uint8_t len = Utils::getVal<uint8_t>(is);
01257         if (is.str().substr(1).size() == len) {
01258                 m_signature = Utils::getVal<std::string>(i, len);
01259         } else {
01260                 // SecIdent v2
01261                 m_signature = Utils::getVal<std::string>(i, len);
01262                 m_ipType = Utils::getVal<uint8_t>(i);
01263         }
01264 }
01265 
01266 Signature::operator std::string() {
01267         std::ostringstream tmp;
01268         Utils::putVal<uint8_t>(tmp, OP_SIGNATURE);
01269         Utils::putVal<uint8_t>(tmp, m_signature.size());
01270         Utils::putVal(tmp, m_signature, m_signature.size());
01271         if (m_ipType) {
01272                 Utils::putVal<uint8_t>(tmp, m_ipType);
01273         }
01274         return makePacket(tmp.str());
01275 }
01276 
01277                         /*************************
01278                          * Client <-> Client UDP *
01279                          *************************/
01280 
01281 // ReaskFilePing class
01282 // -------------------
01283 ReaskFilePing::ReaskFilePing(
01284         const Hash<ED2KHash> &h, const PartData *pd, uint16_t srcCnt,
01285         uint8_t udpVersion
01286 ) : m_hash(h), m_partMap(makePartMap(pd)), m_srcCnt(srcCnt),
01287 m_udpVersion(udpVersion) {}
01288 ReaskFilePing::ReaskFilePing(std::istream &i) {
01289         m_hash = Utils::getVal<std::string>(i, 16);
01290         std::istringstream &tmp = dynamic_cast<std::istringstream&>(i);
01291         if (tmp.str().size() >= 20) { // UDPv4
01292                 readPartMap(i, &m_partMap);
01293         }
01294         if (tmp.str().size() >= 18) { // UDPv3
01295                 m_srcCnt = Utils::getVal<uint16_t>(i);
01296         }
01297 }
01298 ReaskFilePing::operator std::string() {
01299         std::ostringstream tmp;
01300         Utils::putVal<uint8_t>(tmp, PR_EMULE);
01301         Utils::putVal<uint8_t>(tmp, OP_REASKFILEPING);
01302         Utils::putVal(tmp, m_hash.getData(), 16);
01303         if (m_udpVersion >= 4) {
01304                 writePartMap(tmp, m_partMap);
01305         }
01306         if (m_udpVersion >= 3) {
01307                 Utils::putVal<uint16_t>(tmp, m_srcCnt);
01308         }
01309         return tmp.str();
01310 }
01311 
01312 // QueueFull class
01313 // ----------------
01314 QueueFull::QueueFull() {}
01315 QueueFull::QueueFull(std::istream &) {}
01316 QueueFull::operator std::string() {
01317         std::ostringstream tmp;
01318         Utils::putVal<uint8_t>(tmp, PR_EMULE);
01319         Utils::putVal<uint8_t>(tmp, OP_QUEUEFULL);
01320         return tmp.str();
01321 }
01322 
01323 // ReaskAck class
01324 // --------------
01325 ReaskAck::ReaskAck(const PartData *pd, uint16_t qr, uint8_t udpVersion)
01326 : Packet(PR_EMULE), m_partMap(makePartMap(pd)), m_qr(qr),
01327 m_udpVersion(udpVersion) {}
01328 ReaskAck::ReaskAck(std::istream &i) {
01329         std::istringstream &tmp = dynamic_cast<std::istringstream&>(i);
01330         if (tmp.str().size() >= 4) {
01331                 readPartMap(tmp, &m_partMap);
01332         }
01333         m_qr = Utils::getVal<uint16_t>(i);
01334 }
01335 ReaskAck::operator std::string() {
01336         std::ostringstream tmp;
01337         Utils::putVal<uint8_t>(tmp, PR_EMULE);
01338         Utils::putVal<uint8_t>(tmp, OP_REASKACK);
01339         if (m_udpVersion >= 4) {
01340                 writePartMap(tmp, m_partMap);
01341         }
01342         Utils::putVal<uint16_t>(tmp, m_qr);
01343         return tmp.str();
01344 }
01345 
01346 // FileNotFound class
01347 // ------------------
01348 FileNotFound::FileNotFound() {}
01349 FileNotFound::FileNotFound(std::istream &) {}
01350 FileNotFound::operator std::string() {
01351         std::ostringstream tmp;
01352         Utils::putVal<uint8_t>(tmp, PR_EMULE);
01353         Utils::putVal<uint8_t>(tmp, OP_FILENOTFOUND);
01354         return tmp.str();
01355 }
01356 
01357 // PortTest class
01358 // --------------
01359 PortTest::PortTest() {}
01360 PortTest::PortTest(std::istream &) {}
01361 PortTest::operator std::string() {
01362         std::ostringstream tmp;
01363         Utils::putVal<uint8_t>(tmp, PR_EMULE);
01364         Utils::putVal<uint8_t>(tmp, OP_PORTTEST);
01365         Utils::putVal<uint8_t>(tmp, 1);
01366         return tmp.str();
01367 }
01368 
01369 } // namespace ED2KPacket