From: Guus Sliepen Date: Tue, 26 Aug 2014 12:33:19 +0000 (+0200) Subject: Various small fixes, clarifications. X-Git-Url: https://git.meshlink.io/?a=commitdiff_plain;h=f4c52312544ee99bcce46ebcfc0c8e6ac6356fd5;p=utcp Various small fixes, clarifications. --- diff --git a/README b/README index 6e14a31..9906a2c 100644 --- 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 -------------------- diff --git a/selftest.c b/selftest.c index 2c29943..f6e4c8c 100644 --- a/selftest.c +++ b/selftest.c @@ -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 d362845..757364f 100644 --- 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 1fae32c..9f668ed 100644 --- a/utcp.c +++ b/utcp.c @@ -19,6 +19,7 @@ #define _GNU_SOURCE +#include #include #include #include @@ -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 707cabe..0bf8417 100644 --- 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); diff --git a/utcp_priv.h b/utcp_priv.h index 184e338..d8f6554 100644 --- a/utcp_priv.h +++ b/utcp_priv.h @@ -113,7 +113,6 @@ struct utcp_connection { // Send buffer char *sndbuf; - uint32_t sndbufused; uint32_t sndbufsize; uint32_t maxsndbufsize;