doompanning/external/nng/tests/udp.c
2023-02-03 21:18:59 +01:00

292 lines
7.5 KiB
C

//
// Copyright 2021 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
// Basic UDP tests.
#ifndef _WIN32
#include <arpa/inet.h>
#endif
#include "convey.h"
#include "core/nng_impl.h"
#include "trantest.h"
TestMain("UDP support", {
nni_init();
trantest_port = trantest_port ? trantest_port : 5555;
Convey("We can start a pair of UDP ports", {
nng_sockaddr sa1;
nng_sockaddr sa2;
uint16_t p1;
uint16_t p2;
nni_plat_udp *u1;
nni_plat_udp *u2;
uint32_t loopback;
loopback = htonl(0x7f000001); // 127.0.0.1
p1 = trantest_port++;
p2 = trantest_port++;
sa1.s_in.sa_family = NNG_AF_INET;
sa1.s_in.sa_addr = loopback;
sa1.s_in.sa_port = htons(p1);
sa2.s_in.sa_family = NNG_AF_INET;
sa2.s_in.sa_addr = loopback;
sa2.s_in.sa_port = htons(p2);
So(nni_plat_udp_open(&u1, &sa1) == 0);
So(nni_plat_udp_open(&u2, &sa2) == 0);
Reset({
nni_plat_udp_close(u1);
nni_plat_udp_close(u2);
});
Convey("They can talk to each other", {
char msg[] = "hello";
char rbuf[1024];
nng_sockaddr to;
nng_sockaddr from;
nng_aio * aio1;
nng_aio * aio2;
nng_iov iov1;
nng_iov iov2;
So(nng_aio_alloc(&aio1, NULL, NULL) == 0);
So(nng_aio_alloc(&aio2, NULL, NULL) == 0);
to = sa2;
iov1.iov_buf = msg;
iov1.iov_len = strlen(msg) + 1;
So(nng_aio_set_iov(aio1, 1, &iov1) == 0);
nng_aio_set_input(aio1, 0, &to);
iov2.iov_buf = rbuf;
iov2.iov_len = 1024;
So(nng_aio_set_iov(aio2, 1, &iov2) == 0);
nng_aio_set_input(aio2, 0, &from);
nni_plat_udp_recv(u2, aio2);
nni_plat_udp_send(u1, aio1);
nng_aio_wait(aio1);
nng_aio_wait(aio2);
So(nng_aio_result(aio1) == 0);
So(nng_aio_result(aio2) == 0);
So(nng_aio_count(aio2) == strlen(msg) + 1);
So(strcmp(msg, rbuf) == 0);
So(from.s_in.sa_family == sa1.s_in.sa_family);
So(from.s_in.sa_port == sa1.s_in.sa_port);
So(from.s_in.sa_addr == sa1.s_in.sa_addr);
// Set up some calls that will ever complete, so
// we test cancellation, etc.
nni_plat_udp_recv(u2, aio2);
nni_plat_udp_send(u2, aio1);
nng_aio_free(aio1);
nng_aio_free(aio2);
});
Convey("Sending without an address fails", {
nng_aio *aio1;
char * msg = "nope";
nng_iov iov;
So(nng_aio_alloc(&aio1, NULL, NULL) == 0);
iov.iov_buf = msg;
iov.iov_len = strlen(msg) + 1;
So(nng_aio_set_iov(aio1, 1, &iov) == 0);
nni_plat_udp_send(u1, aio1);
nng_aio_wait(aio1);
So(nng_aio_result(aio1) == NNG_EADDRINVAL);
nng_aio_free(aio1);
});
Convey("Multiple operations work", {
char msg1[] = "hello";
char msg2[] = "there";
char rbuf1[32];
char rbuf2[32];
nng_sockaddr to1;
nng_sockaddr to2;
nng_sockaddr from1;
nng_sockaddr from2;
nng_aio * aio1;
nng_aio * aio2;
nng_aio * aio3;
nng_aio * aio4;
nng_iov iov1;
nng_iov iov2;
nng_iov iov3;
nng_iov iov4;
So(nng_aio_alloc(&aio1, NULL, NULL) == 0);
So(nng_aio_alloc(&aio2, NULL, NULL) == 0);
So(nng_aio_alloc(&aio3, NULL, NULL) == 0);
So(nng_aio_alloc(&aio4, NULL, NULL) == 0);
to1 = sa2;
iov1.iov_buf = msg1;
iov1.iov_len = strlen(msg1) + 1;
So(nng_aio_set_iov(aio1, 1, &iov1) == 0);
nng_aio_set_input(aio1, 0, &to1);
to2 = sa2;
iov2.iov_buf = msg2;
iov2.iov_len = strlen(msg2) + 1;
So(nng_aio_set_iov(aio2, 1, &iov2) == 0);
nng_aio_set_input(aio2, 0, &to2);
iov3.iov_buf = rbuf1;
iov3.iov_len = 1024;
So(nng_aio_set_iov(aio3, 1, &iov3) == 0);
nng_aio_set_input(aio3, 0, &from1);
iov4.iov_buf = rbuf2;
iov4.iov_len = 1024;
So(nng_aio_set_iov(aio4, 1, &iov4) == 0);
nng_aio_set_input(aio4, 0, &from2);
nni_plat_udp_recv(u2, aio4);
nni_plat_udp_recv(u2, aio3);
nni_plat_udp_send(u1, aio2);
// This delay here is required to test for a race
// condition that does not occur if it is absent.
nng_msleep(1);
nni_plat_udp_send(u1, aio1);
nng_aio_wait(aio2);
nng_aio_wait(aio1);
nng_aio_wait(aio3);
nng_aio_wait(aio4);
So(nng_aio_result(aio1) == 0);
So(nng_aio_result(aio2) == 0);
So(nng_aio_result(aio3) == 0);
So(nng_aio_result(aio4) == 0);
So(from1.s_in.sa_family == sa1.s_in.sa_family);
So(from1.s_in.sa_port == sa1.s_in.sa_port);
So(from1.s_in.sa_addr == sa1.s_in.sa_addr);
nng_aio_free(aio1);
nng_aio_free(aio2);
nng_aio_free(aio3);
nng_aio_free(aio4);
});
Convey("Sending without an address fails", {
nng_aio *aio1;
char * msg = "nope";
nng_iov iov;
So(nng_aio_alloc(&aio1, NULL, NULL) == 0);
iov.iov_buf = msg;
iov.iov_len = strlen(msg) + 1;
So(nng_aio_set_iov(aio1, 1, &iov) == 0);
nni_plat_udp_send(u1, aio1);
nng_aio_wait(aio1);
So(nng_aio_result(aio1) == NNG_EADDRINVAL);
nng_aio_free(aio1);
});
Convey("Sending to an IPv6 address on IPv4 fails", {
nng_aio * aio1;
char * msg = "nope";
nng_sockaddr sa;
int rv;
nng_iov iov;
sa.s_in6.sa_family = NNG_AF_INET6;
// address is for google.com
inet_ntop(AF_INET6, "2607:f8b0:4007:804::200e",
(void *) sa.s_in6.sa_addr, 16);
sa.s_in6.sa_port = 80;
So(nng_aio_alloc(&aio1, NULL, NULL) == 0);
iov.iov_buf = msg;
iov.iov_len = strlen(msg) + 1;
So(nng_aio_set_iov(aio1, 1, &iov) == 0);
nng_aio_set_input(aio1, 0, &sa);
nni_plat_udp_send(u1, aio1);
nng_aio_wait(aio1);
So((rv = nng_aio_result(aio1)) != 0);
So(rv == NNG_EADDRINVAL || rv == NNG_ENOTSUP ||
rv == NNG_EUNREACHABLE || rv == NNG_EINVAL);
nng_aio_free(aio1);
});
Convey("Sending to an IPC address fails", {
nng_aio * aio1;
char * msg = "nope";
nng_sockaddr sa;
int rv;
nng_iov iov;
sa.s_in6.sa_family = NNG_AF_INET6;
// address is for google.com
inet_ntop(AF_INET6, "2607:f8b0:4007:804::200e",
(void *) sa.s_in6.sa_addr, 16);
sa.s_in6.sa_port = 80;
So(nng_aio_alloc(&aio1, NULL, NULL) == 0);
iov.iov_buf = msg;
iov.iov_len = strlen(msg) + 1;
So(nng_aio_set_iov(aio1, 1, &iov) == 0);
nng_aio_set_input(aio1, 0, &sa);
nni_plat_udp_send(u1, aio1);
nng_aio_wait(aio1);
So((rv = nng_aio_result(aio1)) != 0);
So(rv == NNG_EADDRINVAL || rv == NNG_ENOTSUP ||
rv == NNG_EUNREACHABLE || rv == NNG_EINVAL);
nng_aio_free(aio1);
});
});
Convey("Cannot open using bogus sockaddr", {
nni_plat_udp *u;
nng_sockaddr sa;
int rv;
sa.s_ipc.sa_family = NNG_AF_IPC;
strcpy(sa.s_ipc.sa_path, "/tmp/t");
So((rv = nni_plat_udp_open(&u, &sa)) != 0);
// Some platforms reject IPC addresses altogether (Windows),
// whereas others just say it's not supported with UDP.
So((rv == NNG_ENOTSUP) || (rv == NNG_EADDRINVAL));
// NULL address also bad.
So((rv = nni_plat_udp_open(&u, NULL)) == NNG_EADDRINVAL);
});
Convey("Duplicate binds fail", {
nni_plat_udp *u1;
nni_plat_udp *u2;
nng_sockaddr sa;
uint16_t p1;
p1 = trantest_port++;
sa.s_in.sa_family = NNG_AF_INET;
sa.s_in.sa_port = htons(p1);
sa.s_in.sa_addr = htonl(0x7f000001);
So(nni_plat_udp_open(&u1, &sa) == 0);
So(nni_plat_udp_open(&u2, &sa) == NNG_EADDRINUSE);
nni_plat_udp_close(u1);
});
})