return NULL;
c->recv = recv;
+ c->priv = priv;
struct hdr hdr;
// 3. Advance snd.una
uint32_t advanced = seqdiff(hdr.ack, c->snd.una);
- c->snd.una = hdr.ack;
+ uint32_t prevrcvnxt = c->rcv.nxt;
if(advanced) {
- debug("%p advanced %u\n", utcp, advanced);
+ int32_t data_acked = advanced;
+
+ switch(c->state) {
+ case SYN_SENT:
+ case SYN_RECEIVED:
+ data_acked--;
+ break;
+ // TODO: handle FIN as well.
+ default:
+ break;
+ }
+
+ assert(data_acked >= 0);
+
+ int32_t bufused = seqdiff(c->snd.last, c->snd.una);
+ assert(data_acked <= bufused);
+
// Make room in the send buffer.
// TODO: try to avoid memmoving too much. Circular buffer?
- uint32_t left = seqdiff(c->snd.nxt, hdr.ack);
- if(left)
- memmove(c->sndbuf, c->sndbuf + advanced, left);
+ uint32_t left = bufused - data_acked;
+ if(data_acked && left)
+ memmove(c->sndbuf, c->sndbuf + data_acked, left);
+
+ c->snd.una = hdr.ack;
+
c->dupack = 0;
c->snd.cwnd += utcp->mtu;
if(c->snd.cwnd > c->maxsndbufsize)
c->snd.cwnd = c->maxsndbufsize;
- debug("%p increasing cwnd to %u\n", utcp, c->snd.cwnd);
// Check if we have sent a FIN that is now ACKed.
switch(c->state) {
}
}
- if(!len && !advanced)
- return 0;
-
- if(!len && !(hdr.ctl & SYN) && !(hdr.ctl & FIN))
- return 0;
+ // Now we send something back if:
+ // - we advanced rcv.nxt (ie, we got some data that needs to be ACKed)
+ // -> sendatleastone = true
+ // - or we got an ack, so we should maybe send a bit more data
+ // -> sendatleastone = false
ack:
- ack(c, true);
+ ack(c, prevrcvnxt != c->rcv.nxt);
return 0;
reset:
retransmit(c);
}
+ if(c->poll && c->sndbufsize < c->maxsndbufsize / 2)
+ c->poll(c, c->maxsndbufsize - c->sndbufsize);
+
if(timerisset(&c->conn_timeout) && timercmp(&c->conn_timeout, &next, <))
next = c->conn_timeout;
return c->maxsndbufsize;
}
+size_t utcp_get_sndbuf_free(struct utcp_connection *c) {
+ return c->maxsndbufsize - c->sndbufsize;
+}
+
void utcp_set_sndbuf(struct utcp_connection *c, size_t size) {
c->maxsndbufsize = size;
if(c->maxsndbufsize != size)
size_t utcp_get_outq(struct utcp_connection *c) {
return seqdiff(c->snd.nxt, c->snd.una);
}
+
+void utcp_set_recv_cb(struct utcp_connection *c, utcp_recv_t recv) {
+ c->recv = recv;
+}
+
+void utcp_set_poll_cb(struct utcp_connection *c, utcp_poll_t poll) {
+ c->poll = poll;
+}