]> git.meshlink.io Git - utcp/blobdiff - utcp.c
Always send an ACK back when we receive data from the peer.
[utcp] / utcp.c
diff --git a/utcp.c b/utcp.c
index 3a299476616f08674a26aaa703a1f0754b94b968..d0e56d2c41e6dd278d1791828ff59375fc5b6391 100644 (file)
--- a/utcp.c
+++ b/utcp.c
@@ -627,11 +627,17 @@ ssize_t utcp_send(struct utcp_connection *c, const void *data, size_t len) {
 
        // Add data to send buffer.
 
-       len = buffer_put(&c->sndbuf, data, len);
+       if(is_reliable(c) || (c->state != SYN_SENT && c->state != SYN_RECEIVED)) {
+               len = buffer_put(&c->sndbuf, data, len);
+       }
 
        if(len <= 0) {
-               errno = EWOULDBLOCK;
-               return 0;
+               if(is_reliable(c)) {
+                       errno = EWOULDBLOCK;
+                       return 0;
+               } else {
+                       return len;
+               }
        }
 
        c->snd.last += len;
@@ -1005,6 +1011,8 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) {
                ptr += 2;
        }
 
+       bool has_data = len;
+
        // Try to match the packet to an existing connection
 
        struct utcp_connection *c = find_connection(utcp, hdr.dst, hdr.src);
@@ -1099,8 +1107,6 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) {
 
        // It is for an existing connection.
 
-       uint32_t prevrcvnxt = c->rcv.nxt;
-
        // 1. Drop invalid packets.
 
        // 1a. Drop packets that should not happen in our current state.
@@ -1124,41 +1130,43 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) {
                break;
        }
 
-       // 1b. Drop packets with a sequence number not in our receive window.
+       // 1b. Discard data that is not in our receive window.
 
-       bool acceptable;
+       if(is_reliable(c)) {
+               bool acceptable;
 
-       if(c->state == SYN_SENT) {
-               acceptable = true;
-       } else if(len == 0) {
-               acceptable = seqdiff(hdr.seq, c->rcv.nxt) >= 0;
-       } else {
-               int32_t rcv_offset = seqdiff(hdr.seq, c->rcv.nxt);
+               if(c->state == SYN_SENT) {
+                       acceptable = true;
+               } else if(len == 0) {
+                       acceptable = seqdiff(hdr.seq, c->rcv.nxt) >= 0;
+               } else {
+                       int32_t rcv_offset = seqdiff(hdr.seq, c->rcv.nxt);
 
-               // cut already accepted front overlapping
-               if(rcv_offset < 0) {
-                       acceptable = len > (size_t) - rcv_offset;
+                       // cut already accepted front overlapping
+                       if(rcv_offset < 0) {
+                               acceptable = len > (size_t) - rcv_offset;
 
-                       if(acceptable) {
-                               ptr -= rcv_offset;
-                               len += rcv_offset;
-                               hdr.seq -= rcv_offset;
+                               if(acceptable) {
+                                       ptr -= rcv_offset;
+                                       len += rcv_offset;
+                                       hdr.seq -= rcv_offset;
+                               }
+                       } else {
+                               acceptable = seqdiff(hdr.seq, c->rcv.nxt) >= 0 && seqdiff(hdr.seq, c->rcv.nxt) + len <= c->rcvbuf.maxsize;
                        }
-               } else {
-                       acceptable = seqdiff(hdr.seq, c->rcv.nxt) >= 0 && seqdiff(hdr.seq, c->rcv.nxt) + len <= c->rcvbuf.maxsize;
                }
-       }
 
-       if(!acceptable) {
-               debug("Packet not acceptable, %u <= %u + %lu < %u\n", c->rcv.nxt, hdr.seq, (unsigned long)len, c->rcv.nxt + c->rcvbuf.maxsize);
+               if(!acceptable) {
+                       debug("Packet not acceptable, %u <= %u + %lu < %u\n", c->rcv.nxt, hdr.seq, (unsigned long)len, c->rcv.nxt + c->rcvbuf.maxsize);
 
-               // Ignore unacceptable RST packets.
-               if(hdr.ctl & RST) {
-                       return 0;
-               }
+                       // Ignore unacceptable RST packets.
+                       if(hdr.ctl & RST) {
+                               return 0;
+                       }
 
-               // Otherwise, continue processing.
-               len = 0;
+                       // Otherwise, continue processing.
+                       len = 0;
+               }
        }
 
        c->snd.wnd = hdr.wnd; // TODO: move below
@@ -1167,6 +1175,12 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) {
        // ackno should not roll back, and it should also not be bigger than what we ever could have sent
        // (= snd.una + c->sndbuf.used).
 
+       if(!is_reliable(c)) {
+               if(hdr.ack != c->snd.last && c->state >= ESTABLISHED) {
+                       hdr.ack = c->snd.una;
+               }
+       }
+
        if(hdr.ctl & ACK && (seqdiff(hdr.ack, c->snd.last) > 0 || seqdiff(hdr.ack, c->snd.una) < 0)) {
                debug("Packet ack seqno out of range, %u <= %u < %u\n", c->snd.una, hdr.ack, c->snd.una + c->sndbuf.used);
 
@@ -1195,6 +1209,10 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) {
                                c->recv(c, NULL, 0);
                        }
 
+                       if(c->poll && !c->reapable) {
+                               c->poll(c, 0);
+                       }
+
                        return 0;
 
                case SYN_RECEIVED:
@@ -1222,6 +1240,10 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) {
                                c->recv(c, NULL, 0);
                        }
 
+                       if(c->poll && !c->reapable) {
+                               c->poll(c, 0);
+                       }
+
                        return 0;
 
                case CLOSING:
@@ -1260,7 +1282,6 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) {
        // 3. Advance snd.una
 
        advanced = seqdiff(hdr.ack, c->snd.una);
-       prevrcvnxt = c->rcv.nxt;
 
        if(advanced) {
                // RTT measurement
@@ -1464,7 +1485,7 @@ skip_ack:
 
        // 7. Process FIN stuff
 
-       if((hdr.ctl & FIN) && hdr.seq + len == c->rcv.nxt) {
+       if((hdr.ctl & FIN) && (!is_reliable(c) || hdr.seq + len == c->rcv.nxt)) {
                switch(c->state) {
                case SYN_SENT:
                case SYN_RECEIVED:
@@ -1506,7 +1527,7 @@ skip_ack:
                c->rcv.nxt++;
                len++;
 
-               // Inform the application that the peer closed the connection.
+               // Inform the application that the peer closed its end of the connection.
                if(c->recv) {
                        errno = 0;
                        c->recv(c, NULL, 0);
@@ -1514,12 +1535,15 @@ skip_ack:
        }
 
        // Now we send something back if:
-       // - we advanced rcv.nxt (ie, we got some data that needs to be ACKed)
+       // - we received data, so we have to send back an ACK
        //   -> sendatleastone = true
        // - or we got an ack, so we should maybe send a bit more data
        //   -> sendatleastone = false
 
-       ack(c, len || prevrcvnxt != c->rcv.nxt);
+       if(is_reliable(c) || hdr.ctl & SYN || hdr.ctl & FIN) {
+               ack(c, has_data);
+       }
+
        return 0;
 
 reset:
@@ -1685,6 +1709,7 @@ void utcp_abort_all_connections(struct utcp *utcp) {
                }
 
                utcp_recv_t old_recv = c->recv;
+               utcp_poll_t old_poll = c->poll;
 
                reset_connection(c);
 
@@ -1692,6 +1717,11 @@ void utcp_abort_all_connections(struct utcp *utcp) {
                        errno = 0;
                        old_recv(c, NULL, 0);
                }
+
+               if(old_poll && !c->reapable) {
+                       errno = 0;
+                       old_poll(c, 0);
+               }
        }
 
        return;
@@ -1754,7 +1784,7 @@ struct timeval utcp_timeout(struct utcp *utcp) {
                                c->recv(c, NULL, 0);
                        }
 
-                       if(c->poll) {
+                       if(c->poll && !c->reapable) {
                                c->poll(c, 0);
                        }
 
@@ -1838,11 +1868,16 @@ void utcp_exit(struct utcp *utcp) {
        for(int i = 0; i < utcp->nconnections; i++) {
                struct utcp_connection *c = utcp->connections[i];
 
-               if(!c->reapable)
+               if(!c->reapable) {
                        if(c->recv) {
                                c->recv(c, NULL, 0);
                        }
 
+                       if(c->poll && !c->reapable) {
+                               c->poll(c, 0);
+                       }
+               }
+
                buffer_exit(&c->rcvbuf);
                buffer_exit(&c->sndbuf);
                free(c);