Blame src/DHT.h

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