File indexing completed on 2025-01-05 04:37:11
0001 /* 0002 SPDX-FileCopyrightText: 2012 Joris Guisson <joris.guisson@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kbuckettable.h" 0008 #include "dht.h" 0009 #include "nodelookup.h" 0010 #include <QFile> 0011 #include <bcodec/bdecoder.h> 0012 #include <bcodec/bencoder.h> 0013 #include <bcodec/bnode.h> 0014 #include <util/error.h> 0015 #include <util/file.h> 0016 #include <util/log.h> 0017 0018 using namespace bt; 0019 0020 namespace dht 0021 { 0022 KBucketTable::KBucketTable(const Key &our_id) 0023 : our_id(our_id) 0024 { 0025 } 0026 0027 KBucketTable::~KBucketTable() 0028 { 0029 } 0030 0031 void KBucketTable::insert(const dht::KBucketEntry &entry, dht::RPCServerInterface *srv) 0032 { 0033 if (buckets.empty()) { 0034 KBucket::Ptr initial(new KBucket(srv, our_id)); 0035 buckets.push_back(initial); 0036 } 0037 0038 KBucketList::iterator kb = findBucket(entry.getID()); 0039 0040 // return if we can't find a bucket, should never happen' 0041 if (kb == buckets.end()) { 0042 Out(SYS_DHT | LOG_IMPORTANT) << "Unable to find bucket !" << endl; 0043 return; 0044 } 0045 0046 // insert it into the bucket 0047 try { 0048 if ((*kb)->insert(entry)) { 0049 // Bucket needs to be split 0050 std::pair<KBucket::Ptr, KBucket::Ptr> result = (*kb)->split(); 0051 /* 0052 Out(SYS_DHT | LOG_DEBUG) << "Splitting bucket " << (*kb)->minKey().toString() << "-" << (*kb)->maxKey().toString() << endl; 0053 Out(SYS_DHT | LOG_DEBUG) << "L: " << result.first->minKey().toString() << "-" << result.first->maxKey().toString() << endl; 0054 Out(SYS_DHT | LOG_DEBUG) << "L range: " << (result.first->maxKey() - result.first->minKey()).toString() << endl; 0055 Out(SYS_DHT | LOG_DEBUG) << "R: " << result.second->minKey().toString() << "-" << result.second->maxKey().toString() << endl; 0056 Out(SYS_DHT | LOG_DEBUG) << "R range: " << (result.second->maxKey() - result.second->minKey()).toString() << endl; 0057 */ 0058 buckets.insert(kb, result.first); 0059 buckets.insert(kb, result.second); 0060 buckets.erase(kb); 0061 if (result.first->keyInRange(entry.getID())) 0062 result.first->insert(entry); 0063 else 0064 result.second->insert(entry); 0065 } 0066 } catch (const KBucket::UnableToSplit &) { 0067 // Can't split, so stop this 0068 Out(SYS_DHT | LOG_IMPORTANT) << "Unable to split buckets further !" << endl; 0069 return; 0070 } 0071 } 0072 0073 int KBucketTable::numEntries() const 0074 { 0075 int count = 0; 0076 for (const KBucket::Ptr &b : std::as_const(buckets)) { 0077 count += b->getNumEntries(); 0078 } 0079 0080 return count; 0081 } 0082 0083 KBucketTable::KBucketList::iterator KBucketTable::findBucket(const dht::Key &id) 0084 { 0085 for (KBucketList::iterator i = buckets.begin(); i != buckets.end(); ++i) { 0086 if ((*i)->keyInRange(id)) 0087 return i; 0088 } 0089 0090 return buckets.end(); 0091 } 0092 0093 void KBucketTable::refreshBuckets(DHT *dh_table) 0094 { 0095 for (const KBucket::Ptr &b : std::as_const(buckets)) { 0096 if (b->needsToBeRefreshed()) { 0097 // the key needs to be the refreshed 0098 dht::Key m = dht::Key::mid(b->minKey(), b->maxKey()); 0099 NodeLookup *nl = dh_table->refreshBucket(m, *b); 0100 if (nl) 0101 b->setRefreshTask(nl); 0102 } 0103 } 0104 } 0105 0106 void KBucketTable::onTimeout(const net::Address &addr) 0107 { 0108 for (const KBucket::Ptr &b : std::as_const(buckets)) { 0109 if (b->onTimeout(addr)) 0110 return; 0111 } 0112 } 0113 0114 void KBucketTable::loadTable(const QString &file, RPCServerInterface *srv) 0115 { 0116 QFile fptr(file); 0117 if (!fptr.open(QIODevice::ReadOnly)) { 0118 Out(SYS_DHT | LOG_IMPORTANT) << "DHT: Cannot open file " << file << " : " << fptr.errorString() << endl; 0119 return; 0120 } 0121 0122 try { 0123 QByteArray data = fptr.readAll(); 0124 bt::BDecoder dec(data, false, 0); 0125 0126 QScopedPointer<BListNode> bucket_list(dec.decodeList()); 0127 if (!bucket_list) 0128 return; 0129 0130 for (bt::Uint32 i = 0; i < bucket_list->getNumChildren(); i++) { 0131 BDictNode *dict = bucket_list->getDict(i); 0132 if (!dict) 0133 continue; 0134 0135 KBucket::Ptr bucket(new KBucket(srv, our_id)); 0136 bucket->load(dict); 0137 buckets.push_back(bucket); 0138 } 0139 } catch (bt::Error &e) { 0140 Out(SYS_DHT | LOG_IMPORTANT) << "DHT: Failed to load bucket table: " << e.toString() << endl; 0141 } 0142 } 0143 0144 void KBucketTable::saveTable(const QString &file) 0145 { 0146 bt::File fptr; 0147 if (!fptr.open(file, "wb")) { 0148 Out(SYS_DHT | LOG_IMPORTANT) << "DHT: Cannot open file " << file << " : " << fptr.errorString() << endl; 0149 return; 0150 } 0151 0152 BEncoder enc(&fptr); 0153 0154 try { 0155 enc.beginList(); 0156 for (const KBucket::Ptr &b : std::as_const(buckets)) { 0157 b->save(enc); 0158 } 0159 enc.end(); 0160 } catch (bt::Error &err) { 0161 Out(SYS_DHT | LOG_IMPORTANT) << "DHT: Failed to save table to " << file << " : " << err.toString() << endl; 0162 } 0163 } 0164 0165 void KBucketTable::findKClosestNodes(KClosestNodesSearch &kns) const 0166 { 0167 for (const KBucket::Ptr &b : std::as_const(buckets)) { 0168 b->findKClosestNodes(kns); 0169 } 0170 } 0171 0172 }