|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 2012-2016 by Alexander V. Lukyanov (lav@yars.free.net)
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8f70b4 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8f70b4 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit |
8f70b4 |
* (at your option) any later version.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
8f70b4 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8f70b4 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8f70b4 |
* GNU General Public License for more details.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
8f70b4 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
8f70b4 |
*/
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#ifndef DHT_H
|
|
Packit |
8f70b4 |
#define DHT_H
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
class Torrent;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
class DHT : public SMTask, protected ProtoLog, public ResClient
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static const int K = 8;
|
|
Packit |
8f70b4 |
static const int MAX_NODES = 160*K;
|
|
Packit |
8f70b4 |
static const int MAX_TORRENTS = 1024;
|
|
Packit |
8f70b4 |
static const int MAX_PEERS = 60; // per torrent
|
|
Packit |
8f70b4 |
static const int MAX_SEND_QUEUE = 256;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
class Node
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
xstring id;
|
|
Packit |
8f70b4 |
xstring token;
|
|
Packit |
8f70b4 |
xstring my_token;
|
|
Packit |
8f70b4 |
xstring my_last_token;
|
|
Packit |
8f70b4 |
xstring origin_id;
|
|
Packit |
8f70b4 |
sockaddr_u addr;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Timer good_timer; // 15 minutes, questionable when expired
|
|
Packit |
8f70b4 |
Timer token_timer;
|
|
Packit |
8f70b4 |
Timer ping_timer; // don't send pings too often
|
|
Packit |
8f70b4 |
bool responded; // has ever responded to our query
|
|
Packit |
8f70b4 |
bool in_routes; // belongs to the routing table;
|
|
Packit |
8f70b4 |
int ping_lost_count;
|
|
Packit |
8f70b4 |
int id_change_count;
|
|
Packit |
8f70b4 |
int bad_node_count;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool IsGood() const { return !good_timer.Stopped(); }
|
|
Packit |
8f70b4 |
void SetGood() { good_timer.Reset(); }
|
|
Packit |
8f70b4 |
bool IsBad() const { return (!IsGood() && ping_lost_count>=2) || id_change_count>=2; }
|
|
Packit |
8f70b4 |
void LostPing() { ping_lost_count++; }
|
|
Packit |
8f70b4 |
void ResetLostPing() { ping_lost_count=0; }
|
|
Packit |
8f70b4 |
void SetOrigin(const Node *o) { origin_id.set(o->id); }
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *GetName() const { return addr.to_string(); }
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Node(const xstring& i,const sockaddr_u& a)
|
|
Packit |
8f70b4 |
: id(i.copy()), addr(a), good_timer(15*60), token_timer(5*60),
|
|
Packit |
8f70b4 |
ping_timer(30), responded(false), in_routes(false),
|
|
Packit |
8f70b4 |
ping_lost_count(0), id_change_count(0), bad_node_count(0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
good_timer.Stop();
|
|
Packit |
8f70b4 |
ping_timer.Stop();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const xstring& GetToken();
|
|
Packit |
8f70b4 |
bool TokenIsValid(const xstring& token) const;
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
class RouteBucket
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
int prefix_bits;
|
|
Packit |
8f70b4 |
xstring prefix;
|
|
Packit |
8f70b4 |
xarray<Node*> nodes;
|
|
Packit |
8f70b4 |
Timer fresh_timer;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool IsFresh() const { return !fresh_timer.Stopped(); }
|
|
Packit |
8f70b4 |
void SetFresh() { fresh_timer.Reset(); }
|
|
Packit |
8f70b4 |
bool PrefixMatch(const xstring& i,int skew=0) const;
|
|
Packit |
8f70b4 |
void RemoveNode(Node *n);
|
|
Packit |
8f70b4 |
void RemoveNode(int i);
|
|
Packit |
8f70b4 |
bool HasGoodNodes() const {
|
|
Packit |
8f70b4 |
for(int i=0; i
|
|
Packit |
8f70b4 |
if(nodes[i]->IsGood())
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
RouteBucket(int pb,const xstring& p)
|
|
Packit |
8f70b4 |
: prefix_bits(pb), prefix(p.copy()), fresh_timer(15*60)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
assert(prefix.length()>=size_t((prefix_bits+7)/8));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *to_string() const;
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
class Request
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
Ref<BeNode> data;
|
|
Packit |
8f70b4 |
sockaddr_u addr;
|
|
Packit |
8f70b4 |
xstring node_id;
|
|
Packit |
8f70b4 |
Timer expire_timer;
|
|
Packit |
8f70b4 |
bool Expired() const { return expire_timer.Stopped(); }
|
|
Packit |
8f70b4 |
const xstring& GetNodeId() const { return node_id; }
|
|
Packit |
8f70b4 |
const xstring& GetSearchTarget() const;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Request(BeNode *b,const sockaddr_u& a,const xstring& id)
|
|
Packit |
8f70b4 |
: data(b), addr(a), node_id(id.copy()), expire_timer(180) {}
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
class Search
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
xstring target_id;
|
|
Packit |
8f70b4 |
xstring best_node_id;
|
|
Packit |
8f70b4 |
xmap<bool> searched;
|
|
Packit |
8f70b4 |
int depth;
|
|
Packit |
8f70b4 |
Timer search_timer;
|
|
Packit |
8f70b4 |
bool want_peers;
|
|
Packit |
8f70b4 |
bool noseed;
|
|
Packit |
8f70b4 |
bool bootstrap;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Search(const xstring& i)
|
|
Packit |
8f70b4 |
: target_id(i.copy()), depth(0), search_timer(185),
|
|
Packit |
8f70b4 |
want_peers(false), noseed(false), bootstrap(false) {}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool IsFeasible(const xstring &id) const;
|
|
Packit |
8f70b4 |
bool IsFeasible(const Node *n) const { return IsFeasible(n->id); }
|
|
Packit |
8f70b4 |
void ContinueOn(DHT *d,const Node *n);
|
|
Packit |
8f70b4 |
void WantPeers(bool ns) { want_peers=true; noseed=ns; }
|
|
Packit |
8f70b4 |
void Bootstrap() { bootstrap=true; }
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
class Peer
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
sockaddr_compact compact_addr;
|
|
Packit |
8f70b4 |
Timer good_timer;
|
|
Packit |
8f70b4 |
bool seed;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Peer(const sockaddr_compact &a,bool s)
|
|
Packit |
8f70b4 |
: compact_addr(a), good_timer(15*60), seed(s) {}
|
|
Packit |
8f70b4 |
bool IsGood() const { return !good_timer.Stopped(); }
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
class KnownTorrent
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
xarray_p<Peer> peers;
|
|
Packit |
8f70b4 |
void AddPeer(Peer *);
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
class BlackList : private ProtoLog
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xmap_p<Timer> bl;
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
bool Listed(const sockaddr_u &a);
|
|
Packit |
8f70b4 |
void Add(const sockaddr_u &a,const char *t="1h");
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int af;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
BlackList black_list;
|
|
Packit |
8f70b4 |
RateLimit rate_limit;
|
|
Packit |
8f70b4 |
RefQueue<Request> send_queue;
|
|
Packit |
8f70b4 |
xmap_p<Request> sent_req; // the key is "t"
|
|
Packit |
8f70b4 |
Timer sent_req_expire_scan;
|
|
Packit |
8f70b4 |
Timer search_cleanup_timer;
|
|
Packit |
8f70b4 |
Timer refresh_timer;
|
|
Packit |
8f70b4 |
Timer nodes_cleanup_timer;
|
|
Packit |
8f70b4 |
Timer save_timer;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// voting for new external IP
|
|
Packit |
8f70b4 |
xmap<unsigned> ip_votes;
|
|
Packit |
8f70b4 |
xmap<bool> ip_voted;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring node_id;
|
|
Packit |
8f70b4 |
xmap_p<Node> nodes;
|
|
Packit |
8f70b4 |
xmap<Node*> node_by_addr;
|
|
Packit |
8f70b4 |
RefArray<RouteBucket> routes;
|
|
Packit |
8f70b4 |
xmap_p<Search> search;
|
|
Packit |
8f70b4 |
xmap_p<KnownTorrent> torrents;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xqueue_p<xstring> bootstrap_nodes;
|
|
Packit |
8f70b4 |
SMTaskRef<Resolver> resolver;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Bootstrap();
|
|
Packit |
8f70b4 |
void AddNode(Node *);
|
|
Packit |
8f70b4 |
void RemoveNode(Node *);
|
|
Packit |
8f70b4 |
void ChangeNodeId(Node *n,const xstring& new_node_id);
|
|
Packit |
8f70b4 |
void BlackListNode(Node *n,const char *timeout);
|
|
Packit |
8f70b4 |
void AddRoute(Node *);
|
|
Packit |
8f70b4 |
void RemoveRoute(Node *n);
|
|
Packit |
8f70b4 |
bool SplitRoute0();
|
|
Packit |
8f70b4 |
Node *FoundNode(const xstring& id,const sockaddr_u& a,bool responded,Search *s=0);
|
|
Packit |
8f70b4 |
int FindRoute(const xstring& i,int start=0,int skew=0);
|
|
Packit |
8f70b4 |
void FindNodes(const xstring& i,xarray<Node*> &a,int max_count,bool only_good,const xmap<bool> *exclude=0);
|
|
Packit |
8f70b4 |
void StartSearch(Search *s);
|
|
Packit |
8f70b4 |
void RestartSearch(Search *s);
|
|
Packit |
8f70b4 |
void AddPeer(const xstring& ih,const sockaddr_compact& ca,bool seed);
|
|
Packit |
8f70b4 |
Node *GetOrigin(const Node *n);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
unsigned t; // transaction id
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
BeNode *NewQuery(const char *q,xmap_p<BeNode>& a);
|
|
Packit |
8f70b4 |
BeNode *NewReply(const xstring& t0,xmap_p<BeNode>& r);
|
|
Packit |
8f70b4 |
BeNode *NewError(const xstring& t0,int code,const char *msg);
|
|
Packit |
8f70b4 |
void SendMessage(BeNode *q,const sockaddr_u& a,const xstring& id=xstring::null);
|
|
Packit |
8f70b4 |
void SendMessage(Request *);
|
|
Packit |
8f70b4 |
bool MaySendMessage();
|
|
Packit |
8f70b4 |
static const char *MessageType(BeNode *q);
|
|
Packit |
8f70b4 |
static int AddNodesToReply(xmap_p<BeNode> &r,const xstring& target,bool want_n4,bool want_n6);
|
|
Packit |
8f70b4 |
int AddNodesToReply(xmap_p<BeNode> &r,const xstring& target,int max_count);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
enum {
|
|
Packit |
8f70b4 |
ERR_GENERIC=201,
|
|
Packit |
8f70b4 |
ERR_SERVER=202,
|
|
Packit |
8f70b4 |
ERR_PROTOCOL=203,
|
|
Packit |
8f70b4 |
ERR_UNKNOWN_METHOD=204,
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
SMTaskRef<IOBuffer> state_io;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
DHT(int af,const xstring &id;;
|
|
Packit |
8f70b4 |
~DHT();
|
|
Packit |
8f70b4 |
int Do();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static void MakeNodeId(xstring &id,const sockaddr_compact& ip,int r=random()/13);
|
|
Packit |
8f70b4 |
static bool ValidNodeId(const xstring &id,const sockaddr_compact& ip);
|
|
Packit |
8f70b4 |
void Restart();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Reconfig(const char *name);
|
|
Packit |
8f70b4 |
const char *GetLogContext() { return af==AF_INET?"DHT":"DHT6"; }
|
|
Packit |
8f70b4 |
const xstring& GetNodeID() const { return node_id; }
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void SendPing(const sockaddr_u& addr,const xstring& id=xstring::null);
|
|
Packit |
8f70b4 |
void SendPing(Node *n);
|
|
Packit |
8f70b4 |
int PingQuestionable(const xarray<Node*>& nodes,int limit);
|
|
Packit |
8f70b4 |
void AnnouncePeer(const Torrent *);
|
|
Packit |
8f70b4 |
void DenouncePeer(const Torrent *);
|
|
Packit |
8f70b4 |
void HandlePacket(BeNode *b,const sockaddr_u& src);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Save(const SMTaskRef<IOBuffer>& buf);
|
|
Packit |
8f70b4 |
void Load(const SMTaskRef<IOBuffer>& buf);
|
|
Packit |
8f70b4 |
xstring state_file;
|
|
Packit |
8f70b4 |
void Save();
|
|
Packit |
8f70b4 |
void Load();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void AddBootstrapNode(const char *n) { bootstrap_nodes.push(new xstring(n)); }
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#endif//DHT_H
|