X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=utcp.c;h=75553d72567be387667b7ced7871cac32d0d6a46;hb=5d25d40b5baf4bd60ccc1dc6db65b3e5b094e2cd;hp=9f668edd37256e214db12347722c48a79dd8f4cf;hpb=f4c52312544ee99bcce46ebcfc0c8e6ac6356fd5;p=utcp diff --git a/utcp.c b/utcp.c index 9f668ed..75553d7 100644 --- a/utcp.c +++ b/utcp.c @@ -32,6 +32,27 @@ #include "utcp_priv.h" +#ifndef EBADMSG +#define EBADMSG 104 +#endif + +#ifndef SHUT_RDWR +#define SHUT_RDWR 2 +#endif + +#ifdef poll +#undef poll +#endif + +#ifndef timersub +#define timersub(a, b, r) do {\ + (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;\ +} while (0) +#endif + #ifdef UTCP_DEBUG #include @@ -202,6 +223,7 @@ struct utcp_connection *utcp_connect(struct utcp *utcp, uint16_t dst, utcp_recv_ return NULL; c->recv = recv; + c->priv = priv; struct hdr hdr; @@ -596,20 +618,38 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) { // 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) { @@ -775,14 +815,14 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) { } } - 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: @@ -1003,6 +1043,9 @@ int utcp_timeout(struct utcp *utcp) { 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; @@ -1078,6 +1121,10 @@ size_t utcp_get_sndbuf(struct utcp_connection *c) { 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) @@ -1103,3 +1150,11 @@ void utcp_set_keepalive(struct utcp_connection *c, bool keepalive) { 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; +}