clients.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 /** @file clients.cpp Implementation of clients-related classes */
00020 
00021 #include <hn/hnprec.h>
00022 #include "clients.h"
00023 #include "ed2k.h"
00024 #include "serverlist.h"
00025 #include "creditsdb.h"
00026 #include "parser.h"
00027 #include "clientext.h"
00028 #include <hn/metadb.h>
00029 #include <hn/sharedfile.h>
00030 #include <hn/partdata.h>
00031 #include <hn/fileslist.h>
00032 #include <hn/lambda_placeholders.h>
00033 #include <hn/hydranode.h>
00034 #include <hn/ssocket.h>
00035 #include <hn/hashsetmaker.h>        // for ed2khashmaker
00036 #include <boost/lambda/bind.hpp>
00037 
00038 /**
00039  * Static variable keeping current tick. This is updated before time-calcuation
00040  * operations to reduce getTick() calls during calculations.
00041  */
00042 uint64_t s_curTick = 0;
00043 
00044 /**
00045  * Here's a collection of things that can be used to tweak the ed2k inter-client
00046  * communication procedures. Don't change these unless you know what you'r
00047  * doing. Incorrect values here can seriously affect the modules' networking
00048  * performance.
00049  */
00050 enum Ed2k_ClientConstants {
00051         /**
00052          * Time between source queue ranking reasks. Ed2K netiquette says that
00053          * you shouldn't do reasks more often than once per 30 minutes. Major
00054          * clients drop queued clients from uploadqueue when no reask has been
00055          * done during 1 hour. UDP reasks should be used when possible, falling
00056          * back to TCP only if neccesery.
00057          */
00058         SOURCE_REASKTIME = 30*60*1000,
00059 
00060         /**
00061          * UDP reask timeout. How long to wait for response after sending UDP
00062          * ReaskFilePing. If two UDP reasks fail, we attempt TCP reask, if that
00063          * also fails, drop the client as dead.
00064          */
00065         UDP_TIMEOUT = 30000,
00066 
00067         /**
00068          * Specifies the TCP stream socket timeout; when there's no activity
00069          * in the socket for this amount of time, the socket connection is
00070          * dropped.
00071          */
00072         SOCKET_TIMEOUT = 30000,
00073 
00074         /**
00075          * Specifices LowID callback request timeout; if the called client
00076          * doesn't respond within this timeframe, the client is considered dead.
00077          *
00078          * lugdunum servers can delay LowId callbacks up to 12 seconds
00079          * internally, in order to group several callback requests, so values
00080          * lower than 15 seconds are not recommended.
00081          */
00082         CALLBACK_TIMEOUT = 60000,
00083 
00084         /**
00085          * Specifies the TCP connection attempt timeout.
00086          */
00087         CONNECT_TIMEOUT = 15000
00088 };
00089 
00090 //! Client trace mask
00091 const std::string TRACE_CLIENT = "Ed2kClient";
00092 const std::string TRACE_SECIDENT = "Ed2kClient::SecIdent";
00093 const std::string TRACE_DEADSRC = "ED2KClient::DeadSource";
00094 const std::string TRACE_SRCEXCH = "ED2KClient::SourceExchange";
00095 
00096 //! UDP Socket for performing Client <-> Client UDP communication
00097 ED2KUDPSocket *s_clientUdpSocket = 0;
00098 ED2KUDPSocket*& Client::getUdpSocket() { return s_clientUdpSocket; }
00099 
00100 namespace Detail {
00101         boost::signal<void (Client*, uint32_t)> changeId;
00102         boost::signal<
00103                 bool (const Hash<ED2KHash>&, IPV4Address, IPV4Address, bool)
00104         > foundSource;
00105         boost::signal<void (IPV4Address)> foundServer;
00106 }
00107 
00108 // Client class
00109 // ------------
00110 IMPLEMENT_EVENT_TABLE(Client, Client*, ClientEvent);
00111 
00112 // Packet handlers declarations
00113 // get-to-know-you chit-chat
00114 DECLARE_PACKET_HANDLER(Client, Hello          );
00115 DECLARE_PACKET_HANDLER(Client, HelloAnswer    );
00116 DECLARE_PACKET_HANDLER(Client, MuleInfo       );
00117 DECLARE_PACKET_HANDLER(Client, MuleInfoAnswer );
00118 // uploading/downloading
00119 DECLARE_PACKET_HANDLER(Client, ReqFile        );
00120 DECLARE_PACKET_HANDLER(Client, SetReqFileId   );
00121 DECLARE_PACKET_HANDLER(Client, ReqHashSet     );
00122 DECLARE_PACKET_HANDLER(Client, StartUploadReq );
00123 DECLARE_PACKET_HANDLER(Client, ReqChunks      );
00124 DECLARE_PACKET_HANDLER(Client, CancelTransfer );
00125 DECLARE_PACKET_HANDLER(Client, FileName       );
00126 DECLARE_PACKET_HANDLER(Client, FileDesc       );
00127 DECLARE_PACKET_HANDLER(Client, FileStatus     );
00128 DECLARE_PACKET_HANDLER(Client, NoFile         );
00129 DECLARE_PACKET_HANDLER(Client, HashSet        );
00130 DECLARE_PACKET_HANDLER(Client, AcceptUploadReq);
00131 DECLARE_PACKET_HANDLER(Client, QueueRanking   );
00132 DECLARE_PACKET_HANDLER(Client, MuleQueueRank  );
00133 DECLARE_PACKET_HANDLER(Client, DataChunk      );
00134 DECLARE_PACKET_HANDLER(Client, PackedChunk    );
00135 // source exchange
00136 DECLARE_PACKET_HANDLER(Client, SourceExchReq  );
00137 DECLARE_PACKET_HANDLER(Client, AnswerSources  );
00138 DECLARE_PACKET_HANDLER(Client, AnswerSources2 );
00139 // misc
00140 DECLARE_PACKET_HANDLER(Client, Message        );
00141 DECLARE_PACKET_HANDLER(Client, ChangeId       );
00142 // secident
00143 DECLARE_PACKET_HANDLER(Client, SecIdentState  );
00144 DECLARE_PACKET_HANDLER(Client, PublicKey      );
00145 DECLARE_PACKET_HANDLER(Client, Signature      );
00146 
00147 // Constructor
00148 Client::Client(ED2KClientSocket *c) : m_id(), m_tcpPort(), m_udpPort(),
00149 m_features(), m_clientSoft(), m_parser(new ED2KParser<Client>(this)),
00150 m_socket(c), m_credits(), m_callbackInProgress(false),m_reaskInProgress(false),
00151 m_failedUdpReasks(), m_lastReaskTime(), m_sentChallenge(), m_reqChallenge(),
00152 m_upReqInProgress(), m_dnReqInProgress() {
00153         CHECK_THROW(c);
00154         CHECK_THROW(c->isConnected() || c->isConnecting());
00155 
00156         m_id      = c->getPeer().getAddr();
00157         m_tcpPort = c->getPeer().getPort();
00158 
00159         c->setHandler(this, &Client::onSocketEvent);
00160         m_parser->parse(c->getData());
00161 }
00162 
00163 Client::Client(IPV4Address addr, Download *file)
00164 : m_id(addr.getAddr()), m_tcpPort(addr.getPort()), m_udpPort(), m_features(),
00165 m_clientSoft(), m_parser(new ED2KParser<Client>(this)), m_socket(),m_credits(),
00166 m_callbackInProgress(false), m_reaskInProgress(false), m_failedUdpReasks(),
00167 m_lastReaskTime(), m_sentChallenge(), m_reqChallenge(), m_upReqInProgress(),
00168 m_dnReqInProgress() {
00169 
00170         addOffered(file, false); // don't connect right away
00171 }
00172 
00173 Client::~Client() {
00174         delete m_socket;
00175 }
00176 
00177 void Client::destroy() {
00178         getEventTable().postEvent(this, EVT_DESTROY);
00179         delete m_socket;
00180         m_socket = 0;
00181         m_downloadInfo.reset();
00182         m_queueInfo.reset();
00183         m_sourceInfo.reset();
00184         m_uploadInfo.reset();
00185 }
00186 
00187 void Client::checkDestroy() {
00188         if (!m_sourceInfo && !m_downloadInfo && !m_queueInfo && !m_uploadInfo) {
00189                 destroy();
00190         }
00191 }
00192 
00193 std::string Client::getIpPort() const {
00194         boost::format fmt("%s:%s");
00195         if (isHighId()) {
00196                 fmt % Socket::getAddr(getId());
00197         } else {
00198                 fmt % boost::lexical_cast<std::string>(getId());
00199         }
00200         fmt % getTcpPort();
00201         return fmt.str();
00202 }
00203 
00204 /**
00205  * Attempt to establish connection with the remote client. If the remote client
00206  * is LowID, we will request a callback via server (but only if we are connected
00207  * to a server, and the remote client is on same server as we are). If the
00208  * remote client is HighID, we attempt to connect it directly. If anything
00209  * goes wrong, std::runtime_error will be thrown.
00210  *
00211  * If this method is called and socket already exists, it silently returns. The
00212  * reason for not throwing exceptions on that case is that there's a lot of race
00213  * conditions floating around regarding re-establishing connections. While some
00214  * of them are internal, and could (should) be fixed, many of them are inherent
00215  * from remote client's bad protocol usage, and it is nearly impossible to
00216  * handle all cases correctly.
00217  */
00218 void Client::establishConnection() {
00219         if (m_socket) {
00220                 return; // silently ignored
00221         }
00222 
00223         if (isLowId()) try {
00224                 IPV4Address curServ = ServerList::instance().getCurServerAddr();
00225                 if (m_serverAddr && m_serverAddr != curServ) {
00226                         logTrace(TRACE_DEADSRC,
00227                                 boost::format(
00228                                         "[%s] We are on server %s, client is "
00229                                         "on server %s; dropping."
00230                                 ) % getIpPort() % curServ % m_serverAddr
00231                         );
00232                         destroy();
00233                         return;
00234                 }
00235                 logTrace(TRACE_CLIENT,
00236                         boost::format("[%s] %p: Performing LowID callback...")
00237                         % getIpPort() % this
00238                 );
00239                 ServerList::instance().reqCallback(m_id);
00240                 getEventTable().postEvent(
00241                         this, EVT_CALLBACK_T, CALLBACK_TIMEOUT
00242                 );
00243                 m_callbackInProgress = true;
00244         } catch (std::exception &e) {
00245                 logTrace(
00246                         TRACE_DEADSRC, boost::format(
00247                                 "[%s] Error performing LowID callback: %s"
00248                         ) % getIpPort() % e.what()
00249                 );
00250                 destroy();
00251         } else { // highid
00252                 logTrace(
00253                         TRACE_CLIENT,
00254                         boost::format("[%s] Connecting...") % getIpPort()
00255                 );
00256                 m_socket = new ED2KClientSocket();
00257                 m_socket->setHandler(this, &Client::onSocketEvent);
00258                 IPV4Address addr(m_id, m_tcpPort);
00259                 m_socket->connect(addr, CONNECT_TIMEOUT);
00260         }
00261 }
00262 
00263 bool Client::isConnected() const { return m_socket && m_socket->isConnected(); }
00264 
00265 // Queue Score calculation.
00266 // This should be implemented similarly to how emule does it to be compatible.
00267 // We start out with waiting time (in seconds), and modify it by:
00268 // - Client's credits modifier (if present)
00269 // - \todo Requested file priority
00270 // - \todo Friend status (friends get increased score)
00271 float Client::getScore() const {
00272         CHECK_THROW(m_queueInfo);
00273         // Score calculation: Start with waiting time amount
00274         float score = (s_curTick - m_queueInfo->getWaitStartTime())/1000;
00275         // Modify it (if possible) with credit score
00276         if (m_credits) {
00277                 score *= m_credits->getScore();
00278         }
00279         return score;
00280 }
00281 
00282 // Add an offered file. This is the public accessor and really forwards the
00283 // call to DownloadInfo sub-object (constructing it if neccesery).
00284 // doConn variable allows delaying connection attempt for later
00285 void Client::addOffered(Download *file, bool doConn) {
00286         if (!m_sourceInfo) {
00287                 logTrace(TRACE_CLIENT,
00288                         boost::format("[%s] %p: Creating new SourceInfo")
00289                         % getIpPort() % this
00290                 );
00291 
00292                 m_sourceInfo.reset(new Detail::SourceInfo(this, file));
00293 
00294                 if (isConnected() && !m_downloadInfo) {
00295                         reqDownload();
00296                 } else if (!m_socket && doConn) {
00297                         establishConnection();
00298                 }
00299         } else {
00300                 logTrace(TRACE_CLIENT,
00301                         boost::format("[%s] %p: Adding offered file.")
00302                         % getIpPort() % this
00303                 );
00304 
00305                 m_sourceInfo->addOffered(file);
00306         }
00307 }
00308 
00309 void Client::remOffered(Download *file, bool cleanUp) {
00310         CHECK_THROW(file);
00311 
00312         if (m_sourceInfo) {
00313                 m_sourceInfo->remOffered(file, cleanUp);
00314                 if (!m_sourceInfo->getOffCount()) {
00315                         m_sourceInfo.reset();
00316                 }
00317         }
00318         if (m_downloadInfo) {
00319                 if (m_downloadInfo->getReqPD() == file->getPartData()) {
00320                         m_downloadInfo.reset();
00321                 }
00322         }
00323         checkDestroy();
00324 }
00325 
00326 // merge all the information that we need from the other client. Keep in mind
00327 // that the other client will be deleted shortly after this function is called
00328 // by clientlist, so we must take everything we need from that client.
00329 void Client::merge(Client *c) {
00330         CHECK_THROW(c != this);
00331 
00332         if (m_socket && c->m_socket) {
00333                 throw std::runtime_error("Client is already connected!");
00334         } else if (c->m_socket && !m_socket) {
00335                 m_socket = c->m_socket;
00336                 m_socket->setHandler(this, &Client::onSocketEvent);
00337                 c->m_socket = 0;
00338         }
00339 
00340         m_parser = c->m_parser;
00341         m_parser->setParent(this);
00342         if (c->m_queueInfo && !m_queueInfo) {
00343                 m_queueInfo = c->m_queueInfo;
00344         }
00345         if (c->m_sourceInfo && !m_sourceInfo) {
00346                 m_sourceInfo = c->m_sourceInfo;
00347         }
00348         if (c->m_uploadInfo && !m_uploadInfo) {
00349                 m_uploadInfo = c->m_uploadInfo;
00350         }
00351         if (c->m_downloadInfo && !m_downloadInfo) {
00352                 m_downloadInfo = c->m_downloadInfo;
00353         }
00354         if (c->m_hash && !m_hash) {
00355                 m_hash = c->m_hash;
00356         }
00357         if (c->m_udpPort && !m_udpPort) {
00358                 m_udpPort = c->m_udpPort;
00359         }
00360         if (c->m_pubKey && !m_pubKey) {
00361                 m_pubKey = c->m_pubKey;
00362         }
00363         if (c->m_serverAddr && !m_serverAddr) {
00364                 m_serverAddr = c->m_serverAddr;
00365         }
00366         if (c->m_nick.size() && !m_nick.size()) {
00367                 m_nick = c->m_nick;
00368         }
00369         if (c->m_clientSoft && !m_clientSoft) {
00370                 m_clientSoft = c->m_clientSoft;
00371         }
00372         if (c->m_credits && !m_credits) {
00373                 m_credits = c->m_credits;
00374         }
00375         if (c->m_lastReaskTime && !m_lastReaskTime) {
00376                 m_lastReaskTime = c->m_lastReaskTime;
00377         }
00378         if (c->m_sentChallenge && !m_sentChallenge) {
00379                 m_sentChallenge = c->m_sentChallenge;
00380         }
00381         if (c->m_reqChallenge && !m_reqChallenge) {
00382                 m_reqChallenge = c->m_reqChallenge;
00383         }
00384         if (m_callbackInProgress) {
00385                 logTrace(TRACE_CLIENT,
00386                         boost::format("[%s] %p: LowID callback succeeded.")
00387                         % getIpPort() % this
00388                 );
00389                 m_callbackInProgress = false;
00390         }
00391 }
00392 
00393 // Event handler for socket events.
00394 // note that due to changeId() signal handlers, we might be deleted when
00395 // returning from parser, so do NOT do anything in this function after returning
00396 // from parse(), since we might have been deleted.
00397 void Client::onSocketEvent(ED2KClientSocket *c, SocketEvent evt) {
00398         CHECK_THROW(m_socket);
00399         CHECK_THROW(c == m_socket);
00400 
00401         m_socket->setTimeout(SOCKET_TIMEOUT);
00402 
00403         if (evt == SOCK_READ) try {
00404                 m_parser->parse(c->getData());
00405         } catch (std::runtime_error &er) {
00406                 logDebug(
00407                         boost::format(
00408                                 "[%s] Error during client stream "
00409                                 "parsing/handling: %s"
00410                         ) % getIpPort() % er.what()
00411                 );
00412 
00413                 if (m_socket) {
00414                         m_socket->disconnect();
00415                         delete m_socket;
00416                         m_socket = 0;
00417                 }
00418                 m_downloadInfo.reset();
00419 
00420                 if (m_uploadInfo) {
00421                         m_uploadInfo.reset();
00422                         getEventTable().postEvent(this, EVT_CANCEL_UPLOADREQ);
00423                 }
00424 
00425                 if (!m_sourceInfo && !m_queueInfo) {
00426                         logTrace(TRACE_DEADSRC,
00427                                 boost::format(
00428                                         "[%s] Destroying client: Error during "
00429                                         "TCP stream parsing/handling and no "
00430                                         "source/queue information is available."
00431                                 ) % getIpPort()
00432                         );
00433                         destroy();
00434                 }
00435         } else if (evt == SOCK_WRITE && m_uploadInfo) {
00436                 sendNextChunk();
00437         } else if (evt == SOCK_CONNECTED) {
00438                 logTrace(TRACE_CLIENT,
00439                         boost::format(
00440                                 "[%s] Connection established, sending Hello"
00441                         ) % getIpPort()
00442                 );
00443                 *m_socket << ED2KPacket::Hello();
00444                 m_failedUdpReasks = 0;
00445                 m_upReqInProgress = false;
00446                 m_dnReqInProgress = false;
00447         } else if (evt == SOCK_CONNFAILED) {
00448                 logTrace(
00449                         TRACE_DEADSRC, boost::format(
00450                                 "[%s] Dropping client (unable to connect)"
00451                         ) % getIpPort()
00452                 );
00453                 destroy();
00454         } else if (evt == SOCK_TIMEOUT || evt == SOCK_LOST || evt == SOCK_ERR) {
00455                 logTrace(TRACE_CLIENT,
00456                         boost::format("[%s] Connection lost.") % getIpPort()
00457                 );
00458 
00459                 if (!m_queueInfo && m_sourceInfo && !m_lastReaskTime) {
00460                         logTrace(TRACE_DEADSRC,
00461                                 boost::format(
00462                                         "[%s] Destroying client: Source, but "
00463                                         "never connected."
00464                                 ) % getIpPort()
00465                         );
00466                         destroy();
00467                 } else if (!m_sourceInfo && !m_queueInfo) {
00468                         logTrace(TRACE_DEADSRC,
00469                                 boost::format(
00470                                         "[%s] Destroying client: TCP connection"
00471                                         " lost/failed, and no src/queue info is"
00472                                         " available."
00473                                 ) % getIpPort()
00474                         );
00475                         destroy();
00476                 } else if (m_failedUdpReasks > 2) {
00477                         logTrace(TRACE_DEADSRC,
00478                                 boost::format(
00479                                         "[%s] Destroying client: 3 UDP Reasks "
00480                                         "failed, and TCP Reask also failed."
00481                                 ) % getIpPort()
00482                         );
00483                         destroy();
00484                 } else {
00485                         delete m_socket;
00486                         m_socket = 0;
00487                         m_upReqInProgress = false;
00488                         m_dnReqInProgress = false;
00489                 }
00490 
00491                 m_downloadInfo.reset();
00492 
00493                 if (m_uploadInfo) {
00494                         m_uploadInfo.reset();
00495                         getEventTable().postEvent(this, EVT_CANCEL_UPLOADREQ);
00496                 }
00497         }
00498 }
00499 
00500 // Get to know you chit chat
00501 // -------------------------
00502 // Before we can do anything other useful things with the remote client, we
00503 // must first get to know him/her and also introduce ourselves. We do it by
00504 // saying Hello, and expecting HelloAnswer. Alternatively, if he/she said
00505 // Hello to us, we politely respond with HelloAnswer.
00506 //
00507 // There are rumors about some old mules walking around the network, using some
00508 // odd mule-language. Newer-generation mules have learned english, and no longer
00509 // require the usage of mule-language, however, for old-generation mules, we
00510 // must speak their language, and thus also say MuleInfo and/or MuleInfoAnswer.
00511 //
00512 
00513 // Stores client info found in packet internally. This is used as helper
00514 // method by Hello/HelloAnswer packet handler
00515 void Client::storeInfo(const ED2KPacket::Hello &p) {
00516         m_tcpPort    = p.getClientAddr().getPort();
00517         m_udpPort    = p.getUdpPort();
00518         m_features   = p.getFeatures();
00519         m_hash       = p.getHash();
00520         m_serverAddr = p.getServerAddr();
00521         m_nick       = p.getNick();
00522 
00523         if (getClientSoft() != CS_MLDONKEY_NEW2) {
00524                 // new mldonkeys send muleinfo with mldonkey info, and THEN
00525                 // hello with ID 0x00 (emule) - this check detects it.
00526                 m_clientSoft = p.getMuleVer();
00527         }
00528         if (!m_clientSoft) {
00529                 m_clientSoft |= p.getVersion() << 24;
00530         }
00531         logTrace(TRACE_CLIENT,
00532                 boost::format(
00533                         "[%s] (Hello) ClientSoftware is " COL_BBLUE
00534                         "%s" COL_BGREEN " %s" COL_NONE
00535                 ) % getIpPort() % getSoftStr() % getVerStr()
00536         );
00537 
00538         Detail::changeId(this, p.getClientAddr().getAddr());
00539 
00540 }
00541 
00542 std::string Client::getSoftStr() const {
00543         switch (m_clientSoft >> 24) {
00544                 case CS_EMULE:         return "eMule";
00545                 case CS_CDONKEY:       return "cDonkey";
00546                 case CS_LXMULE:        return "(l/x)mule";
00547                 case CS_AMULE:         return "aMule";
00548                 case CS_SHAREAZA:      return "ShareAza";
00549                 case CS_EMULEPLUS:     return "eMulePlus";
00550                 case CS_HYDRANODE:     return "HydraNode";
00551                 case CS_MLDONKEY_NEW2: return "MLDonkey";
00552                 case CS_LPHANT:        return "lphant";
00553                 case CS_HYBRID:        return "eDonkeyHybrid";
00554                 case CS_DONKEY:        return "eDonkey";
00555                 case CS_MLDONKEY:      return "OldMLDonkey";
00556                 case CS_OLDEMULE:      return "OldeMule";
00557                 case CS_MLDONKEY_NEW:  return "MLDonkey";
00558                 case CS_UNKNOWN:
00559                 default: return (
00560                         boost::format("Unknown %s")
00561                         % Utils::hexDump(m_clientSoft >> 24)
00562                 ).str();
00563         }
00564 }
00565 
00566 std::string Client::getVerStr() const {
00567         std::string ret;
00568         if (getClientSoft() == CS_EMULE) {
00569                 ret += "0.";
00570                 ret += boost::lexical_cast<std::string>(getVerMin());
00571                 ret += static_cast<uint8_t>(getVerPch() + 0x61);
00572         } else {
00573                 boost::format fmt("%d.%d.%d-%d");
00574                 fmt % getVerMjr() % getVerMin() % getVerPch() % getVerBld();
00575                 ret += fmt.str();
00576         }
00577         return ret;
00578 }
00579 
00580 bool Client::isMule() const {
00581         if (getClientSoft() == CS_EMULE && m_hash) {
00582                 return m_hash.getData()[5] == 14 && m_hash.getData()[14] == 111;
00583         } else {
00584                 return false;
00585         }
00586 }
00587 
00588 // Hi there little one
00589 void Client::onPacket(const ED2KPacket::Hello &p) {
00590         CHECK_THROW(m_socket);
00591 
00592         *m_socket << ED2KPacket::HelloAnswer();
00593 
00594         if (isMule() && getVerMin() < 43) {
00595                 logTrace(TRACE_CLIENT, "Old eMule detected, sending MuleInfo.");
00596                 // eMule (old) extended protocol - also send MuleInfo
00597                 *m_socket << ED2KPacket::MuleInfo();
00598         }
00599 
00600         storeInfo(p);
00601 }
00602 
00603 // Nice to meet you too
00604 void Client::onPacket(const ED2KPacket::HelloAnswer &p) {
00605         logTrace(TRACE_CLIENT,
00606                 boost::format("[%s] Received HelloAnswer.") % getIpPort()
00607         );
00608         storeInfo(p);
00609 }
00610 
00611 void Client::onPacket(const ED2KPacket::MuleInfo &p) {
00612         logTrace(TRACE_CLIENT,
00613                 boost::format("[%s] Received MuleInfo.") % getIpPort()
00614         );
00615         processMuleInfo(p);
00616         CHECK_THROW(m_socket);
00617         *m_socket << ED2KPacket::MuleInfoAnswer();
00618 }
00619 
00620 // the old extinct mule language
00621 void Client::onPacket(const ED2KPacket::MuleInfoAnswer &p) {
00622         logTrace(TRACE_CLIENT,
00623                 boost::format("[%s] Received MuleInfoAnswer") % getIpPort()
00624         );
00625         processMuleInfo(p);
00626 }
00627 
00628 void Client::processMuleInfo(const ED2KPacket::MuleInfo &p) {
00629         m_clientSoft |= p.getCompatCliID()   << 24; // compat client id
00630         m_clientSoft |= (p.getVersion() + 8) << 10; // minor version, in hex
00631 
00632         logTrace(TRACE_CLIENT,
00633                 boost::format("[%s] %s %s using old eMule protocol.")
00634                 % getIpPort() % getSoftStr() % getVerStr()
00635         );
00636 
00637         if (isMule() && getVerMin() < 42) {
00638                 handshakeCompleted();
00639         }
00640 }
00641 
00642 // Upload requests
00643 // ---------------
00644 // Here we go again. Just as we arrived on the net, ppl start wanting something
00645 // from us. Can't they just leave us alone and stop wanting every last bit of
00646 // our preciousssss files? *sigh*
00647 //
00648 // Well, here goes.
00649 
00650 // He/she wants a file. "Ask, and thou shall receive."
00651 void Client::onPacket(const ED2KPacket::ReqFile &p) {
00652         CHECK_THROW(isConnected());
00653         using boost::signals::connection;
00654 
00655         logTrace(TRACE_CLIENT,
00656                 boost::format("[%s] Received ReqFile for %s")
00657                 % getIpPort() % p.getHash().decode()
00658         );
00659         SharedFile *sf = MetaDb::instance().findSharedFile(p.getHash());
00660         if (sf) {
00661                 *m_socket << ED2KPacket::FileName(p.getHash(), sf->getName());
00662                 m_upReqInProgress = true;
00663                 if (sf->isPartial() && !m_sourceInfo) {
00664                         logTrace(TRACE_CLIENT,
00665                                 boost::format(
00666                                         "[%s] Passivly adding source "
00667                                         "and sending ReqFile."
00668                                 ) % getIpPort()
00669                         );
00670                         Download *file = 0;
00671                         file = DownloadList::instance().find(p.getHash());
00672                         CHECK_THROW(file);
00673                         m_sourceInfo.reset(new Detail::SourceInfo(this, file));
00674                         reqDownload();
00675                 }
00676         } else {
00677                 *m_socket << ED2KPacket::NoFile(p.getHash());
00678         }
00679 }
00680 
00681 // Seems he/she is confident in his/her wishes. Well, can't argue there.
00682 // Confidence is a virtue :)
00683 void Client::onPacket(const ED2KPacket::SetReqFileId &p) {
00684         CHECK_THROW(isConnected());
00685 
00686         SharedFile *sf = MetaDb::instance().findSharedFile(p.getHash());
00687         if (sf) {
00688                 *m_socket << ED2KPacket::FileStatus(
00689                         p.getHash(), sf->getPartData()
00690                 );
00691                 logTrace(TRACE_CLIENT,
00692                         boost::format("[%s] Received SetReqFileId for %s")
00693                         % getIpPort() % sf->getName()
00694                 );
00695                 if (m_uploadInfo) {
00696                         if (m_uploadInfo->getReqChunkCount()) {
00697                                 logTrace(TRACE_CLIENT,
00698                                         boost::format(
00699                                                 "[%s] Cannot SetReqFileId "
00700                                                 "after ReqChunks!"
00701                                         ) % getIpPort()
00702                                 );
00703                                 return;
00704                         } else {
00705                                 m_uploadInfo->setReqFile(sf);
00706                         }
00707                 } else if (m_queueInfo) {
00708                         m_queueInfo->setReqFile(sf, p.getHash());
00709                 } else {
00710                         m_queueInfo.reset(
00711                                 new Detail::QueueInfo(this, sf, p.getHash())
00712                         );
00713                         m_queueInfo->m_lastQueueReask = Utils::getTick();
00714                         m_uploadInfo.reset();
00715                         getEventTable().postEvent(this, EVT_UPLOADREQ);
00716                 }
00717         } else {
00718                 *m_socket << ED2KPacket::NoFile(p.getHash());
00719                 logTrace(TRACE_CLIENT,
00720                         boost::format(
00721                                 "[%s] Received request for unknown file %s"
00722                         ) % getIpPort() % p.getHash().decode()
00723                 );
00724         }
00725 }
00726 
00727 // So, seems they'r really sure they want this file. Ohwell, let's see what
00728 // we can do. But wait - we can't do anything yet - we need to ask permission
00729 // from our parent first. More on this later...
00730 //
00731 // PS: Rumors say some mules starting with A letter want to start upload before
00732 //     actually saying what they want in setreqfileid. Poor bastards, but
00733 //     we must serve all equally, so try to work around it and grant the request
00734 //     anyway, if we have enough information at this point.
00735 void Client::onPacket(const ED2KPacket::StartUploadReq &p) {
00736         logTrace(TRACE_CLIENT,
00737                 boost::format("[%s] Received StartUploadReq.") % getIpPort()
00738         );
00739         onUploadReq(p.getHash());
00740 }
00741 
00742 // handles upload requests
00743 void Client::onUploadReq(const Hash<ED2KHash> &hash) {
00744         if (hash.isEmpty() && !m_uploadInfo && !m_queueInfo) {
00745                 return; // not enough info to do anything with this request
00746         }
00747         SharedFile *sf = MetaDb::instance().findSharedFile(hash);
00748         CHECK_THROW(sf);
00749         if (m_uploadInfo) {
00750                 m_uploadInfo->setReqFile(sf);
00751                 if (hash) {
00752                         m_uploadInfo->setReqHash(hash);
00753                 }
00754                 startUpload();
00755         } else if (m_queueInfo) {
00756                 m_queueInfo->setReqFile(sf, hash);
00757                 m_queueInfo->m_lastQueueReask = Utils::getTick();
00758                 getEventTable().postEvent(this, EVT_UPLOADREQ);
00759         } else {
00760                 m_queueInfo.reset(new Detail::QueueInfo(this, sf, hash));
00761                 m_queueInfo->m_lastQueueReask = Utils::getTick();
00762                 getEventTable().postEvent(this, EVT_UPLOADREQ);
00763         }
00764 }
00765 
00766 // So, they want to know the entire hashset of the file? Interesting concept.
00767 // Do we have the hashset? Do WE actually know what we are sharing? Might not
00768 // always be the case, if we don't have the file ourselves yet, or something
00769 // else is wrong. On the other hand, if we have even few bytes of the file,
00770 // and thus are sharing it, then we should have the hashset of it anyway, since
00771 // we ask for a hashset ourselves first time we start a download. So we can
00772 // be pretty sure we know the hashset of the file we'r sharing at this point.
00773 void Client::onPacket(const ED2KPacket::ReqHashSet &p) {
00774         logTrace(TRACE_CLIENT,
00775                 boost::format("[%s] Received ReqHashSet for %s")
00776                 % getIpPort() % p.getHash().decode()
00777         );
00778 
00779         MetaData *md = MetaDb::instance().find(p.getHash());
00780         if (md == 0) {
00781                 return; // ignored
00782         }
00783         HashSetBase *hs = 0;
00784         for (uint32_t i = 0; i < md->getHashSetCount(); ++i) {
00785                 hs = md->getHashSet(i);
00786                 if (hs->getFileHashTypeId() == CGComm::OP_HT_ED2K) {
00787                         break;
00788                 }
00789         }
00790         if (hs == 0) {
00791                 return; // ignored
00792         }
00793         ED2KHashSet *ehs = dynamic_cast<ED2KHashSet*>(hs);
00794         if (!ehs) {
00795                 logDebug("Internal type error upcasting HashSetBase.");
00796                 return;
00797         }
00798         CHECK_THROW(m_socket);
00799         *m_socket << ED2KPacket::HashSet(ehs);
00800 }
00801 
00802 // Actual uploading
00803 // ----------------
00804 // Well, this is fun. We wait for chunk requests, once those arrive, we send
00805 // those chunks, and so on and so forth, until we run out of chunks. But in
00806 // reality, they never stop sending chunk requests, so at some point we'll have
00807 // to pull the plug. When exactly we do it is up to us - I guess we'll just
00808 // treat all the same and kick 'em after few MB's or so.
00809 
00810 // Initialize upload sequence. This is done by sending AcceptUploadReq packet
00811 // to the remote client. If we already have requested chunks list at this point,
00812 // we can start sending data right away. However, some clients seem request
00813 // chunks only AFTER receiving AcceptUploadReq packet, so in that case, the
00814 // data sending is delayed until we receive the chunk request.
00815 void Client::startUpload() {
00816         if (!m_uploadInfo) {
00817                 m_uploadInfo.reset(new Detail::UploadInfo(this, m_queueInfo));
00818         }
00819         if (m_queueInfo) {
00820                 m_queueInfo.reset();
00821         }
00822         if (isConnected()) {
00823                 logTrace(TRACE_CLIENT,
00824                         boost::format("[%s] Starting upload.") % getIpPort()
00825                 );
00826                 *m_socket << ED2KPacket::AcceptUploadReq();
00827                 if (m_uploadInfo->getReqChunkCount()) {
00828                         sendNextChunk();
00829                 } else {
00830                         logTrace(TRACE_CLIENT, boost::format(
00831                                 "[%s] Waiting for chunk requests."
00832                         ) % getIpPort());
00833                 }
00834         } else try {
00835                 establishConnection();
00836         } catch (std::exception &e) {
00837                 logTrace(TRACE_DEADSRC,
00838                         boost::format("[%s] Unable to connect to client: %s")
00839                         % getIpPort() % e.what()
00840                 );
00841                 destroy();
00842         }
00843 }
00844 
00845 // You are #X on my queue. Please stay calm and wait your turn, it'll come
00846 // (eventually anyway).
00847 void Client::sendQR() {
00848         CHECK_THROW(isConnected());
00849         CHECK_THROW(m_queueInfo);
00850         CHECK_THROW(m_queueInfo->getQR());
00851         CHECK_THROW(!m_uploadInfo);
00852         logTrace(TRACE_CLIENT,
00853                 boost::format("[%s] Sending QueueRanking %d.")
00854                 % getIpPort() % m_queueInfo->getQR()
00855         );
00856         if (isMule()) {
00857                 *m_socket << ED2KPacket::MuleQueueRank(m_queueInfo->getQR());
00858         } else {
00859                 *m_socket << ED2KPacket::QueueRanking(m_queueInfo->getQR());
00860         }
00861         m_upReqInProgress = false;
00862         if (
00863                 !m_dnReqInProgress && !m_downloadInfo && !m_uploadInfo
00864                 && m_socket && !m_parser->hasBuffered()
00865         ) {
00866                 logTrace(TRACE_CLIENT,
00867                         boost::format("[%s] Early disconnect") % getIpPort()
00868                 );
00869                 m_socket->disconnect();
00870                 delete m_socket;
00871                 m_socket = 0;
00872         }
00873 }
00874 
00875 // More work? work work.
00876 void Client::onPacket(const ED2KPacket::ReqChunks &p) {
00877         CHECK_THROW(m_uploadInfo);
00878         CHECK_THROW(isConnected());
00879         for (uint8_t i = 0; i < p.getReqChunkCount(); ++i) {
00880                 m_uploadInfo->addReqChunk(p.getReqChunk(i));
00881         }
00882         sendNextChunk();
00883 }
00884 
00885 // Send next requested chunk to client.
00886 //
00887 // We send data in 10k chunks, starting from lowest requested offset and moving
00888 // our way up. The requested chunks in RangeList do not have merging policy,
00889 // because existing ed2k clients check reqchunk completition based on the end
00890 // offset value matching the requested chunks offset (even if the next requested
00891 // chunk directly follows the previous one). As such, we must compensate it by
00892 // sending partial (<10kb) chunk during those overlapping places. This naturally
00893 // results in certain logic errors here, since if RangeList logic doesn't allow
00894 // merging, but we still need to erase those 10k chunks from the RangeList, we
00895 // will have to perform it manually outside RangeList engine. This needs to be
00896 // done until the other ed2k clients become smarter (which most likely isn't
00897 // going to happen), so there.
00898 void Client::sendNextChunk() try {
00899         CHECK_THROW(m_uploadInfo);
00900         CHECK_THROW(!m_queueInfo);
00901         CHECK_THROW(isConnected());
00902 
00903         if (!m_uploadInfo->getReqChunkCount()) {
00904                 if (!m_uploadInfo->getSent()) {
00905                         return;
00906                 }
00907                 logTrace(TRACE_CLIENT,
00908                         boost::format("[%s] No more reqchunks.")
00909                         % getIpPort()
00910                 );
00911                 m_uploadInfo.reset();
00912                 getEventTable().postEvent(this, EVT_CANCEL_UPLOADREQ);
00913                 m_queueInfo.reset();
00914                 if (!m_downloadInfo) {
00915                         m_socket->disconnect();
00916                         delete m_socket;
00917                         m_socket = 0;
00918                 }
00919                 if (!m_sourceInfo) {
00920                         logTrace(TRACE_DEADSRC, boost::format(
00921                                 "[%s] Destroying client: No more requested "
00922                                 "chunks for uploading, and no source "
00923                                 "information.") % getIpPort()
00924                         );
00925                         destroy();
00926                 }
00927                 return;
00928         }
00929 
00930         if (!m_credits && m_pubKey) {
00931                 m_credits = CreditsDb::instance().create(m_pubKey, m_hash);
00932         }
00933 
00934         logTrace(TRACE_CLIENT,
00935                 boost::format(
00936                         COL_SEND "[%s] Uploading file %s%s, total sent %s"
00937                         COL_NONE
00938                 ) % getIpPort() % m_uploadInfo->getReqFile()->getName()
00939                 % (m_uploadInfo->isCompressed()
00940                         ? COL_COMP " (compressed)" COL_SEND
00941                         : ""
00942                 ) % Utils::bytesToString(m_uploadInfo->getSent())
00943         );
00944 
00945         if (!m_uploadInfo->hasBuffered()) {
00946                 m_uploadInfo->bufferData();
00947                 if (getComprVer()) {
00948                         m_uploadInfo->compress();
00949                 }
00950         }
00951         boost::tuple<uint32_t, uint32_t, std::string> nextChunk;
00952         nextChunk = m_uploadInfo->getNext(10240);
00953 
00954         if (getComprVer() && m_uploadInfo->isCompressed()) {
00955                 *m_socket << ED2KPacket::PackedChunk(
00956                         m_uploadInfo->getReqHash(), nextChunk.get<0>(),
00957                         nextChunk.get<1>(), nextChunk.get<2>()
00958                 );
00959         } else {
00960                 *m_socket << ED2KPacket::DataChunk(
00961                         m_uploadInfo->getReqHash(), nextChunk.get<0>(),
00962                         nextChunk.get<1>(), nextChunk.get<2>()
00963                 );
00964         }
00965 
00966         if (m_credits) {
00967                 m_credits->addUploaded(nextChunk.get<2>().size());
00968         }
00969 } catch (std::exception &e) {
00970         logDebug(
00971                 boost::format("[%s] Sending next chunk to ed2kclient: %s")
00972                 % getIpPort() % e.what()
00973         );
00974         CHECK_THROW(m_uploadInfo); // just in case
00975         m_queueInfo.reset(new Detail::QueueInfo(this, m_uploadInfo));
00976         m_queueInfo->m_lastQueueReask = Utils::getTick();
00977         m_uploadInfo.reset();
00978         getEventTable().postEvent(this, EVT_UPLOADREQ);
00979 
00980 }
00981 MSVC_ONLY(;)
00982 
00983 // No more? No less. Was a bad file anyway.
00984 void Client::onPacket(const ED2KPacket::CancelTransfer &) {
00985         logTrace(TRACE_CLIENT,
00986                 boost::format("[%s] Received CancelTransfer.") % getIpPort()
00987         );
00988         m_uploadInfo.reset();
00989         m_queueInfo.reset();
00990         if (!m_sourceInfo) {
00991                 logTrace(TRACE_DEADSRC, boost::format(
00992                         "[%s] Destroying client: Received CancelTransfer, and "
00993                         "no sourceinfo is available.") % getIpPort()
00994                 );
00995                 destroy();
00996         } else {
00997                 getEventTable().postEvent(this, EVT_CANCEL_UPLOADREQ);
00998         }
00999 }
01000 
01001 // Downloading
01002 // -----------
01003 // Enough of serving others. Time to get something for ourselves too, right?
01004 // Let's get started right away. Let's see what can they tell us.
01005 
01006 // Oh? A filename? Riiight, very useful. Stuff it somewhere and get over it.
01007 void Client::onPacket(const ED2KPacket::FileName &p) {
01008         logTrace(TRACE_CLIENT,
01009                 boost::format("[%s] Received FileName for hash %s: %s.")
01010                 % getIpPort() % p.getHash().decode() % p.getName()
01011         );
01012 
01013         // this quickly gets out of hand, namely, in metadb.cpp:370 loop
01014         // in the end, we do NOT need ALL the damn filenames we get from
01015         // the network, so - disabling this for now.
01016         // also - this eventually causes some integer overflow somewhere around
01017         // metadata input/output routines, which in turn corrupts metadata
01018         // and partdata reloading. do NOT enable this before verifying that
01019         // that overflow has been fixed.
01020 //      MetaData *md = MetaDb::instance().find(p.getHash());
01021 //      if (md) {
01022 //              md->addFileName(p.getName());
01023 //      }
01024         if (!m_sourceInfo) {
01025                 Download *d = DownloadList::instance().find(p.getHash());
01026                 if (d) {
01027                         addOffered(d, false);
01028                 }
01029         }
01030         if (!m_sourceInfo) {
01031                 // happens when addOffered() discovers we don't need the file
01032                 // from the client afterall. Just ignore it then.
01033                 return;
01034         }
01035         CHECK_THROW(isConnected());
01036         CHECK_THROW(m_sourceInfo);
01037 
01038         *m_socket << ED2KPacket::SetReqFileId(
01039                 m_sourceInfo->getReqFile()->getHash()
01040         );
01041 
01042         Download *d = m_sourceInfo->getReqFile();
01043         if (d->isSourceReqAllowed(this)) {
01044                 *m_socket << ED2KPacket::SourceExchReq(d->getHash());
01045                 d->setLastSrcExch(Utils::getTick());
01046 
01047                 logTrace(TRACE_SRCEXCH, boost::format(
01048                         "[%s] SourceExchange: Requesting sources for file %s."
01049                 ) % getIpPort() % d->getHash().decode());
01050         }
01051 }
01052 
01053 // Description of the file ... well, actually, a comment. Rather useless, if
01054 // you ask me, but well - some like them.
01055 void Client::onPacket(const ED2KPacket::FileDesc &p) {
01056         CHECK_THROW(m_sourceInfo);
01057         CHECK_THROW(m_sourceInfo->getReqFile());
01058 
01059         boost::format fmt(
01060                 "Received comment for file %s:\nRating: %s Comment: %s"
01061         );
01062         fmt %m_sourceInfo->getReqFile()->getPartData()->getDestination().leaf();
01063         fmt % ED2KFile::ratingToString(p.getRating());
01064         fmt % p.getComment();
01065 
01066         logMsg(fmt);
01067 }
01068 
01069 // Status of the file ... now we'r getting somewhere. Among other useful things,
01070 // this contains which chunks of the file the sender has. Niice. This is useful,
01071 // keep it around somewhere, since we might want to x-ref it with our own chunk
01072 // lists to generate nice chunk requests.
01073 //
01074 // Now we can indicate that we are really really sure we really want the file
01075 // we'v been trying to request so far, so tell it to it -> startuploadreq.
01076 // As a sidenote though, we might want to know more of the file than we already
01077 // know, e.g. part hashes, so locate the corresponding hashset from metadb, and
01078 // request a hashset if we need one.
01079 //
01080 // Note that if the source does not have any needed parts for us (checked via
01081 // m_sourceInfo->hasNeededParts() method), we keep the source alive for now -
01082 // it might become useful at some later time.
01083 void Client::onPacket(const ED2KPacket::FileStatus &p) {
01084         logTrace(TRACE_CLIENT,
01085                 boost::format("[%s] Received FileStatus.") % getIpPort()
01086         );
01087         CHECK_THROW(isConnected());
01088 
01089         if (!m_sourceInfo) {
01090                 Download *d = DownloadList::instance().find(p.getHash());
01091                 if (d) {
01092                         addOffered(d);
01093                 }
01094         }
01095 
01096         if (!m_sourceInfo) {
01097                 // happens when addOffered() discovers we don't need the file
01098                 // from the client afterall. Just ignore it then.
01099                 return;
01100         }
01101 
01102         m_sourceInfo->setPartMap(p.getPartMap());
01103 
01104         // only send StartUploadReq if we don't have downloadinfo yet
01105         if (m_sourceInfo->hasNeededParts() && !m_downloadInfo) {
01106                 logTrace(TRACE_CLIENT,
01107                         boost::format("[%s] Sending StartUploadReq")
01108                         % getIpPort()
01109                 );
01110                 ED2KPacket::StartUploadReq p(
01111                         m_sourceInfo->getReqFile()->getHash()
01112                 );
01113                 *m_socket << p;
01114 
01115                 m_lastReaskTime = Utils::getTick();
01116                 getEventTable().postEvent(
01117                         this, EVT_REASKFILEPING, SOURCE_REASKTIME
01118                 );
01119         } else if (!m_sourceInfo->hasNeededParts()) {
01120                 logTrace(TRACE_CLIENT,
01121                         boost::format("[%s] Client has no needed parts.")
01122                         % getIpPort()
01123                 );
01124         }
01125 
01126         if (m_sourceInfo->getReqFile()->getSize() <= ED2K_PARTSIZE) {
01127                 return; // don't need hashset
01128         }
01129 
01130         MetaData *md = m_sourceInfo->getReqFile()->getPartData()->getMetaData();
01131         for (uint32_t i = 0; i < md->getHashSetCount(); ++i) {
01132                 HashSetBase *hs = md->getHashSet(i);
01133                 if (hs->getFileHashTypeId() != CGComm::OP_HT_ED2K) {
01134                         continue;
01135                 }
01136                 if (!hs->getChunkCnt()) {
01137                         *m_socket << ED2KPacket::ReqHashSet(
01138                                 m_sourceInfo->getReqFile()->getHash()
01139                         );
01140                 }
01141         }
01142 }
01143 
01144 // Oh? But ... but you said you had the file ? What did you do it ? Did you
01145 // delete it already? But why? Was it a bad file? ....
01146 // So many questions.... so little time.
01147 void Client::onPacket(const ED2KPacket::NoFile &p) {
01148         logTrace(TRACE_CLIENT,
01149                 boost::format("[%s] Received NoFile.") % getIpPort()
01150         );
01151         if (!m_sourceInfo) {
01152                 logTrace(TRACE_CLIENT,
01153                         boost::format("[%s] Got NoFile, but no sourceinfo?")
01154                         % getIpPort()
01155                 );
01156                 return;
01157         }
01158         Download *d = DownloadList::instance().find(p.getHash());
01159         if (d && m_sourceInfo->offers(d)) {
01160                 remOffered(d);
01161         }
01162 }
01163 
01164 // This could be useful... any cool info is always welcome. So here ... hashes?
01165 // hum, let's update MetaDb then, if we received this, we probably needed them.
01166 void Client::onPacket(const ED2KPacket::HashSet &p) {
01167         logTrace(TRACE_CLIENT,
01168                 boost::format("[%s] Received HashSet for %s")
01169                 % getIpPort() % p.getHashSet()->getFileHash().decode()
01170         );
01171 
01172         verifyHashSet(p.getHashSet());
01173 
01174         MetaData *md = MetaDb::instance().find(p.getHashSet()->getFileHash());
01175         if (!md) {
01176                 logTrace(TRACE_CLIENT,
01177                         boost::format(
01178                                 "[%s] Received HashSet, but for what file?"
01179                         ) % getIpPort()
01180                 );
01181                 return;
01182         }
01183         HashSetBase *hs = 0;
01184         for (uint32_t i = 0; i < md->getHashSetCount(); ++i) {
01185                 if (md->getHashSet(i)->getFileHashTypeId()!=CGComm::OP_HT_ED2K){
01186                         continue;
01187                 }
01188                 hs = md->getHashSet(i);
01189                 break;
01190         }
01191         if (!hs) {
01192                 logTrace(TRACE_CLIENT,
01193                         boost::format(
01194                                 "[%s] Received HashSet, but for what file?"
01195                         ) % getIpPort()
01196                 );
01197                 return;
01198         }
01199         ED2KHashSet *ehs = dynamic_cast<ED2KHashSet*>(hs);
01200         CHECK_THROW(ehs);
01201         CHECK_THROW(ehs->getFileHash() == p.getHashSet()->getFileHash());
01202 
01203         if (ehs->getChunkCnt()) {
01204                 return; // no chunk hashes needed
01205         }
01206         for (uint32_t i = 0; i < p.getHashSet()->getChunkCnt(); ++i) {
01207                 ehs->addChunkHash((*p.getHashSet())[i].getData());
01208         }
01209         if (m_sourceInfo && m_sourceInfo->getReqFile()) {
01210                 m_sourceInfo->getReqFile()->getPartData()->addHashSet(ehs);
01211         }
01212 }
01213 
01214 // verify the contents of passed hashset
01215 void Client::verifyHashSet(boost::shared_ptr<ED2KHashSet> hs) {
01216         ED2KHashMaker maker;
01217         for (uint32_t i = 0; i < hs->getChunkCnt(); ++i) {
01218                 maker.sumUp((*hs)[i].getData().get(), 16);
01219         }
01220         boost::scoped_ptr<HashSetBase> ret(maker.getHashSet());
01221 
01222         if (ret->getFileHash() != hs->getFileHash()) {
01223                 throw std::runtime_error("Client sent invalid hashset!");
01224         }
01225 }
01226 
01227 // note: don't disconnect the client here, since he might want smth from us
01228 // too. While this does impose up to 30-sec longer delay in keeping sockets
01229 // open, if we disconnect here, we ruin remote client's attempt to request
01230 // stuff from us.
01231 void Client::setOnQueue(uint32_t qr) {
01232         CHECK_THROW(m_sourceInfo);
01233         CHECK_THROW(m_sourceInfo->getReqFile());
01234 
01235         logTrace(TRACE_CLIENT,
01236                 boost::format(
01237                         COL_GREEN "[%s] Queued on position" COL_COMP " %d "
01238                         COL_GREEN "for file %s" COL_NONE
01239                 ) % getIpPort() % qr
01240                 % m_sourceInfo->getReqFile()->
01241                         getPartData()->getDestination().leaf()
01242         );
01243 
01244         m_sourceInfo->setQR(qr);
01245 
01246         m_dnReqInProgress = false;
01247         if (
01248                 !m_upReqInProgress && !m_uploadInfo && !m_downloadInfo
01249                 && m_socket && !m_parser->hasBuffered()
01250         ) {
01251                 logTrace(TRACE_CLIENT,
01252                         boost::format("[%s] Early disconnect") % getIpPort()
01253                 );
01254                 m_socket->disconnect();
01255                 delete m_socket;
01256                 m_socket = 0;
01257         }
01258 }
01259 
01260 void Client::onPacket(const ED2KPacket::QueueRanking &p) {
01261         setOnQueue(p.getQR());
01262 }
01263 
01264 void Client::onPacket(const ED2KPacket::MuleQueueRank &p) {
01265         setOnQueue(p.getQR());
01266 }
01267 
01268 void Client::reqDownload() {
01269         CHECK_THROW(m_sourceInfo);
01270         CHECK_THROW(isConnected());
01271         // don't reask more often than allowed
01272         if (m_lastReaskTime + SOURCE_REASKTIME > Utils::getTick()) {
01273                 return;
01274         }
01275 
01276         logTrace(TRACE_CLIENT,
01277                 boost::format("[%s] Requesting download.") % getIpPort()
01278         );
01279         Download *d = m_sourceInfo->getReqFile();
01280         *m_socket << ED2KPacket::ReqFile(d->getHash(), d->getPartData());
01281 
01282         // reset it here, to avoid requesting multiple times in row.
01283         // Note that we shouldn't emit REASKFILEPING event here - that's done
01284         // after sending StartUploadReq
01285         m_lastReaskTime = Utils::getTick();
01286 
01287         m_dnReqInProgress = true;
01288 }
01289 
01290 // Ok, now we'r really getting somewhere - seems we can start downloading now.
01291 // Send out chunk requests and start waiting for data.
01292 // We may already have m_downloadInfo alive at this point if we were already
01293 // downloading from this client, and it simply re-sent us AcceptUploadReq
01294 // again for some reason (mules seem to do it after every 9500kb part.
01295 //
01296 // It's also possible that we were called back, and the sending client sent
01297 // Hello + Accept in straight row (mules do it), in which case we get here
01298 // before we have handled id-change properly (parsing is done via direct
01299 // calls, events go through main event loop, thus slower). In that case, just
01300 // don't do anything here - after merging (or whatever happens on idchange),
01301 // we'll start dloading anyway.
01302 void Client::onPacket(const ED2KPacket::AcceptUploadReq &) try {
01303         logTrace(TRACE_CLIENT,
01304                 boost::format("[%s] Received AcceptUploadReq.") % getIpPort()
01305         );
01306         if (m_sourceInfo && m_sourceInfo->getPartMap()) {
01307                 if (!m_downloadInfo) {
01308                         PartData *pd =m_sourceInfo->getReqFile()->getPartData();
01309                         m_downloadInfo.reset(
01310                                 new Detail::DownloadInfo(
01311                                         this, pd, m_sourceInfo->getPartMap()
01312                                 )
01313                         );
01314                 sendChunkReqs();
01315                 }
01316         } else {
01317                 logTrace(TRACE_CLIENT,
01318                         boost::format(
01319                                 "[%s] Client accepted download request, "
01320                                 "but what shall we download?"
01321                         ) % getIpPort()
01322                 );
01323         }
01324 } catch (std::exception &e) {
01325         logDebug(
01326                 boost::format("[%s] Starting download: %s")
01327                 % getIpPort() % e.what()
01328         );
01329         m_downloadInfo.reset();
01330 }
01331 
01332 // Little helper method - we send chunk requests from several locations, so
01333 // localize this in this helper function.
01334 // If onlyNew is set true, we only send the back-most chunk request in the list.
01335 // While mules and edonkeys request chunk in a rotational way, (e.g.
01336 // [c1, c2, c3], [c2, c3, c4], [c3, c4, c5], it seems even they get confused
01337 // sometimes with this thing, and start sending chunks twice. Or it could be
01338 // we fail to do it exactly the way they expect it. Whatever the reason, it
01339 // seems way too error-prone and un-neccesery, so we'r just going to fall back
01340 // to requesting exactly the chunks we need, nothing more.
01341 void Client::sendChunkReqs(bool onlyNew) try {
01342         using ED2KPacket::ReqChunks;
01343         typedef std::list<Range32>::iterator Iter;
01344 
01345         CHECK_THROW(isConnected());
01346         CHECK_THROW(m_downloadInfo);
01347 
01348         std::list<Range32> creqs = m_downloadInfo->getChunkReqs();
01349 
01350         if (creqs.size()) {
01351                 if (onlyNew) {
01352                         while (creqs.size() > 1) {
01353                                 creqs.pop_front();
01354                         }
01355                 }
01356 
01357                 for (Iter i = creqs.begin(); i != creqs.end(); ++i) {
01358                         boost::format fmt("[%s] Requesting chunk %d..%d");
01359                         fmt % getIpPort();
01360                         logTrace(TRACE_CLIENT, fmt % (*i).begin() % (*i).end());
01361                 }
01362 
01363                 *m_socket << ReqChunks(
01364                         m_sourceInfo->getReqFile()->getHash(), creqs
01365                 );
01366         }
01367 } catch (std::exception &e) {
01368         // Something went wrong internally... might be we failed to aquire more
01369         // locks in partdata, might be partdata was completed ... whatever the
01370         // reason, it's internal, and we might have previously requested chunks
01371         // that are still being downloaded, so don't self-destruct here just
01372         // yet. If PartData was completed, we get notified of it and will handle
01373         // it appropriately then. If we did fail to generate more locks, sooner
01374         // or later, the remote client will disconnect us, after it has sent
01375         // us everything we requested, and we'll handle it there. So don't do
01376         // anything here.
01377         logTrace(TRACE_CLIENT,
01378                 boost::format("[%s] Exception while sending chunk reqests: %s")
01379                 % getIpPort() % e.what()
01380         );
01381 }
01382 
01383 MSVC_ONLY(;)
01384 
01385 // Receiving data. If downloadInfo->write() returns true, it means we completed
01386 // a chunk, and need to send more chunk requests.
01387 void Client::onPacket(const ED2KPacket::DataChunk &p) {
01388         CHECK_THROW(m_downloadInfo);
01389         CHECK_THROW(isConnected());
01390 
01391         logTrace(TRACE_CLIENT,
01392                 boost::format(
01393                         COL_RECV "[%s] Received %d bytes data for `%s'"COL_NONE
01394                 ) % getIpPort() % p.getData().size()
01395                 % m_downloadInfo->getReqPD()->getDestination().leaf()
01396         );
01397 
01398         Range32 r(p.getBegin(), p.getEnd() - 1);
01399         bool ret = m_downloadInfo->write(r, p.getData());
01400 
01401         if (!m_credits && m_pubKey) {
01402                 m_credits = CreditsDb::instance().create(m_pubKey, m_hash);
01403         }
01404         if (m_credits) {
01405                 m_credits->addDownloaded(p.getData().size());
01406         }
01407 
01408         if (ret) {
01409                 sendChunkReqs(true);
01410         }
01411 }
01412 
01413 // Packed data - handled slightly differently from normal data.
01414 void Client::onPacket(const ED2KPacket::PackedChunk &p) {
01415         CHECK_THROW(m_downloadInfo);
01416         CHECK_THROW(isConnected());
01417         logTrace(TRACE_CLIENT,
01418                 boost::format(
01419                         COL_RECV "[%s] Received %d bytes data for `%s' "
01420                         COL_BYELLOW "(compressed)" COL_NONE
01421                 ) % getIpPort() % p.getData().size()
01422                 % m_downloadInfo->getReqPD()->getDestination().leaf()
01423         );
01424 
01425         bool ret = m_downloadInfo->writePacked(
01426                 p.getBegin(), p.getSize(),p.getData()
01427         );
01428 
01429         if (!m_credits && m_pubKey) {
01430                 m_credits = CreditsDb::instance().create(m_pubKey, m_hash);
01431         }
01432         if (m_credits) {
01433                 m_credits->addDownloaded(p.getData().size());
01434         }
01435 
01436         if (ret) {
01437                 sendChunkReqs(true);
01438         }
01439 }
01440 
01441 void Client::onPacket(const ED2KPacket::SourceExchReq &p) {
01442         CHECK_THROW(m_socket);
01443 
01444         Download *d = 0;
01445         if (m_sourceInfo) {
01446                 if (m_sourceInfo->getReqFile()->getHash() == p.getHash()) {
01447                         d = m_sourceInfo->getReqFile();
01448                 }
01449         } else {
01450                 d = DownloadList::instance().find(p.getHash());
01451         }
01452 
01453         if (d && d->getSourceCount() > 0 && d->getSourceCount() < 50) {
01454                 ED2KPacket::AnswerSources packet(p.getHash(), d->getSources());
01455                 packet.setSwapIds(getSrcExchVer() >= 3);
01456                 *m_socket << packet;
01457 
01458                 logTrace(TRACE_SRCEXCH,
01459                         boost::format(
01460                                 "[%s] SourceExchange: Sending %d sources for "
01461                                 "hash %s"
01462                         ) % getIpPort() % packet.size() % p.getHash().decode()
01463                 );
01464         }
01465 }
01466 
01467 void Client::onPacket(const ED2KPacket::AnswerSources &p) try {
01468         uint32_t cnt = 0;
01469         bool swapIds = getSrcExchVer() >= 3;
01470         ED2KPacket::AnswerSources::CIter it = p.begin();
01471         while (it != p.end()) {
01472                 IPV4Address src((*it).get<0>(), (*it).get<1>());
01473                 IPV4Address srv((*it).get<2>(), (*it).get<3>());
01474                 if (swapIds) {
01475                         src.setAddr(SWAP32_ON_LE(src.getAddr()));
01476                 }
01477                 if (src) {
01478                         cnt += Detail::foundSource(p.getHash(), src, srv, true);
01479                 }
01480                 if (srv) {
01481                         Detail::foundServer(srv);
01482                 }
01483                 ++it;
01484         }
01485 
01486         logTrace(TRACE_SRCEXCH,
01487                 boost::format(
01488                         "[%s] SourceExchange: Received %d sources for hash "
01489                         "%s (and %d duplicates)"
01490                 ) % getIpPort() % cnt % p.getHash().decode() % (p.size() - cnt)
01491         );
01492 } catch (std::exception &e) {
01493         logTrace(TRACE_SRCEXCH,
01494                 boost::format("[%s] SourceExchange error: %s")
01495                 % getIpPort() % e.what()
01496         );
01497 }
01498 
01499 void Client::onPacket(const ED2KPacket::ChangeId &p) {
01500         boost::format fmt("[%s] ChangeId: %d -> %d");
01501         fmt % getIpPort();
01502         if (::isHighId(p.getOldId())) {
01503                 fmt % Socket::getAddr(p.getOldId());
01504         } else {
01505                 fmt % p.getOldId();
01506         }
01507         if (::isHighId(p.getNewId())) {
01508                 fmt % Socket::getAddr(p.getNewId());
01509         } else {
01510                 fmt % p.getNewId();
01511         }
01512         logTrace(TRACE_CLIENT, fmt);
01513         Detail::changeId(this, p.getNewId());
01514 }
01515 
01516 void Client::onPacket(const ED2KPacket::Message &p) {
01517         logMsg(
01518                 boost::format("Received message from %s: %s")
01519                 % getIpPort() % p.getMsg()
01520         );
01521 }
01522 
01523 void Client::onPacket(const ED2KPacket::SecIdentState &p) {
01524         using namespace ED2KPacket;
01525         boost::format fmt(
01526                 "[%s] Received SecIdentState %s (ch=%d)"
01527         );
01528         fmt % getIpPort();
01529         if (p.getState() == SI_SIGNEEDED) {
01530                 logTrace(TRACE_SECIDENT, fmt % "NeedSign" % p.getChallenge());
01531         } else if (p.getState() == SI_KEYANDSIGNEEDED) {
01532                 logTrace(TRACE_SECIDENT, fmt%"NeedKeyAndSign"%p.getChallenge());
01533         } else {
01534                 logTrace(TRACE_SECIDENT, fmt % "Unknown" % p.getChallenge());
01535         }
01536 
01537         m_reqChallenge = p.getChallenge();
01538 
01539         if (!m_pubKey && !m_sentChallenge) {
01540                 verifyIdent();
01541         }
01542         if (p.getState() == SI_KEYANDSIGNEEDED) {
01543                 sendPublicKey();
01544         }
01545         if (m_pubKey) {
01546                 sendSignature();
01547         }
01548 }
01549 
01550 void Client::onPacket(const ED2KPacket::PublicKey &p) {
01551         logTrace(TRACE_SECIDENT,
01552                 boost::format("[%s] Received PublicKey.") %getIpPort()
01553         );
01554         if (m_pubKey && m_pubKey != p.getKey()) {
01555                 logDebug(
01556                         boost::format(
01557                                 "[%s] Client sent DIFFERENT public "
01558                                 "keys! Someone is doing something bad."
01559                         ) % getIpPort()
01560                 );
01561                 m_pubKey.clear();
01562                 m_credits = 0;  // no credits anymore
01563         } else {
01564                 m_pubKey = p.getKey();
01565                 if (m_reqChallenge) {
01566                         sendSignature();
01567                 }
01568         }
01569 }
01570 
01571 void Client::onPacket(const ED2KPacket::Signature &p) {
01572         CHECK_RET(m_pubKey);
01573         CHECK_RET(m_sentChallenge);
01574 
01575         boost::format fmt(
01576                 "[%s] Received Signature (iType=%s) (ch=%d)"
01577         );
01578         fmt % getIpPort();
01579         if (p.getIpType() == IP_REMOTE) {
01580                 fmt % "Remote";
01581         } else if (p.getIpType() == IP_LOCAL) {
01582                 fmt % "Local";
01583         } else {
01584                 fmt % "Null";
01585         }
01586         logTrace(TRACE_SECIDENT, fmt % m_sentChallenge);
01587 
01588         IpType iType = 0;
01589         uint32_t id = 0;
01590         if (getSecIdentVer() > 1 && p.getIpType()) {
01591                 iType = p.getIpType();
01592                 if (iType == IP_LOCAL || isLowId()) {
01593                         id = ED2K::instance().getId();
01594                 } else if (iType == IP_REMOTE && isHighId()) {
01595                         id = m_socket->getPeer().getIp();
01596                 }
01597         }
01598 
01599         bool ret = false;
01600         try {
01601                 ret = CreditsDb::verifySignature(
01602                         m_pubKey, m_sentChallenge, p.getSign(), iType, id
01603                 );
01604         } catch (std::exception &e) {
01605                 logTrace(TRACE_CLIENT,
01606                         boost::format("[%s] Error verifying signature: %s")
01607                         % getIpPort() % e.what()
01608                 );
01609         }
01610 
01611         if (ret) {
01612                 logTrace(TRACE_SECIDENT,
01613                         boost::format("[%s] Ident succeeded.")
01614                         % getIpPort()
01615                 );
01616                 if (!m_credits) {
01617                         m_credits = CreditsDb::instance().find(m_pubKey);
01618                 }
01619                 if (m_credits) {
01620                         CHECK_THROW(m_pubKey == m_credits->getPubKey());
01621                         // save some ram - avoid storing PubKey twice
01622                         // (it has refcounted implementation)
01623                         m_pubKey = m_credits->getPubKey();
01624                         logTrace(TRACE_SECIDENT,
01625                                 boost::format(
01626                                         "[%s] Found credits: %s up, %s down"
01627                                 ) % getIpPort() % Utils::bytesToString(
01628                                         m_credits->getUploaded()
01629                                 ) % Utils::bytesToString(
01630                                         m_credits->getDownloaded()
01631                                 )
01632                         );
01633                 }
01634                 try {
01635                         initTransfer();
01636                 } catch (std::exception &e) {
01637                         logDebug(
01638                                 boost::format(
01639                                         "[%s] Failed to initTransfer(): %s"
01640                                 ) % getIpPort() % e.what()
01641                         );
01642                         destroy(); // what else can we do here ?
01643                 }
01644         } else {
01645                 logTrace(TRACE_SECIDENT,
01646                         boost::format("[%s] Ident failed!")
01647                         % getIpPort()
01648                 );
01649                 m_credits = 0;
01650         }
01651         m_sentChallenge = 0;
01652 }
01653 
01654 void Client::sendPublicKey() {
01655         CHECK_THROW(isConnected());
01656 
01657         *m_socket<< ED2KPacket::PublicKey(CreditsDb::instance().getPublicKey());
01658 }
01659 
01660 void Client::sendSignature() {
01661         CHECK_THROW(m_pubKey); // need client's public key to send signature!
01662         CHECK_THROW(m_reqChallenge); // challenge this sig responds to
01663         CHECK_THROW(isConnected());
01664 
01665         logTrace(TRACE_SECIDENT,
01666                 boost::format("[%s] Sending Signature (ch=%d)")
01667                 % getIpPort() % m_reqChallenge
01668         );
01669 
01670         IpType iType = 0;
01671         uint32_t ip = 0;
01672         if (getSecIdentVer() > 1) {
01673                 if (::isLowId(ED2K::instance().getId())) {
01674                         iType = IP_REMOTE;
01675                         ip = getId();
01676                 } else {
01677                         iType = IP_LOCAL;
01678                         ip  = ED2K::instance().getId();
01679                 }
01680         }
01681 
01682         std::string sign(
01683                 CreditsDb::createSignature(m_pubKey, m_reqChallenge, iType, ip)
01684         );
01685 
01686         ED2KPacket::Signature packet(sign, iType);
01687         *m_socket << packet;
01688         m_reqChallenge = 0;
01689 }
01690 
01691 void Client::verifyIdent() {
01692         if (!getSecIdentVer() || m_sentChallenge) {
01693                 return;
01694         }
01695         CHECK_THROW(isConnected());
01696         boost::format fmt("[%s] Requesting %s");
01697 
01698         SecIdentState state(SI_SIGNEEDED);
01699         if (!m_pubKey) {
01700                 state = SI_KEYANDSIGNEEDED;
01701                 fmt % getIpPort() % "KeyAndSign";
01702         } else {
01703                 fmt % getIpPort() % "Sign";
01704         }
01705         logTrace(TRACE_SECIDENT, fmt);
01706 
01707         ED2KPacket::SecIdentState packet(state);
01708         m_sentChallenge = packet.getChallenge();
01709         *m_socket << packet;
01710 }
01711 
01712 void Client::handshakeCompleted() try {
01713         if (getSecIdentVer() && !m_sentChallenge) {
01714                 verifyIdent();
01715         } else {
01716                 initTransfer();
01717         }
01718 } catch (std::exception &e) {
01719         logDebug(
01720                 boost::format("[%s] Failed to initTransfer(): %s")
01721                 % getIpPort() % e.what()
01722         );
01723         destroy(); // what else can we do here ?
01724 }
01725 
01726 void Client::initTransfer() {
01727         if (m_uploadInfo) {
01728                 m_queueInfo.reset();
01729                 startUpload();
01730         }
01731         if (isConnected() && m_sourceInfo && !m_downloadInfo) {
01732                 reqDownload();
01733         }
01734 }
01735 
01736 // perform a reask for download
01737 void Client::reaskForDownload() {
01738         CHECK_THROW(m_sourceInfo);
01739         CHECK_THROW(!m_downloadInfo);
01740 
01741         if (m_lastReaskTime + SOURCE_REASKTIME > Utils::getTick()) {
01742                 logTrace(TRACE_CLIENT,
01743                         boost::format(
01744                                 "[%s] Reask time, we already did that %.2f "
01745                                 "seconds ago. Ignoring this reask."
01746                         ) % getIpPort()
01747                         % ((Utils::getTick() - m_lastReaskTime) / 1000)
01748                 );
01749                 return;
01750         }
01751 
01752         if (ED2K::instance().isLowId() && isLowId()) {
01753                 logTrace(TRACE_CLIENT,
01754                         boost::format("[%s] Cannot do LowID<->LowID reask!")
01755                         % getIpPort()
01756                 );
01757                 return;
01758         }
01759 
01760         // TCP reask if we'r not already connected, and remote client is lowid,
01761         // or doesn't have UDP capabilities.
01762         if (!isConnected() && (isLowId() || !getUdpPort())) {
01763                 // do tcp reask
01764                 logTrace(TRACE_CLIENT,
01765                         boost::format("[%s] TCP Reask in progress...")
01766                         % getIpPort()
01767                 );
01768                 establishConnection();
01769         } else if (getUdpPort() && isHighId()) try {
01770                 Download *d = m_sourceInfo->getReqFile();
01771                 const PartData *pd = d->getPartData();
01772                 Hash<ED2KHash> hash = d->getHash();
01773                 uint32_t srcCnt = d->getSourceCount();
01774                 const IPV4Address addr(getId(), getUdpPort());
01775 
01776                 ED2KPacket::ReaskFilePing packet(hash, pd, srcCnt, getUdpVer());
01777                 s_clientUdpSocket->send(packet, addr);
01778 
01779                 getEventTable().postEvent(this, EVT_REASKTIMEOUT, UDP_TIMEOUT);
01780                 m_reaskInProgress = true;
01781 
01782                 logTrace(TRACE_CLIENT,
01783                         boost::format("[%s] UDP Reask in progress...")
01784                         % getIpPort()
01785                 );
01786         } catch (SocketError &e) {
01787                 logDebug(
01788                         boost::format(
01789                                 "[%s] Fatal error performing UDP reask: %s"
01790                         ) % getIpPort() % e.what()
01791                 );
01792         }
01793 }
01794 
01795 // UDP file reasks handler
01796 //
01797 // If we do not have queueinfo when this packet is received, this indicates the
01798 // client isn't in our queue; this usually happens when we have just restarted,
01799 // and our queue has been lost, but clients come reasking. In that case, to be
01800 // fair to the remote clients, we passivly initiate the file upload request.
01801 //
01802 // However, we will send QR 0 in response in this function, because getting it
01803 // to send the right QR here means more breaking things apart, and keeping even
01804 // more state variables than we already have, so - sending QR0 to ppl for a
01805 // while after restart is acceptable loss, at least for now - internally we'r
01806 // still handling everything properly, so this only affects "visible" side on
01807 // the remote client anyway.
01808 void Client::onPacket(const ED2KPacket::ReaskFilePing &p) {
01809         // no queue-info - usually happens when we do a restart, and forget
01810         // our queue - add it to our queue by our normal queueing rules.
01811         if (!m_queueInfo) {
01812                 logTrace(TRACE_CLIENT,
01813                         boost::format(
01814                                 "[%s] UDP ReaskFilePing: Passivly initiating "
01815                                 "remote UploadReq."
01816                         ) % getIpPort()
01817                 );
01818                 onUploadReq(p.getHash());
01819                 Download *d = DownloadList::instance().find(p.getHash());
01820                 if (d) {
01821                         addOffered(d);
01822                 }
01823         }
01824 
01825         // can't send to LowId clients; or already uploading; or no queue info
01826         if (isLowId() || m_uploadInfo || !m_queueInfo) {
01827                 return;
01828         }
01829 
01830         logTrace(TRACE_CLIENT,
01831                 boost::format("[%s] Received ReaskFilePing.") % getIpPort()
01832         );
01833 
01834         IPV4Address addr(getId(), getUdpPort());
01835 
01836         if (p.getHash() != m_queueInfo->getReqHash()) {
01837                 SharedFile *sf = MetaDb::instance().findSharedFile(p.getHash());
01838                 if (sf) {
01839                         logTrace(TRACE_CLIENT,
01840                                 boost::format(
01841                                         "[%s] UDP SwapToAnotherFile performed."
01842                                 ) % getIpPort()
01843                         );
01844                         m_queueInfo->setReqFile(sf, p.getHash());
01845                 } else try {
01846                         logTrace(TRACE_CLIENT,
01847                                 boost::format(
01848                                         "[%s] UDP SwapToAnotherFile failed."
01849                                 ) % getIpPort()
01850                         );
01851                         ED2KPacket::FileNotFound packet;
01852                         s_clientUdpSocket->send(packet, addr);
01853                 } catch (SocketError &e) {
01854                         logDebug(boost::format(
01855                                 "[%s] Fatal error sending UDP packet: %s"
01856                         ) % getIpPort() % e.what());
01857                 }
01858         }
01859 
01860         const PartData *pd = m_queueInfo->getReqFile()->getPartData();
01861         uint16_t queueRank = m_queueInfo->getQR();
01862 
01863         try {
01864                 ED2KPacket::ReaskAck packet(pd, queueRank, getUdpVer());
01865                 s_clientUdpSocket->send(packet, addr);
01866 
01867                 logTrace(TRACE_CLIENT,
01868                         boost::format(
01869                                 "[%s] ReaskFilePing: Sending QueueRank %s"
01870                         ) % getIpPort() % queueRank
01871                 );
01872 
01873                 m_queueInfo->m_lastQueueReask = Utils::getTick();
01874         } catch (SocketError &e) {
01875                 logDebug(
01876                         boost::format(
01877                                 "[%s] Fatal error sending ReaskFilePing: %s"
01878                         ) % getIpPort() % e.what()
01879                 );
01880         }
01881 }
01882 
01883 void Client::onPacket(const ED2KPacket::ReaskAck &p) {
01884         CHECK_THROW(m_sourceInfo);
01885         m_reaskInProgress = false;
01886         m_failedUdpReasks = 0;
01887         m_lastReaskTime = Utils::getTick();
01888 
01889         logTrace(TRACE_CLIENT,
01890                 boost::format(
01891                         "[%s] UDP Reask: Received ReaskAck; "
01892                         "we are queued on position %d"
01893                 ) % getIpPort() % p.getQR()
01894         );
01895 
01896         m_sourceInfo->setPartMap(p.getPartMap());
01897         m_sourceInfo->setQR(p.getQR());
01898 
01899         getEventTable().postEvent(this, EVT_REASKFILEPING, SOURCE_REASKTIME);
01900 }
01901 
01902 // We can only assume that the FileNotFound is about currently requested
01903 // file, because the packet doesn't contain hash. There might be a race
01904 // condition hidden here, when we swap to another file DURING the UDP callback,
01905 // in which case we incorrectly remove the wrong offered file from m_sourceInfo.
01906 void Client::onPacket(const ED2KPacket::FileNotFound &) {
01907         m_reaskInProgress = false;
01908         m_failedUdpReasks = 0;
01909         m_lastReaskTime = Utils::getTick();
01910 
01911         logTrace(TRACE_CLIENT,
01912                 boost::format("[%s] UDP Reask: Received FileNotFound")
01913                 % getIpPort()
01914         );
01915 
01916         if (m_sourceInfo) {
01917                 remOffered(m_sourceInfo->getReqFile());
01918         }
01919 }
01920 
01921 void Client::onPacket(const ED2KPacket::QueueFull &) {
01922         m_reaskInProgress = false;
01923         m_failedUdpReasks = 0;
01924         m_lastReaskTime = Utils::getTick();
01925 
01926         logTrace(TRACE_CLIENT,
01927                 boost::format("[%s] UDP Reask: Received QueueFull")
01928                 % getIpPort()
01929         );
01930 
01931         if (m_sourceInfo) {
01932                 m_sourceInfo->setQR(0);
01933         }
01934 
01935         getEventTable().postEvent(this, EVT_REASKFILEPING, SOURCE_REASKTIME);
01936 }
01937 
01938 void Client::removeFromQueue() {
01939         m_queueInfo.reset();
01940         getEventTable().postEvent(this, EVT_CANCEL_UPLOADREQ);
01941         checkDestroy();
01942 }
01943