File indexing completed on 2025-01-05 04:37:11

0001 /*
0002     SPDX-FileCopyrightText: 2005 Joris Guisson <joris.guisson@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 #include "nodelookup.h"
0007 #include "findnodereq.h"
0008 #include "findnodersp.h"
0009 #include "kbucket.h"
0010 #include "node.h"
0011 #include "pack.h"
0012 #include "rpcmsg.h"
0013 #include <torrent/globals.h>
0014 #include <util/log.h>
0015 
0016 using namespace bt;
0017 
0018 namespace dht
0019 {
0020 NodeLookup::NodeLookup(const dht::Key &key, RPCServer *rpc, Node *node, QObject *parent)
0021     : Task(rpc, node, parent)
0022     , node_id(key)
0023     , num_nodes_rsp(0)
0024 {
0025 }
0026 
0027 NodeLookup::~NodeLookup()
0028 {
0029 }
0030 
0031 void NodeLookup::handleNodes(const QByteArray &nodes, int ip_version)
0032 {
0033     Uint32 address_size = ip_version == 4 ? 26 : 38;
0034     Uint32 nnodes = nodes.size() / address_size;
0035     for (Uint32 j = 0; j < nnodes; j++) {
0036         // unpack an entry and add it to the todo list
0037         try {
0038             KBucketEntry e = UnpackBucketEntry(nodes, j * address_size, ip_version);
0039             // lets not talk to ourself
0040             if (e.getID() != node->getOurID() && !todo.contains(e) && !visited.contains(e))
0041                 todo.insert(e);
0042         } catch (...) {
0043             // bad data, just ignore it
0044         }
0045     }
0046 }
0047 
0048 void NodeLookup::callFinished(RPCCall *, RPCMsg::Ptr rsp)
0049 {
0050     // Out(SYS_DHT|LOG_DEBUG) << "NodeLookup::callFinished" << endl;
0051     if (isFinished())
0052         return;
0053 
0054     // check the response and see if it is a good one
0055     if (rsp->getMethod() == dht::FIND_NODE && rsp->getType() == dht::RSP_MSG) {
0056         FindNodeRsp::Ptr fnr = rsp.dynamicCast<FindNodeRsp>();
0057         if (!fnr)
0058             return;
0059 
0060         const QByteArray &nodes = fnr->getNodes();
0061         if (nodes.size() > 0)
0062             handleNodes(nodes, 4);
0063 
0064         const QByteArray &nodes6 = fnr->getNodes6();
0065         if (nodes6.size() > 0)
0066             handleNodes(nodes6, 6);
0067         num_nodes_rsp++;
0068     }
0069 }
0070 
0071 void NodeLookup::callTimeout(RPCCall *)
0072 {
0073     //  Out(SYS_DHT|LOG_DEBUG) << "NodeLookup::callTimeout" << endl;
0074 }
0075 
0076 void NodeLookup::update()
0077 {
0078     //  Out(SYS_DHT|LOG_DEBUG) << "NodeLookup::update" << endl;
0079     //  Out(SYS_DHT|LOG_DEBUG) << "todo = " << todo.count() << " ; visited = " << visited.count() << endl;
0080     // go over the todo list and send find node calls
0081     // until we have nothing left
0082     while (!todo.empty() && canDoRequest()) {
0083         KBucketEntrySet::iterator itr = todo.begin();
0084         // only send a findNode if we haven't allrready visited the node
0085         if (!visited.contains(*itr)) {
0086             // send a findNode to the node
0087             RPCMsg::Ptr fnr(new FindNodeReq(node->getOurID(), node_id));
0088             fnr->setOrigin(itr->getAddress());
0089             rpcCall(fnr);
0090             visited.insert(*itr);
0091         }
0092         // remove the entry from the todo list
0093         todo.erase(itr);
0094     }
0095 
0096     if (todo.empty() && getNumOutstandingRequests() == 0 && !isFinished()) {
0097         Out(SYS_DHT | LOG_NOTICE) << "DHT: NodeLookup done" << endl;
0098         done();
0099     } else if (visited.size() > 200) {
0100         // don't let the task run forever
0101         Out(SYS_DHT | LOG_NOTICE) << "DHT: NodeLookup done" << endl;
0102         done();
0103     }
0104 }
0105 }