+static void ack(struct utcp_connection *c, bool sendatleastone) {
+ int32_t left = seqdiff(c->snd.last, c->snd.nxt);
+ int32_t cwndleft = c->snd.cwnd - seqdiff(c->snd.nxt, c->snd.una);
+ char *data = c->sndbuf + seqdiff(c->snd.nxt, c->snd.una);
+
+ fprintf(stderr, "ack, left=%d, cwndleft=%d, sendatleastone=%d\n", left, cwndleft, sendatleastone);
+ if(left < 0)
+ abort();
+
+ if(cwndleft <= 0)
+ cwndleft = 0;
+
+ if(cwndleft < left)
+ left = cwndleft;
+
+ if(!left && !sendatleastone)
+ return;
+
+ struct {
+ struct hdr hdr;
+ char data[c->utcp->mtu];
+ } pkt;
+
+ pkt.hdr.src = c->src;
+ pkt.hdr.dst = c->dst;
+ pkt.hdr.ack = c->rcv.nxt;
+ pkt.hdr.wnd = c->snd.wnd;
+ pkt.hdr.ctl = ACK;
+
+ do {
+ uint32_t seglen = left > c->utcp->mtu ? c->utcp->mtu : left;
+ pkt.hdr.seq = c->snd.nxt;
+
+ memcpy(pkt.data, data, seglen);
+
+ c->snd.nxt += seglen;
+ data += seglen;
+ left -= seglen;
+
+ if(c->state != ESTABLISHED && !left && seglen) {
+ switch(c->state) {
+ case FIN_WAIT_1:
+ case CLOSING:
+ seglen--;
+ pkt.hdr.ctl |= FIN;
+ break;
+ default:
+ break;
+ }
+ }
+
+ print_packet(c->utcp, "send", &pkt, sizeof pkt.hdr + seglen);
+ c->utcp->send(c->utcp, &pkt, sizeof pkt.hdr + seglen);
+ } while(left);
+}
+