about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRichard Nyberg <rnyberg@murmeldjur.se>2006-01-09 21:20:14 +0000
committerRichard Nyberg <rnyberg@murmeldjur.se>2006-01-09 21:20:14 +0000
commit2d21101699e34ee1e29d1789771fddbf1733d0a1 (patch)
treee7260e6bf0f1c43e8ef5e795fd91eee8f3e97143
parent0aa097548611b6eada065caf7eddb5a715904e74 (diff)
downloadbtpd-2d21101699e34ee1e29d1789771fddbf1733d0a1.tar.gz
btpd-2d21101699e34ee1e29d1789771fddbf1733d0a1.zip
* Move the network related parts of the torrent struct to a sub struct.
* 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 :P

-rw-r--r--btpd/Makefile.am2
-rw-r--r--btpd/btpd.h1
-rw-r--r--btpd/content.c4
-rw-r--r--btpd/download.c75
-rw-r--r--btpd/download.h7
-rw-r--r--btpd/download_subr.c114
-rw-r--r--btpd/net.c98
-rw-r--r--btpd/net.h2
-rw-r--r--btpd/net_types.h114
-rw-r--r--btpd/peer.c41
-rw-r--r--btpd/peer.h67
-rw-r--r--btpd/torrent.c17
-rw-r--r--btpd/torrent.h49
-rw-r--r--btpd/tracker_req.c8
-rw-r--r--btpd/upload.c16
-rw-r--r--btpd/upload.h2
16 files changed, 310 insertions, 307 deletions
diff --git a/btpd/Makefile.am b/btpd/Makefile.am
index cd3870f..ab67b5e 100644
--- a/btpd/Makefile.am
+++ b/btpd/Makefile.am
@@ -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\
diff --git a/btpd/btpd.h b/btpd/btpd.h
index 323c939..c00469d 100644
--- a/btpd/btpd.h
+++ b/btpd/btpd.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"
diff --git a/btpd/content.c b/btpd/content.c
index a86a815..06a282d 100644
--- a/btpd/content.c
+++ b/btpd/content.c
@@ -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);
 }
diff --git a/btpd/download.c b/btpd/download.c
index a4398db..5948425 100644
--- a/btpd/download.c
+++ b/btpd/download.c
@@ -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);
diff --git a/btpd/download.h b/btpd/download.h
index 94f71da..baeed94 100644
--- a/btpd/download.h
+++ b/btpd/download.h
@@ -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);
 
diff --git a/btpd/download_subr.c b/btpd/download_subr.c
index f1db9a7..225effc 100644
--- a/btpd/download_subr.c
+++ b/btpd/download_subr.c
@@ -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) {
diff --git a/btpd/net.c b/btpd/net.c
index cfc6813..fca3143 100644
--- a/btpd/net.c
+++ b/btpd/net.c
@@ -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;
     }
diff --git a/btpd/net.h b/btpd/net.h
index 2fafbcd..6a79b78 100644
--- a/btpd/net.h
+++ b/btpd/net.h
@@ -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);
 
diff --git a/btpd/net_types.h b/btpd/net_types.h
new file mode 100644
index 0000000..6b17bac
--- /dev/null
+++ b/btpd/net_types.h
@@ -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
diff --git a/btpd/peer.c b/btpd/peer.c
index 779ae7d..f043056 100644
--- a/btpd/peer.c
+++ b/btpd/peer.c
@@ -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++;
diff --git a/btpd/peer.h b/btpd/peer.h
index 722f70e..0921438 100644
--- a/btpd/peer.h
+++ b/btpd/peer.h
@@ -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);
diff --git a/btpd/torrent.c b/btpd/torrent.c
index 902e765..909b18b 100644
--- a/btpd/torrent.c
+++ b/btpd/torrent.c
@@ -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;
     }
 }
 
diff --git a/btpd/torrent.h b/btpd/torrent.h
index 10d6691..6ce07a4 100644
--- a/btpd/torrent.h
+++ b/btpd/torrent.h
@@ -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);
 
diff --git a/btpd/tracker_req.c b/btpd/tracker_req.c
index db65e54..58246e3 100644
--- a/btpd/tracker_req.c
+++ b/btpd/tracker_req.c
@@ -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]);
 }
diff --git a/btpd/upload.c b/btpd/upload.c
index 5e5174d..7de5243 100644
--- a/btpd/upload.c
+++ b/btpd/upload.c
@@ -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();
 }
diff --git a/btpd/upload.h b/btpd/upload.h
index 49956ff..43a8560 100644
--- a/btpd/upload.h
+++ b/btpd/upload.h
@@ -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);