o Unhook cli_if.c from build temporarily. It needs to be fixed. o Torrent meta data is now kept in subdirectories to $BTPD_HOME/library. o Added some very incomplete life cycle logic for torrents.master
@@ -3,11 +3,11 @@ btpd_SOURCES=\ | |||
main.c util.c\ | |||
btpd.c btpd.h\ | |||
opts.c opts.h\ | |||
cli_if.c\ | |||
net.c net.h\ | |||
net_buf.c net_buf.h\ | |||
queue.h \ | |||
peer.c peer.h\ | |||
content.c content.h\ | |||
download.c download_subr.c download.h\ | |||
torrent.c torrent.h\ | |||
tracker_req.c tracker_req.h\ | |||
@@ -52,7 +52,7 @@ btpd_shutdown(void) | |||
tp = BTPDQ_FIRST(&m_torrents); | |||
while (tp != NULL) { | |||
struct torrent *next = BTPDQ_NEXT(tp, entry); | |||
torrent_unload(tp); | |||
torrent_deactivate(tp); | |||
tp = next; | |||
} | |||
btpd_log(BTPD_L_BTPD, "Exiting.\n"); | |||
@@ -136,6 +136,30 @@ btpd_get_peer_id(void) | |||
return m_peer_id; | |||
} | |||
static int | |||
nodot(struct dirent *dp) | |||
{ | |||
return !(strcmp(".", dp->d_name) == 0 || strcmp("..", dp->d_name) == 0); | |||
} | |||
static void | |||
load_library(void) | |||
{ | |||
int ne; | |||
struct dirent **entries; | |||
if ((ne = scandir("library", &entries, nodot, NULL)) < 0) | |||
btpd_err("Couldn't open the library.\n"); | |||
for (int i = 0; i < ne; i++) { | |||
struct torrent *tp; | |||
struct dirent *e = entries[i]; | |||
if (torrent_create(&tp, e->d_name) == 0) | |||
btpd_add_torrent(tp); | |||
free(e); | |||
} | |||
free(entries); | |||
} | |||
extern void ipc_init(void); | |||
void | |||
@@ -148,9 +172,15 @@ btpd_init(void) | |||
m_peer_id[i] = rand_between(0, 255); | |||
net_init(); | |||
ipc_init(); | |||
//ipc_init(); | |||
ul_init(); | |||
load_library(); | |||
struct torrent *tp; | |||
BTPDQ_FOREACH(tp, &m_torrents, entry) | |||
torrent_activate(tp); | |||
signal(SIGPIPE, SIG_IGN); | |||
signal_set(&m_sigint, SIGINT, signal_cb, NULL); | |||
@@ -25,7 +25,7 @@ | |||
#include "download.h" | |||
#include "upload.h" | |||
#include "subr.h" | |||
#include "content.h" | |||
#include "opts.h" | |||
#define BTPD_VERSION (PACKAGE_NAME "/" PACKAGE_VERSION) | |||
@@ -1,5 +1,4 @@ | |||
#include <sys/types.h> | |||
#include <sys/mman.h> | |||
#include <math.h> | |||
#include "btpd.h" | |||
#include "tracker_req.h" | |||
@@ -7,6 +6,10 @@ | |||
void | |||
dl_start(struct torrent *tp) | |||
{ | |||
BTPDQ_INIT(&tp->getlst); | |||
tp->busy_field = btpd_calloc((size_t)ceil(tp->meta.npieces / 8.0), 1); | |||
tp->piece_count = btpd_calloc(tp->meta.npieces, | |||
sizeof(*(tp->piece_count))); | |||
} | |||
void | |||
@@ -15,6 +18,8 @@ dl_stop(struct torrent *tp) | |||
struct piece *pc; | |||
while ((pc = BTPDQ_FIRST(&tp->getlst)) != NULL) | |||
piece_free(pc); | |||
free(tp->busy_field); | |||
free(tp->piece_count); | |||
} | |||
/* | |||
@@ -28,7 +33,7 @@ dl_on_piece_ann(struct peer *p, uint32_t index) | |||
{ | |||
struct torrent *tp = p->tp; | |||
tp->piece_count[index]++; | |||
if (has_bit(tp->piece_field, index)) | |||
if (cm_has_piece(tp, index)) | |||
return; | |||
struct piece *pc = dl_find_piece(tp, index); | |||
if (tp->endgame) { | |||
@@ -98,10 +103,6 @@ dl_on_ok_piece(struct piece *pc) | |||
btpd_log(BTPD_L_POL, "Got piece: %u.\n", pc->index); | |||
set_bit(tp->piece_field, pc->index); | |||
tp->have_npieces++; | |||
msync(tp->imem, tp->isiz, MS_ASYNC); | |||
struct net_buf *have = nb_create_have(pc->index); | |||
BTPDQ_FOREACH(p, &tp->peers, p_entry) | |||
peer_send(p, have); | |||
@@ -114,7 +115,7 @@ dl_on_ok_piece(struct piece *pc) | |||
assert(pc->nreqs == 0); | |||
piece_free(pc); | |||
if (torrent_has_all(tp)) { | |||
if (cm_full(tp)) { | |||
btpd_log(BTPD_L_BTPD, "Finished: %s.\n", tp->relpath); | |||
tracker_req(tp, TR_COMPLETED); | |||
BTPDQ_FOREACH(p, &tp->peers, p_entry) | |||
@@ -133,13 +134,11 @@ dl_on_bad_piece(struct piece *pc) | |||
btpd_log(BTPD_L_ERROR, "Bad hash for piece %u of %s.\n", | |||
pc->index, tp->relpath); | |||
for (uint32_t i = 0; i < pc->nblocks; i++) { | |||
for (uint32_t i = 0; i < pc->nblocks; i++) | |||
clear_bit(pc->down_field, i); | |||
clear_bit(pc->have_field, i); | |||
} | |||
pc->ngot = 0; | |||
pc->nbusy = 0; | |||
msync(tp->imem, tp->isiz, MS_ASYNC); | |||
if (tp->endgame) { | |||
struct peer *p; | |||
@@ -177,10 +176,7 @@ dl_on_block(struct peer *p, struct block_request *req, | |||
struct block *blk = req->blk; | |||
struct piece *pc = blk->pc; | |||
off_t cbegin = index * p->tp->meta.piece_length + begin; | |||
torrent_put_bytes(p->tp, data, cbegin, length); | |||
set_bit(pc->have_field, begin / PIECE_BLOCKLEN); | |||
cm_put_block(p->tp, index, begin / PIECE_BLOCKLEN, data); | |||
pc->ngot++; | |||
if (tp->endgame) { | |||
@@ -204,7 +200,7 @@ dl_on_block(struct peer *p, struct block_request *req, | |||
} | |||
BTPDQ_INIT(&blk->reqs); | |||
if (pc->ngot == pc->nblocks) | |||
dl_on_piece(pc); | |||
cm_test_piece(pc); | |||
} else { | |||
BTPDQ_REMOVE(&blk->reqs, req, blk_entry); | |||
free(req); | |||
@@ -213,7 +209,7 @@ dl_on_block(struct peer *p, struct block_request *req, | |||
clear_bit(pc->down_field, begin / PIECE_BLOCKLEN); | |||
pc->nbusy--; | |||
if (pc->ngot == pc->nblocks) | |||
dl_on_piece(pc); | |||
cm_test_piece(pc); | |||
if (peer_leech_ok(p) && !peer_laden(p)) | |||
dl_assign_requests(p); | |||
} | |||
@@ -7,7 +7,6 @@ int piece_full(struct piece *pc); | |||
void piece_free(struct piece *pc); | |||
void dl_on_piece_unfull(struct piece *pc); | |||
void dl_on_piece(struct piece *pc); | |||
struct piece *dl_new_piece(struct torrent *tp, uint32_t index); | |||
struct piece *dl_find_piece(struct torrent *tp, uint32_t index); | |||
@@ -47,9 +47,7 @@ piece_alloc(struct torrent *tp, uint32_t index) | |||
pc = btpd_calloc(1, mem); | |||
pc->tp = tp; | |||
pc->down_field = (uint8_t *)(pc + 1); | |||
pc->have_field = | |||
tp->block_field + | |||
index * (size_t)ceil(tp->meta.piece_length / (double)(1 << 17)); | |||
pc->have_field = cm_get_block_field(tp, index); | |||
pc->index = index; | |||
pc->nblocks = nblocks; | |||
@@ -60,6 +58,7 @@ piece_alloc(struct torrent *tp, uint32_t index) | |||
for (unsigned i = 0; i < nblocks; i++) | |||
if (has_bit(pc->have_field, i)) | |||
pc->ngot++; | |||
assert(pc->ngot < pc->nblocks); | |||
pc->blocks = (struct block *)(pc->down_field + field); | |||
for (unsigned i = 0; i < nblocks; i++) { | |||
@@ -108,7 +107,7 @@ static int | |||
dl_should_enter_endgame(struct torrent *tp) | |||
{ | |||
int should; | |||
if (tp->have_npieces + tp->npcs_busy == tp->meta.npieces) { | |||
if (cm_get_npieces(tp) + tp->npcs_busy == tp->meta.npieces) { | |||
should = 1; | |||
struct piece *pc; | |||
BTPDQ_FOREACH(pc, &tp->getlst, entry) { | |||
@@ -195,79 +194,10 @@ dl_find_piece(struct torrent *tp, uint32_t index) | |||
return pc; | |||
} | |||
static int | |||
test_hash(struct torrent *tp, uint8_t *hash, unsigned long index) | |||
{ | |||
if (tp->meta.piece_hash != NULL) | |||
return memcmp(hash, tp->meta.piece_hash[index], SHA_DIGEST_LENGTH); | |||
else { | |||
char piece_hash[SHA_DIGEST_LENGTH]; | |||
int fd; | |||
int bufi; | |||
int err; | |||
err = vopen(&fd, O_RDONLY, "%s/torrent", tp->relpath); | |||
if (err != 0) | |||
btpd_err("test_hash: %s\n", strerror(err)); | |||
err = lseek(fd, tp->meta.pieces_off + index * SHA_DIGEST_LENGTH, | |||
SEEK_SET); | |||
if (err < 0) | |||
btpd_err("test_hash: %s\n", strerror(errno)); | |||
bufi = 0; | |||
while (bufi < SHA_DIGEST_LENGTH) { | |||
ssize_t nread = | |||
read(fd, piece_hash + bufi, SHA_DIGEST_LENGTH - bufi); | |||
bufi += nread; | |||
} | |||
close(fd); | |||
return memcmp(hash, piece_hash, SHA_DIGEST_LENGTH); | |||
} | |||
} | |||
static int | |||
ro_fd_cb(const char *path, int *fd, void *arg) | |||
{ | |||
struct torrent *tp = arg; | |||
return vopen(fd, O_RDONLY, "%s/content/%s", tp->relpath, path); | |||
} | |||
static void | |||
torrent_test_piece(struct piece *pc) | |||
{ | |||
struct torrent *tp = pc->tp; | |||
int err; | |||
uint8_t hash[20]; | |||
struct bt_stream_ro *bts; | |||
off_t plen = torrent_piece_size(tp, pc->index); | |||
if ((bts = bts_open_ro(&tp->meta, pc->index * tp->meta.piece_length, | |||
ro_fd_cb, tp)) == NULL) | |||
btpd_err("Out of memory.\n"); | |||
if ((err = bts_sha(bts, plen, hash)) != 0) | |||
btpd_err("Ouch! %s\n", strerror(err)); | |||
bts_close_ro(bts); | |||
if (test_hash(tp, hash, pc->index) == 0) | |||
dl_on_ok_piece(pc); | |||
else | |||
dl_on_bad_piece(pc); | |||
} | |||
void | |||
dl_on_piece(struct piece *pc) | |||
{ | |||
torrent_test_piece(pc); | |||
} | |||
static int | |||
dl_piece_startable(struct peer *p, uint32_t index) | |||
{ | |||
return peer_has(p, index) && !has_bit(p->tp->piece_field, index) | |||
return peer_has(p, index) && !cm_has_piece(p->tp, index) | |||
&& !has_bit(p->tp->busy_field, index); | |||
} | |||
@@ -319,10 +249,9 @@ dl_choose_rarest(struct peer *p, uint32_t *res) | |||
} | |||
/* | |||
* Called from either dl_piece_assign_requests or dl_new_piece, | |||
* when a pice becomes full. The wanted level of the peers | |||
* that has this piece will be decreased. This function is | |||
* the only one that may trigger end game. | |||
* Called from dl_piece_assign_requests when a piece becomes full. | |||
* The wanted level of the peers that has this piece will be decreased. | |||
* This function is the only one that may trigger end game. | |||
*/ | |||
static void | |||
dl_on_piece_full(struct piece *pc) | |||
@@ -349,15 +278,7 @@ struct piece * | |||
dl_new_piece(struct torrent *tp, uint32_t index) | |||
{ | |||
btpd_log(BTPD_L_POL, "Started on piece %u.\n", index); | |||
struct piece *pc = piece_alloc(tp, index); | |||
if (pc->ngot == pc->nblocks) { | |||
dl_on_piece_full(pc); | |||
dl_on_piece(pc); | |||
if (dl_should_enter_endgame(tp)) | |||
dl_enter_endgame(tp); | |||
return NULL; | |||
} else | |||
return pc; | |||
return piece_alloc(tp, index); | |||
} | |||
/* | |||
@@ -57,6 +57,9 @@ setup_daemon(const char *dir) | |||
if (chdir(dir) != 0) | |||
err(1, "Couldn't change working directory to '%s'", dir); | |||
if (mkdir("library", 0777) == -1 && errno != EEXIST) | |||
err(1, "Couldn't create library"); | |||
pidfd = open("pid", O_CREAT|O_WRONLY|O_NONBLOCK|O_EXLOCK, 0666); | |||
if (pidfd == -1) | |||
err(1, "Couldn't open 'pid'"); | |||
@@ -170,9 +173,9 @@ args_done: | |||
event_init(); | |||
btpd_init(); | |||
torrent_load("test"); | |||
event_dispatch(); | |||
btpd_err("Unexpected exit from libevent.\n"); | |||
return 1; | |||
@@ -208,7 +208,7 @@ net_dispatch_msg(struct peer *p, const char *buf) | |||
length = net_read32(buf + 8); | |||
if ((length > PIECE_BLOCKLEN | |||
|| index >= p->tp->meta.npieces | |||
|| !has_bit(p->tp->piece_field, index) | |||
|| cm_has_piece(p->tp, index) | |||
|| begin + length > torrent_piece_size(p->tp, index))) { | |||
btpd_log(BTPD_L_MSG, "bad request: (%u, %u, %u) from %p\n", | |||
index, begin, length, p); | |||
@@ -121,9 +121,10 @@ nb_create_have(uint32_t index) | |||
struct net_buf * | |||
nb_create_multihave(struct torrent *tp) | |||
{ | |||
struct net_buf *out = nb_create_alloc(NB_MULTIHAVE, 9 * tp->have_npieces); | |||
for (uint32_t i = 0, count = 0; count < tp->have_npieces; i++) { | |||
if (has_bit(tp->piece_field, i)) { | |||
uint32_t have_npieces = cm_get_npieces(tp); | |||
struct net_buf *out = nb_create_alloc(NB_MULTIHAVE, 9 * have_npieces); | |||
for (uint32_t i = 0, count = 0; count < have_npieces; i++) { | |||
if (cm_has_piece(tp, i)) { | |||
net_write32(out->buf + count * 9, 5); | |||
out->buf[count * 9 + 4] = MSG_HAVE; | |||
net_write32(out->buf + count * 9 + 5, i); | |||
@@ -183,7 +184,7 @@ nb_create_bitdata(struct torrent *tp) | |||
{ | |||
uint32_t plen = ceil(tp->meta.npieces / 8.0); | |||
struct net_buf *out = | |||
nb_create_set(NB_BITDATA, tp->piece_field, plen, kill_buf_no); | |||
nb_create_set(NB_BITDATA, cm_get_piece_field(tp), plen, kill_buf_no); | |||
return out; | |||
} | |||
@@ -336,8 +336,8 @@ peer_on_shake(struct peer *p) | |||
printid[i] = '\0'; | |||
btpd_log(BTPD_L_MSG, "received shake(%s) from %p\n", printid, p); | |||
p->piece_field = btpd_calloc(1, (int)ceil(p->tp->meta.npieces / 8.0)); | |||
if (p->tp->have_npieces > 0) { | |||
if (p->tp->have_npieces * 9 < 5 + ceil(p->tp->meta.npieces / 8.0)) | |||
if (cm_get_npieces(p->tp) > 0) { | |||
if (cm_get_npieces(p->tp) * 9 < 5 + ceil(p->tp->meta.npieces / 8.0)) | |||
peer_send(p, nb_create_multihave(p->tp)); | |||
else { | |||
peer_send(p, nb_create_bitfield(p->tp)); | |||
@@ -467,15 +467,16 @@ peer_on_request(struct peer *p, uint32_t index, uint32_t begin, | |||
btpd_log(BTPD_L_MSG, "received request(%u,%u,%u) from %p\n", | |||
index, begin, length, p); | |||
if ((p->flags & PF_NO_REQUESTS) == 0) { | |||
off_t cbegin = index * p->tp->meta.piece_length + begin; | |||
char * content = torrent_get_bytes(p->tp, cbegin, length); | |||
peer_send(p, nb_create_piece(index, begin, length)); | |||
peer_send(p, nb_create_torrentdata(content, length)); | |||
p->npiece_msgs++; | |||
if (p->npiece_msgs >= MAXPIECEMSGS) { | |||
peer_send(p, nb_create_choke()); | |||
peer_send(p, nb_create_unchoke()); | |||
p->flags |= PF_NO_REQUESTS; | |||
char *content; | |||
if (cm_get_bytes(p->tp, index, begin, length, &content) == 0) { | |||
peer_send(p, nb_create_piece(index, begin, length)); | |||
peer_send(p, nb_create_torrentdata(content, length)); | |||
p->npiece_msgs++; | |||
if (p->npiece_msgs >= MAXPIECEMSGS) { | |||
peer_send(p, nb_create_choke()); | |||
peer_send(p, nb_create_unchoke()); | |||
p->flags |= PF_NO_REQUESTS; | |||
} | |||
} | |||
} | |||
} | |||
@@ -19,194 +19,6 @@ | |||
#include "tracker_req.h" | |||
#include "stream.h" | |||
static int | |||
ro_fd_cb(const char *path, int *fd, void *arg) | |||
{ | |||
struct torrent *tp = arg; | |||
return vopen(fd, O_RDONLY, "%s/content/%s", tp->relpath, path); | |||
} | |||
static int | |||
wo_fd_cb(const char *path, int *fd, void *arg) | |||
{ | |||
struct torrent *tp = arg; | |||
return vopen(fd, O_WRONLY|O_CREAT, "%s/content/%s", tp->relpath, path); | |||
} | |||
static int | |||
torrent_load3(const char *file, struct metainfo *mi, char *mem, size_t memsiz) | |||
{ | |||
struct torrent *tp = btpd_calloc(1, sizeof(*tp)); | |||
tp->relpath = strdup(file); | |||
if (tp->relpath == NULL) | |||
btpd_err("Out of memory.\n"); | |||
tp->piece_count = btpd_calloc(mi->npieces, sizeof(tp->piece_count[0])); | |||
tp->busy_field = btpd_calloc(ceil(mi->npieces / 8.0), 1); | |||
BTPDQ_INIT(&tp->peers); | |||
BTPDQ_INIT(&tp->getlst); | |||
tp->imem = mem; | |||
tp->isiz = memsiz; | |||
tp->piece_field = tp->imem; | |||
tp->block_field = | |||
(uint8_t *)tp->imem + (size_t)ceil(mi->npieces / 8.0); | |||
for (uint32_t i = 0; i < mi->npieces; i++) | |||
if (has_bit(tp->piece_field, i)) | |||
tp->have_npieces++; | |||
tp->meta = *mi; | |||
free(mi); | |||
btpd_add_torrent(tp); | |||
net_add_torrent(tp); | |||
tracker_req(tp, TR_STARTED); | |||
return 0; | |||
} | |||
static int | |||
torrent_load2(const char *name, struct metainfo *mi) | |||
{ | |||
int error, ifd; | |||
struct stat sb; | |||
char *mem; | |||
size_t memsiz; | |||
const char *file = name; | |||
if ((error = vopen(&ifd, O_RDWR, "%s/resume", file)) != 0) { | |||
btpd_log(BTPD_L_ERROR, "Error opening %s.i: %s.\n", | |||
file, strerror(error)); | |||
return error; | |||
} | |||
if (fstat(ifd, &sb) == -1) { | |||
error = errno; | |||
btpd_log(BTPD_L_ERROR, "Error stating %s.i: %s.\n", | |||
file, strerror(error)); | |||
close(ifd); | |||
return error; | |||
} | |||
memsiz = | |||
ceil(mi->npieces / 8.0) + | |||
mi->npieces * ceil(mi->piece_length / (double)(1 << 17)); | |||
if (sb.st_size != memsiz) { | |||
btpd_log(BTPD_L_ERROR, "File has wrong size: %s.i.\n", file); | |||
close(ifd); | |||
return EINVAL; | |||
} | |||
mem = mmap(NULL, memsiz, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0); | |||
if (mem == MAP_FAILED) | |||
btpd_err("Error mmap'ing %s.i: %s.\n", file, strerror(errno)); | |||
close(ifd); | |||
if ((error = torrent_load3(file, mi, mem, memsiz) != 0)) { | |||
munmap(mem, memsiz); | |||
return error; | |||
} | |||
return 0; | |||
} | |||
int | |||
torrent_load(const char *name) | |||
{ | |||
struct metainfo *mi; | |||
int error; | |||
char file[PATH_MAX]; | |||
snprintf(file, PATH_MAX, "%s/torrent", name); | |||
if ((error = load_metainfo(file, -1, 0, &mi)) != 0) { | |||
btpd_log(BTPD_L_ERROR, "Couldn't load metainfo file %s: %s.\n", | |||
file, strerror(error)); | |||
return error; | |||
} | |||
if (btpd_get_torrent(mi->info_hash) != NULL) { | |||
btpd_log(BTPD_L_BTPD, "%s has same hash as an already loaded torrent.\n", file); | |||
error = EEXIST; | |||
} | |||
if (error == 0) | |||
error = torrent_load2(name, mi); | |||
if (error != 0) { | |||
clear_metainfo(mi); | |||
free(mi); | |||
} | |||
return error; | |||
} | |||
void | |||
torrent_unload(struct torrent *tp) | |||
{ | |||
btpd_log(BTPD_L_BTPD, "Unloading %s.\n", tp->relpath); | |||
net_del_torrent(tp); | |||
tracker_req(tp, TR_STOPPED); | |||
free(tp->piece_count); | |||
free(tp->busy_field); | |||
free((void *)tp->relpath); | |||
clear_metainfo(&tp->meta); | |||
munmap(tp->imem, tp->isiz); | |||
btpd_del_torrent(tp); | |||
free(tp); | |||
} | |||
off_t | |||
torrent_bytes_left(struct torrent *tp) | |||
{ | |||
if (tp->have_npieces == 0) | |||
return tp->meta.total_length; | |||
else if (has_bit(tp->piece_field, tp->meta.npieces - 1)) { | |||
return tp->meta.total_length - | |||
((tp->have_npieces - 1) * tp->meta.piece_length + | |||
tp->meta.total_length % tp->meta.piece_length); | |||
} else | |||
return tp->meta.total_length - | |||
tp->have_npieces * tp->meta.piece_length; | |||
} | |||
char * | |||
torrent_get_bytes(struct torrent *tp, off_t start, size_t len) | |||
{ | |||
char *buf = btpd_malloc(len); | |||
struct bt_stream_ro *bts; | |||
if ((bts = bts_open_ro(&tp->meta, start, ro_fd_cb, tp)) == NULL) | |||
btpd_err("Out of memory.\n"); | |||
if (bts_read_ro(bts, buf, len) != 0) | |||
btpd_err("Io error.\n"); | |||
bts_close_ro(bts); | |||
return buf; | |||
} | |||
void | |||
torrent_put_bytes(struct torrent *tp, const char *buf, off_t start, size_t len) | |||
{ | |||
int err; | |||
struct bt_stream_wo *bts; | |||
if ((bts = bts_open_wo(&tp->meta, start, wo_fd_cb, tp)) == NULL) | |||
btpd_err("Out of memory.\n"); | |||
if ((err = bts_write_wo(bts, buf, len)) != 0) | |||
btpd_err("Io error1: %s\n", strerror(err)); | |||
if ((err = bts_close_wo(bts)) != 0) | |||
btpd_err("Io error2: %s\n", strerror(err)); | |||
} | |||
int | |||
torrent_has_peer(struct torrent *tp, const uint8_t *id) | |||
{ | |||
@@ -244,8 +56,62 @@ torrent_block_size(struct piece *pc, uint32_t index) | |||
} | |||
} | |||
void | |||
torrent_activate(struct torrent *tp) | |||
{ | |||
assert(tp->state == T_INACTIVE); | |||
tp->state = T_STARTING; | |||
cm_start(tp); | |||
} | |||
void | |||
torrent_deactivate(struct torrent *tp) | |||
{ | |||
} | |||
int | |||
torrent_has_all(struct torrent *tp) | |||
torrent_create(struct torrent **res, const char *path) | |||
{ | |||
return tp->have_npieces == tp->meta.npieces; | |||
struct metainfo *mi; | |||
int error; | |||
char file[PATH_MAX]; | |||
snprintf(file, PATH_MAX, "library/%s/torrent", path); | |||
if ((error = load_metainfo(file, -1, 0, &mi)) != 0) { | |||
btpd_log(BTPD_L_ERROR, "Couldn't load metainfo file %s: %s.\n", | |||
file, strerror(error)); | |||
return error; | |||
} | |||
if (btpd_get_torrent(mi->info_hash) != NULL) { | |||
btpd_log(BTPD_L_BTPD, | |||
"%s has same hash as an already loaded torrent.\n", path); | |||
error = EEXIST; | |||
} | |||
if (error == 0) { | |||
*res = btpd_calloc(1, sizeof(**res)); | |||
(*res)->relpath = strdup(path); | |||
(*res)->meta = *mi; | |||
free(mi); | |||
} else { | |||
clear_metainfo(mi); | |||
free(mi); | |||
} | |||
return error; | |||
} | |||
void torrent_cm_cb(struct torrent *tp, enum cm_state state) | |||
{ | |||
switch (state) { | |||
case CM_STARTED: | |||
net_add_torrent(tp); | |||
tracker_req(tp, TR_STARTED); | |||
case CM_STOPPED: | |||
abort(); | |||
case CM_ERROR: | |||
abort(); | |||
} | |||
} |
@@ -23,7 +23,7 @@ struct piece { | |||
struct block *blocks; | |||
uint8_t *have_field; | |||
const uint8_t *have_field; | |||
uint8_t *down_field; | |||
BTPDQ_ENTRY(piece) entry; | |||
@@ -31,26 +31,29 @@ struct piece { | |||
BTPDQ_HEAD(piece_tq, piece); | |||
enum torrent_state { | |||
T_INACTIVE, | |||
T_STARTING, | |||
T_ACTIVE, | |||
T_STOPPING | |||
}; | |||
struct torrent { | |||
const char *relpath; | |||
struct metainfo meta; | |||
enum torrent_state state; | |||
struct content *cp; | |||
BTPDQ_ENTRY(torrent) entry; | |||
BTPDQ_ENTRY(torrent) net_entry; | |||
void *imem; | |||
size_t isiz; | |||
int net_active; | |||
uint8_t *piece_field; | |||
uint8_t *block_field; | |||
uint8_t *busy_field; | |||
uint32_t npcs_busy; | |||
uint32_t have_npieces; | |||
unsigned *piece_count; | |||
uint64_t uploaded, downloaded; | |||
@@ -66,21 +69,21 @@ struct torrent { | |||
BTPDQ_HEAD(torrent_tq, torrent); | |||
off_t torrent_bytes_left(struct torrent *tp); | |||
char *torrent_get_bytes(struct torrent *tp, off_t start, size_t len); | |||
void torrent_put_bytes(struct torrent *tp, const char *buf, | |||
off_t start, size_t len); | |||
int torrent_load(const char *metafile); | |||
void torrent_unload(struct torrent *tp); | |||
int torrent_create(struct torrent **res, const char *path); | |||
void torrent_activate(struct torrent *tp); | |||
void torrent_deactivate(struct torrent *tp); | |||
int torrent_has_peer(struct torrent *tp, const uint8_t *id); | |||
off_t torrent_piece_size(struct torrent *tp, uint32_t index); | |||
uint32_t torrent_block_size(struct piece *pc, uint32_t index); | |||
int torrent_has_all(struct torrent *tp); | |||
enum cm_state { | |||
CM_STARTED, | |||
CM_STOPPED, | |||
CM_ERROR | |||
}; | |||
void torrent_cm_cb(struct torrent *tp, enum cm_state state); | |||
#endif |
@@ -128,14 +128,9 @@ tracker_done(pid_t pid, void *arg) | |||
} | |||
out: | |||
if (failed) { | |||
if (req->tr_event == TR_STARTED) { | |||
btpd_log(BTPD_L_BTPD, | |||
"Start request failed for %s.\n", tp->relpath); | |||
torrent_unload(tp); | |||
} else | |||
;//tp->tracker_time = btpd_seconds + 10; | |||
} | |||
if (failed) | |||
;//tp->tracker_time = btpd_seconds + 10; | |||
munmap(req->res, REQ_SIZE); | |||
free(req); | |||
} | |||
@@ -165,7 +160,7 @@ create_url(struct tracker_req *req, struct torrent *tp, char **url) | |||
const uint8_t *peer_id = btpd_get_peer_id(); | |||
char qc; | |||
int i; | |||
uint64_t left; | |||
off_t left; | |||
const char *event; | |||
event = event2str(req->tr_event); | |||
@@ -178,7 +173,7 @@ create_url(struct tracker_req *req, struct torrent *tp, char **url) | |||
for (i = 0; i < 20; i++) | |||
snprintf(e_id + i * 3, 4, "%%%.2x", peer_id[i]); | |||
left = torrent_bytes_left(tp); | |||
left = cm_bytes_left(tp); | |||
i = asprintf(url, "%s%cinfo_hash=%s" | |||
"&peer_id=%s" | |||
@@ -19,8 +19,8 @@ rate_cmp(const void *arg1, const void *arg2) | |||
{ | |||
struct peer *p1 = (*(struct peer_sort **)arg1)->p; | |||
struct peer *p2 = (*(struct peer_sort **)arg2)->p; | |||
unsigned long rate1 = torrent_has_all(p1->tp) ? p1->rate_up : p1->rate_dwn; | |||
unsigned long rate2 = torrent_has_all(p2->tp) ? p2->rate_up : p2->rate_dwn; | |||
unsigned long rate1 = cm_full(p1->tp) ? p1->rate_up : p1->rate_dwn; | |||
unsigned long rate2 = cm_full(p2->tp) ? p2->rate_up : p2->rate_dwn; | |||
if (rate1 < rate2) | |||
return -1; | |||
else if (rate1 == rate2) | |||
@@ -51,8 +51,8 @@ choke_do(void) | |||
int unchoked[m_npeers]; | |||
BTPDQ_FOREACH(p, &m_peerq, ul_entry) { | |||
if (((torrent_has_all(p->tp) && p->rate_up > 0) | |||
|| (!torrent_has_all(p->tp) && p->rate_dwn > 0))) { | |||
if (((cm_full(p->tp) && p->rate_up > 0) | |||
|| (!cm_full(p->tp) && p->rate_dwn > 0))) { | |||
worthy[nworthy].p = p; | |||
worthy[nworthy].i = i; | |||
nworthy++; | |||