debug("ACK");
if(len > sizeof hdr) {
- debug(" data=");
- for(int i = sizeof hdr; i < len; i++) {
- const char *data = pkt;
- debug("%c", data[i] >= 32 ? data[i] : '.');
+ uint32_t datalen = len - sizeof hdr;
+ uint8_t *str = malloc((datalen << 1) + 7);
+ memcpy(str, " data=", 6);
+ uint8_t *strptr = str + 6;
+ const uint8_t *data = pkt;
+ const uint8_t *dataend = data + datalen;
+
+ while(data != dataend) {
+ *strptr = (*data >> 4) > 9? (*data >> 4) + 55 : (*data >> 4) + 48;
+ ++strptr;
+ *strptr = (*data & 0xf) > 9? (*data & 0xf) + 55 : (*data & 0xf) + 48;
+ ++strptr;
+ ++data;
}
+ *strptr = 0;
+
+ debug(str);
+ free(str);
}
debug("\n");
memmove(cp, cp + 1, (utcp->nconnections - i - 1) * sizeof *cp);
utcp->nconnections--;
+ buffer_exit(&c->rcvbuf);
buffer_exit(&c->sndbuf);
free(c);
}
}
if(!buffer_init(&c->rcvbuf, DEFAULT_RCVBUFSIZE, DEFAULT_MAXRCVBUFSIZE)) {
+ buffer_exit(&c->sndbuf);
free(c);
return NULL;
}
pkt->hdr.src = c->src;
pkt->hdr.dst = c->dst;
+ pkt->hdr.wnd = c->rcv.wnd;
+ pkt->hdr.aux = 0;
switch(c->state) {
case SYN_SENT:
// Send our SYN again
pkt->hdr.seq = c->snd.iss;
pkt->hdr.ack = 0;
- pkt->hdr.wnd = c->rcv.wnd;
pkt->hdr.ctl = SYN;
print_packet(c->utcp, "rtrx", pkt, sizeof pkt->hdr);
utcp->send(utcp, pkt, sizeof pkt->hdr);
if(c->state == SYN_SENT)
acceptable = true;
-
- // TODO: handle packets overlapping c->rcv.nxt.
-#if 1
- // Only use this when accepting out-of-order packets.
else if(len == 0)
acceptable = seqdiff(hdr.seq, c->rcv.nxt) >= 0;
- else
+ else {
+ int32_t rcv_offset = seqdiff(hdr.seq, c->rcv.nxt);
+
+ // cut already accepted front overlapping
+ if(rcv_offset < 0) {
+ acceptable = rcv_offset + len >= 0;
+ if(acceptable) {
+ data -= rcv_offset;
+ len += rcv_offset;
+ }
+ }
+
acceptable = seqdiff(hdr.seq, c->rcv.nxt) >= 0 && seqdiff(hdr.seq, c->rcv.nxt) + len <= c->rcvbuf.maxsize;
-#else
- if(c->state != SYN_SENT)
- acceptable = hdr.seq == c->rcv.nxt;
-#endif
+ }
if(!acceptable) {
debug("Packet not acceptable, %u <= %u + %zu < %u\n", c->rcv.nxt, hdr.seq, len, c->rcv.nxt + c->rcvbuf.maxsize);
// ackno should not roll back, and it should also not be bigger than what we ever could have sent
// (= snd.una + c->sndbuf.used).
- if(hdr.ctl & ACK &&
- ((seqdiff(hdr.ack, c->snd.una + c->sndbuf.used) > 0 &&
- seqdiff(hdr.ack, c->snd.nxt) > 0) // TODO: simplify this if
- || seqdiff(hdr.ack, c->snd.una) < 0)) {
+ if(hdr.ctl & ACK && (seqdiff(hdr.ack, c->snd.last) > 0 || seqdiff(hdr.ack, c->snd.una) < 0)) {
debug("Packet ack seqno out of range, %u <= %u < %u\n", c->snd.una, hdr.ack, c->snd.una + c->sndbuf.used);
// Ignore unacceptable RST packets.
if(hdr.ctl & RST)
//Reset the congestion window so we wait for ACKs.
c->snd.nxt = c->snd.una;
c->snd.cwnd = utcp->mtu;
+ start_retransmit_timer(c);
}
}
}
// - or we got an ack, so we should maybe send a bit more data
// -> sendatleastone = false
-ack:
- ack(c, prevrcvnxt != c->rcv.nxt);
+ ack(c, len || prevrcvnxt != c->rcv.nxt);
return 0;
reset:
c->snd.last++;
ack(c, false);
+ if(!timerisset(&c->rtrx_timeout))
+ start_retransmit_timer(c);
return 0;
}
if(!c)
continue;
+ // delete connections that have been utcp_close()d.
if(c->state == CLOSED) {
if(c->reapable) {
debug("Reaping %p\n", c);
}
if(timerisset(&c->rtrx_timeout) && timercmp(&c->rtrx_timeout, &now, <)) {
+ debug("retransmit()\n");
retransmit(c);
}
for(int i = 0; i < utcp->nconnections; i++) {
if(!utcp->connections[i]->reapable)
debug("Warning, freeing unclosed connection %p\n", utcp->connections[i]);
+ buffer_exit(&utcp->connections[i]->rcvbuf);
buffer_exit(&utcp->connections[i]->sndbuf);
free(utcp->connections[i]);
}