-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;
+ }
+
- 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(!is_reliable(c)) {
c->snd.una = c->snd.nxt = c->snd.last;
buffer_discard(&c->sndbuf, c->sndbuf.used);
if(!is_reliable(c)) {
c->snd.una = c->snd.nxt = c->snd.last;
buffer_discard(&c->sndbuf, c->sndbuf.used);
// Packet loss or reordering occured. Store the data in the buffer.
ssize_t rxd = buffer_put_at(&c->rcvbuf, offset, data, len);
// Packet loss or reordering occured. Store the data in the buffer.
ssize_t rxd = buffer_put_at(&c->rcvbuf, offset, data, len);
- if(rxd < 0 || (size_t)rxd < len) {
- abort();
+ if(rxd <= 0) {
+ debug(c, "packet outside receive buffer, dropping\n");
+ return;
+ }
+
+ if((size_t)rxd < len) {
+ debug(c, "packet partially outside receive buffer\n");
+ len = rxd;
- ssize_t rxd = buffer_call(&c->rcvbuf, c->recv, c, offset, remainder);
+
+ ssize_t rxd = buffer_call(c, &c->rcvbuf, offset, remainder);
static void handle_unreliable(struct utcp_connection *c, const struct hdr *hdr, const void *data, size_t len) {
// Fast path for unfragmented packets
if(!hdr->wnd && !(hdr->ctl & MF)) {
static void handle_unreliable(struct utcp_connection *c, const struct hdr *hdr, const void *data, size_t len) {
// Fast path for unfragmented packets
if(!hdr->wnd && !(hdr->ctl & MF)) {
- buffer_call(&c->rcvbuf, c->recv, c, 0, hdr->wnd + len);
+ buffer_call(c, &c->rcvbuf, 0, hdr->wnd + len);
if(offset) {
handle_out_of_order(c, offset, data, len);
} else {
if(offset) {
handle_out_of_order(c, offset, data, len);
} else {
print_packet(c, "send", &pkt, sizeof(hdr));
utcp->send(utcp, &pkt, sizeof(hdr));
}
print_packet(c, "send", &pkt, sizeof(hdr));
utcp->send(utcp, &pkt, sizeof(hdr));
}