* 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\ | |||
http.c http.h\ | |||
main.c\ | |||
net.c net.h\ | |||
net.c net.h net_types.h\ | |||
net_buf.c net_buf.h\ | |||
opts.c opts.h\ | |||
peer.c peer.h\ | |||
@@ -19,6 +19,7 @@ | |||
#include "metainfo.h" | |||
#include "iobuf.h" | |||
#include "net_buf.h" | |||
#include "net_types.h" | |||
#include "net.h" | |||
#include "peer.h" | |||
#include "torrent.h" | |||
@@ -104,8 +104,8 @@ static | |||
void test_cb(int fd, short type, void *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); | |||
free(t); | |||
} | |||
@@ -3,25 +3,6 @@ | |||
#include "btpd.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. | |||
* | |||
@@ -31,12 +12,12 @@ dl_stop(struct torrent *tp) | |||
void | |||
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; | |||
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); | |||
peer_want(p, index); | |||
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) { | |||
peer_want(p, index); | |||
if (!peer_chokes(p) && !peer_laden(p)) { | |||
pc = dl_new_piece(tp, index); | |||
pc = dl_new_piece(n, index); | |||
if (pc != NULL) | |||
dl_piece_assign_requests(pc, p); | |||
} | |||
@@ -59,12 +40,12 @@ void | |||
dl_on_download(struct peer *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); | |||
} else { | |||
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)); | |||
} | |||
} | |||
@@ -79,7 +60,7 @@ dl_on_unchoke(struct peer *p) | |||
void | |||
dl_on_undownload(struct peer *p) | |||
{ | |||
if (!p->tp->endgame) | |||
if (!p->n->endgame) | |||
dl_unassign_requests(p); | |||
else | |||
dl_unassign_requests_eg(p); | |||
@@ -99,26 +80,26 @@ void | |||
dl_on_ok_piece(struct piece *pc) | |||
{ | |||
struct peer *p; | |||
struct torrent *tp = pc->tp; | |||
struct net *n = pc->n; | |||
btpd_log(BTPD_L_POL, "Got piece: %u.\n", 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); | |||
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)) | |||
peer_unwant(p, pc->index); | |||
assert(pc->nreqs == 0); | |||
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); | |||
} | |||
} | |||
@@ -129,10 +110,10 @@ dl_on_ok_piece(struct piece *pc) | |||
void | |||
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", | |||
pc->index, tp->relpath); | |||
pc->index, n->tp->relpath); | |||
for (uint32_t i = 0; i < pc->nblocks; i++) | |||
clear_bit(pc->down_field, i); | |||
@@ -140,9 +121,9 @@ dl_on_bad_piece(struct piece *pc) | |||
pc->ngot = 0; | |||
pc->nbusy = 0; | |||
if (tp->endgame) { | |||
if (n->endgame) { | |||
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)) | |||
dl_assign_requests_eg(p); | |||
} | |||
@@ -158,11 +139,11 @@ dl_on_new_peer(struct peer *p) | |||
void | |||
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)) | |||
tp->piece_count[i]--; | |||
n->piece_count[i]--; | |||
if (p->nreqs_out > 0) | |||
dl_on_undownload(p); | |||
@@ -172,14 +153,14 @@ void | |||
dl_on_block(struct peer *p, struct block_request *req, | |||
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 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++; | |||
if (tp->endgame) { | |||
if (n->endgame) { | |||
struct block_request *req; | |||
struct net_buf *cancel = nb_create_cancel(index, begin, length); | |||
nb_hold(cancel); | |||
@@ -8,8 +8,8 @@ void piece_free(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_assign_requests(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 | |||
void dl_start(struct torrent *tp); | |||
void dl_stop(struct torrent *tp); | |||
void dl_on_new_peer(struct peer *p); | |||
void dl_on_lost_peer(struct peer *p); | |||
@@ -30,14 +30,14 @@ | |||
#include "stream.h" | |||
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; | |||
size_t mem, field, blocks; | |||
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); | |||
blocks = sizeof(pc->blocks[0]) * nblocks; | |||
@@ -45,9 +45,9 @@ piece_alloc(struct torrent *tp, uint32_t index) | |||
mem = sizeof(*pc) + field + blocks; | |||
pc = btpd_calloc(1, mem); | |||
pc->tp = tp; | |||
pc->n = n; | |||
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->nblocks = nblocks; | |||
@@ -71,20 +71,20 @@ piece_alloc(struct torrent *tp, uint32_t index) | |||
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; | |||
} | |||
void | |||
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++) { | |||
struct block_request *req = BTPDQ_FIRST(&pc->blocks[i].reqs); | |||
while (req != NULL) { | |||
@@ -104,13 +104,13 @@ piece_full(struct piece *pc) | |||
} | |||
static int | |||
dl_should_enter_endgame(struct torrent *tp) | |||
dl_should_enter_endgame(struct net *n) | |||
{ | |||
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; | |||
struct piece *pc; | |||
BTPDQ_FOREACH(pc, &tp->getlst, entry) { | |||
BTPDQ_FOREACH(pc, &n->getlst, entry) { | |||
if (!piece_full(pc)) { | |||
should = 0; | |||
break; | |||
@@ -124,7 +124,7 @@ dl_should_enter_endgame(struct torrent *tp) | |||
static void | |||
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) | |||
BTPDQ_INSERT_TAIL(getlst, pc, entry); | |||
else { | |||
@@ -145,37 +145,37 @@ dl_piece_insert_eg(struct piece *pc) | |||
void | |||
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); | |||
} | |||
static void | |||
dl_enter_endgame(struct torrent *tp) | |||
dl_enter_endgame(struct net *n) | |||
{ | |||
struct peer *p; | |||
struct piece *pc; | |||
struct piece *pcs[tp->npcs_busy]; | |||
struct piece *pcs[n->npcs_busy]; | |||
unsigned pi; | |||
btpd_log(BTPD_L_POL, "Entering end game\n"); | |||
tp->endgame = 1; | |||
n->endgame = 1; | |||
pi = 0; | |||
BTPDQ_FOREACH(pc, &tp->getlst, entry) { | |||
BTPDQ_FOREACH(pc, &n->getlst, entry) { | |||
for (unsigned i = 0; i < pc->nblocks; i++) | |||
clear_bit(pc->down_field, i); | |||
pc->nbusy = 0; | |||
pcs[pi] = pc; | |||
pi++; | |||
} | |||
BTPDQ_INIT(&tp->getlst); | |||
BTPDQ_INIT(&n->getlst); | |||
while (pi > 0) { | |||
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); | |||
BTPDQ_FOREACH(pc, &tp->getlst, entry) { | |||
BTPDQ_FOREACH(pc, &n->getlst, entry) { | |||
if (peer_has(p, pc->index)) | |||
peer_want(p, pc->index); | |||
} | |||
@@ -185,10 +185,10 @@ dl_enter_endgame(struct torrent *tp) | |||
} | |||
struct piece * | |||
dl_find_piece(struct torrent *tp, uint32_t index) | |||
dl_find_piece(struct net *n, uint32_t index) | |||
{ | |||
struct piece *pc; | |||
BTPDQ_FOREACH(pc, &tp->getlst, entry) | |||
BTPDQ_FOREACH(pc, &n->getlst, entry) | |||
if (pc->index == index) | |||
break; | |||
return pc; | |||
@@ -197,8 +197,8 @@ dl_find_piece(struct torrent *tp, uint32_t index) | |||
static int | |||
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) | |||
{ | |||
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; | |||
uint32_t min_i = i; | |||
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 (tp->piece_count[i] == tp->piece_count[min_i]) | |||
if (n->piece_count[i] == n->piece_count[min_i]) | |||
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_c = 1; | |||
} | |||
@@ -238,7 +238,7 @@ dl_choose_rarest(struct peer *p, uint32_t *res) | |||
min_c = rand_between(1, min_c); | |||
for (i = min_i; min_c > 0; 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_i = i; | |||
} | |||
@@ -257,12 +257,12 @@ static void | |||
dl_on_piece_full(struct piece *pc) | |||
{ | |||
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)) | |||
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. | |||
*/ | |||
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); | |||
return piece_alloc(tp, index); | |||
return piece_alloc(n, index); | |||
} | |||
/* | |||
@@ -291,13 +291,13 @@ dl_new_piece(struct torrent *tp, uint32_t index) | |||
void | |||
dl_on_piece_unfull(struct piece *pc) | |||
{ | |||
struct torrent *tp = pc->tp; | |||
struct net *n = pc->n; | |||
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)) | |||
peer_want(p, pc->index); | |||
p = BTPDQ_FIRST(&tp->peers); | |||
p = BTPDQ_FIRST(&n->peers); | |||
while (p != NULL && !piece_full(pc)) { | |||
if (peer_leech_ok(p) && !peer_laden(p)) | |||
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 | |||
dl_assign_requests(struct peer *p) | |||
{ | |||
assert(!p->tp->endgame && !peer_laden(p)); | |||
assert(!p->n->endgame && !peer_laden(p)); | |||
struct piece *pc; | |||
struct torrent *tp = p->tp; | |||
struct net *n = p->n; | |||
unsigned count = 0; | |||
BTPDQ_FOREACH(pc, &tp->getlst, entry) { | |||
BTPDQ_FOREACH(pc, &n->getlst, entry) { | |||
if (piece_full(pc) || !peer_has(p, pc->index)) | |||
continue; | |||
count += dl_piece_assign_requests(pc, p); | |||
if (tp->endgame) | |||
if (n->endgame) | |||
break; | |||
if (!piece_full(pc)) | |||
assert(peer_laden(p)); | |||
if (peer_laden(p)) | |||
break; | |||
} | |||
while (!peer_laden(p) && !tp->endgame) { | |||
while (!peer_laden(p) && !n->endgame) { | |||
uint32_t index; | |||
if (dl_choose_rarest(p, &index) == 0) { | |||
pc = dl_new_piece(tp, index); | |||
pc = dl_new_piece(n, index); | |||
if (pc != NULL) | |||
count += dl_piece_assign_requests(pc, p); | |||
} else | |||
@@ -445,16 +445,16 @@ void | |||
dl_assign_requests_eg(struct peer *p) | |||
{ | |||
assert(!peer_laden(p)); | |||
struct torrent *tp = p->tp; | |||
struct net *n = p->n; | |||
struct piece_tq tmp; | |||
BTPDQ_INIT(&tmp); | |||
struct piece *pc = BTPDQ_FIRST(&tp->getlst); | |||
struct piece *pc = BTPDQ_FIRST(&n->getlst); | |||
while (!peer_laden(p) && pc != NULL) { | |||
struct piece *next = BTPDQ_NEXT(pc, entry); | |||
if (peer_has(p, pc->index) && pc->nblocks != pc->ngot) { | |||
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); | |||
} | |||
pc = next; | |||
@@ -480,7 +480,7 @@ dl_unassign_requests_eg(struct peer *p) | |||
req = BTPDQ_FIRST(&p->my_reqs); | |||
pc = req->blk->pc; | |||
BTPDQ_REMOVE(&pc->tp->getlst, pc, entry); | |||
BTPDQ_REMOVE(&pc->n->getlst, pc, entry); | |||
BTPDQ_INSERT_HEAD(&tmp, pc, entry); | |||
while (req != NULL) { | |||
@@ -18,8 +18,6 @@ | |||
#include "btpd.h" | |||
#define min(x, y) ((x) <= (y) ? (x) : (y)) | |||
static struct event m_bw_timer; | |||
static unsigned long m_bw_bytes_in; | |||
static unsigned long m_bw_bytes_out; | |||
@@ -30,7 +28,7 @@ static unsigned long m_rate_dwn; | |||
static struct event m_net_incoming; | |||
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; | |||
@@ -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_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 | |||
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++; | |||
dl_start(tp); | |||
} | |||
void | |||
net_del_torrent(struct torrent *tp) | |||
{ | |||
tp->net_active = 0; | |||
struct net *n = tp->net; | |||
tp->net = NULL; | |||
assert(m_ntorrents > 0); | |||
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); | |||
while (p != NULL) { | |||
struct peer *next = BTPDQ_NEXT(p, p_entry); | |||
if (p->tp == tp) | |||
if (p->n == n) | |||
peer_kill(p); | |||
p = next; | |||
} | |||
p = BTPDQ_FIRST(&tp->peers); | |||
p = BTPDQ_FIRST(&n->peers); | |||
while (p != NULL) { | |||
struct peer *next = BTPDQ_NEXT(p, p_entry); | |||
peer_kill(p); | |||
p = next; | |||
} | |||
free(n); | |||
} | |||
void | |||
@@ -142,7 +176,7 @@ net_write(struct peer *p, unsigned long wmax) | |||
if (bcount >= bufdelta) { | |||
peer_sent(p, nl->nb); | |||
if (nl->nb->type == NB_TORRENTDATA) { | |||
p->tp->uploaded += bufdelta; | |||
p->n->uploaded += bufdelta; | |||
p->count_up += bufdelta; | |||
} | |||
bcount -= bufdelta; | |||
@@ -153,7 +187,7 @@ net_write(struct peer *p, unsigned long wmax) | |||
nl = BTPDQ_FIRST(&p->outq); | |||
} else { | |||
if (nl->nb->type == NB_TORRENTDATA) { | |||
p->tp->uploaded += bcount; | |||
p->n->uploaded += bcount; | |||
p->count_up += bcount; | |||
} | |||
p->outq_off += bcount; | |||
@@ -200,9 +234,9 @@ net_dispatch_msg(struct peer *p, const char *buf) | |||
begin = net_read32(buf + 4); | |||
length = net_read32(buf + 8); | |||
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", | |||
index, begin, length, p); | |||
res = 1; | |||
@@ -240,7 +274,7 @@ net_mh_ok(struct peer *p) | |||
case MSG_HAVE: | |||
return mlen == 5; | |||
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_CANCEL: | |||
return mlen == 13; | |||
@@ -255,7 +289,7 @@ static void | |||
net_progress(struct peer *p, size_t length) | |||
{ | |||
if (p->in.state == BTP_MSGBODY && p->in.msg_num == MSG_PIECE) { | |||
p->tp->downloaded += length; | |||
p->n->downloaded += length; | |||
p->count_dwn += length; | |||
} | |||
} | |||
@@ -271,20 +305,20 @@ net_state(struct peer *p, const char *buf) | |||
break; | |||
case SHAKE_INFO: | |||
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; | |||
if (tp == NULL) | |||
if (n == NULL) | |||
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; | |||
peer_set_in_state(p, SHAKE_ID, 20); | |||
break; | |||
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)) | |||
goto bad; | |||
bcopy(buf, p->id, 20); | |||
@@ -487,11 +521,11 @@ compute_rate_sub(unsigned long rate) | |||
static void | |||
compute_rates(void) { | |||
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; | |||
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)) { | |||
tp_up += p->count_up; | |||
p->rate_up += p->count_up - compute_rate_sub(p->rate_up); | |||
@@ -503,8 +537,8 @@ compute_rates(void) { | |||
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_dwn += tp_dwn; | |||
} | |||
@@ -23,6 +23,8 @@ void net_init(void); | |||
void net_add_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_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); | |||
if (p->flags & PF_ATTACHED) { | |||
if (p->tp->net_active) { | |||
if (p->n->active) { | |||
ul_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 | |||
BTPDQ_REMOVE(&net_unattached, p, p_entry); | |||
if (p->flags & PF_ON_READQ) | |||
@@ -284,7 +284,7 @@ peer_create_in(int sd) | |||
} | |||
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) | |||
{ | |||
int sd; | |||
@@ -294,12 +294,12 @@ peer_create_out(struct torrent *tp, const uint8_t *id, | |||
return; | |||
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 | |||
peer_create_out_compact(struct torrent *tp, const char *compact) | |||
peer_create_out_compact(struct net *n, const char *compact) | |||
{ | |||
int sd; | |||
struct peer *p; | |||
@@ -313,8 +313,8 @@ peer_create_out_compact(struct torrent *tp, const char *compact) | |||
return; | |||
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 | |||
@@ -342,20 +342,21 @@ peer_on_shake(struct peer *p) | |||
printid[i] = p->id[i]; | |||
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 (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 { | |||
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_INSERT_HEAD(&p->tp->peers, p, p_entry); | |||
BTPDQ_INSERT_HEAD(&p->n->peers, p, p_entry); | |||
p->flags |= PF_ATTACHED; | |||
p->tp->npeers++; | |||
p->n->npeers++; | |||
ul_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); | |||
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)) { | |||
p->npieces++; | |||
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); | |||
if ((p->flags & PF_NO_REQUESTS) == 0) { | |||
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_torrentdata(content, length)); | |||
p->npiece_msgs++; | |||
@@ -15,69 +15,6 @@ | |||
#define MAXPIECEMSGS 128 | |||
#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_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); | |||
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); | |||
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_on_no_reqs(struct peer *p); | |||
@@ -19,21 +19,6 @@ | |||
#include "tracker_req.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 | |||
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; | |||
else { | |||
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) | |||
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 { | |||
T_INACTIVE, | |||
T_STARTING, | |||
@@ -46,26 +18,9 @@ struct torrent { | |||
struct content *cm; | |||
struct tracker *tr; | |||
struct net *net; | |||
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); | |||
@@ -74,8 +29,6 @@ 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); | |||
@@ -61,7 +61,7 @@ maybe_connect_to(struct torrent *tp, const char *pinfo) | |||
if (bcmp(btpd_get_peer_id(), pid, 20) == 0) | |||
return; | |||
if (torrent_has_peer(tp, pid)) | |||
if (net_torrent_has_peer(tp->net, pid)) | |||
return; | |||
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) | |||
goto out; | |||
peer_create_out(tp, pid, ip, port); | |||
peer_create_out(tp->net, pid, ip, port); | |||
out: | |||
if (ip != NULL) | |||
@@ -118,7 +118,7 @@ parse_reply(struct torrent *tp, const char *content, size_t size) | |||
if (error == 0 && length % 6 == 0) { | |||
size_t i; | |||
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" | |||
"&downloaded=%ju&left=%ju&compact=1%s%s", | |||
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), | |||
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 *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) | |||
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 (((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].i = i; | |||
nworthy++; | |||
@@ -143,14 +143,12 @@ ul_on_lost_peer(struct peer *p) | |||
} | |||
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); | |||
m_npeers--; | |||
p = next; | |||
} | |||
choke_do(); | |||
} | |||
@@ -3,7 +3,7 @@ | |||
void ul_on_new_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_uninterest(struct peer *p); | |||
void ul_init(void); | |||