mirror of
https://github.com/rkd77/elinks.git
synced 2024-10-29 08:17:18 -04:00
439 lines
14 KiB
C
439 lines
14 KiB
C
|
|
#ifndef EL__PROTOCOL_BITTORRENT_COMMON_H
|
|
#define EL__PROTOCOL_BITTORRENT_COMMON_H
|
|
|
|
#include "main/timer.h"
|
|
#include "network/progress.h"
|
|
#include "network/socket.h"
|
|
#include "network/state.h"
|
|
#include "protocol/protocol.h"
|
|
#include "protocol/uri.h"
|
|
#include "util/error.h"
|
|
#include "util/lists.h"
|
|
#include "util/md5.h"
|
|
#include "util/sha1.h"
|
|
#include "util/time.h"
|
|
|
|
struct bitfield;
|
|
struct bittorrent_fetcher;
|
|
struct connection;
|
|
struct terminal;
|
|
|
|
/* The least acceptable default sharing rate. */
|
|
#define BITTORRENT_DEFAULT_SHARING_RATE 0.250
|
|
|
|
/* The number of seconds between updating the connection state and most
|
|
* importantly choke and unchoke peer connections. */
|
|
#define BITTORRENT_DEFAULT_CHOKE_INTERVAL 10
|
|
|
|
/* The length regarded as ``typical'' by the community wiki specification. */
|
|
/* Looks like Bram uses 2^14 here. */
|
|
/* Used for the protocol.bittorrent.request_length option */
|
|
#define BITTORRENT_REQUEST_LENGTH (1 << 14)
|
|
|
|
/* The length of requested blocks of pieces should not exceed 2^17 bytes. */
|
|
/* Used for the protocol.bittorrent.max_request_length option */
|
|
/* Bram uses 2^23 here. */
|
|
#define BITTORRENT_REQUEST_ACCEPT_LENGTH (1 << 23)
|
|
|
|
/* The maximum size to allow a peer message to have. */
|
|
/* Bram uses 2^23 here. */
|
|
#define BITTORRENT_MESSAGE_MAX_SIZE (1 << 23)
|
|
|
|
|
|
/* 20-byte string ID used for both peer IDs and info-hashes. */
|
|
typedef sha1_digest_bin_T bittorrent_id_T;
|
|
|
|
/* Special peer ID used for determining whether an ID has been set. */
|
|
const bittorrent_id_T BITTORRENT_NULL_ID;
|
|
|
|
#define bittorrent_id_is_empty(id) \
|
|
(!memcmp(id, BITTORRENT_NULL_ID, sizeof(bittorrent_id_T)))
|
|
|
|
|
|
/* BitTorrent error states. */
|
|
enum bittorrent_state {
|
|
BITTORRENT_STATE_OK, /* All is well. */
|
|
BITTORRENT_STATE_ERROR, /* Some error happened. */
|
|
BITTORRENT_STATE_REQUEST_FAILURE, /* Failure from tracker. */
|
|
BITTORRENT_STATE_OUT_OF_MEM, /* Allocation failure. */
|
|
BITTORRENT_STATE_CACHE_FAILURE, /* Cache data access failed. */
|
|
BITTORRENT_STATE_CACHE_RESUME, /* Resume state from disk.. */
|
|
BITTORRENT_STATE_FILE_MISSING, /* File does not exist. */
|
|
};
|
|
|
|
/* For showing tracker failure responses to the user. */
|
|
struct bittorrent_message {
|
|
LIST_HEAD(struct bittorrent_message);
|
|
|
|
struct uri *uri;
|
|
enum connection_state state;
|
|
unsigned char string[1];
|
|
};
|
|
|
|
|
|
/* ************************************************************************** */
|
|
/* Peer-wire types: */
|
|
/* ************************************************************************** */
|
|
|
|
/* BitTorrent peer-wire state and message IDs. */
|
|
enum bittorrent_message_id {
|
|
/* Special internal state and message type. */
|
|
BITTORRENT_MESSAGE_ERROR = -3,
|
|
BITTORRENT_MESSAGE_INCOMPLETE = -2,
|
|
BITTORRENT_MESSAGE_KEEP_ALIVE = -1,
|
|
|
|
/* Valid message types. */
|
|
BITTORRENT_MESSAGE_CHOKE = 0,
|
|
BITTORRENT_MESSAGE_UNCHOKE = 1,
|
|
BITTORRENT_MESSAGE_INTERESTED = 2,
|
|
BITTORRENT_MESSAGE_NOT_INTERESTED = 3,
|
|
BITTORRENT_MESSAGE_HAVE = 4,
|
|
BITTORRENT_MESSAGE_BITFIELD = 5,
|
|
BITTORRENT_MESSAGE_REQUEST = 6,
|
|
BITTORRENT_MESSAGE_PIECE = 7,
|
|
BITTORRENT_MESSAGE_CANCEL = 8,
|
|
};
|
|
|
|
/* The peer request matches information sent in the request and cancel messages
|
|
* in the peer-wire protocol. See the piece cache header file (cache.h) for more
|
|
* information about the cloned flag. */
|
|
struct bittorrent_peer_request {
|
|
LIST_HEAD(struct bittorrent_peer_request);
|
|
|
|
uint32_t piece; /* Zero-based piece index. */
|
|
uint32_t offset; /* Zero-based piece byte offset. */
|
|
uint32_t length; /* The wanted number of bytes. */
|
|
|
|
uint16_t block; /* The block index in the piece. */
|
|
|
|
/* This holds the message id when the request struct is used for queuing
|
|
* pending messages. */
|
|
char id; /* -> enum bittorrent_message_id */
|
|
|
|
unsigned int cloned:1; /* The request was cloned. */
|
|
unsigned int requested:1; /* Whether it has been requested. */
|
|
};
|
|
|
|
struct bittorrent_peer_status {
|
|
/* FIFO-like recording of requests. */
|
|
struct list_head requests; /* -> struct bittorrent_peer_request */
|
|
|
|
/* Flags for scheduling updating of the peer state. */
|
|
unsigned int choked:1; /* The peer was choked. */
|
|
unsigned int interested:1; /* The peer is interested. */
|
|
unsigned int snubbed:1; /* The peer was snubbed. */
|
|
|
|
/* State flags used for determining what to accept. */
|
|
unsigned int handshake:1; /* The handshake was sent. */
|
|
unsigned int bitfield:1; /* The bitfield was sent. */
|
|
unsigned int initiater:1; /* Initiater of the connection. */
|
|
unsigned int seeder:1; /* The peer has the complete torrent. */
|
|
};
|
|
|
|
struct bittorrent_peer_stats {
|
|
time_t last_time;
|
|
time_t age;
|
|
|
|
double download_rate;
|
|
double have_rate;
|
|
|
|
off_t downloaded;
|
|
off_t uploaded;
|
|
};
|
|
|
|
/* Peer connection information. */
|
|
struct bittorrent_peer_connection {
|
|
LIST_HEAD(struct bittorrent_peer_connection);
|
|
|
|
/* Unique peer ID string which can be used to look-up the peer hash. */
|
|
bittorrent_id_T id;
|
|
|
|
/* Timer handle for scheduling timeouts. */
|
|
timer_id_T timer;
|
|
|
|
/* Socket information. */
|
|
struct socket *socket;
|
|
|
|
/* Progress information and counter for the number of uploaded or
|
|
* downloaded bytes depending on the mode. */
|
|
struct bittorrent_peer_stats stats;
|
|
|
|
/* The BitTorrent connection the peer connection is associated with.
|
|
* For recently accepted peer connections it might be NULL indicating
|
|
* that the info_hash has not yet been read from the handshake. */
|
|
struct bittorrent_connection *bittorrent;
|
|
|
|
/* Local client and remote peer status info. */
|
|
struct bittorrent_peer_status local;
|
|
struct bittorrent_peer_status remote;
|
|
|
|
/* Outgoing message queue. Note piece messages are maintained entirely
|
|
* in the request list in the bittorrent_peer_status struct. */
|
|
struct list_head queue; /* -> struct bittorrent_peer_request */
|
|
|
|
/* A bitfield of the available pieces from the peer. */
|
|
/* The size depends on the number of pieces. */
|
|
struct bitfield *bitfield;
|
|
};
|
|
|
|
|
|
/* ************************************************************************** */
|
|
/* Tracker types: */
|
|
/* ************************************************************************** */
|
|
|
|
/* Event state information needed by the tracker. */
|
|
enum bittorrent_tracker_event {
|
|
BITTORRENT_EVENT_STARTED = 0, /* XXX: Zero, to always send first */
|
|
BITTORRENT_EVENT_STOPPED, /* Graceful shut down */
|
|
BITTORRENT_EVENT_COMPLETED, /* Download was completed */
|
|
BITTORRENT_EVENT_REGULAR, /* Regular (periodical) tracker request */
|
|
};
|
|
|
|
/* This stores info about tracker requests. */
|
|
/* It is not a real connection because it consists of a series of HTTP requests
|
|
* but both the tracker and client is supposed to keep state information across
|
|
* all requests. */
|
|
struct bittorrent_tracker_connection {
|
|
/* Used for keeping track of when to send event info to the tracker. */
|
|
enum bittorrent_tracker_event event;
|
|
|
|
/* Time in seconds between contacting the tracker and a timer handle. */
|
|
timer_id_T timer;
|
|
int interval;
|
|
|
|
/* Requesting the tracker failed or was never started so no
|
|
* event=stopped should be sent. */
|
|
unsigned int failed:1;
|
|
unsigned int started:1;
|
|
};
|
|
|
|
|
|
/* ************************************************************************** */
|
|
/* Metafile types: */
|
|
/* ************************************************************************** */
|
|
|
|
/* Information about peers returned by the tracker. */
|
|
struct bittorrent_peer {
|
|
LIST_HEAD(struct bittorrent_peer);
|
|
|
|
bittorrent_id_T id; /* Unique peer ID string. */
|
|
uint16_t port; /* The port number to connect to. */
|
|
unsigned char ip[1]; /* String with a IPv4 or IPv6 address. */
|
|
};
|
|
|
|
/* Information about a file in the torrent. */
|
|
struct bittorrent_file {
|
|
LIST_HEAD(struct bittorrent_file);
|
|
|
|
off_t length; /* Length of the file in bytes. */
|
|
md5_digest_hex_T md5sum; /* Hexadecimal MD5 sum of the file. */
|
|
int selected;
|
|
unsigned char name[1]; /* Filename converted from path list. */
|
|
};
|
|
|
|
/* Static information from the .torrent metafile. */
|
|
struct bittorrent_meta {
|
|
/* The SHA1 info hash of the value of the info key from the metainfo
|
|
* .torrent file is used regularly when connecting to both the tracker
|
|
* and peers. */
|
|
bittorrent_id_T info_hash;
|
|
|
|
/* Optional information about the creation time of the torrent. */
|
|
/* Used if the document.download.set_original_time is true. */
|
|
time_t creation_date;
|
|
|
|
/* Optional comment in free-form text. */
|
|
unsigned char *comment;
|
|
|
|
/* The announced URI of each available tracker. */
|
|
struct uri_list tracker_uris;
|
|
|
|
/* The number of pieces. */
|
|
uint32_t pieces;
|
|
|
|
/* The number of bytes in each piece. The last piece can be shorter
|
|
* than the others. */
|
|
uint32_t piece_length;
|
|
uint32_t last_piece_length;
|
|
|
|
/* List of concatenated SHA1 hash values for each piece. */
|
|
unsigned char *piece_hash;
|
|
|
|
/* The type of the torrent. */
|
|
enum { BITTORRENT_SINGLE_FILE, BITTORRENT_MULTI_FILE } type;
|
|
|
|
unsigned int malicious_paths:1; /* Potential bad file path detected. */
|
|
|
|
/* The name of either the single file or the top-most directory. */
|
|
unsigned char *name;
|
|
|
|
/* A list with information about files in the torrent. */
|
|
/* The list is a singleton for single-file torrents. */
|
|
struct list_head files; /* -> struct bittorrent_file */
|
|
};
|
|
|
|
enum bittorrent_connection_mode {
|
|
BITTORRENT_MODE_PIECELESS, /* The client has no piece to share. */
|
|
BITTORRENT_MODE_NORMAL, /* The client is up- and downloading. */
|
|
BITTORRENT_MODE_END_GAME, /* All remaining pieces are requested. */
|
|
BITTORRENT_MODE_SEEDER, /* The client is only uploading. */
|
|
};
|
|
|
|
/* This stores info about an active BitTorrent connection. Note, the list head
|
|
* is used by the handling of the peer-wire listening socket and should only be
|
|
* managed by that. */
|
|
struct bittorrent_connection {
|
|
LIST_HEAD(struct bittorrent_connection);
|
|
|
|
enum bittorrent_connection_mode mode;
|
|
|
|
/* Static information from the .torrent metafile. */
|
|
struct bittorrent_meta meta;
|
|
|
|
/* Dynamic tracker information. */
|
|
struct bittorrent_tracker_connection tracker;
|
|
|
|
/* Dynamic tracker information. */
|
|
struct bittorrent_piece_cache *cache;
|
|
|
|
/* Back-reference to the connection the bittorrent connection belongs
|
|
* to. */
|
|
struct connection *conn;
|
|
|
|
/* Active peer list */
|
|
/* The size is controlled by the protocol.bittorrent.max_active_peers
|
|
* option. */
|
|
struct list_head peers; /* -> struct bittorrent_peer_connection */
|
|
|
|
/* List of information about potential peers. */
|
|
/* TODO: Use hash. */
|
|
struct list_head peer_pool; /* -> struct bittorrent_peer */
|
|
|
|
/* The peer ID of the client. */
|
|
bittorrent_id_T peer_id;
|
|
|
|
/* The port of the listening socket */
|
|
uint16_t port;
|
|
|
|
/* Timer handle for scheduling periodic updating and rating of peer
|
|
* connections. */
|
|
timer_id_T timer;
|
|
|
|
/* Statistics for the tracker and total progress information for the
|
|
* user interface. */
|
|
struct progress upload_progress;
|
|
off_t uploaded;
|
|
off_t downloaded;
|
|
off_t left;
|
|
|
|
/* Number of seeders and leechers. */
|
|
uint32_t complete;
|
|
uint32_t incomplete;
|
|
|
|
double sharing_rate;
|
|
|
|
/* Information about any running metainfo file or tracker request. */
|
|
struct bittorrent_fetcher *fetch;
|
|
|
|
/* For notifying on completion. May be NULL. */
|
|
struct terminal *term;
|
|
};
|
|
|
|
|
|
static inline uint32_t
|
|
get_bittorrent_piece_length(struct bittorrent_meta *meta, uint32_t piece)
|
|
{
|
|
return piece == meta->pieces - 1
|
|
? meta->last_piece_length : meta->piece_length;
|
|
}
|
|
|
|
unsigned char *get_hexed_bittorrent_id(bittorrent_id_T id);
|
|
|
|
|
|
int
|
|
bittorrent_piece_is_valid(struct bittorrent_meta *meta,
|
|
uint32_t piece, unsigned char *data, uint32_t datalen);
|
|
|
|
void init_bittorrent_peer_id(bittorrent_id_T peer_id);
|
|
|
|
int
|
|
bittorrent_id_is_known(struct bittorrent_connection *bittorrent,
|
|
bittorrent_id_T id);
|
|
|
|
enum bittorrent_state
|
|
add_peer_to_bittorrent_pool(struct bittorrent_connection *bittorrent,
|
|
bittorrent_id_T id, int port,
|
|
unsigned char *ip, int iplen);
|
|
|
|
struct bittorrent_peer *
|
|
get_peer_from_bittorrent_pool(struct bittorrent_connection *bittorrent,
|
|
bittorrent_id_T id);
|
|
|
|
void done_bittorrent_meta(struct bittorrent_meta *meta);
|
|
void done_bittorrent_message(struct bittorrent_message *message);
|
|
|
|
|
|
/* ************************************************************************** */
|
|
/* Debug 'pretty printing' functions: */
|
|
/* ************************************************************************** */
|
|
|
|
unsigned char *get_peer_id(bittorrent_id_T peer);
|
|
unsigned char *get_peer_message(enum bittorrent_message_id message_id);
|
|
|
|
/* ************************************************************************** */
|
|
/* Peer request management: */
|
|
/* ************************************************************************** */
|
|
|
|
struct bittorrent_peer_request *
|
|
get_bittorrent_peer_request(struct bittorrent_peer_status *status,
|
|
uint32_t piece, uint32_t offset, uint32_t length);
|
|
|
|
void
|
|
add_bittorrent_peer_request(struct bittorrent_peer_status *status,
|
|
uint32_t piece, uint32_t offset, uint32_t length);
|
|
|
|
void
|
|
del_bittorrent_peer_request(struct bittorrent_peer_status *status,
|
|
uint32_t piece, uint32_t offset, uint32_t length);
|
|
|
|
|
|
/* ************************************************************************** */
|
|
/* URI fetching: */
|
|
/* ************************************************************************** */
|
|
|
|
typedef void (*bittorrent_fetch_callback_T)(void *, enum connection_state, struct string *);
|
|
|
|
struct bittorrent_fetcher *
|
|
init_bittorrent_fetch(struct bittorrent_fetcher **fetcher_ref,
|
|
struct uri *uri, bittorrent_fetch_callback_T callback,
|
|
void *data, int delete);
|
|
void done_bittorrent_fetch(struct bittorrent_fetcher **fetcher_ref);
|
|
|
|
|
|
/* ************************************************************************** */
|
|
/* Blacklisting: */
|
|
/* ************************************************************************** */
|
|
|
|
enum bittorrent_blacklist_flags {
|
|
BITTORRENT_BLACKLIST_NONE, /* No blacklisting is in effect */
|
|
BITTORRENT_BLACKLIST_PEER_POOL, /* Blacklist from peer pool. */
|
|
BITTORRENT_BLACKLIST_MALICIOUS, /* Malicious peer, refuse connection */
|
|
BITTORRENT_BLACKLIST_BEHAVIOUR, /* Unfair behaviour, refuse connection */
|
|
};
|
|
|
|
void
|
|
add_bittorrent_blacklist_flags(bittorrent_id_T peer_id,
|
|
enum bittorrent_blacklist_flags flags);
|
|
|
|
void
|
|
del_bittorrent_blacklist_flags(bittorrent_id_T peer_id,
|
|
enum bittorrent_blacklist_flags flags);
|
|
|
|
enum bittorrent_blacklist_flags
|
|
get_bittorrent_blacklist_flags(bittorrent_id_T peer_id);
|
|
|
|
void done_bittorrent_blacklist(void);
|
|
|
|
#endif
|