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 "node.h"
0007 
0008 #include "dht.h"
0009 #include "kbuckettable.h"
0010 #include "kclosestnodessearch.h"
0011 #include "key.h"
0012 #include "nodelookup.h"
0013 #include "rpccall.h"
0014 #include "rpcmsg.h"
0015 #include "rpcserver.h"
0016 #include <torrent/globals.h>
0017 #include <util/error.h>
0018 #include <util/file.h>
0019 #include <util/fileops.h>
0020 #include <util/functions.h>
0021 #include <util/log.h>
0022 
0023 using namespace bt;
0024 
0025 namespace dht
0026 {
0027 class Node::Private
0028 {
0029 public:
0030     Private(RPCServer *srv)
0031         : srv(srv)
0032     {
0033         num_receives = 0;
0034         new_key = false;
0035     }
0036 
0037     ~Private()
0038     {
0039     }
0040 
0041     void saveKey(const dht::Key &key, const QString &key_file)
0042     {
0043         bt::File fptr;
0044         if (!fptr.open(key_file, "wb")) {
0045             Out(SYS_DHT | LOG_IMPORTANT) << "DHT: Cannot open file " << key_file << " : " << fptr.errorString() << endl;
0046             return;
0047         }
0048 
0049         fptr.write(key.getData(), 20);
0050         fptr.close();
0051     }
0052 
0053     dht::Key loadKey(const QString &key_file)
0054     {
0055         bt::File fptr;
0056         if (!fptr.open(key_file, "rb")) {
0057             Out(SYS_DHT | LOG_IMPORTANT) << "DHT: Cannot open file " << key_file << " : " << fptr.errorString() << endl;
0058             dht::Key r = dht::Key::random();
0059             saveKey(r, key_file);
0060             new_key = true;
0061             return r;
0062         }
0063 
0064         Uint8 data[20];
0065         if (fptr.read(data, 20) != 20) {
0066             dht::Key r = dht::Key::random();
0067             saveKey(r, key_file);
0068             new_key = true;
0069             return r;
0070         }
0071 
0072         new_key = false;
0073         return dht::Key(data);
0074     }
0075 
0076     QScopedPointer<KBucketTable> ipv4_table;
0077     QScopedPointer<KBucketTable> ipv6_table;
0078     RPCServer *srv;
0079     Uint32 num_receives;
0080     bool new_key;
0081 };
0082 
0083 Node::Node(RPCServer *srv, const QString &key_file)
0084     : d(new Private(srv))
0085 {
0086     num_entries = 0;
0087     our_id = d->loadKey(key_file);
0088     d->ipv4_table.reset(new KBucketTable(our_id));
0089     d->ipv6_table.reset(new KBucketTable(our_id));
0090 }
0091 
0092 Node::~Node()
0093 {
0094     delete d;
0095 }
0096 
0097 void Node::received(dht::DHT *dh_table, const dht::RPCMsg &msg)
0098 {
0099     if (msg.getOrigin().ipVersion() == 4)
0100         d->ipv4_table->insert(KBucketEntry(msg.getOrigin(), msg.getID()), d->srv);
0101     else
0102         d->ipv6_table->insert(KBucketEntry(msg.getOrigin(), msg.getID()), d->srv);
0103 
0104     d->num_receives++;
0105     if (d->num_receives == 3) {
0106         // do a node lookup upon our own id
0107         // when we insert the first entry in the table
0108         dh_table->findOwnNode();
0109     }
0110 
0111     num_entries = d->ipv4_table->numEntries() + d->ipv6_table->numEntries();
0112 }
0113 
0114 void Node::findKClosestNodes(KClosestNodesSearch &kns, bt::Uint32 want)
0115 {
0116     if (want & WANT_IPV4)
0117         d->ipv4_table->findKClosestNodes(kns);
0118     if (want & WANT_IPV6)
0119         d->ipv6_table->findKClosestNodes(kns);
0120 }
0121 
0122 void Node::onTimeout(RPCMsg::Ptr msg)
0123 {
0124     if (msg->getOrigin().ipVersion() == 4)
0125         d->ipv4_table->onTimeout(msg->getOrigin());
0126     else
0127         d->ipv6_table->onTimeout(msg->getOrigin());
0128 }
0129 
0130 void Node::refreshBuckets(DHT *dh_table)
0131 {
0132     d->ipv4_table->refreshBuckets(dh_table);
0133     d->ipv6_table->refreshBuckets(dh_table);
0134 }
0135 
0136 void Node::saveTable(const QString &file)
0137 {
0138     d->ipv4_table->saveTable(file + ".ipv4");
0139     d->ipv6_table->saveTable(file + ".ipv6");
0140 }
0141 
0142 void Node::loadTable(const QString &file)
0143 {
0144     if (d->new_key) {
0145         d->new_key = false;
0146         bt::Delete(file + ".ipv4", true);
0147         bt::Delete(file + ".ipv6", true);
0148         Out(SYS_DHT | LOG_IMPORTANT) << "DHT: new key, so removing tables" << endl;
0149     } else {
0150         d->ipv4_table->loadTable(file + ".ipv4", d->srv);
0151         d->ipv6_table->loadTable(file + ".ipv6", d->srv);
0152         num_entries = d->ipv4_table->numEntries() + d->ipv6_table->numEntries();
0153     }
0154 }
0155 }
0156 
0157 #include "moc_node.cpp"