* Move some struct and type definitions to net_types.h * Fix ul_on_lost_peer. I must've been very tired when I wrote it :Pmaster
@@ -5,7 +5,7 @@ btpd_SOURCES=\ | |||||
download.c download_subr.c download.h\ | download.c download_subr.c download.h\ | ||||
http.c http.h\ | http.c http.h\ | ||||
main.c\ | main.c\ | ||||
net.c net.h\ | |||||
net.c net.h net_types.h\ | |||||
net_buf.c net_buf.h\ | net_buf.c net_buf.h\ | ||||
opts.c opts.h\ | opts.c opts.h\ | ||||
peer.c peer.h\ | peer.c peer.h\ | ||||
@@ -19,6 +19,7 @@ | |||||
#include "metainfo.h" | #include "metainfo.h" | ||||
#include "iobuf.h" | #include "iobuf.h" | ||||
#include "net_buf.h" | #include "net_buf.h" | ||||
#include "net_types.h" | |||||
#include "net.h" | #include "net.h" | ||||
#include "peer.h" | #include "peer.h" | ||||
#include "torrent.h" | #include "torrent.h" | ||||
@@ -104,8 +104,8 @@ static | |||||
void test_cb(int fd, short type, void *arg) | void test_cb(int fd, short type, void *arg) | ||||
{ | { | ||||
struct test *t = arg; | struct test *t = arg; | ||||
set_bit(t->pc->tp->cm->piece_field, t->pc->index); | |||||
t->pc->tp->cm->npieces++; | |||||
set_bit(t->pc->n->tp->cm->piece_field, t->pc->index); | |||||
t->pc->n->tp->cm->npieces++; | |||||
dl_on_ok_piece(t->pc); | dl_on_ok_piece(t->pc); | ||||
free(t); | free(t); | ||||
} | } | ||||
@@ -3,25 +3,6 @@ | |||||
#include "btpd.h" | #include "btpd.h" | ||||
#include "tracker_req.h" | #include "tracker_req.h" | ||||
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 | |||||
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); | |||||
} | |||||
/* | /* | ||||
* Called when a peer announces it's got a new piece. | * Called when a peer announces it's got a new piece. | ||||
* | * | ||||
@@ -31,12 +12,12 @@ dl_stop(struct torrent *tp) | |||||
void | void | ||||
dl_on_piece_ann(struct peer *p, uint32_t index) | dl_on_piece_ann(struct peer *p, uint32_t index) | ||||
{ | { | ||||
struct torrent *tp = p->tp; | |||||
tp->piece_count[index]++; | |||||
if (cm_has_piece(tp, index)) | |||||
struct net *n = p->n; | |||||
n->piece_count[index]++; | |||||
if (cm_has_piece(n->tp, index)) | |||||
return; | return; | ||||
struct piece *pc = dl_find_piece(tp, index); | |||||
if (tp->endgame) { | |||||
struct piece *pc = dl_find_piece(n, index); | |||||
if (n->endgame) { | |||||
assert(pc != NULL); | assert(pc != NULL); | ||||
peer_want(p, index); | peer_want(p, index); | ||||
if (!peer_chokes(p) && !peer_laden(p)) | if (!peer_chokes(p) && !peer_laden(p)) | ||||
@@ -44,7 +25,7 @@ dl_on_piece_ann(struct peer *p, uint32_t index) | |||||
} else if (pc == NULL) { | } else if (pc == NULL) { | ||||
peer_want(p, index); | peer_want(p, index); | ||||
if (!peer_chokes(p) && !peer_laden(p)) { | if (!peer_chokes(p) && !peer_laden(p)) { | ||||
pc = dl_new_piece(tp, index); | |||||
pc = dl_new_piece(n, index); | |||||
if (pc != NULL) | if (pc != NULL) | ||||
dl_piece_assign_requests(pc, p); | dl_piece_assign_requests(pc, p); | ||||
} | } | ||||
@@ -59,12 +40,12 @@ void | |||||
dl_on_download(struct peer *p) | dl_on_download(struct peer *p) | ||||
{ | { | ||||
assert(peer_wanted(p)); | assert(peer_wanted(p)); | ||||
struct torrent *tp = p->tp; | |||||
if (tp->endgame) { | |||||
struct net *n = p->n; | |||||
if (n->endgame) { | |||||
dl_assign_requests_eg(p); | dl_assign_requests_eg(p); | ||||
} else { | } else { | ||||
unsigned count = dl_assign_requests(p); | unsigned count = dl_assign_requests(p); | ||||
if (count == 0 && !p->tp->endgame) // We may have entered end game. | |||||
if (count == 0 && !p->n->endgame) // We may have entered end game. | |||||
assert(!peer_wanted(p) || peer_laden(p)); | assert(!peer_wanted(p) || peer_laden(p)); | ||||
} | } | ||||
} | } | ||||
@@ -79,7 +60,7 @@ dl_on_unchoke(struct peer *p) | |||||
void | void | ||||
dl_on_undownload(struct peer *p) | dl_on_undownload(struct peer *p) | ||||
{ | { | ||||
if (!p->tp->endgame) | |||||
if (!p->n->endgame) | |||||
dl_unassign_requests(p); | dl_unassign_requests(p); | ||||
else | else | ||||
dl_unassign_requests_eg(p); | dl_unassign_requests_eg(p); | ||||
@@ -99,26 +80,26 @@ void | |||||
dl_on_ok_piece(struct piece *pc) | dl_on_ok_piece(struct piece *pc) | ||||
{ | { | ||||
struct peer *p; | struct peer *p; | ||||
struct torrent *tp = pc->tp; | |||||
struct net *n = pc->n; | |||||
btpd_log(BTPD_L_POL, "Got piece: %u.\n", pc->index); | btpd_log(BTPD_L_POL, "Got piece: %u.\n", pc->index); | ||||
struct net_buf *have = nb_create_have(pc->index); | struct net_buf *have = nb_create_have(pc->index); | ||||
BTPDQ_FOREACH(p, &tp->peers, p_entry) | |||||
BTPDQ_FOREACH(p, &n->peers, p_entry) | |||||
peer_send(p, have); | peer_send(p, have); | ||||
if (tp->endgame) | |||||
BTPDQ_FOREACH(p, &tp->peers, p_entry) | |||||
if (n->endgame) | |||||
BTPDQ_FOREACH(p, &n->peers, p_entry) | |||||
if (peer_has(p, pc->index)) | if (peer_has(p, pc->index)) | ||||
peer_unwant(p, pc->index); | peer_unwant(p, pc->index); | ||||
assert(pc->nreqs == 0); | assert(pc->nreqs == 0); | ||||
piece_free(pc); | piece_free(pc); | ||||
if (cm_full(tp)) { | |||||
btpd_log(BTPD_L_BTPD, "Finished: %s.\n", tp->relpath); | |||||
tr_complete(tp); | |||||
BTPDQ_FOREACH(p, &tp->peers, p_entry) | |||||
if (cm_full(n->tp)) { | |||||
btpd_log(BTPD_L_BTPD, "Finished: %s.\n", n->tp->relpath); | |||||
tr_complete(n->tp); | |||||
BTPDQ_FOREACH(p, &n->peers, p_entry) | |||||
assert(p->nwant == 0); | assert(p->nwant == 0); | ||||
} | } | ||||
} | } | ||||
@@ -129,10 +110,10 @@ dl_on_ok_piece(struct piece *pc) | |||||
void | void | ||||
dl_on_bad_piece(struct piece *pc) | dl_on_bad_piece(struct piece *pc) | ||||
{ | { | ||||
struct torrent *tp = pc->tp; | |||||
struct net *n = pc->n; | |||||
btpd_log(BTPD_L_ERROR, "Bad hash for piece %u of %s.\n", | btpd_log(BTPD_L_ERROR, "Bad hash for piece %u of %s.\n", | ||||
pc->index, tp->relpath); | |||||
pc->index, n->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->down_field, i); | ||||
@@ -140,9 +121,9 @@ dl_on_bad_piece(struct piece *pc) | |||||
pc->ngot = 0; | pc->ngot = 0; | ||||
pc->nbusy = 0; | pc->nbusy = 0; | ||||
if (tp->endgame) { | |||||
if (n->endgame) { | |||||
struct peer *p; | struct peer *p; | ||||
BTPDQ_FOREACH(p, &tp->peers, p_entry) { | |||||
BTPDQ_FOREACH(p, &n->peers, p_entry) { | |||||
if (peer_has(p, pc->index) && peer_leech_ok(p) && !peer_laden(p)) | if (peer_has(p, pc->index) && peer_leech_ok(p) && !peer_laden(p)) | ||||
dl_assign_requests_eg(p); | dl_assign_requests_eg(p); | ||||
} | } | ||||
@@ -158,11 +139,11 @@ dl_on_new_peer(struct peer *p) | |||||
void | void | ||||
dl_on_lost_peer(struct peer *p) | dl_on_lost_peer(struct peer *p) | ||||
{ | { | ||||
struct torrent *tp = p->tp; | |||||
struct net *n = p->n; | |||||
for (uint32_t i = 0; i < tp->meta.npieces; i++) | |||||
for (uint32_t i = 0; i < n->tp->meta.npieces; i++) | |||||
if (peer_has(p, i)) | if (peer_has(p, i)) | ||||
tp->piece_count[i]--; | |||||
n->piece_count[i]--; | |||||
if (p->nreqs_out > 0) | if (p->nreqs_out > 0) | ||||
dl_on_undownload(p); | dl_on_undownload(p); | ||||
@@ -172,14 +153,14 @@ void | |||||
dl_on_block(struct peer *p, struct block_request *req, | dl_on_block(struct peer *p, struct block_request *req, | ||||
uint32_t index, uint32_t begin, uint32_t length, const char *data) | uint32_t index, uint32_t begin, uint32_t length, const char *data) | ||||
{ | { | ||||
struct torrent *tp = p->tp; | |||||
struct net *n = p->n; | |||||
struct block *blk = req->blk; | struct block *blk = req->blk; | ||||
struct piece *pc = blk->pc; | struct piece *pc = blk->pc; | ||||
cm_put_block(p->tp, index, begin / PIECE_BLOCKLEN, data); | |||||
cm_put_block(p->n->tp, index, begin / PIECE_BLOCKLEN, data); | |||||
pc->ngot++; | pc->ngot++; | ||||
if (tp->endgame) { | |||||
if (n->endgame) { | |||||
struct block_request *req; | struct block_request *req; | ||||
struct net_buf *cancel = nb_create_cancel(index, begin, length); | struct net_buf *cancel = nb_create_cancel(index, begin, length); | ||||
nb_hold(cancel); | nb_hold(cancel); | ||||
@@ -8,8 +8,8 @@ void piece_free(struct piece *pc); | |||||
void dl_on_piece_unfull(struct piece *pc); | void dl_on_piece_unfull(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); | |||||
struct piece *dl_new_piece(struct net *n, uint32_t index); | |||||
struct piece *dl_find_piece(struct net *n, uint32_t index); | |||||
unsigned dl_piece_assign_requests(struct piece *pc, struct peer *p); | unsigned dl_piece_assign_requests(struct piece *pc, struct peer *p); | ||||
unsigned dl_assign_requests(struct peer *p); | unsigned dl_assign_requests(struct peer *p); | ||||
void dl_assign_requests_eg(struct peer *p); | void dl_assign_requests_eg(struct peer *p); | ||||
@@ -19,9 +19,6 @@ void dl_piece_reorder_eg(struct piece *pc); | |||||
// download.c | // download.c | ||||
void dl_start(struct torrent *tp); | |||||
void dl_stop(struct torrent *tp); | |||||
void dl_on_new_peer(struct peer *p); | void dl_on_new_peer(struct peer *p); | ||||
void dl_on_lost_peer(struct peer *p); | void dl_on_lost_peer(struct peer *p); | ||||
@@ -30,14 +30,14 @@ | |||||
#include "stream.h" | #include "stream.h" | ||||
static struct piece * | static struct piece * | ||||
piece_alloc(struct torrent *tp, uint32_t index) | |||||
piece_alloc(struct net *n, uint32_t index) | |||||
{ | { | ||||
assert(!has_bit(tp->busy_field, index) | |||||
&& tp->npcs_busy < tp->meta.npieces); | |||||
assert(!has_bit(n->busy_field, index) | |||||
&& n->npcs_busy < n->tp->meta.npieces); | |||||
struct piece *pc; | struct piece *pc; | ||||
size_t mem, field, blocks; | size_t mem, field, blocks; | ||||
unsigned nblocks; | unsigned nblocks; | ||||
off_t piece_length = torrent_piece_size(tp, index); | |||||
off_t piece_length = torrent_piece_size(n->tp, index); | |||||
nblocks = (unsigned)ceil((double)piece_length / PIECE_BLOCKLEN); | nblocks = (unsigned)ceil((double)piece_length / PIECE_BLOCKLEN); | ||||
blocks = sizeof(pc->blocks[0]) * nblocks; | blocks = sizeof(pc->blocks[0]) * nblocks; | ||||
@@ -45,9 +45,9 @@ piece_alloc(struct torrent *tp, uint32_t index) | |||||
mem = sizeof(*pc) + field + blocks; | mem = sizeof(*pc) + field + blocks; | ||||
pc = btpd_calloc(1, mem); | pc = btpd_calloc(1, mem); | ||||
pc->tp = tp; | |||||
pc->n = n; | |||||
pc->down_field = (uint8_t *)(pc + 1); | pc->down_field = (uint8_t *)(pc + 1); | ||||
pc->have_field = cm_get_block_field(tp, index); | |||||
pc->have_field = cm_get_block_field(n->tp, index); | |||||
pc->index = index; | pc->index = index; | ||||
pc->nblocks = nblocks; | pc->nblocks = nblocks; | ||||
@@ -71,20 +71,20 @@ piece_alloc(struct torrent *tp, uint32_t index) | |||||
nb_hold(blk->msg); | nb_hold(blk->msg); | ||||
} | } | ||||
tp->npcs_busy++; | |||||
set_bit(tp->busy_field, index); | |||||
BTPDQ_INSERT_HEAD(&tp->getlst, pc, entry); | |||||
n->npcs_busy++; | |||||
set_bit(n->busy_field, index); | |||||
BTPDQ_INSERT_HEAD(&n->getlst, pc, entry); | |||||
return pc; | return pc; | ||||
} | } | ||||
void | void | ||||
piece_free(struct piece *pc) | piece_free(struct piece *pc) | ||||
{ | { | ||||
struct torrent *tp = pc->tp; | |||||
assert(tp->npcs_busy > 0); | |||||
tp->npcs_busy--; | |||||
clear_bit(tp->busy_field, pc->index); | |||||
BTPDQ_REMOVE(&pc->tp->getlst, pc, entry); | |||||
struct net *n = pc->n; | |||||
assert(n->npcs_busy > 0); | |||||
n->npcs_busy--; | |||||
clear_bit(n->busy_field, pc->index); | |||||
BTPDQ_REMOVE(&pc->n->getlst, pc, entry); | |||||
for (unsigned i = 0; i < pc->nblocks; i++) { | for (unsigned i = 0; i < pc->nblocks; i++) { | ||||
struct block_request *req = BTPDQ_FIRST(&pc->blocks[i].reqs); | struct block_request *req = BTPDQ_FIRST(&pc->blocks[i].reqs); | ||||
while (req != NULL) { | while (req != NULL) { | ||||
@@ -104,13 +104,13 @@ piece_full(struct piece *pc) | |||||
} | } | ||||
static int | static int | ||||
dl_should_enter_endgame(struct torrent *tp) | |||||
dl_should_enter_endgame(struct net *n) | |||||
{ | { | ||||
int should; | int should; | ||||
if (cm_get_npieces(tp) + tp->npcs_busy == tp->meta.npieces) { | |||||
if (cm_get_npieces(n->tp) + n->npcs_busy == n->tp->meta.npieces) { | |||||
should = 1; | should = 1; | ||||
struct piece *pc; | struct piece *pc; | ||||
BTPDQ_FOREACH(pc, &tp->getlst, entry) { | |||||
BTPDQ_FOREACH(pc, &n->getlst, entry) { | |||||
if (!piece_full(pc)) { | if (!piece_full(pc)) { | ||||
should = 0; | should = 0; | ||||
break; | break; | ||||
@@ -124,7 +124,7 @@ dl_should_enter_endgame(struct torrent *tp) | |||||
static void | static void | ||||
dl_piece_insert_eg(struct piece *pc) | dl_piece_insert_eg(struct piece *pc) | ||||
{ | { | ||||
struct piece_tq *getlst = &pc->tp->getlst; | |||||
struct piece_tq *getlst = &pc->n->getlst; | |||||
if (pc->nblocks == pc->ngot) | if (pc->nblocks == pc->ngot) | ||||
BTPDQ_INSERT_TAIL(getlst, pc, entry); | BTPDQ_INSERT_TAIL(getlst, pc, entry); | ||||
else { | else { | ||||
@@ -145,37 +145,37 @@ dl_piece_insert_eg(struct piece *pc) | |||||
void | void | ||||
dl_piece_reorder_eg(struct piece *pc) | dl_piece_reorder_eg(struct piece *pc) | ||||
{ | { | ||||
BTPDQ_REMOVE(&pc->tp->getlst, pc, entry); | |||||
BTPDQ_REMOVE(&pc->n->getlst, pc, entry); | |||||
dl_piece_insert_eg(pc); | dl_piece_insert_eg(pc); | ||||
} | } | ||||
static void | static void | ||||
dl_enter_endgame(struct torrent *tp) | |||||
dl_enter_endgame(struct net *n) | |||||
{ | { | ||||
struct peer *p; | struct peer *p; | ||||
struct piece *pc; | struct piece *pc; | ||||
struct piece *pcs[tp->npcs_busy]; | |||||
struct piece *pcs[n->npcs_busy]; | |||||
unsigned pi; | unsigned pi; | ||||
btpd_log(BTPD_L_POL, "Entering end game\n"); | btpd_log(BTPD_L_POL, "Entering end game\n"); | ||||
tp->endgame = 1; | |||||
n->endgame = 1; | |||||
pi = 0; | pi = 0; | ||||
BTPDQ_FOREACH(pc, &tp->getlst, entry) { | |||||
BTPDQ_FOREACH(pc, &n->getlst, entry) { | |||||
for (unsigned i = 0; i < pc->nblocks; i++) | for (unsigned i = 0; i < pc->nblocks; i++) | ||||
clear_bit(pc->down_field, i); | clear_bit(pc->down_field, i); | ||||
pc->nbusy = 0; | pc->nbusy = 0; | ||||
pcs[pi] = pc; | pcs[pi] = pc; | ||||
pi++; | pi++; | ||||
} | } | ||||
BTPDQ_INIT(&tp->getlst); | |||||
BTPDQ_INIT(&n->getlst); | |||||
while (pi > 0) { | while (pi > 0) { | ||||
pi--; | pi--; | ||||
dl_piece_insert_eg(pcs[pi]); | dl_piece_insert_eg(pcs[pi]); | ||||
} | } | ||||
BTPDQ_FOREACH(p, &tp->peers, p_entry) { | |||||
BTPDQ_FOREACH(p, &n->peers, p_entry) { | |||||
assert(p->nwant == 0); | assert(p->nwant == 0); | ||||
BTPDQ_FOREACH(pc, &tp->getlst, entry) { | |||||
BTPDQ_FOREACH(pc, &n->getlst, entry) { | |||||
if (peer_has(p, pc->index)) | if (peer_has(p, pc->index)) | ||||
peer_want(p, pc->index); | peer_want(p, pc->index); | ||||
} | } | ||||
@@ -185,10 +185,10 @@ dl_enter_endgame(struct torrent *tp) | |||||
} | } | ||||
struct piece * | struct piece * | ||||
dl_find_piece(struct torrent *tp, uint32_t index) | |||||
dl_find_piece(struct net *n, uint32_t index) | |||||
{ | { | ||||
struct piece *pc; | struct piece *pc; | ||||
BTPDQ_FOREACH(pc, &tp->getlst, entry) | |||||
BTPDQ_FOREACH(pc, &n->getlst, entry) | |||||
if (pc->index == index) | if (pc->index == index) | ||||
break; | break; | ||||
return pc; | return pc; | ||||
@@ -197,8 +197,8 @@ dl_find_piece(struct torrent *tp, uint32_t index) | |||||
static int | static int | ||||
dl_piece_startable(struct peer *p, uint32_t index) | dl_piece_startable(struct peer *p, uint32_t index) | ||||
{ | { | ||||
return peer_has(p, index) && !cm_has_piece(p->tp, index) | |||||
&& !has_bit(p->tp->busy_field, index); | |||||
return peer_has(p, index) && !cm_has_piece(p->n->tp, index) | |||||
&& !has_bit(p->n->busy_field, index); | |||||
} | } | ||||
/* | /* | ||||
@@ -212,23 +212,23 @@ static int | |||||
dl_choose_rarest(struct peer *p, uint32_t *res) | dl_choose_rarest(struct peer *p, uint32_t *res) | ||||
{ | { | ||||
uint32_t i; | uint32_t i; | ||||
struct torrent *tp = p->tp; | |||||
struct net *n = p->n; | |||||
assert(tp->endgame == 0); | |||||
assert(n->endgame == 0); | |||||
for (i = 0; i < tp->meta.npieces && !dl_piece_startable(p, i); i++) | |||||
for (i = 0; i < n->tp->meta.npieces && !dl_piece_startable(p, i); i++) | |||||
; | ; | ||||
if (i == tp->meta.npieces) | |||||
if (i == n->tp->meta.npieces) | |||||
return ENOENT; | return ENOENT; | ||||
uint32_t min_i = i; | uint32_t min_i = i; | ||||
uint32_t min_c = 1; | uint32_t min_c = 1; | ||||
for(i++; i < tp->meta.npieces; i++) { | |||||
for(i++; i < n->tp->meta.npieces; i++) { | |||||
if (dl_piece_startable(p, i)) { | if (dl_piece_startable(p, i)) { | ||||
if (tp->piece_count[i] == tp->piece_count[min_i]) | |||||
if (n->piece_count[i] == n->piece_count[min_i]) | |||||
min_c++; | min_c++; | ||||
else if (tp->piece_count[i] < tp->piece_count[min_i]) { | |||||
else if (n->piece_count[i] < n->piece_count[min_i]) { | |||||
min_i = i; | min_i = i; | ||||
min_c = 1; | min_c = 1; | ||||
} | } | ||||
@@ -238,7 +238,7 @@ dl_choose_rarest(struct peer *p, uint32_t *res) | |||||
min_c = rand_between(1, min_c); | min_c = rand_between(1, min_c); | ||||
for (i = min_i; min_c > 0; i++) { | for (i = min_i; min_c > 0; i++) { | ||||
if (dl_piece_startable(p, i) | if (dl_piece_startable(p, i) | ||||
&& tp->piece_count[i] == tp->piece_count[min_i]) { | |||||
&& n->piece_count[i] == n->piece_count[min_i]) { | |||||
min_c--; | min_c--; | ||||
min_i = i; | min_i = i; | ||||
} | } | ||||
@@ -257,12 +257,12 @@ static void | |||||
dl_on_piece_full(struct piece *pc) | dl_on_piece_full(struct piece *pc) | ||||
{ | { | ||||
struct peer *p; | struct peer *p; | ||||
BTPDQ_FOREACH(p, &pc->tp->peers, p_entry) { | |||||
BTPDQ_FOREACH(p, &pc->n->peers, p_entry) { | |||||
if (peer_has(p, pc->index)) | if (peer_has(p, pc->index)) | ||||
peer_unwant(p, pc->index); | peer_unwant(p, pc->index); | ||||
} | } | ||||
if (dl_should_enter_endgame(pc->tp)) | |||||
dl_enter_endgame(pc->tp); | |||||
if (dl_should_enter_endgame(pc->n)) | |||||
dl_enter_endgame(pc->n); | |||||
} | } | ||||
/* | /* | ||||
@@ -275,10 +275,10 @@ dl_on_piece_full(struct piece *pc) | |||||
* Return the piece or NULL. | * Return the piece or NULL. | ||||
*/ | */ | ||||
struct piece * | struct piece * | ||||
dl_new_piece(struct torrent *tp, uint32_t index) | |||||
dl_new_piece(struct net *n, uint32_t index) | |||||
{ | { | ||||
btpd_log(BTPD_L_POL, "Started on piece %u.\n", index); | btpd_log(BTPD_L_POL, "Started on piece %u.\n", index); | ||||
return piece_alloc(tp, index); | |||||
return piece_alloc(n, index); | |||||
} | } | ||||
/* | /* | ||||
@@ -291,13 +291,13 @@ dl_new_piece(struct torrent *tp, uint32_t index) | |||||
void | void | ||||
dl_on_piece_unfull(struct piece *pc) | dl_on_piece_unfull(struct piece *pc) | ||||
{ | { | ||||
struct torrent *tp = pc->tp; | |||||
struct net *n = pc->n; | |||||
struct peer *p; | struct peer *p; | ||||
assert(!piece_full(pc) && tp->endgame == 0); | |||||
BTPDQ_FOREACH(p, &tp->peers, p_entry) | |||||
assert(!piece_full(pc) && n->endgame == 0); | |||||
BTPDQ_FOREACH(p, &n->peers, p_entry) | |||||
if (peer_has(p, pc->index)) | if (peer_has(p, pc->index)) | ||||
peer_want(p, pc->index); | peer_want(p, pc->index); | ||||
p = BTPDQ_FIRST(&tp->peers); | |||||
p = BTPDQ_FIRST(&n->peers); | |||||
while (p != NULL && !piece_full(pc)) { | while (p != NULL && !piece_full(pc)) { | ||||
if (peer_leech_ok(p) && !peer_laden(p)) | if (peer_leech_ok(p) && !peer_laden(p)) | ||||
dl_piece_assign_requests(pc, p); // Cannot provoke end game here. | dl_piece_assign_requests(pc, p); // Cannot provoke end game here. | ||||
@@ -360,25 +360,25 @@ dl_piece_assign_requests(struct piece *pc, struct peer *p) | |||||
unsigned | unsigned | ||||
dl_assign_requests(struct peer *p) | dl_assign_requests(struct peer *p) | ||||
{ | { | ||||
assert(!p->tp->endgame && !peer_laden(p)); | |||||
assert(!p->n->endgame && !peer_laden(p)); | |||||
struct piece *pc; | struct piece *pc; | ||||
struct torrent *tp = p->tp; | |||||
struct net *n = p->n; | |||||
unsigned count = 0; | unsigned count = 0; | ||||
BTPDQ_FOREACH(pc, &tp->getlst, entry) { | |||||
BTPDQ_FOREACH(pc, &n->getlst, entry) { | |||||
if (piece_full(pc) || !peer_has(p, pc->index)) | if (piece_full(pc) || !peer_has(p, pc->index)) | ||||
continue; | continue; | ||||
count += dl_piece_assign_requests(pc, p); | count += dl_piece_assign_requests(pc, p); | ||||
if (tp->endgame) | |||||
if (n->endgame) | |||||
break; | break; | ||||
if (!piece_full(pc)) | if (!piece_full(pc)) | ||||
assert(peer_laden(p)); | assert(peer_laden(p)); | ||||
if (peer_laden(p)) | if (peer_laden(p)) | ||||
break; | break; | ||||
} | } | ||||
while (!peer_laden(p) && !tp->endgame) { | |||||
while (!peer_laden(p) && !n->endgame) { | |||||
uint32_t index; | uint32_t index; | ||||
if (dl_choose_rarest(p, &index) == 0) { | if (dl_choose_rarest(p, &index) == 0) { | ||||
pc = dl_new_piece(tp, index); | |||||
pc = dl_new_piece(n, index); | |||||
if (pc != NULL) | if (pc != NULL) | ||||
count += dl_piece_assign_requests(pc, p); | count += dl_piece_assign_requests(pc, p); | ||||
} else | } else | ||||
@@ -445,16 +445,16 @@ void | |||||
dl_assign_requests_eg(struct peer *p) | dl_assign_requests_eg(struct peer *p) | ||||
{ | { | ||||
assert(!peer_laden(p)); | assert(!peer_laden(p)); | ||||
struct torrent *tp = p->tp; | |||||
struct net *n = p->n; | |||||
struct piece_tq tmp; | struct piece_tq tmp; | ||||
BTPDQ_INIT(&tmp); | BTPDQ_INIT(&tmp); | ||||
struct piece *pc = BTPDQ_FIRST(&tp->getlst); | |||||
struct piece *pc = BTPDQ_FIRST(&n->getlst); | |||||
while (!peer_laden(p) && pc != NULL) { | while (!peer_laden(p) && pc != NULL) { | ||||
struct piece *next = BTPDQ_NEXT(pc, entry); | struct piece *next = BTPDQ_NEXT(pc, entry); | ||||
if (peer_has(p, pc->index) && pc->nblocks != pc->ngot) { | if (peer_has(p, pc->index) && pc->nblocks != pc->ngot) { | ||||
dl_piece_assign_requests_eg(pc, p); | dl_piece_assign_requests_eg(pc, p); | ||||
BTPDQ_REMOVE(&tp->getlst, pc, entry); | |||||
BTPDQ_REMOVE(&n->getlst, pc, entry); | |||||
BTPDQ_INSERT_HEAD(&tmp, pc, entry); | BTPDQ_INSERT_HEAD(&tmp, pc, entry); | ||||
} | } | ||||
pc = next; | pc = next; | ||||
@@ -480,7 +480,7 @@ dl_unassign_requests_eg(struct peer *p) | |||||
req = BTPDQ_FIRST(&p->my_reqs); | req = BTPDQ_FIRST(&p->my_reqs); | ||||
pc = req->blk->pc; | pc = req->blk->pc; | ||||
BTPDQ_REMOVE(&pc->tp->getlst, pc, entry); | |||||
BTPDQ_REMOVE(&pc->n->getlst, pc, entry); | |||||
BTPDQ_INSERT_HEAD(&tmp, pc, entry); | BTPDQ_INSERT_HEAD(&tmp, pc, entry); | ||||
while (req != NULL) { | while (req != NULL) { | ||||
@@ -18,8 +18,6 @@ | |||||
#include "btpd.h" | #include "btpd.h" | ||||
#define min(x, y) ((x) <= (y) ? (x) : (y)) | |||||
static struct event m_bw_timer; | static struct event m_bw_timer; | ||||
static unsigned long m_bw_bytes_in; | static unsigned long m_bw_bytes_in; | ||||
static unsigned long m_bw_bytes_out; | static unsigned long m_bw_bytes_out; | ||||
@@ -30,7 +28,7 @@ static unsigned long m_rate_dwn; | |||||
static struct event m_net_incoming; | static struct event m_net_incoming; | ||||
static unsigned m_ntorrents; | static unsigned m_ntorrents; | ||||
static struct torrent_tq m_torrents = BTPDQ_HEAD_INITIALIZER(m_torrents); | |||||
static struct net_tq m_torrents = BTPDQ_HEAD_INITIALIZER(m_torrents); | |||||
unsigned net_npeers; | unsigned net_npeers; | ||||
@@ -38,40 +36,76 @@ struct peer_tq net_bw_readq = BTPDQ_HEAD_INITIALIZER(net_bw_readq); | |||||
struct peer_tq net_bw_writeq = BTPDQ_HEAD_INITIALIZER(net_bw_writeq); | struct peer_tq net_bw_writeq = BTPDQ_HEAD_INITIALIZER(net_bw_writeq); | ||||
struct peer_tq net_unattached = BTPDQ_HEAD_INITIALIZER(net_unattached); | struct peer_tq net_unattached = BTPDQ_HEAD_INITIALIZER(net_unattached); | ||||
int | |||||
net_torrent_has_peer(struct net *n, const uint8_t *id) | |||||
{ | |||||
int has = 0; | |||||
struct peer *p = BTPDQ_FIRST(&n->peers); | |||||
while (p != NULL) { | |||||
if (bcmp(p->id, id, 20) == 0) { | |||||
has = 1; | |||||
break; | |||||
} | |||||
p = BTPDQ_NEXT(p, p_entry); | |||||
} | |||||
return has; | |||||
} | |||||
void | void | ||||
net_add_torrent(struct torrent *tp) | net_add_torrent(struct torrent *tp) | ||||
{ | { | ||||
tp->net_active = 1; | |||||
BTPDQ_INSERT_HEAD(&m_torrents, tp, net_entry); | |||||
size_t field_size = ceil(tp->meta.npieces / 8.0); | |||||
size_t mem = sizeof(*(tp->net)) + field_size + | |||||
tp->meta.npieces * sizeof(*(tp->net->piece_count)); | |||||
struct net *n = btpd_calloc(1, mem); | |||||
n->tp = tp; | |||||
tp->net = n; | |||||
n->active = 1; | |||||
BTPDQ_INIT(&n->getlst); | |||||
n->busy_field = (uint8_t *)(n + 1); | |||||
n->piece_count = (unsigned *)(n->busy_field + field_size); | |||||
BTPDQ_INSERT_HEAD(&m_torrents, n, entry); | |||||
m_ntorrents++; | m_ntorrents++; | ||||
dl_start(tp); | |||||
} | } | ||||
void | void | ||||
net_del_torrent(struct torrent *tp) | net_del_torrent(struct torrent *tp) | ||||
{ | { | ||||
tp->net_active = 0; | |||||
struct net *n = tp->net; | |||||
tp->net = NULL; | |||||
assert(m_ntorrents > 0); | assert(m_ntorrents > 0); | ||||
m_ntorrents--; | m_ntorrents--; | ||||
BTPDQ_REMOVE(&m_torrents, tp, net_entry); | |||||
BTPDQ_REMOVE(&m_torrents, n, entry); | |||||
n->active = 0; | |||||
ul_on_lost_torrent(tp); | |||||
dl_stop(tp); | |||||
ul_on_lost_torrent(n); | |||||
struct piece *pc; | |||||
while ((pc = BTPDQ_FIRST(&n->getlst)) != NULL) | |||||
piece_free(pc); | |||||
struct peer *p = BTPDQ_FIRST(&net_unattached); | struct peer *p = BTPDQ_FIRST(&net_unattached); | ||||
while (p != NULL) { | while (p != NULL) { | ||||
struct peer *next = BTPDQ_NEXT(p, p_entry); | struct peer *next = BTPDQ_NEXT(p, p_entry); | ||||
if (p->tp == tp) | |||||
if (p->n == n) | |||||
peer_kill(p); | peer_kill(p); | ||||
p = next; | p = next; | ||||
} | } | ||||
p = BTPDQ_FIRST(&tp->peers); | |||||
p = BTPDQ_FIRST(&n->peers); | |||||
while (p != NULL) { | while (p != NULL) { | ||||
struct peer *next = BTPDQ_NEXT(p, p_entry); | struct peer *next = BTPDQ_NEXT(p, p_entry); | ||||
peer_kill(p); | peer_kill(p); | ||||
p = next; | p = next; | ||||
} | } | ||||
free(n); | |||||
} | } | ||||
void | void | ||||
@@ -142,7 +176,7 @@ net_write(struct peer *p, unsigned long wmax) | |||||
if (bcount >= bufdelta) { | if (bcount >= bufdelta) { | ||||
peer_sent(p, nl->nb); | peer_sent(p, nl->nb); | ||||
if (nl->nb->type == NB_TORRENTDATA) { | if (nl->nb->type == NB_TORRENTDATA) { | ||||
p->tp->uploaded += bufdelta; | |||||
p->n->uploaded += bufdelta; | |||||
p->count_up += bufdelta; | p->count_up += bufdelta; | ||||
} | } | ||||
bcount -= bufdelta; | bcount -= bufdelta; | ||||
@@ -153,7 +187,7 @@ net_write(struct peer *p, unsigned long wmax) | |||||
nl = BTPDQ_FIRST(&p->outq); | nl = BTPDQ_FIRST(&p->outq); | ||||
} else { | } else { | ||||
if (nl->nb->type == NB_TORRENTDATA) { | if (nl->nb->type == NB_TORRENTDATA) { | ||||
p->tp->uploaded += bcount; | |||||
p->n->uploaded += bcount; | |||||
p->count_up += bcount; | p->count_up += bcount; | ||||
} | } | ||||
p->outq_off += bcount; | p->outq_off += bcount; | ||||
@@ -200,9 +234,9 @@ net_dispatch_msg(struct peer *p, const char *buf) | |||||
begin = net_read32(buf + 4); | begin = net_read32(buf + 4); | ||||
length = net_read32(buf + 8); | length = net_read32(buf + 8); | ||||
if ((length > PIECE_BLOCKLEN | if ((length > PIECE_BLOCKLEN | ||||
|| index >= p->tp->meta.npieces | |||||
|| cm_has_piece(p->tp, index) | |||||
|| begin + length > torrent_piece_size(p->tp, index))) { | |||||
|| index >= p->n->tp->meta.npieces | |||||
|| cm_has_piece(p->n->tp, index) | |||||
|| begin + length > torrent_piece_size(p->n->tp, index))) { | |||||
btpd_log(BTPD_L_MSG, "bad request: (%u, %u, %u) from %p\n", | btpd_log(BTPD_L_MSG, "bad request: (%u, %u, %u) from %p\n", | ||||
index, begin, length, p); | index, begin, length, p); | ||||
res = 1; | res = 1; | ||||
@@ -240,7 +274,7 @@ net_mh_ok(struct peer *p) | |||||
case MSG_HAVE: | case MSG_HAVE: | ||||
return mlen == 5; | return mlen == 5; | ||||
case MSG_BITFIELD: | case MSG_BITFIELD: | ||||
return mlen == (uint32_t)ceil(p->tp->meta.npieces / 8.0) + 1; | |||||
return mlen == (uint32_t)ceil(p->n->tp->meta.npieces / 8.0) + 1; | |||||
case MSG_REQUEST: | case MSG_REQUEST: | ||||
case MSG_CANCEL: | case MSG_CANCEL: | ||||
return mlen == 13; | return mlen == 13; | ||||
@@ -255,7 +289,7 @@ static void | |||||
net_progress(struct peer *p, size_t length) | net_progress(struct peer *p, size_t length) | ||||
{ | { | ||||
if (p->in.state == BTP_MSGBODY && p->in.msg_num == MSG_PIECE) { | if (p->in.state == BTP_MSGBODY && p->in.msg_num == MSG_PIECE) { | ||||
p->tp->downloaded += length; | |||||
p->n->downloaded += length; | |||||
p->count_dwn += length; | p->count_dwn += length; | ||||
} | } | ||||
} | } | ||||
@@ -271,20 +305,20 @@ net_state(struct peer *p, const char *buf) | |||||
break; | break; | ||||
case SHAKE_INFO: | case SHAKE_INFO: | ||||
if (p->flags & PF_INCOMING) { | if (p->flags & PF_INCOMING) { | ||||
struct torrent *tp; | |||||
BTPDQ_FOREACH(tp, &m_torrents, net_entry) | |||||
if (bcmp(buf, tp->meta.info_hash, 20) == 0) | |||||
struct net *n; | |||||
BTPDQ_FOREACH(n, &m_torrents, entry) | |||||
if (bcmp(buf, n->tp->meta.info_hash, 20) == 0) | |||||
break; | break; | ||||
if (tp == NULL) | |||||
if (n == NULL) | |||||
goto bad; | goto bad; | ||||
p->tp = tp; | |||||
peer_send(p, nb_create_shake(p->tp)); | |||||
} else if (bcmp(buf, p->tp->meta.info_hash, 20) != 0) | |||||
p->n = n; | |||||
peer_send(p, nb_create_shake(p->n->tp)); | |||||
} else if (bcmp(buf, p->n->tp->meta.info_hash, 20) != 0) | |||||
goto bad; | goto bad; | ||||
peer_set_in_state(p, SHAKE_ID, 20); | peer_set_in_state(p, SHAKE_ID, 20); | ||||
break; | break; | ||||
case SHAKE_ID: | case SHAKE_ID: | ||||
if ((torrent_has_peer(p->tp, buf) | |||||
if ((net_torrent_has_peer(p->n, buf) | |||||
|| bcmp(buf, btpd_get_peer_id(), 20) == 0)) | || bcmp(buf, btpd_get_peer_id(), 20) == 0)) | ||||
goto bad; | goto bad; | ||||
bcopy(buf, p->id, 20); | bcopy(buf, p->id, 20); | ||||
@@ -487,11 +521,11 @@ compute_rate_sub(unsigned long rate) | |||||
static void | static void | ||||
compute_rates(void) { | compute_rates(void) { | ||||
unsigned long tot_up = 0, tot_dwn = 0; | unsigned long tot_up = 0, tot_dwn = 0; | ||||
struct torrent *tp; | |||||
BTPDQ_FOREACH(tp, &m_torrents, net_entry) { | |||||
struct net *n; | |||||
BTPDQ_FOREACH(n, &m_torrents, entry) { | |||||
unsigned long tp_up = 0, tp_dwn = 0; | unsigned long tp_up = 0, tp_dwn = 0; | ||||
struct peer *p; | struct peer *p; | ||||
BTPDQ_FOREACH(p, &tp->peers, p_entry) { | |||||
BTPDQ_FOREACH(p, &n->peers, p_entry) { | |||||
if (p->count_up > 0 || peer_active_up(p)) { | if (p->count_up > 0 || peer_active_up(p)) { | ||||
tp_up += p->count_up; | tp_up += p->count_up; | ||||
p->rate_up += p->count_up - compute_rate_sub(p->rate_up); | p->rate_up += p->count_up - compute_rate_sub(p->rate_up); | ||||
@@ -503,8 +537,8 @@ compute_rates(void) { | |||||
p->count_dwn = 0; | p->count_dwn = 0; | ||||
} | } | ||||
} | } | ||||
tp->rate_up += tp_up - compute_rate_sub(tp->rate_up); | |||||
tp->rate_dwn += tp_dwn - compute_rate_sub(tp->rate_dwn); | |||||
n->rate_up += tp_up - compute_rate_sub(n->rate_up); | |||||
n->rate_dwn += tp_dwn - compute_rate_sub(n->rate_dwn); | |||||
tot_up += tp_up; | tot_up += tp_up; | ||||
tot_dwn += tp_dwn; | tot_dwn += tp_dwn; | ||||
} | } | ||||
@@ -23,6 +23,8 @@ void net_init(void); | |||||
void net_add_torrent(struct torrent *tp); | void net_add_torrent(struct torrent *tp); | ||||
void net_del_torrent(struct torrent *tp); | void net_del_torrent(struct torrent *tp); | ||||
int net_torrent_has_peer(struct net *n, const uint8_t *id); | |||||
void net_read_cb(int sd, short type, void *arg); | void net_read_cb(int sd, short type, void *arg); | ||||
void net_write_cb(int sd, short type, void *arg); | void net_write_cb(int sd, short type, void *arg); | ||||
@@ -0,0 +1,114 @@ | |||||
#ifndef BTPD_NET_TYPES_H | |||||
#define BTPD_NET_TYPES_H | |||||
BTPDQ_HEAD(net_tq, net); | |||||
BTPDQ_HEAD(peer_tq, peer); | |||||
BTPDQ_HEAD(piece_tq, piece); | |||||
BTPDQ_HEAD(block_request_tq, block_request); | |||||
struct net { | |||||
struct torrent *tp; | |||||
int active; | |||||
int endgame; | |||||
uint8_t *busy_field; | |||||
uint32_t npcs_busy; | |||||
unsigned *piece_count; | |||||
struct piece_tq getlst; | |||||
uint64_t uploaded, downloaded; | |||||
unsigned long rate_up, rate_dwn; | |||||
unsigned npeers; | |||||
struct peer_tq peers; | |||||
BTPDQ_ENTRY(net) entry; | |||||
}; | |||||
enum input_state { | |||||
SHAKE_PSTR, | |||||
SHAKE_INFO, | |||||
SHAKE_ID, | |||||
BTP_MSGSIZE, | |||||
BTP_MSGHEAD, | |||||
BTP_PIECEMETA, | |||||
BTP_MSGBODY | |||||
}; | |||||
struct peer { | |||||
int sd; | |||||
uint16_t flags; | |||||
uint8_t *piece_field; | |||||
uint32_t npieces; | |||||
uint32_t nwant; | |||||
uint8_t id[20]; | |||||
struct net *n; | |||||
struct block_request_tq my_reqs; | |||||
unsigned nreqs_out; | |||||
unsigned npiece_msgs; | |||||
size_t outq_off; | |||||
struct nb_tq outq; | |||||
struct event in_ev; | |||||
struct event out_ev; | |||||
unsigned long rate_up, rate_dwn; | |||||
unsigned long count_up, count_dwn; | |||||
struct { | |||||
uint32_t msg_len; | |||||
uint8_t msg_num; | |||||
uint32_t pc_index; | |||||
uint32_t pc_begin; | |||||
enum input_state state; | |||||
size_t st_bytes; | |||||
char *buf; | |||||
size_t off; | |||||
} in; | |||||
BTPDQ_ENTRY(peer) p_entry; | |||||
BTPDQ_ENTRY(peer) ul_entry; | |||||
BTPDQ_ENTRY(peer) rq_entry; | |||||
BTPDQ_ENTRY(peer) wq_entry; | |||||
}; | |||||
struct piece { | |||||
struct net *n; | |||||
uint32_t index; | |||||
unsigned nreqs; | |||||
unsigned nblocks; | |||||
unsigned ngot; | |||||
unsigned nbusy; | |||||
unsigned next_block; | |||||
struct block *blocks; | |||||
const uint8_t *have_field; | |||||
uint8_t *down_field; | |||||
BTPDQ_ENTRY(piece) entry; | |||||
}; | |||||
struct block { | |||||
struct piece *pc; | |||||
struct net_buf *msg; | |||||
struct block_request_tq reqs; | |||||
}; | |||||
struct block_request { | |||||
struct peer *p; | |||||
struct block *blk; | |||||
BTPDQ_ENTRY(block_request) p_entry; | |||||
BTPDQ_ENTRY(block_request) blk_entry; | |||||
}; | |||||
#endif |
@@ -17,12 +17,12 @@ peer_kill(struct peer *p) | |||||
btpd_log(BTPD_L_CONN, "killed peer %p\n", p); | btpd_log(BTPD_L_CONN, "killed peer %p\n", p); | ||||
if (p->flags & PF_ATTACHED) { | if (p->flags & PF_ATTACHED) { | ||||
if (p->tp->net_active) { | |||||
if (p->n->active) { | |||||
ul_on_lost_peer(p); | ul_on_lost_peer(p); | ||||
dl_on_lost_peer(p); | dl_on_lost_peer(p); | ||||
} | } | ||||
BTPDQ_REMOVE(&p->tp->peers, p, p_entry); | |||||
p->tp->npeers--; | |||||
BTPDQ_REMOVE(&p->n->peers, p, p_entry); | |||||
p->n->npeers--; | |||||
} else | } else | ||||
BTPDQ_REMOVE(&net_unattached, p, p_entry); | BTPDQ_REMOVE(&net_unattached, p, p_entry); | ||||
if (p->flags & PF_ON_READQ) | if (p->flags & PF_ON_READQ) | ||||
@@ -284,7 +284,7 @@ peer_create_in(int sd) | |||||
} | } | ||||
void | void | ||||
peer_create_out(struct torrent *tp, const uint8_t *id, | |||||
peer_create_out(struct net *n, const uint8_t *id, | |||||
const char *ip, int port) | const char *ip, int port) | ||||
{ | { | ||||
int sd; | int sd; | ||||
@@ -294,12 +294,12 @@ peer_create_out(struct torrent *tp, const uint8_t *id, | |||||
return; | return; | ||||
p = peer_create_common(sd); | p = peer_create_common(sd); | ||||
p->tp = tp; | |||||
peer_send(p, nb_create_shake(p->tp)); | |||||
p->n = n; | |||||
peer_send(p, nb_create_shake(n->tp)); | |||||
} | } | ||||
void | void | ||||
peer_create_out_compact(struct torrent *tp, const char *compact) | |||||
peer_create_out_compact(struct net *n, const char *compact) | |||||
{ | { | ||||
int sd; | int sd; | ||||
struct peer *p; | struct peer *p; | ||||
@@ -313,8 +313,8 @@ peer_create_out_compact(struct torrent *tp, const char *compact) | |||||
return; | return; | ||||
p = peer_create_common(sd); | p = peer_create_common(sd); | ||||
p->tp = tp; | |||||
peer_send(p, nb_create_shake(p->tp)); | |||||
p->n = n; | |||||
peer_send(p, nb_create_shake(n->tp)); | |||||
} | } | ||||
void | void | ||||
@@ -342,20 +342,21 @@ peer_on_shake(struct peer *p) | |||||
printid[i] = p->id[i]; | printid[i] = p->id[i]; | ||||
printid[i] = '\0'; | printid[i] = '\0'; | ||||
btpd_log(BTPD_L_MSG, "received shake(%s) from %p\n", printid, p); | 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 (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)); | |||||
p->piece_field = btpd_calloc(1, (int)ceil(p->n->tp->meta.npieces / 8.0)); | |||||
if (cm_get_npieces(p->n->tp) > 0) { | |||||
if ((cm_get_npieces(p->n->tp) * 9 < 5 + | |||||
ceil(p->n->tp->meta.npieces / 8.0))) | |||||
peer_send(p, nb_create_multihave(p->n->tp)); | |||||
else { | else { | ||||
peer_send(p, nb_create_bitfield(p->tp)); | |||||
peer_send(p, nb_create_bitdata(p->tp)); | |||||
peer_send(p, nb_create_bitfield(p->n->tp)); | |||||
peer_send(p, nb_create_bitdata(p->n->tp)); | |||||
} | } | ||||
} | } | ||||
BTPDQ_REMOVE(&net_unattached, p, p_entry); | BTPDQ_REMOVE(&net_unattached, p, p_entry); | ||||
BTPDQ_INSERT_HEAD(&p->tp->peers, p, p_entry); | |||||
BTPDQ_INSERT_HEAD(&p->n->peers, p, p_entry); | |||||
p->flags |= PF_ATTACHED; | p->flags |= PF_ATTACHED; | ||||
p->tp->npeers++; | |||||
p->n->npeers++; | |||||
ul_on_new_peer(p); | ul_on_new_peer(p); | ||||
dl_on_new_peer(p); | dl_on_new_peer(p); | ||||
@@ -434,8 +435,8 @@ peer_on_bitfield(struct peer *p, const uint8_t *field) | |||||
{ | { | ||||
btpd_log(BTPD_L_MSG, "received bitfield from %p\n", p); | btpd_log(BTPD_L_MSG, "received bitfield from %p\n", p); | ||||
assert(p->npieces == 0); | assert(p->npieces == 0); | ||||
bcopy(field, p->piece_field, (size_t)ceil(p->tp->meta.npieces / 8.0)); | |||||
for (uint32_t i = 0; i < p->tp->meta.npieces; i++) { | |||||
bcopy(field, p->piece_field, (size_t)ceil(p->n->tp->meta.npieces / 8.0)); | |||||
for (uint32_t i = 0; i < p->n->tp->meta.npieces; i++) { | |||||
if (has_bit(p->piece_field, i)) { | if (has_bit(p->piece_field, i)) { | ||||
p->npieces++; | p->npieces++; | ||||
dl_on_piece_ann(p, i); | dl_on_piece_ann(p, i); | ||||
@@ -475,7 +476,7 @@ peer_on_request(struct peer *p, uint32_t index, uint32_t begin, | |||||
index, begin, length, p); | index, begin, length, p); | ||||
if ((p->flags & PF_NO_REQUESTS) == 0) { | if ((p->flags & PF_NO_REQUESTS) == 0) { | ||||
char *content; | char *content; | ||||
if (cm_get_bytes(p->tp, index, begin, length, &content) == 0) { | |||||
if (cm_get_bytes(p->n->tp, index, begin, length, &content) == 0) { | |||||
peer_send(p, nb_create_piece(index, begin, length)); | peer_send(p, nb_create_piece(index, begin, length)); | ||||
peer_send(p, nb_create_torrentdata(content, length)); | peer_send(p, nb_create_torrentdata(content, length)); | ||||
p->npiece_msgs++; | p->npiece_msgs++; | ||||
@@ -15,69 +15,6 @@ | |||||
#define MAXPIECEMSGS 128 | #define MAXPIECEMSGS 128 | ||||
#define MAXPIPEDREQUESTS 10 | #define MAXPIPEDREQUESTS 10 | ||||
struct block_request { | |||||
struct peer *p; | |||||
struct block *blk; | |||||
BTPDQ_ENTRY(block_request) p_entry; | |||||
BTPDQ_ENTRY(block_request) blk_entry; | |||||
}; | |||||
BTPDQ_HEAD(block_request_tq, block_request); | |||||
enum input_state { | |||||
SHAKE_PSTR, | |||||
SHAKE_INFO, | |||||
SHAKE_ID, | |||||
BTP_MSGSIZE, | |||||
BTP_MSGHEAD, | |||||
BTP_PIECEMETA, | |||||
BTP_MSGBODY | |||||
}; | |||||
struct peer { | |||||
int sd; | |||||
uint16_t flags; | |||||
uint8_t *piece_field; | |||||
uint32_t npieces; | |||||
uint32_t nwant; | |||||
uint8_t id[20]; | |||||
struct torrent *tp; | |||||
struct block_request_tq my_reqs; | |||||
unsigned nreqs_out; | |||||
unsigned npiece_msgs; | |||||
size_t outq_off; | |||||
struct nb_tq outq; | |||||
struct event in_ev; | |||||
struct event out_ev; | |||||
unsigned long rate_up, rate_dwn; | |||||
unsigned long count_up, count_dwn; | |||||
struct { | |||||
uint32_t msg_len; | |||||
uint8_t msg_num; | |||||
uint32_t pc_index; | |||||
uint32_t pc_begin; | |||||
enum input_state state; | |||||
size_t st_bytes; | |||||
char *buf; | |||||
size_t off; | |||||
} in; | |||||
BTPDQ_ENTRY(peer) p_entry; | |||||
BTPDQ_ENTRY(peer) ul_entry; | |||||
BTPDQ_ENTRY(peer) rq_entry; | |||||
BTPDQ_ENTRY(peer) wq_entry; | |||||
}; | |||||
BTPDQ_HEAD(peer_tq, peer); | |||||
void peer_set_in_state(struct peer *p, enum input_state state, size_t size); | void peer_set_in_state(struct peer *p, enum input_state state, size_t size); | ||||
void peer_send(struct peer *p, struct net_buf *nb); | void peer_send(struct peer *p, struct net_buf *nb); | ||||
@@ -95,9 +32,9 @@ void peer_cancel(struct peer *p, struct block_request *req, | |||||
int peer_requested(struct peer *p, struct block *blk); | int peer_requested(struct peer *p, struct block *blk); | ||||
void peer_create_in(int sd); | void peer_create_in(int sd); | ||||
void peer_create_out(struct torrent *tp, const uint8_t *id, | |||||
void peer_create_out(struct net *n, const uint8_t *id, | |||||
const char *ip, int port); | const char *ip, int port); | ||||
void peer_create_out_compact(struct torrent *tp, const char *compact); | |||||
void peer_create_out_compact(struct net *n, const char *compact); | |||||
void peer_kill(struct peer *p); | void peer_kill(struct peer *p); | ||||
void peer_on_no_reqs(struct peer *p); | void peer_on_no_reqs(struct peer *p); | ||||
@@ -19,21 +19,6 @@ | |||||
#include "tracker_req.h" | #include "tracker_req.h" | ||||
#include "stream.h" | #include "stream.h" | ||||
int | |||||
torrent_has_peer(struct torrent *tp, const uint8_t *id) | |||||
{ | |||||
int has = 0; | |||||
struct peer *p = BTPDQ_FIRST(&tp->peers); | |||||
while (p != NULL) { | |||||
if (bcmp(p->id, id, 20) == 0) { | |||||
has = 1; | |||||
break; | |||||
} | |||||
p = BTPDQ_NEXT(p, p_entry); | |||||
} | |||||
return has; | |||||
} | |||||
off_t | off_t | ||||
torrent_piece_size(struct torrent *tp, uint32_t index) | torrent_piece_size(struct torrent *tp, uint32_t index) | ||||
{ | { | ||||
@@ -52,7 +37,7 @@ torrent_block_size(struct piece *pc, uint32_t index) | |||||
return PIECE_BLOCKLEN; | return PIECE_BLOCKLEN; | ||||
else { | else { | ||||
uint32_t allbutlast = PIECE_BLOCKLEN * (pc->nblocks - 1); | uint32_t allbutlast = PIECE_BLOCKLEN * (pc->nblocks - 1); | ||||
return torrent_piece_size(pc->tp, pc->index) - allbutlast; | |||||
return torrent_piece_size(pc->n->tp, pc->index) - allbutlast; | |||||
} | } | ||||
} | } | ||||
@@ -3,34 +3,6 @@ | |||||
#define PIECE_BLOCKLEN (1 << 14) | #define PIECE_BLOCKLEN (1 << 14) | ||||
struct block { | |||||
struct piece *pc; | |||||
struct net_buf *msg; | |||||
struct block_request_tq reqs; | |||||
}; | |||||
struct piece { | |||||
struct torrent *tp; | |||||
uint32_t index; | |||||
unsigned nreqs; | |||||
unsigned nblocks; | |||||
unsigned ngot; | |||||
unsigned nbusy; | |||||
unsigned next_block; | |||||
struct block *blocks; | |||||
const uint8_t *have_field; | |||||
uint8_t *down_field; | |||||
BTPDQ_ENTRY(piece) entry; | |||||
}; | |||||
BTPDQ_HEAD(piece_tq, piece); | |||||
enum torrent_state { | enum torrent_state { | ||||
T_INACTIVE, | T_INACTIVE, | ||||
T_STARTING, | T_STARTING, | ||||
@@ -46,26 +18,9 @@ struct torrent { | |||||
struct content *cm; | struct content *cm; | ||||
struct tracker *tr; | struct tracker *tr; | ||||
struct net *net; | |||||
BTPDQ_ENTRY(torrent) entry; | BTPDQ_ENTRY(torrent) entry; | ||||
BTPDQ_ENTRY(torrent) net_entry; | |||||
int net_active; | |||||
uint8_t *busy_field; | |||||
uint32_t npcs_busy; | |||||
unsigned *piece_count; | |||||
uint64_t uploaded, downloaded; | |||||
unsigned long rate_up, rate_dwn; | |||||
unsigned npeers; | |||||
struct peer_tq peers; | |||||
int endgame; | |||||
struct piece_tq getlst; | |||||
}; | }; | ||||
BTPDQ_HEAD(torrent_tq, torrent); | BTPDQ_HEAD(torrent_tq, torrent); | ||||
@@ -74,8 +29,6 @@ int torrent_create(struct torrent **res, const char *path); | |||||
void torrent_activate(struct torrent *tp); | void torrent_activate(struct torrent *tp); | ||||
void torrent_deactivate(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); | off_t torrent_piece_size(struct torrent *tp, uint32_t index); | ||||
uint32_t torrent_block_size(struct piece *pc, uint32_t index); | uint32_t torrent_block_size(struct piece *pc, uint32_t index); | ||||
@@ -61,7 +61,7 @@ maybe_connect_to(struct torrent *tp, const char *pinfo) | |||||
if (bcmp(btpd_get_peer_id(), pid, 20) == 0) | if (bcmp(btpd_get_peer_id(), pid, 20) == 0) | ||||
return; | return; | ||||
if (torrent_has_peer(tp, pid)) | |||||
if (net_torrent_has_peer(tp->net, pid)) | |||||
return; | return; | ||||
if (benc_dget_strz(pinfo, "ip", &ip, NULL) != 0) | if (benc_dget_strz(pinfo, "ip", &ip, NULL) != 0) | ||||
@@ -70,7 +70,7 @@ maybe_connect_to(struct torrent *tp, const char *pinfo) | |||||
if (benc_dget_int64(pinfo, "port", &port) != 0) | if (benc_dget_int64(pinfo, "port", &port) != 0) | ||||
goto out; | goto out; | ||||
peer_create_out(tp, pid, ip, port); | |||||
peer_create_out(tp->net, pid, ip, port); | |||||
out: | out: | ||||
if (ip != NULL) | if (ip != NULL) | ||||
@@ -118,7 +118,7 @@ parse_reply(struct torrent *tp, const char *content, size_t size) | |||||
if (error == 0 && length % 6 == 0) { | if (error == 0 && length % 6 == 0) { | ||||
size_t i; | size_t i; | ||||
for (i = 0; i < length && net_npeers < net_max_peers; i += 6) | for (i = 0; i < length && net_npeers < net_max_peers; i += 6) | ||||
peer_create_out_compact(tp, peers + i); | |||||
peer_create_out_compact(tp->net, peers + i); | |||||
} | } | ||||
} | } | ||||
@@ -218,7 +218,7 @@ tr_send(struct torrent *tp, enum tr_event event) | |||||
"%s%cinfo_hash=%s&peer_id=%s&port=%d&uploaded=%ju" | "%s%cinfo_hash=%s&peer_id=%s&port=%d&uploaded=%ju" | ||||
"&downloaded=%ju&left=%ju&compact=1%s%s", | "&downloaded=%ju&left=%ju&compact=1%s%s", | ||||
tp->meta.announce, qc, e_hash, e_id, net_port, | tp->meta.announce, qc, e_hash, e_id, net_port, | ||||
(intmax_t)tp->uploaded, (intmax_t)tp->downloaded, | |||||
(intmax_t)tp->net->uploaded, (intmax_t)tp->net->downloaded, | |||||
(intmax_t)cm_bytes_left(tp), | (intmax_t)cm_bytes_left(tp), | ||||
event == TR_EV_EMPTY ? "" : "&event=", m_events[event]); | event == TR_EV_EMPTY ? "" : "&event=", m_events[event]); | ||||
} | } | ||||
@@ -19,8 +19,8 @@ rate_cmp(const void *arg1, const void *arg2) | |||||
{ | { | ||||
struct peer *p1 = (*(struct peer_sort **)arg1)->p; | struct peer *p1 = (*(struct peer_sort **)arg1)->p; | ||||
struct peer *p2 = (*(struct peer_sort **)arg2)->p; | struct peer *p2 = (*(struct peer_sort **)arg2)->p; | ||||
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; | |||||
unsigned long rate1 = cm_full(p1->n->tp) ? p1->rate_up : p1->rate_dwn; | |||||
unsigned long rate2 = cm_full(p2->n->tp) ? p2->rate_up : p2->rate_dwn; | |||||
if (rate1 < rate2) | if (rate1 < rate2) | ||||
return -1; | return -1; | ||||
else if (rate1 == rate2) | else if (rate1 == rate2) | ||||
@@ -51,8 +51,8 @@ choke_do(void) | |||||
int unchoked[m_npeers]; | int unchoked[m_npeers]; | ||||
BTPDQ_FOREACH(p, &m_peerq, ul_entry) { | BTPDQ_FOREACH(p, &m_peerq, ul_entry) { | ||||
if (((cm_full(p->tp) && p->rate_up > 0) | |||||
|| (!cm_full(p->tp) && p->rate_dwn > 0))) { | |||||
if (((cm_full(p->n->tp) && p->rate_up > 0) | |||||
|| (!cm_full(p->n->tp) && p->rate_dwn > 0))) { | |||||
worthy[nworthy].p = p; | worthy[nworthy].p = p; | ||||
worthy[nworthy].i = i; | worthy[nworthy].i = i; | ||||
nworthy++; | nworthy++; | ||||
@@ -143,14 +143,12 @@ ul_on_lost_peer(struct peer *p) | |||||
} | } | ||||
void | void | ||||
ul_on_lost_torrent(struct torrent *tp) | |||||
ul_on_lost_torrent(struct net *n) | |||||
{ | { | ||||
struct peer *p = BTPDQ_FIRST(&m_peerq); | |||||
while (p != NULL) { | |||||
struct peer *next = BTPDQ_NEXT(p, p_entry); | |||||
struct peer *p; | |||||
BTPDQ_FOREACH(p, &n->peers, p_entry) { | |||||
BTPDQ_REMOVE(&m_peerq, p, ul_entry); | BTPDQ_REMOVE(&m_peerq, p, ul_entry); | ||||
m_npeers--; | m_npeers--; | ||||
p = next; | |||||
} | } | ||||
choke_do(); | choke_do(); | ||||
} | } | ||||
@@ -3,7 +3,7 @@ | |||||
void ul_on_new_peer(struct peer *p); | void ul_on_new_peer(struct peer *p); | ||||
void ul_on_lost_peer(struct peer *p); | void ul_on_lost_peer(struct peer *p); | ||||
void ul_on_lost_torrent(struct torrent *tp); | |||||
void ul_on_lost_torrent(struct net *n); | |||||
void ul_on_interest(struct peer *p); | void ul_on_interest(struct peer *p); | ||||
void ul_on_uninterest(struct peer *p); | void ul_on_uninterest(struct peer *p); | ||||
void ul_init(void); | void ul_init(void); | ||||