diff --git a/btpd/download.c b/btpd/download.c
index 2bb62fc..9ef54be 100644
--- a/btpd/download.c
+++ b/btpd/download.c
@@ -79,14 +79,17 @@ dl_on_choke(struct peer *p)
 void
 dl_on_ok_piece(struct net *n, uint32_t piece)
 {
-    struct peer *p;
+    struct peer *p, *next;
     struct piece *pc = dl_find_piece(n, piece);
 
     btpd_log(BTPD_L_POL, "Got piece: %u.\n", pc->index);
 
     struct net_buf *have = nb_create_have(pc->index);
+    nb_hold(have);
     BTPDQ_FOREACH(p, &n->peers, p_entry)
-        peer_send(p, have);
+        if (!peer_has(p, pc->index))
+            peer_send(p, have);
+    nb_drop(have);
 
     if (n->endgame)
         BTPDQ_FOREACH(p, &n->peers, p_entry)
@@ -100,8 +103,11 @@ dl_on_ok_piece(struct net *n, uint32_t piece)
         btpd_log(BTPD_L_BTPD, "Finished downloading '%s'.\n",
             torrent_name(n->tp));
         tr_complete(n->tp);
-        BTPDQ_FOREACH(p, &n->peers, p_entry)
+        BTPDQ_FOREACH_MUTABLE(p, &n->peers, p_entry, next) {
             assert(p->nwant == 0);
+            if (peer_full(p))
+                peer_kill(p);
+        }
     }
 }
 
diff --git a/btpd/net_types.h b/btpd/net_types.h
index b444eea..9ade854 100644
--- a/btpd/net_types.h
+++ b/btpd/net_types.h
@@ -63,6 +63,7 @@ struct peer {
 
     long t_created;
     long t_wantwrite;
+    long t_nointerest;
 
     struct {
         uint32_t msg_len;
diff --git a/btpd/peer.c b/btpd/peer.c
index 7ce486d..c8f60dc 100644
--- a/btpd/peer.c
+++ b/btpd/peer.c
@@ -250,6 +250,7 @@ peer_unwant(struct peer *p, uint32_t index)
     p->nwant--;
     if (p->nwant == 0) {
         p->flags &= ~PF_I_WANT;
+        p->t_nointerest = btpd_seconds;
         if (p->nreqs_out == 0)
             peer_send(p, nb_create_uninterest());
         else
@@ -265,6 +266,7 @@ peer_create_common(int sd)
     p->sd = sd;
     p->flags = PF_I_CHOKE | PF_P_CHOKE;
     p->t_created = btpd_seconds;
+    p->t_nointerest = btpd_seconds;
     BTPDQ_INIT(&p->my_reqs);
     BTPDQ_INIT(&p->outq);
 
@@ -416,6 +418,7 @@ peer_on_uninterest(struct peer *p)
         return;
     else {
         p->flags &= ~PF_P_WANT;
+        p->t_nointerest = btpd_seconds;
         ul_on_uninterest(p);
     }
 }
@@ -512,13 +515,23 @@ peer_on_cancel(struct peer *p, uint32_t index, uint32_t begin,
 void
 peer_on_tick(struct peer *p)
 {
-    if ((p->flags & PF_ATTACHED) == 0 && btpd_seconds - p->t_created >= 60) {
-        btpd_log(BTPD_L_CONN, "hand shake timed out.\n");
-        peer_kill(p);
-    } else if (!BTPDQ_EMPTY(&p->outq) && btpd_seconds - p->t_wantwrite >= 60) {
-        btpd_log(BTPD_L_CONN, "write attempt timed out.\n");
-        peer_kill(p);
+    if (p->flags & PF_ATTACHED) {
+        if (!BTPDQ_EMPTY(&p->outq) && btpd_seconds - p->t_wantwrite >= 60) {
+            btpd_log(BTPD_L_CONN, "write attempt timed out.\n");
+            goto kill;
+        }
+        if ((cm_full(p->n->tp) && !(p->flags & PF_P_WANT) &&
+                btpd_seconds - p->t_nointerest >= 600)) {
+            btpd_log(BTPD_L_CONN, "no interest for 10 minutes.\n");
+            goto kill;
+        }
+    } else if (btpd_seconds - p->t_created >= 60) {
+            btpd_log(BTPD_L_CONN, "hand shake timed out.\n");
+            goto kill;
     }
+    return;
+kill:
+    peer_kill(p);
 }
 
 int