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.
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;
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)
ret = btr_node_status(btrn, 0, BTR_NT_ROOT);
if (ret < 0)
return;
if (!FD_ISSET(pdd->fd, &s->rfds))
return; /* nothing to do */
return;
if (!FD_ISSET(pdd->fd, &s->rfds))
return; /* nothing to do */
+ iovcnt = btr_pool_get_buffers(pdd->btrp, iov);
- sz = btr_pool_get_buffer(pdd->btrp, &buf);
- if (sz == 0)
- 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;
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);
return;
err:
btr_remove_node(rn->btrn);