diff --git a/btpd/net.c b/btpd/net.c
index 3030ddb..1c22111 100644
--- a/btpd/net.c
+++ b/btpd/net.c
@@ -97,7 +97,6 @@ nb_create_alloc(short type, size_t len)
     nb->buf = (char *)(nb + 1);
     nb->len = len;
     nb->kill_buf = kill_buf_no;
-    nb_hold(nb);
     return nb;
 }
 
@@ -110,7 +109,6 @@ nb_create_set(short type, char *buf, size_t len,
     nb->buf = buf;
     nb->len = len;
     nb->kill_buf = kill_buf;
-    nb_hold(nb);
     return nb;
 }
 
@@ -209,6 +207,7 @@ net_send(struct peer *p, struct net_buf *nb)
 {
     struct nb_link *nl = btpd_calloc(1, sizeof(*nl));
     nl->nb = nb;
+    nb_hold(nb);
 
     if (BTPDQ_EMPTY(&p->outq)) {
 	assert(p->outq_off == 0);
@@ -217,6 +216,33 @@ net_send(struct peer *p, struct net_buf *nb)
     BTPDQ_INSERT_TAIL(&p->outq, nl, entry);
 }
 
+
+/*
+ * Remove a network buffer from the peer's outq.
+ * If a part of the buffer already have been written
+ * to the network it cannot be removed.
+ *
+ * Returns 1 if the buffer is removed, 0 if not.
+ */
+int
+net_unsend(struct peer *p, struct nb_link *nl)
+{
+    if (!(nl == BTPDQ_FIRST(&p->outq) && p->outq_off > 0)) {
+	BTPDQ_REMOVE(&p->outq, nl, entry);
+	nb_drop(nl->nb);
+	free(nl);
+	if (BTPDQ_EMPTY(&p->outq)) {
+	    if (p->flags & PF_ON_WRITEQ) {
+		BTPDQ_REMOVE(&btpd.writeq, p, wq_entry);
+		p->flags &= ~PF_ON_WRITEQ;
+	    } else
+		event_del(&p->out_ev);
+	}
+	return 1;
+    } else
+	return 0;
+}
+
 void
 net_write32(void *buf, uint32_t num)
 {
diff --git a/btpd/net.h b/btpd/net.h
index 25c3c21..048a19b 100644
--- a/btpd/net.h
+++ b/btpd/net.h
@@ -120,7 +120,7 @@ void net_send_request(struct peer *p, struct piece_req *req);
 void net_send_piece(struct peer *p, uint32_t index, uint32_t begin,
     char *block, size_t blen);
 void net_send_cancel(struct peer *p, struct piece_req *req);
-
+int net_unsend(struct peer *p, struct nb_link *nl);
 void net_handshake(struct peer *p, int incoming);
 
 void net_read_cb(int sd, short type, void *arg);
diff --git a/btpd/peer.c b/btpd/peer.c
index c3de819..a8058a6 100644
--- a/btpd/peer.c
+++ b/btpd/peer.c
@@ -110,16 +110,11 @@ peer_choke(struct peer *p)
     struct nb_link *nl = BTPDQ_FIRST(&p->outq);
     while (nl != NULL) {
 	struct nb_link *next = BTPDQ_NEXT(nl, entry);
-	if (nl->nb->info.type == NB_PIECE
-	    && (nl != BTPDQ_FIRST(&p->outq) && p->outq_off > 0)) {
-	    nb_drop(nl->nb);
-	    BTPDQ_REMOVE(&p->outq, nl, entry);
-	    free(nl);
-	    nl = next;
+	if (nl->nb->info.type == NB_PIECE) {
+	    struct nb_link *data = next;
 	    next = BTPDQ_NEXT(next, entry);
-	    nb_drop(nl->nb);
-	    BTPDQ_REMOVE(&p->outq, nl, entry);
-	    free(nl);
+	    if (net_unsend(p, nl))
+		net_unsend(p, data);
 	}
 	nl = next;
     }
@@ -309,34 +304,17 @@ void
 peer_on_cancel(struct peer *p, uint32_t index, uint32_t begin,
     uint32_t length)
 {
-    struct nb_link *nl = BTPDQ_FIRST(&p->outq);
-    if (nl == NULL)
-	return;
-    while (nl != NULL) {
+    struct nb_link *nl;
+    BTPDQ_FOREACH(nl, &p->outq, entry)
 	if (nl->nb->info.type == NB_PIECE
 	    && nl->nb->info.index == index
 	    && nl->nb->info.begin == begin
-	    && nl->nb->info.length == length
-	    && (nl != BTPDQ_FIRST(&p->outq) && p->outq_off > 0)) {
-	    btpd_log(BTPD_L_MSG, "cancel matched.\n");
+	    && nl->nb->info.length == length) {
 	    struct nb_link *data = BTPDQ_NEXT(nl, entry);
-	    nb_drop(nl->nb);
-	    BTPDQ_REMOVE(&p->outq, nl, entry);
-	    free(nl);
-	    nb_drop(data->nb);
-	    BTPDQ_REMOVE(&p->outq, data, entry);
-	    free(data);
+	    if (net_unsend(p, nl))
+		net_unsend(p, data);
+	    break;
 	}
-	nl = BTPDQ_NEXT(nl, entry);
-    }
-
-    if (BTPDQ_EMPTY(&p->outq)) {
-	if (p->flags & PF_ON_WRITEQ) {
-	    BTPDQ_REMOVE(&btpd.writeq, p, wq_entry);
-	    p->flags &= ~PF_ON_WRITEQ;
-	} else
-	    event_del(&p->out_ev);
-    }
 }
 
 int