mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-01-22 12:24:19 +00:00
initial commit for Kademlia DHT
This commit is contained in:
parent
1da9e2e1c0
commit
b8590075e6
238
libi2pd/KadDHT.cpp
Normal file
238
libi2pd/KadDHT.cpp
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
64
libi2pd/KadDHT.h
Normal file
64
libi2pd/KadDHT.h
Normal file
@ -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…
x
Reference in New Issue
Block a user