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