From 9e44ee868aaddc68f2cb18bef0d73093e889b810 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Sat, 13 Feb 2010 13:12:47 +0100 Subject: [PATCH] dccp_recv: Use para_readv() instead of recv_bin_buffer(). When the end of the buffer pool area is reached, the old code ended up calling recv() with a buffer size smaller than a full datagram. This results in data being lost because the remaining part of the datagram will be discarded rather than returned at the next call to recv(). By using the new btr_pool_get_buffers() we obtain two buffers in this case, a small one pointing to the end of the area and a larger one pointing to the area start. Passing both buffers to para_readv() instead of using recv_bin_buffer() receives the full datagram and therefore avoids the above mentioned loss of data. --- dccp_recv.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/dccp_recv.c b/dccp_recv.c index 0fddcfac..e0d3e234 100644 --- a/dccp_recv.c +++ b/dccp_recv.c @@ -111,9 +111,8 @@ static void dccp_recv_post_select(struct sched *s, struct task *t) struct receiver_node *rn = container_of(t, struct receiver_node, task); struct private_dccp_recv_data *pdd = rn->private_data; struct btr_node *btrn = rn->btrn; - int ret; - char *buf; - size_t sz; + struct iovec iov[2]; + int ret, iovcnt; ret = btr_node_status(btrn, 0, BTR_NT_ROOT); if (ret < 0) @@ -122,16 +121,21 @@ static void dccp_recv_post_select(struct sched *s, struct task *t) return; if (!FD_ISSET(pdd->fd, &s->rfds)) return; /* nothing to do */ + iovcnt = btr_pool_get_buffers(pdd->btrp, iov); ret = -E_DCCP_OVERRUN; - sz = btr_pool_get_buffer(pdd->btrp, &buf); - if (sz == 0) + if (iovcnt == 0) goto err; - ret = recv_bin_buffer(pdd->fd, buf, sz); + ret = para_readv(pdd->fd, iov, iovcnt); if (ret == 0) ret = -E_RECV_EOF; if (ret < 0) goto err; - btr_add_output_pool(pdd->btrp, ret, btrn); + if (ret <= iov[0].iov_len) /* only the first buffer was filled */ + btr_add_output_pool(pdd->btrp, ret, btrn); + else { /* both buffers contain data */ + btr_add_output_pool(pdd->btrp, iov[0].iov_len, btrn); + btr_add_output_pool(pdd->btrp, ret - iov[0].iov_len, btrn); + } return; err: btr_remove_node(rn->btrn); -- 2.39.2