]> git.meshlink.io Git - utcp/commitdiff
Various small fixes, clarifications.
authorGuus Sliepen <guus@meshlink.io>
Tue, 26 Aug 2014 12:33:19 +0000 (14:33 +0200)
committerGuus Sliepen <guus@meshlink.io>
Tue, 26 Aug 2014 12:33:19 +0000 (14:33 +0200)
README
selftest.c
test.c
utcp.c
utcp.h
utcp_priv.h

diff --git a/README b/README
index 6e14a31e447be74c50b7d9f5119361400490b49f..9906a2c1eddc0ab865cdad234b5a54d03979b114 100644 (file)
--- a/README
+++ b/README
@@ -178,19 +178,23 @@ RETRANSMIT
 RECEIVE PACKET
 --------------
 
-- Drop invalid packets:
-  - Invalid flags or state
-  - ACK always set
-  - hdr.seq not within our receive window
-  - hdr.ack ahead of snd.nxt
-- Handle RST packets
-- Advance snd.una?
-  - reset conn timer if so
-  - remove ACKed data from send buffer
-- If snd.una == snd.nxt, clear rtrx and conn timer
-- Process state changes due to SYN
-- Send new data to application
-- Process state changes due to FIN
+1 Drop invalid packets:
+  a Invalid flags or state
+  b ACK always set
+  c hdr.seq not within our receive window
+  d hdr.ack ahead of snd.nxt or behind snd.una
+2 Handle RST packets
+3 Advance snd.una?
+  a reset conn timer if so
+  b check if our SYN or FIN has been acked
+  c check if any data been acked
+    - remove ACKed data from send buffer
+    - increase cwnd
+  d no advance? NewReno
+4 If snd.una == snd.nxt, clear rtrx and conn timer
+5 Process state changes due to SYN
+6 Send new data to application
+7 Process state changes due to FIN
 
 CONGESTION AVOIDANCE
 --------------------
index 2c299437388e3d6cef3700860f7f3397bd6a70ea..f6e4c8c4ce5abfa488964fca5776282fe46d58c3 100644 (file)
@@ -10,7 +10,7 @@ struct utcp *a;
 struct utcp *b;
 struct utcp_connection *c;
 
-int do_recv(struct utcp_connection *x, const void *data, size_t len) {
+ssize_t do_recv(struct utcp_connection *x, const void *data, size_t len) {
        if(!len) {
                if(errno)
                        fprintf(stderr, "%p Error: %s\n", x->utcp, strerror(errno));
@@ -24,11 +24,9 @@ int do_recv(struct utcp_connection *x, const void *data, size_t len) {
        }
 
        if(x == c)
-               write(0, data, len);
+               return write(0, data, len);
        else
-               utcp_send(x, data, len);
-
-       return 0;
+               return utcp_send(x, data, len);
 }
 
 bool do_pre_accept(struct utcp *utcp, uint16_t port) {
@@ -43,7 +41,7 @@ void do_accept(struct utcp_connection *c, uint16_t port) {
        utcp_accept(c, do_recv, NULL);
 }
 
-int do_send(struct utcp *utcp, const void *data, size_t len) {
+ssize_t do_send(struct utcp *utcp, const void *data, size_t len) {
        static int count = 0;
        if(++count > 1000) {
                fprintf(stderr, "Too many packets!\n");
diff --git a/test.c b/test.c
index d362845b9a48e6d3570b1cfd130782bb7e0b5896..757364f0f7e63432bf387ce6ce7a2637e45a9370 100644 (file)
--- a/test.c
+++ b/test.c
@@ -19,7 +19,7 @@ bool running = true;
 double dropin;
 double dropout;
 
-int do_recv(struct utcp_connection *c, const void *data, size_t len) {
+ssize_t do_recv(struct utcp_connection *c, const void *data, size_t len) {
        if(!data || !len) {
                if(errno) {
                        fprintf(stderr, "Error: %s\n", strerror(errno));
@@ -28,7 +28,7 @@ int do_recv(struct utcp_connection *c, const void *data, size_t len) {
                        dir &= ~2;
                        fprintf(stderr, "Connection closed by peer\n");
                }
-               return 0;
+               return -1;
        }
        return write(1, data, len);
 }
@@ -38,12 +38,12 @@ void do_accept(struct utcp_connection *nc, uint16_t port) {
        c = nc;
 }
 
-int do_send(struct utcp *utcp, const void *data, size_t len) {
+ssize_t do_send(struct utcp *utcp, const void *data, size_t len) {
        int s = *(int *)utcp->priv;
        if(drand48() >= dropout)
                return send(s, data, len, MSG_DONTWAIT);
        else
-               return 0;
+               return len;
 }
 
 int main(int argc, char *argv[]) {
@@ -88,6 +88,7 @@ int main(int argc, char *argv[]) {
        if(!u)
                return 1;
 
+       utcp_set_mtu(u, 1300);
        utcp_set_user_timeout(u, 10);
 
        if(!server)
@@ -98,7 +99,7 @@ int main(int argc, char *argv[]) {
                {.fd = s, .events = POLLIN | POLLERR | POLLHUP},
        };
 
-       char buf[1024];
+       char buf[102400];
        int timeout = utcp_timeout(u);
 
        while(dir) {
diff --git a/utcp.c b/utcp.c
index 1fae32cd2eaf44430f93311a0787034c58e2861d..9f668edd37256e214db12347722c48a79dd8f4cf 100644 (file)
--- a/utcp.c
+++ b/utcp.c
@@ -19,6 +19,7 @@
 
 #define _GNU_SOURCE
 
+#include <assert.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -49,7 +50,7 @@ static void print_packet(struct utcp *utcp, const char *dir, const void *pkt, si
        }
 
        memcpy(&hdr, pkt, sizeof hdr);
-       fprintf (stderr, "%p %s: src=%u dst=%u seq=%u ack=%u wnd=%u ctl=", utcp, dir, hdr.src, hdr.dst, hdr.seq, hdr.ack, hdr.wnd);
+       fprintf (stderr, "%p %s: len=%zu, src=%u dst=%u seq=%u ack=%u wnd=%u ctl=", utcp, dir, len, hdr.src, hdr.dst, hdr.seq, hdr.ack, hdr.wnd);
        if(hdr.ctl & SYN)
                debug("SYN");
        if(hdr.ctl & RST)
@@ -97,8 +98,9 @@ static int32_t seqdiff(uint32_t a, uint32_t b) {
 static int compare(const void *va, const void *vb) {
        const struct utcp_connection *a = *(struct utcp_connection **)va;
        const struct utcp_connection *b = *(struct utcp_connection **)vb;
-       if(!a->src || !b->src)
-               abort();
+
+       assert(a->src && b->src);
+
        int c = (int)a->src - (int)b->src;
        if(c)
                return c;
@@ -120,8 +122,8 @@ static struct utcp_connection *find_connection(const struct utcp *utcp, uint16_t
 static void free_connection(struct utcp_connection *c) {
        struct utcp *utcp = c->utcp;
        struct utcp_connection **cp = bsearch(&c, utcp->connections, utcp->nconnections, sizeof *utcp->connections, compare);
-       if(!cp)
-               abort();
+
+       assert(cp);
 
        int i = cp - utcp->connections;
        memmove(cp + i, cp + i + 1, (utcp->nconnections - i - 1) * sizeof *cp);
@@ -239,9 +241,7 @@ static void ack(struct utcp_connection *c, bool sendatleastone) {
        int32_t cwndleft = c->snd.cwnd - seqdiff(c->snd.nxt, c->snd.una);
        char *data = c->sndbuf + seqdiff(c->snd.nxt, c->snd.una);
 
-       fprintf(stderr, "ack, left=%d, cwndleft=%d, sendatleastone=%d\n", left, cwndleft, sendatleastone);
-       if(left < 0)
-               abort();
+       assert(left >= 0);
 
        if(cwndleft <= 0)
                cwndleft = 0;
@@ -377,7 +377,7 @@ static void swap_ports(struct hdr *hdr) {
        hdr->dst = tmp;
 }
 
-int utcp_recv(struct utcp *utcp, const void *data, size_t len) {
+ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) {
        if(!utcp) {
                errno = EFAULT;
                return -1;
@@ -632,7 +632,8 @@ int utcp_recv(struct utcp *utcp, const void *data, size_t len) {
                        c->dupack++;
                        if(c->dupack >= 3) {
                                debug("Triplicate ACK\n");
-                               abort();
+                               //TODO: Resend one packet and go to fast recovery mode. See RFC 6582.
+                               //abort();
                        }
                }
        }
@@ -640,7 +641,7 @@ int utcp_recv(struct utcp *utcp, const void *data, size_t len) {
        // 4. Update timers
 
        if(advanced) {
-               timerclear(&c->conn_timeout); // It should be set anew in utcp_timeout() if c->snd.una != c->snd.nxt.
+               timerclear(&c->conn_timeout); // It will be set anew in utcp_timeout() if c->snd.una != c->snd.nxt.
                if(c->snd.una == c->snd.nxt)
                        timerclear(&c->rtrx_timeout);
        }
@@ -714,10 +715,15 @@ int utcp_recv(struct utcp *utcp, const void *data, size_t len) {
                        abort();
                }
 
-               int rxd;
+               ssize_t rxd;
 
                if(c->recv) {
                        rxd = c->recv(c, data, len);
+                       if(rxd != len) {
+                               // TODO: once we have a receive buffer, handle the application not accepting all data.
+                               fprintf(stderr, "c->recv(%p, %p, %zu) returned %zd\n", c, data, len, rxd);
+                               abort();
+                       }
                        if(rxd < 0)
                                rxd = 0;
                        else if(rxd > len)
@@ -797,7 +803,7 @@ reset:
 }
 
 int utcp_shutdown(struct utcp_connection *c, int dir) {
-       debug("%p shutdown %d\n", c->utcp, dir);
+       debug("%p shutdown %d\n", c ? c->utcp : NULL, dir);
        if(!c) {
                errno = EFAULT;
                return -1;
diff --git a/utcp.h b/utcp.h
index 707cabe3736c57033ccfd10ce253ea6b7321c92e..0bf841771a6f76be5d3c75da34559b6eb015ae67 100644 (file)
--- a/utcp.h
+++ b/utcp.h
@@ -41,8 +41,8 @@ struct utcp_connection;
 typedef bool (*utcp_pre_accept_t)(struct utcp *utcp, uint16_t port);
 typedef void (*utcp_accept_t)(struct utcp_connection *utcp_connection, uint16_t port);
 
-typedef int (*utcp_send_t)(struct utcp *utcp, const void *data, size_t len);
-typedef int (*utcp_recv_t)(struct utcp_connection *connection, const void *data, size_t len);
+typedef ssize_t (*utcp_send_t)(struct utcp *utcp, const void *data, size_t len);
+typedef ssize_t (*utcp_recv_t)(struct utcp_connection *connection, const void *data, size_t len);
 
 extern struct utcp *utcp_init(utcp_accept_t accept, utcp_pre_accept_t pre_accept, utcp_send_t send, void *priv);
 extern void utcp_exit(struct utcp *utcp);
@@ -50,7 +50,7 @@ extern void utcp_exit(struct utcp *utcp);
 extern struct utcp_connection *utcp_connect(struct utcp *utcp, uint16_t port, utcp_recv_t recv, void *priv);
 extern void utcp_accept(struct utcp_connection *utcp, utcp_recv_t recv, void *priv);
 extern ssize_t utcp_send(struct utcp_connection *connection, const void *data, size_t len);
-extern int utcp_recv(struct utcp *utcp, const void *data, size_t len);
+extern ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len);
 extern int utcp_close(struct utcp_connection *connection);
 extern int utcp_abort(struct utcp_connection *connection);
 extern int utcp_shutdown(struct utcp_connection *connection, int how);
index 184e3386bf00e8c3a3addabd1c39bd9086f5d40a..d8f65546dcd810f9d6fe33259dbda4578e5a89b9 100644 (file)
@@ -113,7 +113,6 @@ struct utcp_connection {
        // Send buffer
 
        char *sndbuf;
-       uint32_t sndbufused;
        uint32_t sndbufsize;
        uint32_t maxsndbufsize;