* Add function net_unsend to safely remove network buffers from a peer's outq. Use it where needed in peer.c.master
@@ -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) | |||
{ | |||
@@ -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); | |||
@@ -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 | |||