(r)->tv_sec = (a)->tv_sec - (b)->tv_sec;\
(r)->tv_usec = (a)->tv_usec - (b)->tv_usec;\
if((r)->tv_usec < 0)\
- (r)->tv_sec--, (r)->tv_usec += 1000000;\
+ (r)->tv_sec--, (r)->tv_usec += USEC_PER_SEC;\
} while (0)
#endif
-#ifndef max
-#define max(a, b) ((a) > (b) ? (a) : (b))
-#endif
+static inline size_t max(size_t a, size_t b) {
+ return a > b ? a : b;
+}
#ifdef UTCP_DEBUG
#include <stdarg.h>
if(len > sizeof hdr) {
uint32_t datalen = len - sizeof hdr;
uint8_t *str = malloc((datalen << 1) + 7);
+ if(!str) {
+ debug("out of memory");
+ return;
+ }
memcpy(str, " data=", 6);
uint8_t *strptr = str + 6;
const uint8_t *data = pkt;
} else {
do {
newsize *= 2;
- } while(newsize < buf->used + len);
+ } while(newsize < required);
}
if(newsize > buf->maxsize)
newsize = buf->maxsize;
}
static void retransmit(struct utcp_connection *c) {
- if(c->state == CLOSED || c->snd.nxt == c->snd.una)
+ if(c->state == CLOSED || c->snd.last == c->snd.una) {
+ debug("Retransmit() called but nothing to retransmit!\n");
+ stop_retransmit_timer(c);
return;
+ }
struct utcp *utcp = c->utcp;
free(pkt);
}
-// Update receive buffer and SACK entries after consuming data.
+/* Update receive buffer and SACK entries after consuming data.
+ *
+ * Situation:
+ *
+ * |.....0000..1111111111.....22222......3333|
+ * |---------------^
+ *
+ * 0..3 represent the SACK entries. The ^ indicates up to which point we want
+ * to remove data from the receive buffer. The idea is to substract "len"
+ * from the offset of all the SACK entries, and then remove/cut down entries
+ * that are shifted to before the start of the receive buffer.
+ *
+ * There are three cases:
+ * - the SACK entry is after ^, in that case just change the offset.
+ * - the SACK entry starts before and ends after ^, so we have to
+ * change both its offset and size.
+ * - the SACK entry is completely before ^, in that case delete it.
+ */
static void sack_consume(struct utcp_connection *c, size_t len) {
debug("sack_consume %zu\n", len);
if(len > c->rcvbuf.used)
c->sacks[i].offset -= len;
i++;
} else if(len < c->sacks[i].offset + c->sacks[i].len) {
- c->sacks[i].offset = 0;
c->sacks[i].len -= len - c->sacks[i].offset;
+ c->sacks[i].offset = 0;
i++;
} else {
if(i < NSACKS - 1) {
memmove(&c->sacks[i], &c->sacks[i + 1], (NSACKS - 1 - i) * sizeof c->sacks[i]);
- c->sacks[i + 1].len = 0;
+ c->sacks[NSACKS - 1].len = 0;
} else {
c->sacks[i].len = 0;
break;
memmove(&c->sacks[i + 1], &c->sacks[i], (NSACKS - i - 1) * sizeof c->sacks[i]);
c->sacks[i].offset = offset;
c->sacks[i].len = rxd;
+ } else {
+ debug("SACK entries full, dropping packet\n");
}
break;
} else { // merge
// In case this is for a CLOSED connection, ignore the packet.
// TODO: make it so incoming packets can never match a CLOSED connection.
- if(c->state == CLOSED)
+ if(c->state == CLOSED) {
+ debug("Got packet for closed connection\n");
return 0;
+ }
// It is for an existing connection.
c->snd.last++;
ack(c, false);
+ if(!timerisset(&c->rtrx_timeout))
+ start_retransmit_timer(c);
return 0;
}
int utcp_close(struct utcp_connection *c) {
- if(utcp_shutdown(c, SHUT_RDWR))
+ if(utcp_shutdown(c, SHUT_RDWR) && errno != ENOTCONN)
return -1;
c->recv = NULL;
c->poll = NULL;
utcp->send = send;
utcp->priv = priv;
utcp->mtu = DEFAULT_MTU;
- utcp->timeout = DEFAULT_USER_TIMEOUT; // s
- utcp->rto = START_RTO; // us
+ utcp->timeout = DEFAULT_USER_TIMEOUT; // sec
+ utcp->rto = START_RTO; // usec
return utcp;
}