Blame src/Torrent.h

Packit 8f70b4
/*
Packit 8f70b4
 * lftp - file transfer program
Packit 8f70b4
 *
Packit 8f70b4
 * Copyright (c) 1996-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 TORRENT_H
Packit 8f70b4
#define TORRENT_H
Packit 8f70b4
Packit 8f70b4
#include "FileAccess.h"
Packit 8f70b4
#include "Bencode.h"
Packit 8f70b4
#include "Error.h"
Packit 8f70b4
#include "ProtoLog.h"
Packit 8f70b4
#include "network.h"
Packit 8f70b4
#include "RateLimit.h"
Packit 8f70b4
#include "Resolver.h"
Packit 8f70b4
#include "FileCopy.h"
Packit 8f70b4
#include "DHT.h"
Packit 8f70b4
Packit 8f70b4
class FDCache;
Packit 8f70b4
class TorrentBlackList;
Packit 8f70b4
class Torrent;
Packit 8f70b4
class TorrentPeer;
Packit 8f70b4
Packit 8f70b4
class BitField : public xarray<unsigned char>
Packit 8f70b4
{
Packit 8f70b4
   int bit_length;
Packit 8f70b4
public:
Packit 8f70b4
   BitField() { bit_length=0; }
Packit 8f70b4
   BitField(int bits);
Packit 8f70b4
   bool valid_index(int i) const {
Packit 8f70b4
      return i>=0 && i
Packit 8f70b4
   }
Packit 8f70b4
   bool get_bit(int i) const;
Packit 8f70b4
   void set_bit(int i,bool value);
Packit 8f70b4
   bool has_any_set(int from,int to) const;
Packit 8f70b4
   bool has_all_set(int from,int to) const;
Packit 8f70b4
   bool has_any_set() const { return has_any_set(0,bit_length); }
Packit 8f70b4
   bool has_all_set() const { return has_all_set(0,bit_length); }
Packit 8f70b4
   int get_bit_length() const { return bit_length; }
Packit 8f70b4
   void set_bit_length(int b) { bit_length=b; set_length((b+7)/8); }
Packit 8f70b4
   void clear() { memset(buf,0,length()); }
Packit 8f70b4
   void set_range(int from,int to,bool value);
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
class TorrentBuild : public SMTask, public ProtoLog
Packit 8f70b4
{
Packit 8f70b4
   xstring_c top_path;
Packit 8f70b4
   xstring name;
Packit 8f70b4
   FileSet files;
Packit 8f70b4
   StringSet dirs_to_scan;
Packit 8f70b4
   bool done;
Packit 8f70b4
   Ref<Error> error;
Packit 8f70b4
Packit 8f70b4
   Ref<DirectedBuffer> translate;
Packit 8f70b4
   const char *lc_to_utf8(const char *s);
Packit 8f70b4
Packit 8f70b4
   friend class Torrent;
Packit 8f70b4
   Ref<BeNode> info;
Packit 8f70b4
   xstring pieces;
Packit 8f70b4
   off_t total_length;
Packit 8f70b4
   unsigned piece_length;
Packit 8f70b4
Packit 8f70b4
   const char *CurrPath() const { return dirs_to_scan[0]; }
Packit 8f70b4
   void NextDir() { dirs_to_scan.Remove(0); }
Packit 8f70b4
   void QueueDir(const char *dir) { dirs_to_scan.Append(dir); }
Packit 8f70b4
   void AddFile(const char *path,struct stat *st);
Packit 8f70b4
   void Finish();
Packit 8f70b4
Packit 8f70b4
public:
Packit 8f70b4
   TorrentBuild(const char *top);
Packit 8f70b4
   int Do();
Packit 8f70b4
   bool Done() const { return done || error; }
Packit 8f70b4
   bool Failed() const { return error; }
Packit 8f70b4
   const char *ErrorText() const { return error->Text(); }
Packit 8f70b4
   BeNode *GetFilesNode() const { return info->lookup("files"); }
Packit 8f70b4
   void SetPiece(unsigned p,const xstring& sha1);
Packit 8f70b4
   const xstring& GetMetadata();
Packit 8f70b4
   const char *GetBaseDirectory() const { return dirname(top_path); }
Packit 8f70b4
   const xstring& Status() const;
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
class TorrentPiece
Packit 8f70b4
{
Packit 8f70b4
   unsigned sources_count;	    // how many peers have the piece
Packit 8f70b4
   unsigned downloader_count;	    // how many downloaders of the piece are there
Packit 8f70b4
   float ratio;
Packit 8f70b4
   RefToArray<const TorrentPeer*> downloader; // which peers download the blocks
Packit 8f70b4
   Ref<BitField> block_map;	    // which blocks are present.
Packit 8f70b4
Packit 8f70b4
public:
Packit 8f70b4
   TorrentPiece() : sources_count(0), downloader_count(0), ratio(0) {}
Packit 8f70b4
   ~TorrentPiece() {}
Packit 8f70b4
Packit 8f70b4
   unsigned get_sources_count() const { return sources_count; }
Packit 8f70b4
   void add_sources_count(int diff) { sources_count+=diff; }
Packit 8f70b4
   bool has_no_sources() const { return sources_count==0; }
Packit 8f70b4
Packit 8f70b4
   bool has_a_downloader() const { return downloader_count>0; }
Packit 8f70b4
   void set_downloader(unsigned block,const TorrentPeer *o,const TorrentPeer *n,unsigned blk_count) {
Packit 8f70b4
      if(!downloader) {
Packit 8f70b4
	 if(o || !n)
Packit 8f70b4
	    return;
Packit 8f70b4
	 downloader=new const TorrentPeer*[blk_count];
Packit 8f70b4
	 for(unsigned i=0; i
Packit 8f70b4
	    downloader[i]=0;
Packit 8f70b4
      }
Packit 8f70b4
      const TorrentPeer*& d=downloader[block];
Packit 8f70b4
      if(d==o) {
Packit 8f70b4
	 d=n;
Packit 8f70b4
	 downloader_count+=(n!=0)-(o!=0);
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   void cleanup() {
Packit 8f70b4
      if(downloader_count==0 && downloader)
Packit 8f70b4
	 downloader=0;
Packit 8f70b4
   }
Packit 8f70b4
   const TorrentPeer *downloader_for(unsigned block) {
Packit 8f70b4
      return downloader ? downloader[block] : 0;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   void set_block_present(unsigned block,unsigned blk_count) {
Packit 8f70b4
      if(!block_map)
Packit 8f70b4
	 block_map=new BitField(blk_count);
Packit 8f70b4
      block_map->set_bit(block,1);
Packit 8f70b4
   }
Packit 8f70b4
   void set_blocks_absent() {
Packit 8f70b4
      block_map=0;
Packit 8f70b4
   }
Packit 8f70b4
   void free_block_map() {
Packit 8f70b4
      block_map=0;
Packit 8f70b4
   }
Packit 8f70b4
   bool block_present(unsigned block) const {
Packit 8f70b4
      return block_map && block_map->get_bit(block);
Packit 8f70b4
   }
Packit 8f70b4
   bool all_blocks_present(unsigned blk_count) const {
Packit 8f70b4
      return block_map && block_map->has_all_set(0,blk_count);
Packit 8f70b4
   }
Packit 8f70b4
   bool any_blocks_present() const {
Packit 8f70b4
      return block_map; // it's allocated when setting any bit
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   float get_ratio() const { return ratio; }
Packit 8f70b4
   void add_ratio(float add) { ratio+=add; }
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
struct TorrentFile
Packit 8f70b4
{
Packit 8f70b4
   char *path;
Packit 8f70b4
   off_t pos;
Packit 8f70b4
   off_t length;
Packit 8f70b4
   void set(const char *n,off_t p,off_t l) {
Packit 8f70b4
      path=xstrdup(n);
Packit 8f70b4
      pos=p;
Packit 8f70b4
      length=l;
Packit 8f70b4
   }
Packit 8f70b4
   void unset() {
Packit 8f70b4
      xfree(path); path=0;
Packit 8f70b4
   }
Packit 8f70b4
   bool contains_pos(off_t p) const {
Packit 8f70b4
      return p>=pos && p
Packit 8f70b4
   }
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
class TorrentFiles : public xarray<TorrentFile>
Packit 8f70b4
{
Packit 8f70b4
   static int pos_cmp(const TorrentFile *a, const TorrentFile *b) {
Packit 8f70b4
      if(a->pos < b->pos)
Packit 8f70b4
	 return -1;
Packit 8f70b4
      if(a->pos > b->pos)
Packit 8f70b4
	 return 1;
Packit 8f70b4
      // we want zero-sized files to placed before non-zero ones.
Packit 8f70b4
      if(a->length != b->length)
Packit 8f70b4
	 return a->length < b->length ? -1 : 1;
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
public:
Packit 8f70b4
   TorrentFile *file(int i) { return get_non_const()+i; }
Packit 8f70b4
   TorrentFiles(const BeNode *f_node,const Torrent *t);
Packit 8f70b4
   ~TorrentFiles() {
Packit 8f70b4
      for(int i=0; i
Packit 8f70b4
	 file(i)->unset();
Packit 8f70b4
   }
Packit 8f70b4
   TorrentFile *FindByPosition(off_t p);
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
class TorrentListener : public SMTask, protected ProtoLog, protected Networker
Packit 8f70b4
{
Packit 8f70b4
   Ref<Error> error;
Packit 8f70b4
   int af;
Packit 8f70b4
   int type;
Packit 8f70b4
   int sock;
Packit 8f70b4
   sockaddr_u addr;
Packit 8f70b4
   Speedometer rate;
Packit 8f70b4
   void FillAddress(int port);
Packit 8f70b4
   Time last_sent_udp;
Packit 8f70b4
   int  last_sent_udp_count;
Packit 8f70b4
public:
Packit 8f70b4
   TorrentListener(int a,int type=SOCK_STREAM);
Packit 8f70b4
   ~TorrentListener();
Packit 8f70b4
   int Do();
Packit 8f70b4
   int GetPort() const { return addr.port(); }
Packit 8f70b4
   const char *GetAddress() const { return addr.address(); }
Packit 8f70b4
   const char *GetLogContext() { return type==SOCK_DGRAM?(af==AF_INET?"torrent(udp)":"torrent(udp6)"):"torrent"; }
Packit 8f70b4
Packit 8f70b4
   int SendUDP(const sockaddr_u& a,const xstring& buf);
Packit 8f70b4
   bool MaySendUDP();
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
class TorrentTracker;
Packit 8f70b4
Packit 8f70b4
class Torrent : public SMTask, protected ProtoLog, public ResClient
Packit 8f70b4
{
Packit 8f70b4
   friend class TorrentPeer;
Packit 8f70b4
   friend class TorrentDispatcher;
Packit 8f70b4
   friend class TorrentListener;
Packit 8f70b4
   friend class TorrentFiles;
Packit 8f70b4
   friend class DHT;
Packit 8f70b4
Packit 8f70b4
   bool shutting_down;
Packit 8f70b4
   bool complete;
Packit 8f70b4
   bool end_game;
Packit 8f70b4
   bool is_private;
Packit 8f70b4
   bool validating;
Packit 8f70b4
   bool force_valid;
Packit 8f70b4
   bool build_md;
Packit 8f70b4
   bool stop_if_complete;
Packit 8f70b4
   bool stop_if_known;
Packit 8f70b4
   bool md_saved;
Packit 8f70b4
   unsigned validate_index;
Packit 8f70b4
   Ref<Error> invalid_cause;
Packit 8f70b4
Packit 8f70b4
   static const unsigned PEER_ID_LEN = 20;
Packit 8f70b4
   static xstring my_peer_id;
Packit 8f70b4
   static xstring my_key;
Packit 8f70b4
   static unsigned my_key_num;
Packit 8f70b4
   static xmap<Torrent*> torrents;
Packit 8f70b4
   static SMTaskRef<TorrentListener> listener;
Packit 8f70b4
   static SMTaskRef<TorrentListener> listener_udp;
Packit 8f70b4
   static SMTaskRef<DHT> dht;
Packit 8f70b4
#if INET6
Packit 8f70b4
   static SMTaskRef<TorrentListener> listener_ipv6;
Packit 8f70b4
   static SMTaskRef<TorrentListener> listener_ipv6_udp;
Packit 8f70b4
   static SMTaskRef<DHT> dht_ipv6;
Packit 8f70b4
#endif
Packit 8f70b4
   static SMTaskRef<FDCache> fd_cache;
Packit 8f70b4
   static Ref<TorrentBlackList> black_list;
Packit 8f70b4
Packit 8f70b4
   static const SMTaskRef<DHT>& GetDHT(int af)
Packit 8f70b4
   {
Packit 8f70b4
#if INET6
Packit 8f70b4
      if(af==AF_INET6 && dht_ipv6)
Packit 8f70b4
	 return dht_ipv6;
Packit 8f70b4
#endif
Packit 8f70b4
      return dht;
Packit 8f70b4
   }
Packit 8f70b4
   static const SMTaskRef<DHT>& GetDHT(const sockaddr_u& a) { return GetDHT(a.family()); }
Packit 8f70b4
   static const SMTaskRef<TorrentListener>& GetUDPSocket(int af)
Packit 8f70b4
   {
Packit 8f70b4
#if INET6
Packit 8f70b4
      if(af==AF_INET6)
Packit 8f70b4
	 return listener_ipv6_udp;
Packit 8f70b4
#endif
Packit 8f70b4
      return listener_udp;
Packit 8f70b4
   }
Packit 8f70b4
   static const SMTaskRef<TorrentListener>& GetUDPSocket(const sockaddr_u& a) { return GetUDPSocket(a.family()); }
Packit 8f70b4
Packit 8f70b4
   static Torrent *FindTorrent(const xstring& info_hash) { return torrents.lookup(info_hash); }
Packit 8f70b4
   static void AddTorrent(Torrent *t);
Packit 8f70b4
   static void RemoveTorrent(Torrent *t);
Packit 8f70b4
   static int GetTorrentsCount() { return torrents.count(); }
Packit 8f70b4
   static void Dispatch(const xstring& info_hash,int s,const sockaddr_u *remote_addr,IOBuffer *recv_buf);
Packit 8f70b4
   static void DispatchUDP(const char *buf,int len,const sockaddr_u& src);
Packit 8f70b4
Packit 8f70b4
   xstring md_download;
Packit 8f70b4
   size_t metadata_size;
Packit 8f70b4
   void FetchMetadataFromURL(const char *url);
Packit 8f70b4
   void StartMetadataDownload();
Packit 8f70b4
   void MetadataDownloaded();
Packit 8f70b4
   bool SetMetadata(const xstring& md);
Packit 8f70b4
   void ParseMagnet(const char *p);
Packit 8f70b4
   const char *GetMetadataPath() const;
Packit 8f70b4
   bool SaveMetadata() const;
Packit 8f70b4
   bool LoadMetadata(const char *path);
Packit 8f70b4
Packit 8f70b4
   void Startup();
Packit 8f70b4
Packit 8f70b4
   void SetTotalLength(off_t);
Packit 8f70b4
   void StartValidating();
Packit 8f70b4
Packit 8f70b4
   xstring_c metainfo_url;
Packit 8f70b4
   SMTaskRef<FileCopy> metainfo_copy;
Packit 8f70b4
   SMTaskRef<TorrentBuild> building;
Packit 8f70b4
   Ref<BeNode> metainfo_tree;
Packit 8f70b4
   BeNode *info;
Packit 8f70b4
   xstring metadata;
Packit 8f70b4
   xstring info_hash;
Packit 8f70b4
   const xstring *pieces;
Packit 8f70b4
   xstring name;
Packit 8f70b4
   Ref<TorrentFiles> files;
Packit 8f70b4
Packit 8f70b4
   Ref<DirectedBuffer> recv_translate;
Packit 8f70b4
   Ref<DirectedBuffer> recv_translate_utf8;
Packit 8f70b4
   void InitTranslation();
Packit 8f70b4
   void TranslateString(BeNode *node) const;
Packit 8f70b4
   void TranslateStringFromUTF8(BeNode *node) const;
Packit 8f70b4
Packit 8f70b4
   TaskRefArray<TorrentTracker> trackers;
Packit 8f70b4
   bool TrackersDone() const;
Packit 8f70b4
   void StartTrackers();
Packit 8f70b4
   void ShutdownTrackers() const;
Packit 8f70b4
   void SendTrackersRequest(const char *e) const;
Packit 8f70b4
   static void StartListener();
Packit 8f70b4
   static void StartListenerUDP();
Packit 8f70b4
   static void StopListener();
Packit 8f70b4
   static void StopListenerUDP();
Packit 8f70b4
   static void StartDHT();
Packit 8f70b4
   static void StopDHT();
Packit 8f70b4
   void AnnounceDHT();
Packit 8f70b4
   void DenounceDHT();
Packit 8f70b4
Packit 8f70b4
   unsigned piece_length;
Packit 8f70b4
   unsigned last_piece_length;
Packit 8f70b4
   unsigned total_pieces;
Packit 8f70b4
   unsigned complete_pieces;
Packit 8f70b4
   Ref<BitField> my_bitfield;
Packit 8f70b4
Packit 8f70b4
   static const unsigned BLOCK_SIZE = 0x4000;
Packit 8f70b4
Packit 8f70b4
   unsigned long long total_length;
Packit 8f70b4
   unsigned long long total_recv;
Packit 8f70b4
   unsigned long long total_sent;
Packit 8f70b4
   unsigned long long total_left;
Packit 8f70b4
Packit 8f70b4
   void AccountSend(unsigned p,unsigned len);
Packit 8f70b4
   void AccountRecv(unsigned p,unsigned len);
Packit 8f70b4
Packit 8f70b4
   void SetError(Error *);
Packit 8f70b4
   void SetError(const char *);
Packit 8f70b4
Packit 8f70b4
   BeNode *Lookup(xmap_p<BeNode>& d,const char *name,BeNode::be_type_t type);
Packit 8f70b4
   BeNode *Lookup(BeNode *d,const char *name,BeNode::be_type_t type) { return Lookup(d->dict,name,type); }
Packit 8f70b4
   BeNode *Lookup(Ref<BeNode>& d,const char *name,BeNode::be_type_t type) { return Lookup(d->dict,name,type); }
Packit 8f70b4
Packit 8f70b4
   TaskRefArray<TorrentPeer> peers;
Packit 8f70b4
   static int PeersCompareActivity(const SMTaskRef<TorrentPeer> *p1,const SMTaskRef<TorrentPeer> *p2);
Packit 8f70b4
   static int PeersCompareRecvRate(const SMTaskRef<TorrentPeer> *p1,const SMTaskRef<TorrentPeer> *p2);
Packit 8f70b4
   static int PeersCompareSendRate(const SMTaskRef<TorrentPeer> *p1,const SMTaskRef<TorrentPeer> *p2);
Packit 8f70b4
Packit 8f70b4
   RefToArray<TorrentPiece> piece_info;
Packit 8f70b4
   unsigned blocks_in_piece;
Packit 8f70b4
   unsigned blocks_in_last_piece;
Packit 8f70b4
   bool BlockPresent(unsigned piece,unsigned block) const {
Packit 8f70b4
      return piece_info[piece].block_present(block);
Packit 8f70b4
   }
Packit 8f70b4
   bool AllBlocksPresent(unsigned piece) const {
Packit 8f70b4
      return piece_info[piece].all_blocks_present(BlocksInPiece(piece));
Packit 8f70b4
   }
Packit 8f70b4
   bool AnyBlocksPresent(unsigned piece) const {
Packit 8f70b4
      return piece_info[piece].any_blocks_present();
Packit 8f70b4
   }
Packit 8f70b4
   bool AllBlocksAbsent(unsigned piece) const {
Packit 8f70b4
      return !AnyBlocksPresent(piece);
Packit 8f70b4
   }
Packit 8f70b4
   void SetBlocksAbsent(unsigned piece) {
Packit 8f70b4
      piece_info[piece].set_blocks_absent();
Packit 8f70b4
   }
Packit 8f70b4
   void SetBlockPresent(unsigned piece,unsigned block) {
Packit 8f70b4
      piece_info[piece].set_block_present(block,BlocksInPiece(piece));
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   void RebuildPiecesNeeded();
Packit 8f70b4
   Timer pieces_timer; // for periodic pieces scanning
Packit 8f70b4
   xarray<unsigned> pieces_needed;
Packit 8f70b4
   static int PiecesNeededCmp(const unsigned *a,const unsigned *b);
Packit 8f70b4
   unsigned last_piece;
Packit 8f70b4
Packit 8f70b4
   unsigned min_piece_sources;
Packit 8f70b4
   unsigned avg_piece_sources;
Packit 8f70b4
   unsigned pieces_available_pct;
Packit 8f70b4
   float current_min_ppr;
Packit 8f70b4
   float current_max_ppr;
Packit 8f70b4
Packit 8f70b4
   void SetPieceNotWanted(unsigned piece);
Packit 8f70b4
   void SetDownloader(unsigned piece,unsigned block,const TorrentPeer *o,const TorrentPeer *n);
Packit 8f70b4
Packit 8f70b4
   xstring_c cwd;
Packit 8f70b4
   xstring_c output_dir;
Packit 8f70b4
Packit 8f70b4
   const char *FindFileByPosition(unsigned piece,unsigned begin,off_t *f_pos,off_t *f_tail) const;
Packit 8f70b4
   const char *MakePath(BeNode *p) const;
Packit 8f70b4
   int OpenFile(const char *f,int m,off_t size=0);
Packit 8f70b4
   void CloseFile(const char *f) const;
Packit 8f70b4
Packit 8f70b4
   void StoreBlock(unsigned piece,unsigned begin,unsigned len,const char *buf,TorrentPeer *src_peer);
Packit 8f70b4
   const xstring& RetrieveBlock(unsigned piece,unsigned begin,unsigned len);
Packit 8f70b4
Packit 8f70b4
   Speedometer recv_rate;
Packit 8f70b4
   Speedometer send_rate;
Packit 8f70b4
Packit 8f70b4
   RateLimit rate_limit;
Packit 8f70b4
   bool RateLow(RateLimit::dir_t dir) { return rate_limit.Relaxed(dir); }
Packit 8f70b4
Packit 8f70b4
   int connected_peers_count;
Packit 8f70b4
   int active_peers_count;
Packit 8f70b4
   int complete_peers_count;
Packit 8f70b4
   int am_interested_peers_count;
Packit 8f70b4
   int am_not_choking_peers_count;
Packit 8f70b4
   int max_peers;
Packit 8f70b4
   int seed_min_peers;
Packit 8f70b4
Packit 8f70b4
   bool SeededEnough() const;
Packit 8f70b4
   float stop_on_ratio;
Packit 8f70b4
   float stop_min_ppr;
Packit 8f70b4
   Timer seed_timer;
Packit 8f70b4
   Timer timeout_timer;
Packit 8f70b4
Packit 8f70b4
   Timer decline_timer;
Packit 8f70b4
   Timer optimistic_unchoke_timer;
Packit 8f70b4
   Timer peers_scan_timer;
Packit 8f70b4
   Timer am_interested_timer;
Packit 8f70b4
   Timer shutting_down_timer;
Packit 8f70b4
Packit 8f70b4
   Timer dht_announce_timer;
Packit 8f70b4
   int dht_announce_count;
Packit 8f70b4
   int dht_announce_count_ipv6;
Packit 8f70b4
Packit 8f70b4
   static const int max_uploaders = 20;
Packit 8f70b4
   static const int min_uploaders = 1;
Packit 8f70b4
   static const int max_downloaders = 20;
Packit 8f70b4
   static const int min_downloaders = 4;
Packit 8f70b4
Packit 8f70b4
   bool NeedMoreUploaders();
Packit 8f70b4
   bool AllowMoreDownloaders();
Packit 8f70b4
   void UnchokeBestUploaders();
Packit 8f70b4
   void ScanPeers();
Packit 8f70b4
   void OptimisticUnchoke();
Packit 8f70b4
   void ReducePeers();
Packit 8f70b4
   void ReduceUploaders();
Packit 8f70b4
   void ReduceDownloaders();
Packit 8f70b4
Packit 8f70b4
   int PeerBytesAllowed(const TorrentPeer *peer,RateLimit::dir_t dir);
Packit 8f70b4
   void PeerBytesUsed(int b,RateLimit::dir_t dir);
Packit 8f70b4
   void PeerBytesGot(int b) { PeerBytesUsed(b,RateLimit::GET); }
Packit 8f70b4
Packit 8f70b4
   static void BlackListPeer(const TorrentPeer *peer,const char *timeout);
Packit 8f70b4
   static bool BlackListed(const TorrentPeer *peer);
Packit 8f70b4
   TorrentPeer *FindPeerById(const xstring& p_id);
Packit 8f70b4
Packit 8f70b4
public:
Packit 8f70b4
   static void ClassInit();
Packit 8f70b4
Packit 8f70b4
   Torrent(const char *mf,const char *cwd,const char *output_dir);
Packit 8f70b4
   ~Torrent();
Packit 8f70b4
Packit 8f70b4
   int Do();
Packit 8f70b4
   int Done() const;
Packit 8f70b4
Packit 8f70b4
   const xstring& Status();
Packit 8f70b4
Packit 8f70b4
   const Error *GetInvalidCause() const { return invalid_cause; }
Packit 8f70b4
Packit 8f70b4
   void Shutdown();
Packit 8f70b4
   bool ShuttingDown() const { return shutting_down; }
Packit 8f70b4
   void PrepareToDie();
Packit 8f70b4
Packit 8f70b4
   bool CanAccept() const;
Packit 8f70b4
   void Accept(int s,const sockaddr_u *a,IOBuffer *rb);
Packit 8f70b4
   static bool NoTorrentCanAccept();
Packit 8f70b4
Packit 8f70b4
   static void SHA1(const xstring& str,xstring& buf);
Packit 8f70b4
   void ValidatePiece(unsigned p);
Packit 8f70b4
   unsigned PieceLength(unsigned p) const { return p==total_pieces-1 ? last_piece_length : piece_length; }
Packit 8f70b4
   unsigned BlocksInPiece(unsigned p) const { return p==total_pieces-1 ? blocks_in_last_piece : blocks_in_piece; }
Packit 8f70b4
Packit 8f70b4
   const TaskRefArray<TorrentPeer>& GetPeers() const { return peers; }
Packit 8f70b4
   void AddPeer(TorrentPeer *);
Packit 8f70b4
   void CleanPeers();
Packit 8f70b4
Packit 8f70b4
   const xstring& GetInfoHash() const { return info_hash; }
Packit 8f70b4
   int GetPeersCount() const { return peers.count(); }
Packit 8f70b4
   int GetConnectedPeersCount() const { return connected_peers_count; }
Packit 8f70b4
   int GetActivePeersCount() const { return active_peers_count; }
Packit 8f70b4
   int GetCompletePeersCount() const { return complete_peers_count; }
Packit 8f70b4
Packit 8f70b4
   bool Complete() const { return complete; }
Packit 8f70b4
   bool Private() const { return is_private; }
Packit 8f70b4
   double GetRatio() const;
Packit 8f70b4
   void CalcPiecesStats();
Packit 8f70b4
   void CalcPerPieceRatio();
Packit 8f70b4
   float GetMinPerPieceRatio() const { return current_min_ppr; }
Packit 8f70b4
   float GetMaxPerPieceRatio() const { return current_max_ppr; }
Packit 8f70b4
   unsigned MinPieceSources() const { return min_piece_sources; }
Packit 8f70b4
   double AvgPieceSources() const { return avg_piece_sources/256.; }
Packit 8f70b4
   unsigned PiecesAvailablePct() const { return pieces_available_pct; }
Packit 8f70b4
   unsigned long long TotalLength() const { return total_length; }
Packit 8f70b4
   unsigned PieceLength() const { return piece_length; }
Packit 8f70b4
   const char *GetName() const { return name?name.get():metainfo_url.get(); }
Packit 8f70b4
   bool IsDownloading() const { return HasMetadata() && !IsValidating() && !Complete() && !ShuttingDown(); }
Packit 8f70b4
Packit 8f70b4
   void Reconfig(const char *name);
Packit 8f70b4
   const char *GetLogContext() { return GetName(); }
Packit 8f70b4
Packit 8f70b4
   void ForceValid() { force_valid=true; }
Packit 8f70b4
   bool IsValidating() const { return validating; }
Packit 8f70b4
   void Share() { build_md=true; }
Packit 8f70b4
   bool IsSharing() const { return build_md; }
Packit 8f70b4
Packit 8f70b4
   void StopIfComplete() { stop_if_complete=true; }
Packit 8f70b4
   void StopIfKnown() { stop_if_known=stop_if_complete=true; }
Packit 8f70b4
Packit 8f70b4
   static int GetPort();
Packit 8f70b4
   static int GetPortIPv4() { return listener?listener->GetPort():0; }
Packit 8f70b4
#if INET6
Packit 8f70b4
   static int GetPortIPv6() { return listener_ipv6?listener_ipv6->GetPort():0; }
Packit 8f70b4
   static const char *GetAddressIPv6() { return listener_ipv6?listener_ipv6->GetAddress():"::"; }
Packit 8f70b4
#endif
Packit 8f70b4
   int GetWantedPeersCount() const;
Packit 8f70b4
   static const xstring& GetMyPeerId() { return my_peer_id; }
Packit 8f70b4
   static const xstring& GetMyKey() { return my_key; }
Packit 8f70b4
   static unsigned GetMyKeyNum() { return my_key_num; }
Packit 8f70b4
Packit 8f70b4
   unsigned long long GetTotalSent() { return total_sent; }
Packit 8f70b4
   unsigned long long GetTotalRecv() { return total_recv; }
Packit 8f70b4
   unsigned long long GetTotalLeft() { return total_left; }
Packit 8f70b4
Packit 8f70b4
   const TaskRefArray<TorrentTracker>& Trackers() { return trackers; }
Packit 8f70b4
   bool HasMetadata() const { return metadata!=0; }
Packit 8f70b4
   void RestartPeers();
Packit 8f70b4
Packit 8f70b4
   static void BootstrapDHT(const char *n) {
Packit 8f70b4
      StartDHT();
Packit 8f70b4
      if(dht)
Packit 8f70b4
	 dht->AddBootstrapNode(n);
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   static bool HasDHT() {
Packit 8f70b4
#if INET6
Packit 8f70b4
      if(dht_ipv6)
Packit 8f70b4
	 return true;
Packit 8f70b4
#endif
Packit 8f70b4
      if(dht)
Packit 8f70b4
	 return true;
Packit 8f70b4
      return false;
Packit 8f70b4
   }
Packit 8f70b4
   static bool HasDHT(int af) {
Packit 8f70b4
#if INET6
Packit 8f70b4
      if(af==AF_INET6 && dht_ipv6)
Packit 8f70b4
	 return true;
Packit 8f70b4
#endif
Packit 8f70b4
      if(af==AF_INET && dht)
Packit 8f70b4
	 return true;
Packit 8f70b4
      return false;
Packit 8f70b4
   }
Packit 8f70b4
   const char *DHT_Status() const;
Packit 8f70b4
   void DHT_Announced(int af);	 // called from DHT to count announces
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
class FDCache : public SMTask, public ResClient
Packit 8f70b4
{
Packit 8f70b4
   struct FD
Packit 8f70b4
   {
Packit 8f70b4
      int fd;
Packit 8f70b4
      int saved_errno;
Packit 8f70b4
      time_t last_used;
Packit 8f70b4
   };
Packit 8f70b4
   int max_count;
Packit 8f70b4
   int max_time;
Packit 8f70b4
   xmap<FD> cache[3];
Packit 8f70b4
   Timer clean_timer;
Packit 8f70b4
Packit 8f70b4
public:
Packit 8f70b4
   int OpenFile(const char *name,int mode,off_t size=0);
Packit 8f70b4
   void Close(const char *name);
Packit 8f70b4
   int Count() const;
Packit 8f70b4
   void Clean();
Packit 8f70b4
   bool CloseOne();
Packit 8f70b4
   void CloseAll();
Packit 8f70b4
   FDCache();
Packit 8f70b4
   ~FDCache();
Packit 8f70b4
Packit 8f70b4
   int Do();
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
class TorrentPeer : public SMTask, protected ProtoLog, public Networker
Packit 8f70b4
{
Packit 8f70b4
   friend class Torrent;
Packit 8f70b4
Packit 8f70b4
   Ref<Error> error;
Packit 8f70b4
   Torrent *parent;
Packit 8f70b4
Packit 8f70b4
   int tracker_no;
Packit 8f70b4
Packit 8f70b4
   sockaddr_u addr;
Packit 8f70b4
   int sock;
Packit 8f70b4
   int udp_port;
Packit 8f70b4
   bool connected;
Packit 8f70b4
   bool passive;
Packit 8f70b4
Packit 8f70b4
   xstring_c last_dc;
Packit 8f70b4
Packit 8f70b4
   Timer timeout_timer;
Packit 8f70b4
   Timer retry_timer;
Packit 8f70b4
   Timer keepalive_timer;
Packit 8f70b4
   Timer choke_timer;
Packit 8f70b4
   Timer interest_timer;
Packit 8f70b4
   Timer activity_timer;
Packit 8f70b4
Packit 8f70b4
   SMTaskRef<IOBuffer> recv_buf;
Packit 8f70b4
   SMTaskRef<IOBuffer> send_buf;
Packit 8f70b4
Packit 8f70b4
   unsigned long long peer_recv;
Packit 8f70b4
   unsigned long long peer_sent;
Packit 8f70b4
Packit 8f70b4
   Speedometer peer_recv_rate;
Packit 8f70b4
   Speedometer peer_send_rate;
Packit 8f70b4
Packit 8f70b4
   xstring peer_id;
Packit 8f70b4
   unsigned char extensions[8];
Packit 8f70b4
   TorrentPeer *duplicate;
Packit 8f70b4
   bool myself;
Packit 8f70b4
Packit 8f70b4
   bool FastExtensionEnabled() const { return extensions[7]&0x04; }
Packit 8f70b4
   bool LTEPExtensionEnabled() const { return extensions[5]&0x10; }
Packit 8f70b4
   bool DHT_Enabled() const { return extensions[7]&0x01; }
Packit 8f70b4
Packit 8f70b4
   bool am_choking;
Packit 8f70b4
   bool am_interested;
Packit 8f70b4
   bool peer_choking;
Packit 8f70b4
   bool peer_interested;
Packit 8f70b4
Packit 8f70b4
   bool upload_only;
Packit 8f70b4
Packit 8f70b4
   Ref<BitField> peer_bitfield;
Packit 8f70b4
   unsigned peer_complete_pieces;
Packit 8f70b4
Packit 8f70b4
   xqueue<unsigned,xarray<unsigned> > fast_set;
Packit 8f70b4
   bool InFastSet(unsigned) const;
Packit 8f70b4
   xqueue<unsigned,xarray<unsigned> > suggested_set;
Packit 8f70b4
Packit 8f70b4
   enum packet_type
Packit 8f70b4
   {
Packit 8f70b4
      MSG_KEEPALIVE=-1,
Packit 8f70b4
      MSG_CHOKE=0,
Packit 8f70b4
      MSG_UNCHOKE=1,
Packit 8f70b4
      MSG_INTERESTED=2,
Packit 8f70b4
      MSG_UNINTERESTED=3,
Packit 8f70b4
      MSG_HAVE=4,
Packit 8f70b4
      MSG_BITFIELD=5,
Packit 8f70b4
      MSG_REQUEST=6,
Packit 8f70b4
      MSG_PIECE=7,
Packit 8f70b4
      MSG_CANCEL=8,
Packit 8f70b4
      MSG_PORT=9,
Packit 8f70b4
      MSG_SUGGEST_PIECE=13,
Packit 8f70b4
      MSG_HAVE_ALL=14,
Packit 8f70b4
      MSG_HAVE_NONE=15,
Packit 8f70b4
      MSG_REJECT_REQUEST=16,
Packit 8f70b4
      MSG_ALLOWED_FAST=17,
Packit 8f70b4
      MSG_EXTENDED=20,
Packit 8f70b4
   };
Packit 8f70b4
   enum msg_ext_id
Packit 8f70b4
   {
Packit 8f70b4
      MSG_EXT_HANDSHAKE=0,
Packit 8f70b4
      MSG_EXT_PEX=1,
Packit 8f70b4
      MSG_EXT_METADATA=2,
Packit 8f70b4
   };
Packit 8f70b4
   enum ut_metadata_msg_id
Packit 8f70b4
   {
Packit 8f70b4
      UT_METADATA_REQUEST=0,
Packit 8f70b4
      UT_METADATA_DATA=1,
Packit 8f70b4
      UT_METADATA_REJECT=2,
Packit 8f70b4
   };
Packit 8f70b4
public:
Packit 8f70b4
   enum { TR_ACCEPTED=-1, TR_DHT=-2, TR_PEX=-3 };  // special values for tracker_no
Packit 8f70b4
   enum unpack_status_t
Packit 8f70b4
   {
Packit 8f70b4
      UNPACK_SUCCESS=0,
Packit 8f70b4
      UNPACK_WRONG_FORMAT=-1,
Packit 8f70b4
      UNPACK_PREMATURE_EOF=-2,
Packit 8f70b4
      UNPACK_NO_DATA_YET=1
Packit 8f70b4
   };
Packit 8f70b4
   class Packet
Packit 8f70b4
   {
Packit 8f70b4
      static bool is_valid_reply(int p)
Packit 8f70b4
      {
Packit 8f70b4
	 return (p>=0 && p<=MSG_PORT)
Packit 8f70b4
	    || (p>=MSG_SUGGEST_PIECE && p<=MSG_ALLOWED_FAST)
Packit 8f70b4
	    || p==MSG_EXTENDED;
Packit 8f70b4
      }
Packit 8f70b4
   protected:
Packit 8f70b4
      int length;
Packit 8f70b4
      int unpacked;
Packit 8f70b4
      packet_type type;
Packit 8f70b4
   public:
Packit 8f70b4
      Packet(packet_type t);
Packit 8f70b4
      Packet() { length=0; }
Packit 8f70b4
      virtual void ComputeLength() { length=(type>=0); }
Packit 8f70b4
      virtual void Pack(SMTaskRef<IOBuffer>& b);
Packit 8f70b4
      virtual unpack_status_t Unpack(const Buffer *b);
Packit 8f70b4
      virtual ~Packet() {}
Packit 8f70b4
      int GetLength() const { return length; }
Packit 8f70b4
      packet_type GetPacketType() const { return type; }
Packit 8f70b4
      const char *GetPacketTypeText() const;
Packit 8f70b4
      void DropData(SMTaskRef<IOBuffer>& b) { b->Skip(4+length); }
Packit 8f70b4
      bool TypeIs(packet_type t) const { return type==t; }
Packit 8f70b4
      static unpack_status_t UnpackBencoded(const Buffer *b,int *offset,int limit,Ref<BeNode> *out);
Packit 8f70b4
   };
Packit 8f70b4
   class _PacketPiece : public Packet
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      unsigned piece;
Packit 8f70b4
      _PacketPiece(packet_type t,unsigned p) : Packet(t), piece(p) { length+=4; }
Packit 8f70b4
      unpack_status_t Unpack(const Buffer *b)
Packit 8f70b4
	 {
Packit 8f70b4
	    unpack_status_t res;
Packit 8f70b4
	    res=Packet::Unpack(b);
Packit 8f70b4
	    if(res!=UNPACK_SUCCESS)
Packit 8f70b4
	       return res;
Packit 8f70b4
	    piece=b->UnpackUINT32BE(unpacked);
Packit 8f70b4
	    unpacked+=4;
Packit 8f70b4
	    return UNPACK_SUCCESS;
Packit 8f70b4
	 }
Packit 8f70b4
      void ComputeLength() { Packet::ComputeLength(); length+=4; }
Packit 8f70b4
      void Pack(SMTaskRef<IOBuffer>& b) { Packet::Pack(b); b->PackUINT32BE(piece); }
Packit 8f70b4
   };
Packit 8f70b4
   class PacketHave : public _PacketPiece {
Packit 8f70b4
   public:
Packit 8f70b4
      PacketHave(unsigned p=0) : _PacketPiece(MSG_HAVE,p) {}
Packit 8f70b4
   };
Packit 8f70b4
   class PacketBitField : public Packet
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      Ref<BitField> bitfield;
Packit 8f70b4
      PacketBitField() : Packet(MSG_BITFIELD) {}
Packit 8f70b4
      PacketBitField(const BitField *bf);
Packit 8f70b4
      ~PacketBitField();
Packit 8f70b4
      unpack_status_t Unpack(const Buffer *b);
Packit 8f70b4
      void ComputeLength();
Packit 8f70b4
      void Pack(SMTaskRef<IOBuffer>& b);
Packit 8f70b4
   };
Packit 8f70b4
   class _PacketIBL : public Packet
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      unsigned index,begin,req_length;
Packit 8f70b4
      _PacketIBL(packet_type t,unsigned i,unsigned b,unsigned l);
Packit 8f70b4
      unpack_status_t Unpack(const Buffer *b);
Packit 8f70b4
      void ComputeLength();
Packit 8f70b4
      void Pack(SMTaskRef<IOBuffer>& b);
Packit 8f70b4
   };
Packit 8f70b4
   class PacketRequest : public _PacketIBL
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      PacketRequest(unsigned i=0,unsigned b=0,unsigned l=0)
Packit 8f70b4
	 : _PacketIBL(MSG_REQUEST,i,b,l) {}
Packit 8f70b4
   };
Packit 8f70b4
   class PacketCancel : public _PacketIBL {
Packit 8f70b4
   public:
Packit 8f70b4
      PacketCancel(unsigned i=0,unsigned b=0,unsigned l=0)
Packit 8f70b4
	 : _PacketIBL(MSG_CANCEL,i,b,l) {}
Packit 8f70b4
   };
Packit 8f70b4
   class PacketPiece : public Packet
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      unsigned index,begin;
Packit 8f70b4
      xstring data;
Packit 8f70b4
      PacketPiece() : Packet(MSG_PIECE), index(0), begin(0) {}
Packit 8f70b4
      PacketPiece(unsigned i,unsigned b,const xstring &s)
Packit 8f70b4
	 : Packet(MSG_PIECE), index(i), begin(b) { data.set(s); length+=8+data.length(); }
Packit 8f70b4
      unpack_status_t Unpack(const Buffer *b)
Packit 8f70b4
	 {
Packit 8f70b4
	    unpack_status_t res;
Packit 8f70b4
	    res=Packet::Unpack(b);
Packit 8f70b4
	    if(res!=UNPACK_SUCCESS)
Packit 8f70b4
	       return res;
Packit 8f70b4
	    index=b->UnpackUINT32BE(unpacked);unpacked+=4;
Packit 8f70b4
	    begin=b->UnpackUINT32BE(unpacked);unpacked+=4;
Packit 8f70b4
	    unsigned bytes=length+4-unpacked;
Packit 8f70b4
	    data.nset(b->Get()+unpacked,bytes);
Packit 8f70b4
	    unpacked+=bytes;
Packit 8f70b4
	    return UNPACK_SUCCESS;
Packit 8f70b4
	 }
Packit 8f70b4
      void ComputeLength() { Packet::ComputeLength(); length+=8+data.length(); }
Packit 8f70b4
      void Pack(SMTaskRef<IOBuffer>& b) {
Packit 8f70b4
	 Packet::Pack(b);
Packit 8f70b4
	 b->PackUINT32BE(index);
Packit 8f70b4
	 b->PackUINT32BE(begin);
Packit 8f70b4
	 b->Put(data);
Packit 8f70b4
      }
Packit 8f70b4
   };
Packit 8f70b4
   class PacketPort : public Packet
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      unsigned port;
Packit 8f70b4
      PacketPort(unsigned p=0) : Packet(MSG_PORT), port(p) { length+=2; }
Packit 8f70b4
      unpack_status_t Unpack(const Buffer *b)
Packit 8f70b4
	 {
Packit 8f70b4
	    unpack_status_t res;
Packit 8f70b4
	    res=Packet::Unpack(b);
Packit 8f70b4
	    if(res!=UNPACK_SUCCESS)
Packit 8f70b4
	       return res;
Packit 8f70b4
	    port=b->UnpackUINT16BE(unpacked);
Packit 8f70b4
	    unpacked+=2;
Packit 8f70b4
	    return UNPACK_SUCCESS;
Packit 8f70b4
	 }
Packit 8f70b4
      void ComputeLength() { Packet::ComputeLength(); length+=2; }
Packit 8f70b4
      void Pack(SMTaskRef<IOBuffer>& b) { Packet::Pack(b); b->PackUINT16BE(port); }
Packit 8f70b4
   };
Packit 8f70b4
   class PacketSuggestPiece : public _PacketPiece {
Packit 8f70b4
   public:
Packit 8f70b4
      PacketSuggestPiece(unsigned p=0) : _PacketPiece(MSG_SUGGEST_PIECE,p) {}
Packit 8f70b4
   };
Packit 8f70b4
   class PacketAllowedFast : public _PacketPiece {
Packit 8f70b4
   public:
Packit 8f70b4
      PacketAllowedFast(unsigned p=0) : _PacketPiece(MSG_ALLOWED_FAST,p) {}
Packit 8f70b4
   };
Packit 8f70b4
   class PacketRejectRequest : public _PacketIBL {
Packit 8f70b4
   public:
Packit 8f70b4
      PacketRejectRequest(unsigned i=0,unsigned b=0,unsigned l=0)
Packit 8f70b4
	 : _PacketIBL(MSG_REJECT_REQUEST,i,b,l) {}
Packit 8f70b4
   };
Packit 8f70b4
   class PacketExtended : public Packet
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      unsigned char code;
Packit 8f70b4
      Ref<BeNode> data;
Packit 8f70b4
      xstring appendix;
Packit 8f70b4
      PacketExtended(unsigned char c='\0',BeNode *d=0)
Packit 8f70b4
	 : Packet(MSG_EXTENDED), code(c), data(d) { length++; if(data) length+=data->ComputeLength(); }
Packit 8f70b4
      unpack_status_t Unpack(const Buffer *b)
Packit 8f70b4
	 {
Packit 8f70b4
	    unpack_status_t res;
Packit 8f70b4
	    res=Packet::Unpack(b);
Packit 8f70b4
	    if(res!=UNPACK_SUCCESS)
Packit 8f70b4
	       return res;
Packit 8f70b4
	    code=b->UnpackUINT8(unpacked); unpacked++;
Packit 8f70b4
	    res=UnpackBencoded(b,&unpacked,length+4,&data);
Packit 8f70b4
	    if(unpacked
Packit 8f70b4
	       appendix.nset(b->Get()+unpacked,length+4-unpacked);
Packit 8f70b4
	       unpacked=length+4;
Packit 8f70b4
	    }
Packit 8f70b4
	    return res;
Packit 8f70b4
	 }
Packit 8f70b4
      void ComputeLength() { Packet::ComputeLength(); length++; if(data) length+=data->ComputeLength(); length+=appendix.length(); }
Packit 8f70b4
      void Pack(SMTaskRef<IOBuffer>& b) { Packet::Pack(b); b->PackUINT8(code); if(data) data->Pack(b); b->Put(appendix); }
Packit 8f70b4
      void SetAppendix(const char *s,int len) { appendix.nset(s,len); length+=len; }
Packit 8f70b4
   };
Packit 8f70b4
Packit 8f70b4
private:
Packit 8f70b4
   unpack_status_t UnpackPacket(SMTaskRef<IOBuffer>& ,Packet **);
Packit 8f70b4
   void HandlePacket(Packet *);
Packit 8f70b4
   void HandleExtendedMessage(PacketExtended *);
Packit 8f70b4
Packit 8f70b4
   static const int MAX_QUEUE_LEN = 16;
Packit 8f70b4
   RefQueue<PacketRequest> recv_queue;
Packit 8f70b4
   RefQueue<PacketRequest> sent_queue;
Packit 8f70b4
Packit 8f70b4
   unsigned last_piece;
Packit 8f70b4
   static const unsigned NO_PIECE = ~0U;
Packit 8f70b4
   void SetLastPiece(unsigned p);
Packit 8f70b4
   unsigned GetLastPiece() const;
Packit 8f70b4
   bool HasNeededPieces();
Packit 8f70b4
   void SetPieceHaving(unsigned p,bool have);
Packit 8f70b4
   void SetAmInterested(bool);
Packit 8f70b4
   void SetAmChoking(bool);
Packit 8f70b4
Packit 8f70b4
   void ClearSentQueue(int i);
Packit 8f70b4
   void ClearSentQueue() { ClearSentQueue(sent_queue.count()-1); }
Packit 8f70b4
Packit 8f70b4
   int FindRequest(unsigned piece,unsigned begin) const;
Packit 8f70b4
Packit 8f70b4
   void SetError(const char *);
Packit 8f70b4
   void SendHandshake();
Packit 8f70b4
   unpack_status_t RecvHandshake();
Packit 8f70b4
   void SendExtensions();
Packit 8f70b4
   void Disconnect(const char *dc=0);
Packit 8f70b4
   void Restart();
Packit 8f70b4
   int SendDataRequests(unsigned p);
Packit 8f70b4
   void SendDataRequests();
Packit 8f70b4
   void Have(unsigned p);
Packit 8f70b4
   void SendDataReply();
Packit 8f70b4
   void CancelBlock(unsigned p,unsigned b);
Packit 8f70b4
Packit 8f70b4
   void MarkPieceInvalid(unsigned p);
Packit 8f70b4
   unsigned invalid_piece_count;
Packit 8f70b4
Packit 8f70b4
   int peer_bytes_pool[2];
Packit 8f70b4
   int BytesAllowed(RateLimit::dir_t dir);
Packit 8f70b4
   bool BytesAllowed(RateLimit::dir_t dir,unsigned bytes);
Packit 8f70b4
   bool BytesAllowedToGet(unsigned b) { return BytesAllowed(RateLimit::GET,b); }
Packit 8f70b4
   bool BytesAllowedToPut(unsigned b) { return BytesAllowed(RateLimit::PUT,b); }
Packit 8f70b4
   void BytesUsed(int bytes,RateLimit::dir_t dir);
Packit 8f70b4
   void BytesGot(int b) { BytesUsed(b,RateLimit::GET); }
Packit 8f70b4
   void BytesPut(int b) { BytesUsed(b,RateLimit::PUT); }
Packit 8f70b4
Packit 8f70b4
   int msg_ext_metadata;
Packit 8f70b4
   int msg_ext_pex;
Packit 8f70b4
Packit 8f70b4
   size_t metadata_size;
Packit 8f70b4
   void SendMetadataRequest();
Packit 8f70b4
Packit 8f70b4
   struct ut_pex_data
Packit 8f70b4
   {
Packit 8f70b4
      xmap<char> sent; // key is compact addr
Packit 8f70b4
      Timer send_timer;
Packit 8f70b4
      Timer recv_timer;
Packit 8f70b4
      enum flags { ENCRYPTION=1, SEED=2, UTP=4, HOLEPUNCH=8, CONNECTABLE=16 };
Packit 8f70b4
      ut_pex_data() : send_timer(60), recv_timer(59) {}
Packit 8f70b4
   } pex;
Packit 8f70b4
   void AddPEXPeers(BeNode *added,BeNode *added_f,int addr_size);
Packit 8f70b4
   void SendPEXPeers();
Packit 8f70b4
Packit 8f70b4
public:
Packit 8f70b4
   int Do();
Packit 8f70b4
   TorrentPeer(Torrent *p,const sockaddr_u *a,int tracker_no);
Packit 8f70b4
   ~TorrentPeer();
Packit 8f70b4
   void PrepareToDie();
Packit 8f70b4
   void Connect(int s,IOBuffer *rb);
Packit 8f70b4
Packit 8f70b4
   bool Failed() const { return error!=0; }
Packit 8f70b4
   const char *ErrorText() const { return error->Text(); }
Packit 8f70b4
   const char *GetName() const;
Packit 8f70b4
   const char *GetLogContext() { return GetName(); }
Packit 8f70b4
Packit 8f70b4
   bool ActivityTimedOut() const { return activity_timer.Stopped(); }
Packit 8f70b4
   bool NotConnected() const { return sock==-1; }
Packit 8f70b4
   bool Disconnected() const { return passive && NotConnected(); }
Packit 8f70b4
   bool Connected() const { return peer_id && send_buf && recv_buf; }
Packit 8f70b4
   bool Active() const { return Connected() && (am_interested || peer_interested); }
Packit 8f70b4
   bool Complete() const { return peer_complete_pieces==parent->total_pieces && parent->total_pieces>0; }
Packit 8f70b4
   bool Seed() const { return Complete() || upload_only; }
Packit 8f70b4
   bool AddressEq(const TorrentPeer *o) const;
Packit 8f70b4
   bool IsPassive() const { return passive; }
Packit 8f70b4
   const sockaddr_u& GetAddress() const { return addr; }
Packit 8f70b4
Packit 8f70b4
   const char *Status();
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
class TorrentBlackList : private ProtoLog
Packit 8f70b4
{
Packit 8f70b4
   xmap_p<Timer> bl;
Packit 8f70b4
   void check_expire();
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
class TorrentDispatcher : public SMTask, protected ProtoLog
Packit 8f70b4
{
Packit 8f70b4
   int sock;
Packit 8f70b4
   const sockaddr_u addr;
Packit 8f70b4
   SMTaskRef<IOBuffer> recv_buf;
Packit 8f70b4
   Timer timeout_timer;
Packit 8f70b4
   xstring_c peer_name;
Packit 8f70b4
public:
Packit 8f70b4
   TorrentDispatcher(int s,const sockaddr_u *a);
Packit 8f70b4
   ~TorrentDispatcher();
Packit 8f70b4
   int Do();
Packit 8f70b4
   const char *GetLogContext() { return peer_name; }
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
#include "Job.h"
Packit 8f70b4
Packit 8f70b4
class TorrentJob : public Job
Packit 8f70b4
{
Packit 8f70b4
   SMTaskRef<Torrent> torrent;
Packit 8f70b4
   bool completed;
Packit 8f70b4
   bool done;
Packit 8f70b4
public:
Packit 8f70b4
   TorrentJob(Torrent *);
Packit 8f70b4
   ~TorrentJob();
Packit 8f70b4
   int Do();
Packit 8f70b4
   int Done() { return done; }
Packit 8f70b4
   xstring& FormatStatus(xstring&,int v,const char *tab);
Packit 8f70b4
   void ShowRunStatus(const SMTaskRef<StatusLine>& s);
Packit 8f70b4
   int AcceptSig(int);
Packit 8f70b4
   void PrepareToDie();
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
#endif//TORRENT_H