]> git.meshlink.io Git - utcp/blobdiff - utcp.c
Use '== -1' to check for errors from functions.
[utcp] / utcp.c
diff --git a/utcp.c b/utcp.c
index f46cdf7f649f0ee4ef77b0c8ebe0a673d5f24af0..e8755ed14470577b6baafbab0d127476454e4dba 100644 (file)
--- a/utcp.c
+++ b/utcp.c
@@ -103,6 +103,19 @@ static void set_state(struct utcp_connection *c, enum state state) {
        debug("%p new state: %s\n", c->utcp, strstate[state]);
 }
 
+static bool fin_wanted(struct utcp_connection *c, uint32_t seq) {
+       if(seq != c->snd.last)
+               return false;
+       switch(c->state) {
+       case FIN_WAIT_1:
+       case CLOSING:
+       case LAST_ACK:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static inline void list_connections(struct utcp *utcp) {
        debug("%p has %d connections:\n", utcp, utcp->nconnections);
        for(int i = 0; i < utcp->nconnections; i++)
@@ -366,16 +379,9 @@ static void ack(struct utcp_connection *c, bool sendatleastone) {
                c->snd.nxt += 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;
-                       }
+               if(seglen && fin_wanted(c, c->snd.nxt)) {
+                       seglen--;
+                       pkt->hdr.ctl |= FIN;
                }
 
                print_packet(c->utcp, "send", pkt, sizeof pkt->hdr + seglen);
@@ -459,11 +465,8 @@ static void retransmit(struct utcp_connection *c) {
        pkt->hdr.dst = c->dst;
 
        switch(c->state) {
-               case LISTEN:
-                       // TODO: this should not happen
-                       break;
-
                case SYN_SENT:
+                       // Send our SYN again
                        pkt->hdr.seq = c->snd.iss;
                        pkt->hdr.ack = 0;
                        pkt->hdr.wnd = c->rcv.wnd;
@@ -473,6 +476,7 @@ static void retransmit(struct utcp_connection *c) {
                        break;
 
                case SYN_RECEIVED:
+                       // Send SYNACK again
                        pkt->hdr.seq = c->snd.nxt;
                        pkt->hdr.ack = c->rcv.nxt;
                        pkt->hdr.ctl = SYN | ACK;
@@ -482,27 +486,35 @@ static void retransmit(struct utcp_connection *c) {
 
                case ESTABLISHED:
                case FIN_WAIT_1:
+               case CLOSE_WAIT:
+               case CLOSING:
+               case LAST_ACK:
+                       // Send unacked data again.
                        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);
-                       fprintf(stderr, "retransmit %u %u %u\n", pkt->hdr.seq, pkt->hdr.ack, len);
-                       if(c->state == FIN_WAIT_1)
-                               len--;
+                       uint32_t len = seqdiff(c->snd.last, c->snd.una);
                        if(len > utcp->mtu)
                                len = utcp->mtu;
-                       else {
-                               if(c->state == FIN_WAIT_1)
-                                       pkt->hdr.ctl |= FIN;
+                       if(fin_wanted(c, c->snd.una + len)) {
+                               len--;
+                               pkt->hdr.ctl |= FIN;
                        }
                        buffer_copy(&c->sndbuf, pkt->data, 0, len);
                        print_packet(c->utcp, "rtrx", pkt, sizeof pkt->hdr + len);
                        utcp->send(utcp, pkt, sizeof pkt->hdr + len);
                        break;
 
-               default:
-                       // TODO: implement
+               case CLOSED:
+               case LISTEN:
+               case TIME_WAIT:
+               case FIN_WAIT_2:
+                       // We shouldn't need to retransmit anything in this state.
+#ifdef UTCP_DEBUG
                        abort();
+#endif
+                       timerclear(&c->rtrx_timeout);
+                       break;
        }
 
        free(pkt);
@@ -624,7 +636,10 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) {
        case TIME_WAIT:
                break;
        default:
+#ifdef UTCP_DEBUG
                abort();
+#endif
+               break;
        }
 
        // 1b. Drop packets with a sequence number not in our receive window.
@@ -724,7 +739,10 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) {
                        set_state(c, CLOSED);
                        return 0;
                default:
+#ifdef UTCP_DEBUG
                        abort();
+#endif
+                       break;
                }
        }
 
@@ -782,7 +800,6 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) {
                        c->dupack++;
                        if(c->dupack == 3) {
                                debug("Triplicate ACK\n");
-                               fprintf(stderr, "Triplicate ACK\n");
                                //TODO: Resend one packet and go to fast recovery mode. See RFC 6582.
                                //We do a very simple variant here; reset the nxt pointer to the last acknowledged packet from the peer.
                                //This will cause us to start retransmitting, but at the same speed as the incoming ACKs arrive,
@@ -824,7 +841,10 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) {
                        // Ehm, no. We should never receive a second SYN.
                        goto reset;
                default:
+#ifdef UTCP_DEBUG
                        abort();
+#endif
+                       return 0;
                }
 
                // SYN counts as one sequence number
@@ -854,7 +874,10 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) {
                case SYN_SENT:
                case SYN_RECEIVED:
                        // This should never happen.
+#ifdef UTCP_DEBUG
                        abort();
+#endif
+                       return 0;
                case ESTABLISHED:
                case FIN_WAIT_1:
                case FIN_WAIT_2:
@@ -866,7 +889,10 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) {
                        // Ehm no, We should never receive more data after a FIN.
                        goto reset;
                default:
+#ifdef UTCP_DEBUG
                        abort();
+#endif
+                       return 0;
                }
 
                ssize_t rxd;
@@ -895,7 +921,10 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) {
                case SYN_SENT:
                case SYN_RECEIVED:
                        // This should never happen.
+#ifdef UTCP_DEBUG
                        abort();
+#endif
+                       break;
                case ESTABLISHED:
                        set_state(c, CLOSE_WAIT);
                        break;
@@ -914,7 +943,10 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) {
                        // Ehm, no. We should never receive a second FIN.
                        goto reset;
                default:
+#ifdef UTCP_DEBUG
                        abort();
+#endif
+                       break;
                }
 
                // FIN counts as one sequence number
@@ -956,7 +988,7 @@ reset:
 }
 
 int utcp_shutdown(struct utcp_connection *c, int dir) {
-       debug("%p shutdown %d\n", c ? c->utcp : NULL, dir);
+       debug("%p shutdown %d at %u\n", c ? c->utcp : NULL, dir, c->snd.last);
        if(!c) {
                errno = EFAULT;
                return -1;
@@ -969,6 +1001,7 @@ int utcp_shutdown(struct utcp_connection *c, int dir) {
        }
 
        // TODO: handle dir
+       // TODO: check that repeated calls with the same parameters should have no effect
 
        switch(c->state) {
        case CLOSED:
@@ -1155,60 +1188,71 @@ void utcp_exit(struct utcp *utcp) {
 }
 
 uint16_t utcp_get_mtu(struct utcp *utcp) {
-       return utcp->mtu;
+       return utcp ? utcp->mtu : 0;
 }
 
 void utcp_set_mtu(struct utcp *utcp, uint16_t mtu) {
        // TODO: handle overhead of the header
-       utcp->mtu = mtu;
+       if(utcp)
+               utcp->mtu = mtu;
 }
 
 int utcp_get_user_timeout(struct utcp *u) {
-       return u->timeout;
+       return u ? u->timeout : 0;
 }
 
 void utcp_set_user_timeout(struct utcp *u, int timeout) {
-       u->timeout = timeout;
+       if(u)
+               u->timeout = timeout;
 }
 
 size_t utcp_get_sndbuf(struct utcp_connection *c) {
-       return c->sndbuf.maxsize;
+       return c ? c->sndbuf.maxsize : 0;
 }
 
 size_t utcp_get_sndbuf_free(struct utcp_connection *c) {
-       return buffer_free(&c->sndbuf);
+       if(c && (c->state == ESTABLISHED || c->state == CLOSE_WAIT))
+               return buffer_free(&c->sndbuf);
+       else
+               return 0;
 }
 
 void utcp_set_sndbuf(struct utcp_connection *c, size_t size) {
+       if(!c)
+               return;
        c->sndbuf.maxsize = size;
        if(c->sndbuf.maxsize != size)
                c->sndbuf.maxsize = -1;
 }
 
 bool utcp_get_nodelay(struct utcp_connection *c) {
-       return c->nodelay;
+       return c ? c->nodelay : false;
 }
 
 void utcp_set_nodelay(struct utcp_connection *c, bool nodelay) {
-       c->nodelay = nodelay;
+       if(c)
+               c->nodelay = nodelay;
 }
 
 bool utcp_get_keepalive(struct utcp_connection *c) {
-       return c->keepalive;
+       return c ? c->keepalive : false;
 }
 
 void utcp_set_keepalive(struct utcp_connection *c, bool keepalive) {
-       c->keepalive = keepalive;
+       if(c)
+               c->keepalive = keepalive;
 }
 
 size_t utcp_get_outq(struct utcp_connection *c) {
-       return seqdiff(c->snd.nxt, c->snd.una);
+       return c ? seqdiff(c->snd.nxt, c->snd.una) : 0;
 }
 
 void utcp_set_recv_cb(struct utcp_connection *c, utcp_recv_t recv) {
-       c->recv = recv;
+       if(c)
+               c->recv = recv;
 }
 
 void utcp_set_poll_cb(struct utcp_connection *c, utcp_poll_t poll) {
-       c->poll = poll;
+       if(c)
+               c->poll = poll;
 }