Browse Source

initial commit for Kademlia DHT

pull/1883/head
orignal 2 years ago
parent
commit
b8590075e6
  1. 238
      libi2pd/KadDHT.cpp
  2. 64
      libi2pd/KadDHT.h

238
libi2pd/KadDHT.cpp

@ -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);
}
}
}
}

64
libi2pd/KadDHT.h

@ -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…
Cancel
Save