diff --git a/src/testing/marry.c b/src/testing/marry.c index 8cc944733..36b879c7b 100644 --- a/src/testing/marry.c +++ b/src/testing/marry.c @@ -92,6 +92,62 @@ nuts_scratch_addr(const char *scheme, size_t sz, char *addr) abort(); } +void +nuts_scratch_addr_zero(const char *scheme, size_t sz, char *addr) +{ + if ((strcmp(scheme, "inproc") == 0) || + (strcmp(scheme, "abstract") == 0)) { + (void) snprintf(addr, sz, "%s://nuts%04x%04x%04x%04x", scheme, + nng_random(), nng_random(), nng_random(), nng_random()); + return; + } + + if ((strncmp(scheme, "tcp", 3) == 0) || + (strncmp(scheme, "tls", 3) == 0) || + (strncmp(scheme, "udp", 3) == 0)) { + const char *ip = + strchr(scheme, '6') != NULL ? "[::1]" : "127.0.0.1"; + (void) snprintf(addr, sz, "%s://%s:%u", scheme, ip, 0); + return; + } + + if (strncmp(scheme, "ws", 2) == 0) { + const char *ip = + strchr(scheme, '6') != NULL ? "[::1]" : "127.0.0.1"; + (void) snprintf(addr, sz, "%s://%s:%u/nuts%04x%04x%04x%04x", + scheme, ip, 0, nng_random(), nng_random(), nng_random(), + nng_random()); + return; + } + + if ((strncmp(scheme, "ipc", 3) == 0) || + (strncmp(scheme, "unix", 4) == 0)) { +#ifdef _WIN32 + // Windows doesn't place IPC names in the filesystem. + (void) snprintf(addr, sz, "%s://nuts%04x%04x%04x%04x", scheme, + nng_random(), nng_random(), nng_random(), nng_random()); + return; +#else + char *tmpdir; + + if (((tmpdir = getenv("TMPDIR")) == NULL) && + ((tmpdir = getenv("TEMP")) == NULL) && + ((tmpdir = getenv("TMP")) == NULL)) { + tmpdir = "/tmp"; + } + + (void) snprintf(addr, sz, "%s://%s/nuts%04x%04x%04x%04x", + scheme, tmpdir, nng_random(), nng_random(), nng_random(), + nng_random()); + return; +#endif + } + + // We should not be here. + nng_log_err("NUTS", "Unknown scheme"); + abort(); +} + // nuts_next_port returns a "next" allocation port. // Ports are chosen by starting from a random point within a // range (normally 38000-40000, but other good places to choose diff --git a/src/testing/nuts.h b/src/testing/nuts.h index 5fe193db1..f2e50c2c8 100644 --- a/src/testing/nuts.h +++ b/src/testing/nuts.h @@ -85,6 +85,10 @@ extern uint16_t nuts_next_port(void); // 64 bytes to ensure no truncation occurs. extern void nuts_scratch_addr(const char *, size_t, char *); +// like nuts_scratch_addr, but attempts to use an autobind (0 port) +// address instead. +extern void nuts_scratch_addr_zero(const char *, size_t, char *); + // nuts_marry connects two sockets using inproc. It uses socket // pipe hooks to ensure that it does not return before both sockets // are fully connected. @@ -264,6 +268,14 @@ extern const char *nuts_ecdsa_client_crt; (var) = nuts_addr_; \ } while (0) +#define NUTS_ADDR_ZERO(var, scheme) \ + do { \ + static char nuts_addr_[64]; \ + nuts_scratch_addr_zero( \ + scheme, sizeof(nuts_addr_), nuts_addr_); \ + (var) = nuts_addr_; \ + } while (0) + #define NUTS_OPEN(sock) NUTS_PASS(nng_pair1_open(&(sock))) #define NUTS_CLOSE(sock) NUTS_PASS(nng_close(sock)) diff --git a/src/testing/util.c b/src/testing/util.c index d569bf5f4..2bb882b7a 100644 --- a/src/testing/util.c +++ b/src/testing/util.c @@ -286,16 +286,18 @@ nuts_tran_dialer_closed(const char *scheme) void nuts_tran_duplicate_listen(const char *scheme) { - nng_socket s = NNG_SOCKET_INITIALIZER; - nng_listener l1 = NNG_LISTENER_INITIALIZER; - nng_listener l2 = NNG_LISTENER_INITIALIZER; - const char *addr; + nng_socket s = NNG_SOCKET_INITIALIZER; + nng_listener l1 = NNG_LISTENER_INITIALIZER; + nng_listener l2 = NNG_LISTENER_INITIALIZER; + const char *addr; + const nng_url *url; NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); - NUTS_ADDR(addr, scheme); + NUTS_ADDR_ZERO(addr, scheme); NUTS_OPEN(s); NUTS_PASS(nng_listen(s, addr, &l1, 0)); - NUTS_FAIL(nng_listen(s, addr, &l2, 0), NNG_EADDRINUSE); + NUTS_PASS(nng_listener_get_url(l1, &url)); + NUTS_FAIL(nng_listen_url(s, url, &l2, 0), NNG_EADDRINUSE); NUTS_TRUE(nng_listener_id(l1) > 0); NUTS_TRUE(nng_listener_id(l2) < 0); NUTS_CLOSE(s); @@ -309,7 +311,7 @@ nuts_tran_listener_cancel(const char *scheme) const char *addr; NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); - NUTS_ADDR(addr, scheme); + NUTS_ADDR_ZERO(addr, scheme); NUTS_OPEN(s); NUTS_PASS(nng_listen(s, addr, &l, 0)); NUTS_TRUE(nng_listener_id(l) > 0); @@ -325,7 +327,7 @@ nuts_tran_listener_closed(const char *scheme) const char *addr; NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); - NUTS_ADDR(addr, scheme); + NUTS_ADDR_ZERO(addr, scheme); NUTS_OPEN(s); NUTS_PASS(nng_listener_create(&l, s, addr)); NUTS_TRUE(nng_listener_id(l) > 0); @@ -337,15 +339,16 @@ nuts_tran_listener_closed(const char *scheme) void nuts_tran_listen_accept(const char *scheme) { - nng_socket s1 = NNG_SOCKET_INITIALIZER; - nng_socket s2 = NNG_SOCKET_INITIALIZER; - nng_listener l1 = NNG_LISTENER_INITIALIZER; - nng_dialer d1 = NNG_LISTENER_INITIALIZER; - nng_dialer d2 = NNG_LISTENER_INITIALIZER; - const char *addr; + nng_socket s1 = NNG_SOCKET_INITIALIZER; + nng_socket s2 = NNG_SOCKET_INITIALIZER; + nng_listener l1 = NNG_LISTENER_INITIALIZER; + nng_dialer d1 = NNG_LISTENER_INITIALIZER; + nng_dialer d2 = NNG_LISTENER_INITIALIZER; + const char *addr; + const nng_url *url; NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); - NUTS_ADDR(addr, scheme); + NUTS_ADDR_ZERO(addr, scheme); NUTS_OPEN(s1); NUTS_OPEN(s2); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 100)); @@ -353,8 +356,9 @@ nuts_tran_listen_accept(const char *scheme) NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 100)); NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_RECVTIMEO, 100)); NUTS_PASS(nng_listen(s1, addr, &l1, 0)); - NUTS_PASS(nng_dial(s2, addr, &d1, 0)); - NUTS_PASS(nng_dial(s2, addr, &d2, 0)); + NUTS_PASS(nng_listener_get_url(l1, &url)); + NUTS_PASS(nng_dial_url(s2, url, &d1, 0)); + NUTS_PASS(nng_dial_url(s2, url, &d2, 0)); NUTS_TRUE(nng_listener_id(l1) > 0); NUTS_TRUE(nng_dialer_id(d1) > 0); NUTS_TRUE(nng_dialer_id(d2) > 0); @@ -366,14 +370,15 @@ nuts_tran_listen_accept(const char *scheme) void nuts_tran_exchange(const char *scheme) { - nng_socket s1 = NNG_SOCKET_INITIALIZER; - nng_socket s2 = NNG_SOCKET_INITIALIZER; - nng_listener l1 = NNG_LISTENER_INITIALIZER; - nng_dialer d1 = NNG_LISTENER_INITIALIZER; - const char *addr; + nng_socket s1 = NNG_SOCKET_INITIALIZER; + nng_socket s2 = NNG_SOCKET_INITIALIZER; + nng_listener l1 = NNG_LISTENER_INITIALIZER; + nng_dialer d1 = NNG_LISTENER_INITIALIZER; + const char *addr; + const nng_url *url; NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); - NUTS_ADDR(addr, scheme); + NUTS_ADDR_ZERO(addr, scheme); NUTS_OPEN(s1); NUTS_OPEN(s2); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 100)); @@ -381,7 +386,8 @@ nuts_tran_exchange(const char *scheme) NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 100)); NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_RECVTIMEO, 100)); NUTS_PASS(nng_listen(s1, addr, &l1, 0)); - NUTS_PASS(nng_dial(s2, addr, &d1, 0)); + NUTS_PASS(nng_listener_get_url(l1, &url)); + NUTS_PASS(nng_dial_url(s2, url, &d1, 0)); NUTS_TRUE(nng_listener_id(l1) > 0); NUTS_TRUE(nng_dialer_id(d1) > 0); for (int i = 0; i < 5; i++) { @@ -397,17 +403,18 @@ nuts_tran_exchange(const char *scheme) void nuts_tran_pipe_id(const char *scheme) { - nng_socket s1 = NNG_SOCKET_INITIALIZER; - nng_socket s2 = NNG_SOCKET_INITIALIZER; - nng_listener l1 = NNG_LISTENER_INITIALIZER; - nng_dialer d1 = NNG_LISTENER_INITIALIZER; - const char *addr; - nng_msg *msg; - nng_pipe p1; - nng_pipe p2; + nng_socket s1 = NNG_SOCKET_INITIALIZER; + nng_socket s2 = NNG_SOCKET_INITIALIZER; + nng_listener l1 = NNG_LISTENER_INITIALIZER; + nng_dialer d1 = NNG_LISTENER_INITIALIZER; + const char *addr; + nng_msg *msg; + nng_pipe p1; + nng_pipe p2; + const nng_url *url; NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); - NUTS_ADDR(addr, scheme); + NUTS_ADDR_ZERO(addr, scheme); NUTS_OPEN(s1); NUTS_OPEN(s2); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 100)); @@ -415,7 +422,8 @@ nuts_tran_pipe_id(const char *scheme) NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 100)); NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_RECVTIMEO, 100)); NUTS_PASS(nng_listen(s1, addr, &l1, 0)); - NUTS_PASS(nng_dial(s2, addr, &d1, 0)); + NUTS_PASS(nng_listener_get_url(l1, &url)); + NUTS_PASS(nng_dial_url(s2, url, &d1, 0)); NUTS_TRUE(nng_listener_id(l1) > 0); NUTS_TRUE(nng_dialer_id(d1) > 0); NUTS_SEND(s1, "ping"); @@ -438,18 +446,19 @@ nuts_tran_pipe_id(const char *scheme) void nuts_tran_huge_msg(const char *scheme, size_t size) { - nng_socket s1 = NNG_SOCKET_INITIALIZER; - nng_socket s2 = NNG_SOCKET_INITIALIZER; - nng_listener l1 = NNG_LISTENER_INITIALIZER; - nng_dialer d1 = NNG_LISTENER_INITIALIZER; - const char *addr; - char *buf; - nng_msg *msg; + nng_socket s1 = NNG_SOCKET_INITIALIZER; + nng_socket s2 = NNG_SOCKET_INITIALIZER; + nng_listener l1 = NNG_LISTENER_INITIALIZER; + nng_dialer d1 = NNG_LISTENER_INITIALIZER; + const char *addr; + char *buf; + nng_msg *msg; + const nng_url *url; buf = nng_alloc(size); NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); - NUTS_ADDR(addr, scheme); + NUTS_ADDR_ZERO(addr, scheme); NUTS_OPEN(s1); NUTS_OPEN(s2); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 5000)); @@ -457,7 +466,8 @@ nuts_tran_huge_msg(const char *scheme, size_t size) NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 5000)); NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_RECVTIMEO, 5000)); NUTS_PASS(nng_listen(s1, addr, &l1, 0)); - NUTS_PASS(nng_dial(s2, addr, &d1, 0)); + NUTS_PASS(nng_listener_get_url(l1, &url)); + NUTS_PASS(nng_dial_url(s2, url, &d1, 0)); NUTS_TRUE(nng_listener_id(l1) > 0); NUTS_TRUE(nng_dialer_id(d1) > 0); for (int i = 0; i < 5; i++) { @@ -483,12 +493,13 @@ nuts_tran_huge_msg(const char *scheme, size_t size) void nuts_tran_msg_props(const char *scheme, void (*check)(nng_msg *)) { - nng_socket s1 = NNG_SOCKET_INITIALIZER; - nng_socket s2 = NNG_SOCKET_INITIALIZER; - nng_listener l1 = NNG_LISTENER_INITIALIZER; - nng_dialer d1 = NNG_LISTENER_INITIALIZER; - const char *addr; - nng_msg *msg; + nng_socket s1 = NNG_SOCKET_INITIALIZER; + nng_socket s2 = NNG_SOCKET_INITIALIZER; + nng_listener l1 = NNG_LISTENER_INITIALIZER; + nng_dialer d1 = NNG_LISTENER_INITIALIZER; + const char *addr; + nng_msg *msg; + const nng_url *url; NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); NUTS_ADDR(addr, scheme); @@ -499,7 +510,8 @@ nuts_tran_msg_props(const char *scheme, void (*check)(nng_msg *)) NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 100)); NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_RECVTIMEO, 100)); NUTS_PASS(nng_listen(s1, addr, &l1, 0)); - NUTS_PASS(nng_dial(s2, addr, &d1, 0)); + NUTS_PASS(nng_listener_get_url(l1, &url)); + NUTS_PASS(nng_dial_url(s2, url, &d1, 0)); NUTS_TRUE(nng_listener_id(l1) > 0); NUTS_TRUE(nng_dialer_id(d1) > 0); NUTS_SEND(s1, "ping");