mirror of https://github.com/PurpleI2P/i2pd.git
orignal
2 years ago
2 changed files with 302 additions and 0 deletions
@ -0,0 +1,238 @@
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (c) 2023, The PurpleI2P Project |
||||
* |
||||
* This file is part of Purple i2pd project and licensed under BSD3 |
||||
* |
||||
* See full license text in LICENSE file at top of project tree |
||||
* |
||||
*/ |
||||
|
||||
#include "KadDHT.h" |
||||
|
||||
namespace i2p |
||||
{ |
||||
namespace data |
||||
{ |
||||
DHTNode::DHTNode (): |
||||
zero (nullptr), one (nullptr), hash (nullptr) |
||||
{ |
||||
} |
||||
|
||||
DHTNode::~DHTNode () |
||||
{ |
||||
if (zero) delete zero; |
||||
if (one) delete one; |
||||
if (hash) delete hash; |
||||
} |
||||
|
||||
void DHTNode::MoveHashUp (bool fromOne) |
||||
{ |
||||
DHTNode *& side = fromOne ? one : zero; |
||||
if (side) |
||||
{ |
||||
if (hash) delete hash; // shouldn't happen
|
||||
hash = side->hash; |
||||
side->hash = nullptr; |
||||
delete side; |
||||
side = nullptr; |
||||
} |
||||
} |
||||
|
||||
DHTTable::DHTTable (): |
||||
m_Size (0) |
||||
{ |
||||
m_Root = new DHTNode; |
||||
} |
||||
|
||||
DHTTable::~DHTTable () |
||||
{ |
||||
delete m_Root; |
||||
} |
||||
|
||||
DHTNode * DHTTable::Insert (const IdentHash& h) |
||||
{ |
||||
return Insert (new IdentHash (h), m_Root, 0); |
||||
} |
||||
|
||||
DHTNode * DHTTable::Insert (IdentHash * h, DHTNode * root, int level) |
||||
{ |
||||
if (root->hash) |
||||
{ |
||||
if (*(root->hash) == *h) |
||||
{ |
||||
delete h; |
||||
return root; |
||||
} |
||||
auto h2 = root->hash; |
||||
root->hash = nullptr; m_Size--; |
||||
int bit1, bit2; |
||||
do |
||||
{ |
||||
bit1 = h->GetBit (level); |
||||
bit2 = h2->GetBit (level); |
||||
if (bit1 == bit2) |
||||
{ |
||||
if (bit1) |
||||
{ |
||||
if (root->one) return nullptr; // someting wrong
|
||||
root->one = new DHTNode; |
||||
root = root->one; |
||||
} |
||||
else |
||||
{ |
||||
if (root->zero) return nullptr; // someting wrong
|
||||
root->zero = new DHTNode; |
||||
root = root->zero; |
||||
} |
||||
level++; |
||||
} |
||||
} |
||||
while (bit1 == bit2); |
||||
|
||||
if (!root->zero) |
||||
root->zero = new DHTNode; |
||||
if (!root->one) |
||||
root->one = new DHTNode; |
||||
if (bit1) |
||||
{ |
||||
Insert (h2, root->zero, level + 1); |
||||
return Insert (h, root->one, level + 1); |
||||
} |
||||
else |
||||
{ |
||||
Insert (h2, root->one, level + 1); |
||||
return Insert (h, root->zero, level + 1); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
if (!root->zero && !root->one) |
||||
{ |
||||
root->hash = h; m_Size++; |
||||
return root; |
||||
} |
||||
int bit = h->GetBit (level); |
||||
if (bit) |
||||
{ |
||||
if (!root->one) |
||||
root->one = new DHTNode; |
||||
return Insert (h, root->one, level + 1); |
||||
} |
||||
else |
||||
{ |
||||
if (!root->zero) |
||||
root->zero = new DHTNode; |
||||
return Insert (h, root->zero, level + 1); |
||||
} |
||||
} |
||||
return nullptr; |
||||
} |
||||
|
||||
bool DHTTable::Remove (const IdentHash& h) |
||||
{ |
||||
return Remove (h, m_Root, 0); |
||||
} |
||||
|
||||
bool DHTTable::Remove (const IdentHash& h, DHTNode * root, int level) |
||||
{ |
||||
if (root) |
||||
{ |
||||
if (root->hash && *(root->hash) == h) |
||||
{ |
||||
delete root->hash; root->hash = nullptr; |
||||
m_Size--; |
||||
return true; |
||||
} |
||||
int bit = h.GetBit (level); |
||||
if (bit) |
||||
{ |
||||
if (root->one && Remove (h, root->one, level + 1)) |
||||
{ |
||||
if (root->one->IsEmpty ()) |
||||
{ |
||||
delete root->one; |
||||
root->one = nullptr; |
||||
if (root->zero && root->zero->hash) |
||||
root->MoveHashUp (false); |
||||
} |
||||
else if (root->one->hash && !root->zero) |
||||
root->MoveHashUp (true); |
||||
return true; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
if (root->zero && Remove (h, root->zero, level + 1)) |
||||
{ |
||||
if (root->zero->IsEmpty ()) |
||||
{ |
||||
delete root->zero; |
||||
root->zero = nullptr; |
||||
if (root->one && root->one->hash) |
||||
root->MoveHashUp (true); |
||||
} |
||||
else if (root->zero->hash && !root->one) |
||||
root->MoveHashUp (false); |
||||
return true; |
||||
} |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
IdentHash * DHTTable::FindClosest (const IdentHash& h) |
||||
{ |
||||
return FindClosest (h, m_Root, 0); |
||||
} |
||||
|
||||
IdentHash * DHTTable::FindClosest (const IdentHash& h, DHTNode * root, int level) |
||||
{ |
||||
if (root->hash) return root->hash; |
||||
int bit = h.GetBit (level); |
||||
if (bit) |
||||
{ |
||||
if (root->one) |
||||
return FindClosest (h, root->one, level + 1); |
||||
if (root->zero) |
||||
return FindClosest (h, root->zero, level + 1); |
||||
} |
||||
else |
||||
{ |
||||
if (root->zero) |
||||
return FindClosest (h, root->zero, level + 1); |
||||
if (root->one) |
||||
return FindClosest (h, root->one, level + 1); |
||||
} |
||||
return nullptr; |
||||
} |
||||
|
||||
void DHTTable::Print (std::stringstream& s) |
||||
{ |
||||
Print (s, m_Root, 0); |
||||
} |
||||
|
||||
void DHTTable::Print (std::stringstream& s, DHTNode * root, int level) |
||||
{ |
||||
if (!root) return; |
||||
s << std::string (level, '-'); |
||||
if (root->hash) |
||||
{ |
||||
if (!root->zero && !root->one) |
||||
s << '>' << GetIdentHashAbbreviation (*(root->hash)); |
||||
else |
||||
s << "error"; |
||||
} |
||||
s << std::endl; |
||||
if (root->zero) |
||||
{ |
||||
s << std::string (level, '-') << "0" << std::endl; |
||||
Print (s, root->zero, level + 1); |
||||
} |
||||
if (root->one) |
||||
{ |
||||
s << std::string (level, '-') << "1" << std::endl; |
||||
Print (s, root->one, level + 1); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,64 @@
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2023, The PurpleI2P Project |
||||
* |
||||
* This file is part of Purple i2pd project and licensed under BSD3 |
||||
* |
||||
* See full license text in LICENSE file at top of project tree |
||||
* |
||||
*/ |
||||
|
||||
#ifndef KADDHT_H__ |
||||
#define KADDHT_H__ |
||||
|
||||
#include <memory> |
||||
#include <sstream> |
||||
#include "Identity.h" |
||||
|
||||
// Kademlia DHT (XOR distance)
|
||||
|
||||
namespace i2p |
||||
{ |
||||
namespace data |
||||
{ |
||||
struct DHTNode |
||||
{ |
||||
DHTNode * zero, * one; |
||||
IdentHash * hash; |
||||
|
||||
DHTNode (); |
||||
~DHTNode (); |
||||
|
||||
bool IsEmpty () const { return !zero && !one && !hash; }; |
||||
void MoveHashUp (bool fromOne); |
||||
}; |
||||
|
||||
class DHTTable |
||||
{ |
||||
public: |
||||
|
||||
DHTTable (); |
||||
~DHTTable (); |
||||
|
||||
DHTNode * Insert (const IdentHash& h); |
||||
bool Remove (const IdentHash& h); |
||||
IdentHash * FindClosest (const IdentHash& h); |
||||
|
||||
void Print (std::stringstream& s); |
||||
size_t GetSize () const { return m_Size; }; |
||||
|
||||
private: |
||||
|
||||
DHTNode * Insert (IdentHash * h, DHTNode * root, int level); // recursive
|
||||
bool Remove (const IdentHash& h, DHTNode * root, int level); |
||||
IdentHash * FindClosest (const IdentHash& h, DHTNode * root, int level); |
||||
void Print (std::stringstream& s, DHTNode * root, int level); |
||||
|
||||
private: |
||||
|
||||
DHTNode * m_Root; |
||||
size_t m_Size; |
||||
}; |
||||
} |
||||
} |
||||
|
||||
#endif |
Loading…
Reference in new issue