uint32_t realoffset = buf->offset + offset;
- if(buf->size - buf->offset < offset) {
+ if(buf->size - buf->offset <= offset) {
// The offset wrapped
realoffset -= buf->size;
}
uint32_t realoffset = buf->offset + offset;
- if(buf->size - buf->offset < offset) {
+ if(buf->size - buf->offset <= offset) {
// The offset wrapped
realoffset -= buf->size;
}
}
// 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;
uint32_t realoffset = buf->offset + offset;
- if(buf->size - buf->offset < offset) {
+ if(buf->size - buf->offset <= offset) {
// The offset wrapped
realoffset -= buf->size;
}
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;
return rx1 + rx2;
}
} else {
- return cb(arg, buf->data + realoffset, len);
+ return c->recv(c, buf->data + realoffset, len);
}
}
len = buf->used;
}
- if(buf->size - buf->offset < len) {
+ if(buf->size - buf->offset <= len) {
buf->offset -= buf->size;
}
pkt->hdr.ctl |= FIN;
}
- if(!c->rtt_start.tv_sec) {
+ if(!c->rtt_start.tv_sec && is_reliable(c)) {
// Start RTT measurement
clock_gettime(UTCP_CLOCK, &c->rtt_start);
c->rtt_seq = pkt->hdr.seq + seglen;
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();
}
}
}
}
// Ensure reassembled packet are not larger than 64 kiB
- if(hdr->wnd >= MAX_UNRELIABLE_SIZE || hdr->wnd + len > MAX_UNRELIABLE_SIZE) {
+ if(hdr->wnd > MAX_UNRELIABLE_SIZE || hdr->wnd + len > MAX_UNRELIABLE_SIZE) {
return;
}
}
// 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;
}
int utcp_close(struct utcp_connection *c) {
+ if(c->rcvbuf.used) {
+ fprintf(stderr, "UTCP channel closed with stuff in receive buffer\n");
+ return reset_connection(c) ? 0 : -1;
+ }
+
if(utcp_shutdown(c, SHUT_RDWR) && errno != ENOTCONN) {
return -1;
}