From 0cd24285d4f7bbb3cde20ce3ee268336b285dcf9 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 13 Oct 2024 10:07:14 -0700 Subject: UDP: burst testing to improve coverage We are finding that on darwin its very easy for us to lose UDP messages as the socket buffer appears to be depressingly small. --- src/sp/transport/udp/udp.c | 34 ++++++++--- src/sp/transport/udp/udp_tran_test.c | 112 ++++++++++++++++++++++++++++++++++- 2 files changed, 136 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/sp/transport/udp/udp.c b/src/sp/transport/udp/udp.c index b55fcdb1..df5845fe 100644 --- a/src/sp/transport/udp/udp.c +++ b/src/sp/transport/udp/udp.c @@ -1289,7 +1289,8 @@ udp_timer_cb(void *arg) } static int -udp_ep_init(udp_ep **epp, nng_url *url, nni_sock *sock) +udp_ep_init(udp_ep **epp, nng_url *url, nni_sock *sock, nni_dialer *dialer, + nni_listener *listener) { udp_ep *ep; int rv; @@ -1432,7 +1433,29 @@ udp_ep_init(udp_ep **epp, nng_url *url, nni_sock *sock) nni_stat_init(&ep->st_snd_nobuf, &snd_nobuf_info); nni_stat_init(&ep->st_peer_inactive, &peer_inactive_info); - nni_stat_set_value(&ep->st_rcv_max, ep->rcvmax); + if (listener) { + nni_listener_add_stat(listener, &ep->st_rcv_max); + nni_listener_add_stat(listener, &ep->st_copy_max); + nni_listener_add_stat(listener, &ep->st_rcv_copy); + nni_listener_add_stat(listener, &ep->st_rcv_nocopy); + nni_listener_add_stat(listener, &ep->st_rcv_reorder); + nni_listener_add_stat(listener, &ep->st_rcv_toobig); + nni_listener_add_stat(listener, &ep->st_rcv_nomatch); + nni_listener_add_stat(listener, &ep->st_rcv_nobuf); + nni_listener_add_stat(listener, &ep->st_snd_toobig); + nni_listener_add_stat(listener, &ep->st_snd_nobuf); + } else { + nni_dialer_add_stat(dialer, &ep->st_rcv_max); + nni_dialer_add_stat(dialer, &ep->st_copy_max); + nni_dialer_add_stat(dialer, &ep->st_rcv_copy); + nni_dialer_add_stat(dialer, &ep->st_rcv_nocopy); + nni_dialer_add_stat(dialer, &ep->st_rcv_reorder); + nni_dialer_add_stat(dialer, &ep->st_rcv_toobig); + nni_dialer_add_stat(dialer, &ep->st_rcv_nomatch); + nni_dialer_add_stat(dialer, &ep->st_rcv_nobuf); + nni_dialer_add_stat(dialer, &ep->st_snd_toobig); + nni_dialer_add_stat(dialer, &ep->st_snd_nobuf); + } // schedule our timer callback - forever for now // adjusted automatically as we add pipes or other @@ -1474,11 +1497,10 @@ udp_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer) return (rv); } - if ((rv = udp_ep_init(&ep, url, sock)) != 0) { + if ((rv = udp_ep_init(&ep, url, sock, ndialer, NULL)) != 0) { return (rv); } - nni_dialer_add_stat(ndialer, &ep->st_rcv_max); *dp = ep; return (0); } @@ -1497,13 +1519,11 @@ udp_listener_init(void **lp, nng_url *url, nni_listener *nlistener) return (rv); } - if ((rv = udp_ep_init(&ep, url, sock)) != 0) { + if ((rv = udp_ep_init(&ep, url, sock, NULL, nlistener)) != 0) { return (rv); } ep->self_sa = sa; - nni_listener_add_stat(nlistener, &ep->st_rcv_max); - *lp = ep; return (0); } diff --git a/src/sp/transport/udp/udp_tran_test.c b/src/sp/transport/udp/udp_tran_test.c index c2b515e8..304df097 100644 --- a/src/sp/transport/udp/udp_tran_test.c +++ b/src/sp/transport/udp/udp_tran_test.c @@ -1,8 +1,5 @@ // // Copyright 2024 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// Copyright 2018 Devolutions -// Copyright 2018 Cody Piersall // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -195,6 +192,113 @@ test_udp_recv_copy(void) NUTS_CLOSE(s1); } +void +test_udp_multi_send_recv(void) +{ + char msg[256]; + char buf[256]; + nng_socket s0; + nng_socket s1; + nng_listener l; + nng_dialer d; + size_t sz; + char *addr; + + NUTS_ADDR(addr, "udp"); + + NUTS_OPEN(s0); + NUTS_PASS(nng_socket_set_ms(s0, NNG_OPT_RECVTIMEO, 100)); + NUTS_PASS(nng_socket_set_ms(s0, NNG_OPT_SENDTIMEO, 100)); + NUTS_PASS(nng_listener_create(&l, s0, addr)); + NUTS_PASS(nng_listener_set_size(l, NNG_OPT_UDP_COPY_MAX, 100)); + NUTS_PASS(nng_listener_get_size(l, NNG_OPT_UDP_COPY_MAX, &sz)); + NUTS_TRUE(sz == 100); + NUTS_PASS(nng_listener_start(l, 0)); + + NUTS_OPEN(s1); + NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 100)); + NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 100)); + NUTS_PASS(nng_dialer_create(&d, s1, addr)); + NUTS_PASS(nng_dialer_set_size(d, NNG_OPT_UDP_COPY_MAX, 100)); + NUTS_PASS(nng_dialer_get_size(d, NNG_OPT_UDP_COPY_MAX, &sz)); + NUTS_PASS(nng_dialer_start(d, 0)); + nng_msleep(100); + + for (int i = 0; i < 1000; i++) { + NUTS_PASS(nng_send(s1, msg, 95, 0)); + NUTS_PASS(nng_recv(s0, buf, &sz, 0)); + NUTS_TRUE(sz == 95); + NUTS_PASS(nng_send(s0, msg, 95, 0)); + NUTS_PASS(nng_recv(s1, buf, &sz, 0)); + NUTS_TRUE(sz == 95); + } + NUTS_CLOSE(s0); + NUTS_CLOSE(s1); +} + +void +test_udp_multi_small_burst(void) +{ + char msg[256]; + char buf[256]; + nng_socket s0; + nng_socket s1; + nng_listener l; + nng_dialer d; + size_t sz; + char *addr; + + NUTS_ADDR(addr, "udp"); + + NUTS_OPEN(s0); + NUTS_PASS(nng_socket_set_ms(s0, NNG_OPT_RECVTIMEO, 10)); + NUTS_PASS(nng_socket_set_ms(s0, NNG_OPT_SENDTIMEO, 1000)); + NUTS_PASS(nng_listener_create(&l, s0, addr)); + NUTS_PASS(nng_listener_set_size(l, NNG_OPT_UDP_COPY_MAX, 100)); + NUTS_PASS(nng_listener_get_size(l, NNG_OPT_UDP_COPY_MAX, &sz)); + NUTS_TRUE(sz == 100); + NUTS_PASS(nng_listener_start(l, 0)); + + NUTS_OPEN(s1); + NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 10)); + NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 1000)); + NUTS_PASS(nng_dialer_create(&d, s1, addr)); + NUTS_PASS(nng_dialer_set_size(d, NNG_OPT_UDP_COPY_MAX, 100)); + NUTS_PASS(nng_dialer_get_size(d, NNG_OPT_UDP_COPY_MAX, &sz)); + NUTS_PASS(nng_dialer_start(d, 0)); + nng_msleep(100); + + float actual = 0; + float expect = 0; + int burst = 4; + int count = 20; + + // Experimentally at least on Darwin, we see some packet losses + // even for loopback. Loss rates appear depressingly high. + for (int i = 0; i < count; i++) { + for (int j = 0; j < burst; j++) { + NUTS_PASS(nng_send(s1, msg, 95, 0)); + expect++; + } + for (int j = 0; j < burst; j++) { + if (nng_recv(s0, buf, &sz, 0) == 0) { + NUTS_TRUE(sz == 95); + actual++; + } + } + NUTS_PASS(nng_send(s0, msg, 95, 0)); + NUTS_PASS(nng_recv(s1, buf, &sz, 0)); + NUTS_TRUE(sz == 95); + } + NUTS_TRUE(actual <= expect); + NUTS_TRUE( + actual / expect > 0.80); // maximum reasonable packet loss of 20% + NUTS_MSG("Packet loss: %.02f (got %.f of %.f)", 1.0 - actual / expect, + actual, expect); + NUTS_CLOSE(s0); + NUTS_CLOSE(s1); +} + NUTS_TESTS = { { "udp wild card connect fail", test_udp_wild_card_connect_fail }, @@ -205,5 +309,7 @@ NUTS_TESTS = { { "udp malformed address", test_udp_malformed_address }, { "udp recv max", test_udp_recv_max }, { "udp recv copy", test_udp_recv_copy }, + { "udp multi send recv", test_udp_multi_send_recv }, + { "udp multi small burst", test_udp_multi_small_burst }, { NULL, NULL }, }; -- cgit v1.2.3-70-g09d2