|
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
|