From 6b7010c9d90978b60d35abf6242d2a10d6bbd5bc Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Thu, 14 May 2020 23:47:01 +0200 Subject: [PATCH] Handle channel closure during a receive callback when the ringbuffer wraps. 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. --- utcp.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/utcp.c b/utcp.c index fb93f2f..04d2b19 100644 --- a/utcp.c +++ b/utcp.c @@ -322,7 +322,11 @@ static ssize_t buffer_copy(struct buffer *buf, void *data, size_t offset, size_t } // 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; @@ -341,13 +345,18 @@ static ssize_t buffer_call(struct buffer *buf, utcp_recv_t cb, void *arg, size_t 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; } - 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; @@ -355,7 +364,7 @@ static ssize_t buffer_call(struct buffer *buf, utcp_recv_t cb, void *arg, size_t return rx1 + rx2; } } else { - return cb(arg, buf->data + realoffset, len); + return c->recv(c, buf->data + realoffset, len); } } @@ -1110,13 +1119,11 @@ static void handle_in_order(struct utcp_connection *c, const void *data, size_t 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(); } } } @@ -1161,8 +1168,8 @@ static void handle_unreliable(struct utcp_connection *c, const struct hdr *hdr, } // 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; -- 2.39.2