]> git.meshlink.io Git - utcp/blobdiff - utcp.c
Handle retransmissions in CLOSE_WAIT, CLOSING and LAST_ACK states.
[utcp] / utcp.c
diff --git a/utcp.c b/utcp.c
index d49c4ddcce2cfbf5822efb899b49b4cd186419c4..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 && seglen && c->snd.nxt == c->snd.last) {
-                       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,28 +486,34 @@ 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);
-                       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;
        }