If the data in the ringbuffer wraps around, and we call the receive
callback for the first part of the data, the callback function might close
the channel, so we must not call the callback for the second part of the
data.
}
// Copy data from the buffer without removing it.
}
// Copy data from the buffer without removing it.
-static ssize_t buffer_call(struct buffer *buf, utcp_recv_t cb, void *arg, size_t offset, size_t len) {
+static ssize_t buffer_call(struct utcp_connection *c, struct buffer *buf, size_t offset, size_t len) {
+ if(!c->recv) {
+ return len;
+ }
+
// Ensure we don't copy more than is actually stored in the buffer
if(offset >= buf->used) {
return 0;
// Ensure we don't copy more than is actually stored in the buffer
if(offset >= buf->used) {
return 0;
if(buf->size - realoffset < len) {
// The data is wrapped
if(buf->size - realoffset < len) {
// The data is wrapped
- ssize_t rx1 = cb(arg, buf->data + realoffset, buf->size - realoffset);
+ ssize_t rx1 = c->recv(c, buf->data + realoffset, buf->size - realoffset);
if(rx1 < buf->size - realoffset) {
return rx1;
}
if(rx1 < buf->size - realoffset) {
return rx1;
}
- ssize_t rx2 = cb(arg, buf->data, len - (buf->size - realoffset));
+ // The channel might have been closed by the previous callback
+ if(!c->recv) {
+ return len;
+ }
+
+ ssize_t rx2 = c->recv(c, buf->data, len - (buf->size - realoffset));
if(rx2 < 0) {
return rx2;
if(rx2 < 0) {
return rx2;
return rx1 + rx2;
}
} else {
return rx1 + rx2;
}
} else {
- return cb(arg, buf->data + realoffset, len);
+ return c->recv(c, buf->data + realoffset, len);
len = c->sacks[0].offset + c->sacks[0].len;
size_t remainder = len - offset;
len = c->sacks[0].offset + c->sacks[0].len;
size_t remainder = len - offset;
- if(c->recv) {
- ssize_t rxd = buffer_call(&c->rcvbuf, c->recv, c, offset, remainder);
+ ssize_t rxd = buffer_call(c, &c->rcvbuf, offset, remainder);
- if(rxd != (ssize_t)remainder) {
- // TODO: handle the application not accepting all data.
- abort();
- }
+ if(rxd != (ssize_t)remainder) {
+ // TODO: handle the application not accepting all data.
+ abort();
}
// Send the packet if it's the final fragment
}
// Send the packet if it's the final fragment
- if(!(hdr->ctl & MF) && c->recv) {
- buffer_call(&c->rcvbuf, c->recv, c, 0, hdr->wnd + len);
+ if(!(hdr->ctl & MF)) {
+ buffer_call(c, &c->rcvbuf, 0, hdr->wnd + len);
}
c->rcv.nxt = hdr->seq + len;
}
c->rcv.nxt = hdr->seq + len;