+static void retransmit(struct utcp_connection *c) {
+ if(c->state == CLOSED || c->snd.nxt == c->snd.una)
+ return;
+
+ struct utcp *utcp = c->utcp;
+
+ struct {
+ struct hdr hdr;
+ char data[c->utcp->mtu];
+ } pkt;
+
+ pkt.hdr.src = c->src;
+ pkt.hdr.dst = c->dst;
+
+ switch(c->state) {
+ case LISTEN:
+ // TODO: this should not happen
+ break;
+
+ case SYN_SENT:
+ 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);
+ break;
+
+ case SYN_RECEIVED:
+ pkt.hdr.seq = c->snd.nxt;
+ pkt.hdr.ack = c->rcv.nxt;
+ pkt.hdr.ctl = SYN | ACK;
+ print_packet(c->utcp, "rtrx", &pkt, sizeof pkt.hdr);
+ utcp->send(utcp, &pkt, sizeof pkt.hdr);
+ break;
+
+ case ESTABLISHED:
+ case FIN_WAIT_1:
+ pkt.hdr.seq = c->snd.una;
+ pkt.hdr.ack = c->rcv.nxt;
+ pkt.hdr.ctl = ACK;
+ uint32_t len = seqdiff(c->snd.nxt, c->snd.una);
+ if(c->state == FIN_WAIT_1)
+ len--;
+ if(len > utcp->mtu)
+ len = utcp->mtu;
+ else {
+ if(c->state == FIN_WAIT_1)
+ pkt.hdr.ctl |= FIN;
+ }
+ memcpy(pkt.data, c->sndbuf, len);
+ print_packet(c->utcp, "rtrx", &pkt, sizeof pkt.hdr + len);
+ utcp->send(utcp, &pkt, sizeof pkt.hdr + len);
+ break;
+
+ default:
+ // TODO: implement
+ abort();
+ }
+}
+
+/* Handle timeouts.
+ * One call to this function will loop through all connections,
+ * checking if something needs to be resent or not.
+ * The return value is the time to the next timeout in milliseconds,
+ * or maybe a negative value if the timeout is infinite.
+ */
+int utcp_timeout(struct utcp *utcp) {