aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt20
-rw-r--r--src/compat/nanomsg/CMakeLists.txt2
-rw-r--r--src/core/CMakeLists.txt9
-rw-r--r--src/core/aio_test.c245
-rw-r--r--src/core/buf_size_test.c119
-rw-r--r--src/core/errors_test.c46
-rw-r--r--src/core/id_test.c275
-rw-r--r--src/core/reconnect_test.c167
-rw-r--r--src/core/sock_test.c685
-rw-r--r--src/core/url_test.c479
-rw-r--r--src/platform/CMakeLists.txt17
-rw-r--r--src/platform/platform_test.c181
-rw-r--r--src/platform/posix/posix_file.c13
-rw-r--r--src/platform/resolver_test.c199
-rw-r--r--src/protocol/CMakeLists.txt20
-rw-r--r--src/protocol/bus0/CMakeLists.txt9
-rw-r--r--src/protocol/bus0/bug1247_test.c39
-rw-r--r--src/protocol/pair0/CMakeLists.txt5
-rw-r--r--src/protocol/pair1/CMakeLists.txt4
-rw-r--r--src/protocol/pipeline0/CMakeLists.txt6
-rw-r--r--src/protocol/pubsub0/CMakeLists.txt6
-rw-r--r--src/protocol/reqrep0/CMakeLists.txt6
-rw-r--r--src/protocol/survey0/CMakeLists.txt6
-rw-r--r--src/supplemental/websocket/wssfile_test.c10
-rw-r--r--src/transport/CMakeLists.txt19
-rw-r--r--src/transport/inproc/CMakeLists.txt5
-rw-r--r--src/transport/ipc/CMakeLists.txt3
-rw-r--r--src/transport/ipc/ipc_test.c50
-rw-r--r--src/transport/tcp/CMakeLists.txt8
-rw-r--r--src/transport/tcp/tcp_test.c304
-rw-r--r--src/transport/tls/CMakeLists.txt3
-rw-r--r--src/transport/ws/CMakeLists.txt12
-rw-r--r--src/transport/ws/ws_test.c42
-rw-r--r--src/transport/zerotier/CMakeLists.txt2
34 files changed, 2906 insertions, 110 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 57e6596c..5e0170a3 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -11,30 +11,16 @@
nng_sources(nng.c nng_legacy.c)
nng_headers(nng/nng.h)
-
target_include_directories(nng PRIVATE ${PROJECT_SOURCE_DIR}/src)
target_include_directories(nng_testing PRIVATE ${PROJECT_SOURCE_DIR}/src)
add_subdirectory(core)
-add_subdirectory(platform/windows)
-add_subdirectory(platform/posix)
+add_subdirectory(platform)
add_subdirectory(compat/nanomsg)
-add_subdirectory(protocol/bus0)
-add_subdirectory(protocol/pair0)
-add_subdirectory(protocol/pair1)
-add_subdirectory(protocol/pipeline0)
-add_subdirectory(protocol/pubsub0)
-add_subdirectory(protocol/reqrep0)
-add_subdirectory(protocol/survey0)
-
-add_subdirectory(transport/inproc)
-add_subdirectory(transport/ipc)
-add_subdirectory(transport/tcp)
-add_subdirectory(transport/tls)
-add_subdirectory(transport/ws)
-add_subdirectory(transport/zerotier)
+add_subdirectory(protocol)
+add_subdirectory(transport)
add_subdirectory(supplemental/base64)
add_subdirectory(supplemental/http)
diff --git a/src/compat/nanomsg/CMakeLists.txt b/src/compat/nanomsg/CMakeLists.txt
index 5e70e749..953eabad 100644
--- a/src/compat/nanomsg/CMakeLists.txt
+++ b/src/compat/nanomsg/CMakeLists.txt
@@ -9,4 +9,6 @@
nng_sources(nn.c)
+set(NNG_TEST_PREFIX ${NNG_TEST_PREFIX}.compat.nanomsg)
+
nng_test(compat_tcp_test) \ No newline at end of file
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 9ecc46f8..2c954938 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -8,6 +8,7 @@
#
# Core.
+nng_directory(core)
nng_check_sym(strlcpy string.h NNG_HAVE_STRLCPY)
nng_check_sym(strnlen string.h NNG_HAVE_STRNLEN)
@@ -75,3 +76,11 @@ nng_sources(
url.c
url.h
)
+
+nng_test(aio_test)
+nng_test(buf_size_test)
+nng_test(errors_test)
+nng_test(id_test)
+nng_test(reconnect_test)
+nng_test(sock_test)
+nng_test(url_test)
diff --git a/src/core/aio_test.c b/src/core/aio_test.c
new file mode 100644
index 00000000..787b6149
--- /dev/null
+++ b/src/core/aio_test.c
@@ -0,0 +1,245 @@
+//
+// Copyright 2020 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.
+//
+
+#include <string.h>
+
+#include <nng/nng.h>
+#include <nng/protocol/pair1/pair.h>
+#include <nng/supplemental/util/platform.h>
+
+#include "acutest.h"
+#include "testutil.h"
+
+static void
+cb_done(void *p)
+{
+ (*(int *) p)++;
+}
+
+static void
+sleep_done(void *arg)
+{
+ *(nng_time *) arg = nng_clock();
+}
+
+static void
+cancel(nng_aio *aio, void *arg, int rv)
+{
+ *(int *) arg = rv;
+ nng_aio_finish(aio, rv);
+}
+
+void
+test_sleep(void)
+{
+ nng_time start;
+ nng_time end = 0;
+ nng_aio *aio;
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, sleep_done, &end));
+ start = nng_clock();
+ nng_sleep_aio(200, aio);
+ nng_aio_wait(aio);
+ TEST_NNG_PASS(nng_aio_result(aio));
+ TEST_CHECK(end != 0);
+ TEST_CHECK((end - start) >= 200);
+ TEST_CHECK((end - start) <= 1000);
+ TEST_CHECK((nng_clock() - start) >= 200);
+ TEST_CHECK((nng_clock() - start) <= 1000);
+ nng_aio_free(aio);
+}
+
+void
+test_sleep_timeout(void)
+{
+ nng_time start;
+ nng_time end = 0;
+ nng_aio *aio;
+
+ TEST_CHECK(nng_aio_alloc(&aio, sleep_done, &end) == 0);
+ nng_aio_set_timeout(aio, 100);
+ start = nng_clock();
+ nng_sleep_aio(2000, aio);
+ nng_aio_wait(aio);
+ TEST_NNG_FAIL(nng_aio_result(aio), NNG_ETIMEDOUT);
+ TEST_CHECK(end != 0);
+ TEST_CHECK((end - start) >= 100);
+ TEST_CHECK((end - start) <= 1000);
+ TEST_CHECK((nng_clock() - start) >= 100);
+ TEST_CHECK((nng_clock() - start) <= 1000);
+ nng_aio_free(aio);
+}
+
+void
+test_insane_nio(void)
+{
+ nng_aio *aio;
+ nng_iov iov;
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ TEST_NNG_FAIL(nng_aio_set_iov(aio, 1024, &iov), NNG_EINVAL);
+ nng_aio_free(aio);
+}
+
+void
+test_provider_cancel(void)
+{
+ nng_aio *aio;
+ int rv = 0;
+ // We fake an empty provider that does not do anything.
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ TEST_CHECK(nng_aio_begin(aio) == true);
+ nng_aio_defer(aio, cancel, &rv);
+ nng_aio_cancel(aio);
+ nng_aio_wait(aio);
+ TEST_CHECK(rv == NNG_ECANCELED);
+ nng_aio_free(aio);
+}
+
+void
+test_consumer_cancel(void)
+{
+ nng_aio * a;
+ nng_socket s1;
+ int done = 0;
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ TEST_CHECK(nng_aio_alloc(&a, cb_done, &done) == 0);
+
+ nng_aio_set_timeout(a, NNG_DURATION_INFINITE);
+ nng_recv_aio(s1, a);
+ nng_aio_cancel(a);
+ nng_aio_wait(a);
+ TEST_CHECK(done == 1);
+ TEST_CHECK(nng_aio_result(a) == NNG_ECANCELED);
+
+ nng_aio_free(a);
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_traffic(void)
+{
+ nng_socket s1;
+ nng_socket s2;
+ nng_aio * tx_aio;
+ nng_aio * rx_aio;
+ int tx_done = 0;
+ int rx_done = 0;
+ nng_msg * m;
+ char * addr = "inproc://traffic";
+
+ TEST_NNG_PASS(nng_pair1_open(&s1));
+ TEST_NNG_PASS(nng_pair1_open(&s2));
+
+ TEST_NNG_PASS(nng_listen(s1, addr, NULL, 0));
+ TEST_NNG_PASS(nng_dial(s2, addr, NULL, 0));
+
+ TEST_NNG_PASS(nng_aio_alloc(&rx_aio, cb_done, &rx_done));
+ TEST_NNG_PASS(nng_aio_alloc(&tx_aio, cb_done, &tx_done));
+
+ nng_aio_set_timeout(rx_aio, 1000);
+ nng_aio_set_timeout(tx_aio, 1000);
+
+ TEST_NNG_PASS(nng_msg_alloc(&m, 0));
+ TEST_NNG_PASS(nng_msg_append(m, "hello", strlen("hello")));
+
+ nng_recv_aio(s2, rx_aio);
+
+ nng_aio_set_msg(tx_aio, m);
+ nng_send_aio(s1, tx_aio);
+
+ nng_aio_wait(tx_aio);
+ nng_aio_wait(rx_aio);
+
+ TEST_NNG_PASS(nng_aio_result(rx_aio));
+ TEST_NNG_PASS(nng_aio_result(tx_aio));
+
+ TEST_CHECK((m = nng_aio_get_msg(rx_aio)) != NULL);
+ TEST_CHECK(nng_msg_len(m) == strlen("hello"));
+ TEST_CHECK(memcmp(nng_msg_body(m), "hello", strlen("hello")) == 0);
+
+ nng_msg_free(m);
+
+ TEST_CHECK(rx_done == 1);
+ TEST_CHECK(tx_done == 1);
+
+ nng_aio_free(rx_aio);
+ nng_aio_free(tx_aio);
+ TEST_NNG_PASS(nng_close(s1));
+ TEST_NNG_PASS(nng_close(s2));
+}
+
+void
+test_explicit_timeout(void)
+{
+ nng_socket s;
+ nng_aio * a;
+ int done = 0;
+
+ TEST_NNG_PASS(nng_pair1_open(&s));
+ TEST_NNG_PASS(nng_aio_alloc(&a, cb_done, &done));
+ nng_aio_set_timeout(a, 40);
+ nng_recv_aio(s, a);
+ nng_aio_wait(a);
+ TEST_CHECK(done == 1);
+ TEST_NNG_FAIL(nng_aio_result(a), NNG_ETIMEDOUT);
+ nng_aio_free(a);
+ TEST_NNG_PASS(nng_close(s));
+}
+
+void
+test_inherited_timeout(void)
+{
+ nng_socket s;
+ nng_aio * a;
+ int done = 0;
+
+ TEST_NNG_PASS(nng_pair1_open(&s));
+ TEST_NNG_PASS(nng_aio_alloc(&a, cb_done, &done));
+ TEST_NNG_PASS(nng_socket_set_ms(s, NNG_OPT_RECVTIMEO, 40));
+ nng_recv_aio(s, a);
+ nng_aio_wait(a);
+ TEST_CHECK(done == 1);
+ TEST_NNG_FAIL(nng_aio_result(a), NNG_ETIMEDOUT);
+ nng_aio_free(a);
+ TEST_NNG_PASS(nng_close(s));
+}
+
+void
+test_zero_timeout(void)
+{
+ nng_socket s;
+ nng_aio * a;
+ int done = 0;
+
+ TEST_NNG_PASS(nng_pair1_open(&s));
+ TEST_NNG_PASS(nng_aio_alloc(&a, cb_done, &done));
+ nng_aio_set_timeout(a, NNG_DURATION_ZERO);
+ nng_recv_aio(s, a);
+ nng_aio_wait(a);
+ TEST_CHECK(done == 1);
+ TEST_NNG_FAIL(nng_aio_result(a), NNG_ETIMEDOUT);
+ nng_aio_free(a);
+ TEST_NNG_PASS(nng_close(s));
+}
+
+TEST_LIST = {
+ { "sleep", test_sleep },
+ { "sleep timeout", test_sleep_timeout },
+ { "insane nio", test_insane_nio },
+ { "provider cancel", test_provider_cancel },
+ { "consumer cancel", test_consumer_cancel },
+ { "traffic", test_traffic },
+ { "explicit timeout", test_explicit_timeout },
+ { "inherited timeout", test_inherited_timeout },
+ { "zero timeout", test_zero_timeout },
+ { NULL, NULL },
+}; \ No newline at end of file
diff --git a/src/core/buf_size_test.c b/src/core/buf_size_test.c
new file mode 100644
index 00000000..172cb1f0
--- /dev/null
+++ b/src/core/buf_size_test.c
@@ -0,0 +1,119 @@
+//
+// Copyright 2020 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.
+//
+
+#include <nng/nng.h>
+#include <nng/protocol/pair1/pair.h>
+#include <nng/supplemental/util/platform.h>
+
+#include <nng/compat/nanomsg/nn.h>
+
+#include "acutest.h"
+#include "testutil.h"
+
+void
+test_buffer_options(void)
+{
+ nng_socket s1;
+ int val;
+ size_t sz;
+ char * opt;
+
+ char *cases[] = {
+ NNG_OPT_RECVBUF,
+ NNG_OPT_SENDBUF,
+ NULL,
+ };
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ for (int i = 0; (opt = cases[i]) != NULL; i++) {
+
+ TEST_CASE(opt);
+
+ // Can't receive a size into zero bytes.
+ sz = 0;
+ TEST_NNG_FAIL(nng_socket_get(s1, opt, &val, &sz), NNG_EINVAL);
+
+ // Can set a valid size
+ TEST_NNG_PASS(nng_socket_set_int(s1, opt, 1234));
+ TEST_NNG_PASS(nng_socket_get_int(s1, opt, &val));
+ TEST_CHECK(val == 1234);
+
+ val = 0;
+ sz = sizeof(val);
+ TEST_NNG_PASS(nng_socket_get(s1, opt, &val, &sz));
+ TEST_CHECK(val == 1234);
+ TEST_CHECK(sz == sizeof(val));
+
+ // Can't set a negative size
+ TEST_NNG_FAIL(nng_socket_set_int(s1, opt, -5), NNG_EINVAL);
+
+ // Can't pass a buf too small for size
+ sz = sizeof(val) - 1;
+ val = 1;
+ TEST_NNG_FAIL(nng_socket_set(s1, opt, &val, sz), NNG_EINVAL);
+ // Buffer sizes are limited to sane levels
+ TEST_NNG_FAIL(
+ nng_socket_set_int(s1, opt, 0x100000), NNG_EINVAL);
+ }
+ TEST_CHECK(nng_close(s1) == 0);
+}
+
+void
+test_buffer_legacy(void)
+{
+ nng_socket s1;
+ char * opt;
+
+ char *cases[] = {
+ NNG_OPT_RECVBUF,
+ NNG_OPT_SENDBUF,
+ NULL,
+ };
+ int legacy[] = {
+ NN_RCVBUF,
+ NN_SNDBUF,
+ };
+
+ TEST_CHECK(nng_pair1_open(&s1) == 0);
+ for (int i = 0; (opt = cases[i]) != NULL; i++) {
+ int cnt;
+ int os = (int) s1.id;
+ size_t sz;
+ int nno = legacy[i];
+
+ TEST_CASE(opt);
+
+ sz = sizeof(cnt);
+ TEST_NNG_PASS(nng_socket_set_int(s1, opt, 10));
+ TEST_CHECK(
+ nn_getsockopt(os, NN_SOL_SOCKET, nno, &cnt, &sz) == 0);
+ TEST_CHECK(cnt == 10240); // 1k multiple
+
+ cnt = 1;
+ TEST_CHECK(
+ nn_setsockopt(os, NN_SOL_SOCKET, nno, &cnt, sz) == 0);
+ TEST_CHECK(
+ nn_getsockopt(os, NN_SOL_SOCKET, nno, &cnt, &sz) == 0);
+ TEST_CHECK(cnt == 1024); // round up!
+ TEST_NNG_PASS(nng_socket_get_int(s1, opt, &cnt));
+ TEST_CHECK(cnt == 1);
+
+ TEST_CHECK(
+ nn_setsockopt(os, NN_SOL_SOCKET, nno, &cnt, 100) == -1);
+ TEST_CHECK(nn_errno() == EINVAL);
+ }
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+TEST_LIST = {
+ { "buffer options", test_buffer_options },
+ { "buffer legacy", test_buffer_legacy },
+ { NULL, NULL },
+};
diff --git a/src/core/errors_test.c b/src/core/errors_test.c
new file mode 100644
index 00000000..4e50467c
--- /dev/null
+++ b/src/core/errors_test.c
@@ -0,0 +1,46 @@
+//
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
+//
+// 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.
+//
+
+#include <errno.h>
+#include <string.h>
+
+#include <nng/nng.h>
+
+#include <acutest.h>
+#include <testutil.h>
+
+static void
+test_known_errors(void)
+{
+
+ TEST_STREQUAL(nng_strerror(NNG_ECLOSED), "Object closed");
+ TEST_STREQUAL(nng_strerror(NNG_ETIMEDOUT), "Timed out");
+}
+
+static void
+test_unknown_errors(void)
+{
+ for (unsigned i = 1; i < 0x1000000; i = i * 2 + 100) {
+ TEST_CHECK(nng_strerror(i) != NULL);
+ }
+}
+
+static void
+test_system_errors(void)
+{
+ TEST_STREQUAL(nng_strerror(NNG_ESYSERR + ENOENT), strerror(ENOENT));
+ TEST_STREQUAL(nng_strerror(NNG_ESYSERR + EINVAL), strerror(EINVAL));
+}
+
+TEST_LIST = {
+ { "known errors", test_known_errors },
+ { "unknown errors", test_unknown_errors },
+ { "system errors", test_system_errors },
+ { NULL, NULL },
+};
diff --git a/src/core/id_test.c b/src/core/id_test.c
new file mode 100644
index 00000000..8312b5cc
--- /dev/null
+++ b/src/core/id_test.c
@@ -0,0 +1,275 @@
+//
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
+//
+// 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.
+//
+
+#include "acutest.h"
+#include "testutil.h"
+
+#include "idhash.h"
+
+void
+test_basic(void)
+{
+ nni_id_map m;
+ char * five = "five";
+ char * four = "four";
+
+ nni_id_map_init(&m, 0, 0, false);
+
+ // insert it
+ TEST_NNG_PASS(nni_id_set(&m, 5, five));
+ // retrieve it
+ TEST_CHECK(nni_id_get(&m, 5) == five);
+
+ // change it
+ TEST_NNG_PASS(nni_id_set(&m, 5, four));
+ TEST_CHECK(nni_id_get(&m, 5) == four);
+
+ // delete
+ TEST_NNG_PASS(nni_id_remove(&m, 5));
+
+ nni_id_map_fini(&m);
+}
+
+void
+test_random(void)
+{
+ int i;
+ uint32_t id;
+ for (i = 0; i < 2; i++) {
+ nni_id_map m;
+ nni_id_map_init(&m, 0, 0, true);
+ TEST_NNG_PASS(nni_id_alloc(&m, &id, &id));
+ nni_id_map_fini(&m);
+ TEST_CHECK(id != 0);
+ if (id != 1) {
+ break;
+ }
+ // one chance in 4 billion, but try again
+ }
+
+ TEST_CHECK(id != 1);
+ TEST_CHECK(i < 2);
+}
+
+void
+test_collision(void)
+{
+ nni_id_map m;
+ char * five = "five";
+ char * four = "four";
+
+ nni_id_map_init(&m, 0, 0, false);
+
+ // Carefully crafted -- 13 % 8 == 5.
+ TEST_NNG_PASS(nni_id_set(&m, 5, five));
+ TEST_NNG_PASS(nni_id_set(&m, 13, four));
+ TEST_CHECK(nni_id_get(&m, 5) == five);
+ TEST_CHECK(nni_id_get(&m, 13) == four);
+
+ // Delete the intermediate
+ TEST_NNG_PASS(nni_id_remove(&m, 5));
+ TEST_CHECK(nni_id_get(&m, 13) == four);
+
+ nni_id_map_fini(&m);
+}
+
+void
+test_empty(void)
+{
+ nni_id_map m;
+ nni_id_map_init(&m, 0, 0, false);
+
+ TEST_CHECK(nni_id_get(&m, 42) == NULL);
+ TEST_NNG_FAIL(nni_id_remove(&m, 42), NNG_ENOENT);
+ TEST_NNG_FAIL(nni_id_remove(&m, 1), NNG_ENOENT);
+ nni_id_map_fini(&m);
+}
+
+void
+test_not_found(void)
+{
+ nni_id_map m;
+ uint32_t id;
+ nni_id_map_init(&m, 0, 0, false);
+
+ TEST_NNG_PASS(nni_id_alloc(&m, &id, &id));
+ TEST_NNG_FAIL(nni_id_remove(&m, 42), NNG_ENOENT);
+ TEST_NNG_FAIL(nni_id_remove(&m, 2), NNG_ENOENT);
+ TEST_NNG_PASS(nni_id_remove(&m, id));
+ nni_id_map_fini(&m);
+}
+
+void
+test_resize(void)
+{
+ nni_id_map m;
+ int rv;
+ int i;
+ int expect[1024];
+
+ for (i = 0; i < 1024; i++) {
+ expect[i] = i;
+ }
+
+ nni_id_map_init(&m, 0, 0, false);
+
+ for (i = 0; i < 1024; i++) {
+ if ((rv = nni_id_set(&m, i, &expect[i])) != 0) {
+ TEST_NNG_PASS(rv);
+ }
+ }
+
+ for (i = 0; i < 1024; i++) {
+ if ((rv = nni_id_remove(&m, i)) != 0) {
+ TEST_NNG_PASS(rv);
+ }
+ }
+ nni_id_map_fini(&m);
+}
+
+void
+test_dynamic(void)
+{
+ nni_id_map m;
+ int expect[5];
+ uint32_t id;
+
+ nni_id_map_init(&m, 10, 13, false);
+
+ // We can fill the table.
+ TEST_NNG_PASS(nni_id_alloc(&m, &id, &expect[0]));
+ TEST_CHECK(id == 10);
+ TEST_NNG_PASS(nni_id_alloc(&m, &id, &expect[1]));
+ TEST_CHECK(id == 11);
+ TEST_NNG_PASS(nni_id_alloc(&m, &id, &expect[2]));
+ TEST_CHECK(id == 12);
+ TEST_NNG_PASS(nni_id_alloc(&m, &id, &expect[3]));
+ TEST_CHECK(id == 13);
+
+ // Adding another fails.
+ TEST_NNG_FAIL(nni_id_alloc(&m, &id, &expect[4]), NNG_ENOMEM);
+
+ // Delete one.
+ TEST_NNG_PASS(nni_id_remove(&m, 11));
+
+ // And now we can allocate one.
+ TEST_NNG_PASS(nni_id_alloc(&m, &id, &expect[4]));
+ TEST_CHECK(id == 11);
+ nni_id_map_fini(&m);
+}
+
+void
+test_set_out_of_range(void)
+{
+ nni_id_map m;
+ int x;
+ uint32_t id;
+
+ nni_id_map_init(&m, 10, 13, false);
+
+ // We can insert outside the range forcibly.
+ TEST_NNG_PASS(nni_id_set(&m, 1, &x));
+ TEST_NNG_PASS(nni_id_set(&m, 100, &x));
+ TEST_NNG_PASS(nni_id_alloc(&m, &id, &x));
+ TEST_CHECK(id == 10);
+ nni_id_map_fini(&m);
+}
+
+#define STRESS_LOAD 50000
+#define NUM_VALUES 1000
+
+void
+test_stress(void)
+{
+ void * values[NUM_VALUES];
+ nni_id_map m;
+ size_t i;
+ int rv;
+ void * x;
+ int v;
+
+ nni_id_map_init(&m, 0, 0, false);
+ for (i = 0; i < NUM_VALUES; i++) {
+ values[i] = NULL;
+ }
+
+ for (i = 0; i < STRESS_LOAD; i++) {
+ v = rand() % NUM_VALUES; // Keep it constrained
+
+ switch (rand() & 3) {
+ case 0:
+ x = &values[rand() % NUM_VALUES];
+ values[v] = x;
+ if ((rv = nni_id_set(&m, v, x)) != 0) {
+ TEST_NNG_PASS(rv);
+ goto out;
+ }
+ break;
+
+ case 1:
+ rv = nni_id_remove(&m, v);
+ if (values[v] == NULL) {
+ if (rv != NNG_ENOENT) {
+ TEST_NNG_FAIL(rv, NNG_ENOENT);
+ goto out;
+ }
+ } else {
+ values[v] = NULL;
+ if (rv != 0) {
+ TEST_NNG_PASS(rv);
+ goto out;
+ }
+ }
+ break;
+ case 2:
+ x = nni_id_get(&m, v);
+ if (x != values[v]) {
+ TEST_CHECK(x == values[v]);
+ goto out;
+ }
+ break;
+ }
+ }
+out:
+ TEST_CHECK(i == STRESS_LOAD);
+
+ // Post stress check.
+ for (i = 0; i < NUM_VALUES; i++) {
+ x = nni_id_get(&m, i);
+ if (x != values[i]) {
+ TEST_CHECK(x == values[i]);
+ break;
+ }
+
+ // We only use the test macros if we know they are going
+ // to fail. Otherwise there will be too many errors reported.
+ rv = nni_id_remove(&m, i);
+ if ((x == NULL) && (rv != NNG_ENOENT)) {
+ TEST_NNG_FAIL(rv, NNG_ENOENT);
+ } else if ((x != NULL) && (rv != 0)) {
+ TEST_NNG_PASS(rv);
+ }
+ }
+ TEST_CHECK(i == NUM_VALUES);
+
+ nni_id_map_fini(&m);
+}
+
+TEST_LIST = {
+ { "basic", test_basic },
+ { "random", test_random },
+ { "collision", test_collision },
+ { "empty", test_empty },
+ { "not found", test_not_found },
+ { "resize", test_resize },
+ { "dynamic", test_dynamic },
+ { "set out of range", test_set_out_of_range },
+ { "stress", test_stress },
+ { NULL, NULL },
+};
diff --git a/src/core/reconnect_test.c b/src/core/reconnect_test.c
new file mode 100644
index 00000000..669261c9
--- /dev/null
+++ b/src/core/reconnect_test.c
@@ -0,0 +1,167 @@
+//
+// Copyright 2020 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.
+//
+
+#include <string.h>
+
+#include <nng/nng.h>
+#include <nng/protocol/pipeline0/pull.h>
+#include <nng/protocol/pipeline0/push.h>
+#include <nng/supplemental/util/platform.h>
+
+#include "acutest.h"
+#include "testutil.h"
+
+void
+test_dial_before_listen(void)
+{
+ nng_socket push;
+ nng_socket pull;
+ char addr[64];
+
+ testutil_scratch_addr("inproc", sizeof(addr), addr);
+
+ TEST_NNG_PASS(nng_push0_open(&push));
+ TEST_NNG_PASS(nng_pull0_open(&pull));
+
+ TEST_NNG_PASS(nng_socket_set_ms(pull, NNG_OPT_RECONNMINT, 10));
+ TEST_NNG_PASS(nng_socket_set_ms(pull, NNG_OPT_RECONNMAXT, 10));
+
+ TEST_NNG_PASS(nng_dial(pull, addr, NULL, NNG_FLAG_NONBLOCK));
+ testutil_sleep(100);
+ TEST_NNG_PASS(nng_listen(push, addr, NULL, 0));
+
+ TEST_NNG_SEND_STR(push, "hello");
+ TEST_NNG_RECV_STR(pull, "hello");
+
+ TEST_NNG_PASS(nng_close(push));
+ TEST_NNG_PASS(nng_close(pull));
+}
+
+void
+test_reconnect(void)
+{
+ nng_socket push;
+ nng_socket pull;
+ nng_listener l;
+ char addr[64];
+
+ testutil_scratch_addr("inproc", sizeof(addr), addr);
+
+ TEST_NNG_PASS(nng_push0_open(&push));
+ TEST_NNG_PASS(nng_pull0_open(&pull));
+
+ TEST_NNG_PASS(nng_socket_set_ms(pull, NNG_OPT_RECONNMINT, 10));
+ TEST_NNG_PASS(nng_socket_set_ms(pull, NNG_OPT_RECONNMAXT, 10));
+
+ TEST_NNG_PASS(nng_dial(pull, addr, NULL, NNG_FLAG_NONBLOCK));
+ testutil_sleep(100);
+ TEST_NNG_PASS(nng_listen(push, addr, &l, 0));
+
+ TEST_NNG_SEND_STR(push, "hello");
+ TEST_NNG_RECV_STR(pull, "hello");
+
+ // Close the listener
+ TEST_NNG_PASS(nng_listener_close(l));
+
+ TEST_NNG_PASS(nng_listen(push, addr, &l, 0));
+ TEST_NNG_SEND_STR(push, "again");
+ TEST_NNG_RECV_STR(pull, "again");
+
+ TEST_NNG_PASS(nng_close(push));
+ TEST_NNG_PASS(nng_close(pull));
+}
+
+void
+test_reconnect_pipe(void)
+{
+ nng_socket push;
+ nng_socket pull;
+ nng_listener l;
+ nng_msg * msg;
+ char addr[64];
+
+ testutil_scratch_addr("inproc", sizeof(addr), addr);
+
+ TEST_NNG_PASS(nng_push0_open(&push));
+ TEST_NNG_PASS(nng_pull0_open(&pull));
+
+ TEST_NNG_PASS(nng_socket_set_ms(pull, NNG_OPT_RECONNMINT, 10));
+ TEST_NNG_PASS(nng_socket_set_ms(pull, NNG_OPT_RECONNMAXT, 10));
+
+ TEST_NNG_PASS(nng_dial(pull, addr, NULL, NNG_FLAG_NONBLOCK));
+ testutil_sleep(100);
+ TEST_NNG_PASS(nng_listen(push, addr, &l, 0));
+
+ TEST_NNG_SEND_STR(push, "hello");
+
+ TEST_NNG_PASS(nng_recvmsg(pull, &msg, 0));
+ TEST_CHECK(msg != NULL);
+ TEST_CHECK(nng_msg_len(msg) == 6);
+ TEST_CHECK(strcmp(nng_msg_body(msg), "hello") == 0);
+ nng_pipe_close(nng_msg_get_pipe(msg));
+ nng_msg_free(msg);
+
+ // We have to wait a bit, because while we closed the pipe on the
+ // receiver, the receiver might not have got the update. If we
+ // send too soon, then the message gets routed to the sender pipe
+ // that is about to close.
+ testutil_sleep(100);
+
+ // Reconnect should happen more ore less immediately.
+ TEST_NNG_SEND_STR(push, "again");
+ TEST_NNG_RECV_STR(pull, "again");
+
+ TEST_NNG_PASS(nng_close(push));
+ TEST_NNG_PASS(nng_close(pull));
+}
+
+void
+test_reconnect_back_off_zero(void)
+{
+ nng_socket push;
+ nng_socket pull;
+ nng_time start;
+ char addr[64];
+ testutil_scratch_addr("inproc", sizeof(addr), addr);
+
+ TEST_NNG_PASS(nng_push0_open(&push));
+ TEST_NNG_PASS(nng_pull0_open(&pull));
+
+ // redial every 10 ms.
+ TEST_NNG_PASS(nng_socket_set_ms(push, NNG_OPT_RECONNMAXT, 0));
+ TEST_NNG_PASS(nng_socket_set_ms(push, NNG_OPT_RECONNMINT, 10));
+ TEST_NNG_PASS(nng_dial(push, addr, NULL, NNG_FLAG_NONBLOCK));
+
+ // Start up the dialer first. It should keep retrying every 10 ms.
+
+ // Wait 500 milliseconds. This gives a chance for an exponential
+ // back-off to increase to a longer time. It should by this point
+ // be well over 100 and probably closer to 200 ms.
+ nng_msleep(500);
+
+ start = nng_clock();
+ TEST_NNG_PASS(nng_listen(pull, addr, NULL, 0));
+
+ TEST_NNG_SEND_STR(push, "hello");
+ TEST_NNG_RECV_STR(pull, "hello");
+
+ TEST_CHECK(nng_clock() - start < 100);
+
+ TEST_NNG_PASS(nng_close(push));
+ TEST_NNG_PASS(nng_close(pull));
+}
+
+TEST_LIST = {
+ { "dial before listen", test_dial_before_listen },
+ { "reconnect", test_reconnect },
+ { "reconnect back-off zero", test_reconnect_back_off_zero },
+ { "reconnect pipe", test_reconnect_pipe },
+ { NULL, NULL },
+}; \ No newline at end of file
diff --git a/src/core/sock_test.c b/src/core/sock_test.c
new file mode 100644
index 00000000..ab557632
--- /dev/null
+++ b/src/core/sock_test.c
@@ -0,0 +1,685 @@
+//
+// Copyright 2020 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.
+//
+
+#include <string.h>
+
+#include <nng/nng.h>
+#include <nng/protocol/pair1/pair.h>
+#include <nng/supplemental/util/platform.h>
+
+#include "acutest.h"
+#include "testutil.h"
+
+void
+test_recv_timeout(void)
+{
+ nng_socket s1;
+ uint64_t now;
+ nng_msg * msg = NULL;
+
+ TEST_NNG_PASS(nng_pair_open(&s1));
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 10));
+ now = testutil_clock();
+ TEST_NNG_FAIL(nng_recvmsg(s1, &msg, 0), NNG_ETIMEDOUT);
+ TEST_CHECK(msg == NULL);
+ TEST_CHECK(testutil_clock() >= (now + 9));
+ TEST_CHECK(testutil_clock() < (now + 500));
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_recv_nonblock(void)
+{
+ nng_socket s1;
+ uint64_t now;
+ nng_msg * msg = NULL;
+
+ TEST_NNG_PASS(nng_pair1_open(&s1));
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 10));
+ now = testutil_clock();
+ TEST_NNG_FAIL(nng_recvmsg(s1, &msg, NNG_FLAG_NONBLOCK), NNG_EAGAIN);
+ TEST_CHECK(msg == NULL);
+ TEST_CHECK(testutil_clock() < (now + 500));
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_send_timeout(void)
+{
+ nng_socket s1;
+ uint64_t now;
+ nng_msg * msg;
+
+ TEST_NNG_PASS(nng_msg_alloc(&msg, 0));
+ TEST_NNG_PASS(nng_pair_open(&s1));
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 100));
+ now = testutil_clock();
+ TEST_NNG_FAIL(nng_sendmsg(s1, msg, 0), NNG_ETIMEDOUT);
+ TEST_CHECK(testutil_clock() >= (now + 9));
+ TEST_CHECK(testutil_clock() < (now + 500));
+ nng_msg_free(msg);
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_send_nonblock(void)
+{
+ nng_socket s1;
+ uint64_t now;
+ nng_msg * msg;
+
+ TEST_NNG_PASS(nng_msg_alloc(&msg, 0));
+ TEST_NNG_PASS(nng_pair1_open(&s1));
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 500));
+ now = testutil_clock();
+ TEST_NNG_FAIL(nng_sendmsg(s1, msg, NNG_FLAG_NONBLOCK), NNG_EAGAIN);
+ TEST_CHECK(testutil_clock() < (now + 100));
+ TEST_NNG_PASS(nng_close(s1));
+ nng_msg_free(msg);
+}
+
+void
+test_readonly_options(void)
+{
+ nng_socket s1;
+ TEST_NNG_PASS(nng_pair1_open(&s1));
+ TEST_NNG_FAIL(
+ nng_socket_set_int(s1, NNG_OPT_RECVFD, 0), NNG_EREADONLY);
+ TEST_NNG_FAIL(
+ nng_socket_set_int(s1, NNG_OPT_SENDFD, 0), NNG_EREADONLY);
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_socket_base(void)
+{
+ nng_socket s1 = NNG_SOCKET_INITIALIZER;
+
+ TEST_CHECK(nng_socket_id(s1) < 0);
+ TEST_NNG_PASS(nng_pair1_open(&s1));
+ TEST_CHECK(nng_socket_id(s1) > 0);
+
+ // Cannot set bogus options
+ TEST_NNG_FAIL(nng_socket_set_bool(s1, "BAD_OPT", false), NNG_ENOTSUP);
+
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_socket_name(void)
+{
+ nng_socket s1;
+ char name[128]; // 64 is max
+ char * str;
+ long id;
+ char * end;
+ size_t sz;
+
+ sz = sizeof(name);
+ TEST_NNG_PASS(nng_pair_open(&s1));
+ TEST_NNG_PASS(nng_socket_get(s1, NNG_OPT_SOCKNAME, name, &sz));
+ TEST_CHECK(sz > 0 && sz < 64);
+ TEST_CHECK(sz == strlen(name) + 1);
+ id = strtol(name, &end, 10);
+ TEST_CHECK(id == (long) s1.id);
+ TEST_CHECK(end != NULL && *end == '\0');
+
+ TEST_NNG_PASS(nng_socket_set(s1, NNG_OPT_SOCKNAME, "hello", 6));
+ sz = sizeof(name);
+ TEST_NNG_PASS(nng_socket_get(s1, NNG_OPT_SOCKNAME, name, &sz));
+ TEST_CHECK(sz == 6);
+ TEST_STREQUAL(name, "hello");
+
+ memset(name, 'A', 64);
+ name[64] = '\0';
+
+ // strings must be NULL terminated
+ TEST_NNG_FAIL(
+ nng_socket_set(s1, NNG_OPT_SOCKNAME, name, 5), NNG_EINVAL);
+
+ TEST_NNG_PASS(nng_socket_get_string(s1, NNG_OPT_SOCKNAME, &str));
+ TEST_ASSERT(str != NULL);
+ TEST_CHECK(strlen(str) == 5);
+ TEST_STREQUAL(str, "hello");
+ nng_strfree(str);
+
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_socket_name_oversize(void)
+{
+ nng_socket s1;
+ char name[256]; // 64 is max
+ size_t sz = sizeof(name);
+
+ memset(name, 'A', sz);
+ TEST_NNG_PASS(nng_pair_open(&s1));
+
+ TEST_NNG_FAIL(
+ nng_socket_set(s1, NNG_OPT_SOCKNAME, name, sz), NNG_EINVAL);
+ name[sz - 1] = '\0';
+ TEST_NNG_FAIL(
+ nng_socket_set(s1, NNG_OPT_SOCKNAME, name, sz), NNG_EINVAL);
+
+ strcpy(name, "hello");
+ TEST_NNG_PASS(nng_socket_set(s1, NNG_OPT_SOCKNAME, name, sz));
+ sz = sizeof(name);
+ memset(name, 'B', sz);
+ TEST_NNG_PASS(nng_getopt(s1, NNG_OPT_SOCKNAME, name, &sz));
+ TEST_CHECK(sz == 6);
+ TEST_STREQUAL(name, "hello");
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_send_recv(void)
+{
+ nng_socket s1;
+ nng_socket s2;
+ int len;
+ size_t sz;
+ nng_duration to = 3000; // 3 seconds
+ char * buf;
+ char * a = "inproc://t1";
+
+ TEST_NNG_PASS(nng_pair1_open(&s1));
+ TEST_NNG_PASS(nng_pair1_open(&s2));
+
+ TEST_NNG_PASS(nng_socket_set_int(s1, NNG_OPT_RECVBUF, 1));
+ TEST_NNG_PASS(nng_socket_get_int(s1, NNG_OPT_RECVBUF, &len));
+ TEST_CHECK(len == 1);
+
+ TEST_NNG_PASS(nng_socket_set_int(s1, NNG_OPT_SENDBUF, 1));
+ TEST_NNG_PASS(nng_socket_set_int(s2, NNG_OPT_SENDBUF, 1));
+
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, to));
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, to));
+ TEST_NNG_PASS(nng_socket_set_ms(s2, NNG_OPT_SENDTIMEO, to));
+ TEST_NNG_PASS(nng_socket_set_ms(s2, NNG_OPT_RECVTIMEO, to));
+
+ TEST_NNG_PASS(nng_listen(s1, a, NULL, 0));
+ TEST_NNG_PASS(nng_dial(s2, a, NULL, 0));
+
+ TEST_NNG_PASS(nng_send(s1, "abc", 4, 0));
+ TEST_NNG_PASS(nng_recv(s2, &buf, &sz, NNG_FLAG_ALLOC));
+ TEST_CHECK(buf != NULL);
+ TEST_CHECK(sz == 4);
+ TEST_CHECK(memcmp(buf, "abc", 4) == 0);
+ nng_free(buf, sz);
+
+ TEST_NNG_PASS(nng_close(s1));
+ TEST_NNG_PASS(nng_close(s2));
+}
+
+void
+test_send_recv_zero_length(void)
+{
+ nng_socket s1;
+ nng_socket s2;
+ int len;
+ size_t sz;
+ nng_duration to = 3000; // 3 seconds
+ char * buf;
+ char * a = "inproc://send-recv-zero-length";
+
+ TEST_NNG_PASS(nng_pair1_open(&s1));
+ TEST_NNG_PASS(nng_pair1_open(&s2));
+
+ TEST_NNG_PASS(nng_socket_set_int(s1, NNG_OPT_RECVBUF, 1));
+ TEST_NNG_PASS(nng_getopt_int(s1, NNG_OPT_RECVBUF, &len));
+ TEST_CHECK(len == 1);
+
+ TEST_NNG_PASS(nng_socket_set_int(s1, NNG_OPT_SENDBUF, 1));
+ TEST_NNG_PASS(nng_socket_set_int(s2, NNG_OPT_SENDBUF, 1));
+
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, to));
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, to));
+ TEST_NNG_PASS(nng_socket_set_ms(s2, NNG_OPT_SENDTIMEO, to));
+ TEST_NNG_PASS(nng_socket_set_ms(s2, NNG_OPT_RECVTIMEO, to));
+
+ TEST_NNG_PASS(nng_listen(s1, a, NULL, 0));
+ TEST_NNG_PASS(nng_dial(s2, a, NULL, 0));
+
+ TEST_NNG_PASS(nng_send(s1, "", 0, 0));
+ TEST_NNG_PASS(nng_recv(s2, &buf, &sz, NNG_FLAG_ALLOC));
+ TEST_CHECK(buf == NULL);
+ TEST_CHECK(sz == 0);
+ nng_free(buf, sz);
+
+ TEST_NNG_PASS(nng_close(s1));
+ TEST_NNG_PASS(nng_close(s2));
+}
+
+void
+test_connection_refused(void)
+{
+ nng_socket s1;
+
+ TEST_NNG_PASS(nng_pair1_open(&s1));
+ TEST_NNG_FAIL(nng_dial(s1, "inproc://no", NULL, 0), NNG_ECONNREFUSED);
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_late_connection(void)
+{
+ char * buf;
+ size_t sz;
+ nng_socket s1;
+ nng_socket s2;
+ char * a = "inproc://asy";
+
+ TEST_NNG_PASS(nng_pair1_open(&s1));
+ TEST_NNG_PASS(nng_pair1_open(&s2));
+
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_RECONNMINT, 10));
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_RECONNMAXT, 10));
+
+ TEST_NNG_PASS(nng_dial(s1, a, NULL, NNG_FLAG_NONBLOCK));
+ TEST_NNG_PASS(nng_listen(s2, a, NULL, 0));
+ nng_msleep(100);
+ TEST_NNG_PASS(nng_send(s1, "abc", 4, 0));
+ TEST_NNG_PASS(nng_recv(s2, &buf, &sz, NNG_FLAG_ALLOC));
+ TEST_CHECK(sz == 4);
+ TEST_CHECK(memcmp(buf, "abc", 4) == 0);
+ nng_free(buf, sz);
+
+ TEST_NNG_PASS(nng_close(s1));
+ TEST_NNG_PASS(nng_close(s2));
+}
+
+void
+test_address_busy(void)
+{
+ char * a = "inproc://eaddrinuse";
+ nng_listener l = NNG_LISTENER_INITIALIZER;
+ nng_dialer d = NNG_DIALER_INITIALIZER;
+ nng_socket s1;
+ nng_socket s2;
+
+ TEST_NNG_PASS(nng_pair1_open(&s1));
+ TEST_NNG_PASS(nng_pair1_open(&s2));
+
+ TEST_CHECK(nng_listener_id(l) < 0);
+ TEST_NNG_PASS(nng_listen(s1, a, &l, 0));
+ TEST_CHECK(nng_listener_id(l) > 0);
+
+ // Cannot start another one.
+ TEST_NNG_FAIL(nng_listen(s1, a, NULL, 0), NNG_EADDRINUSE);
+
+ // We can't restart it -- it's already running
+ TEST_NNG_FAIL(nng_listener_start(l, 0), NNG_ESTATE);
+
+ // We can connect to it.
+ TEST_CHECK(nng_dialer_id(d) < 0);
+ TEST_NNG_PASS(nng_dial(s2, a, &d, 0));
+ TEST_CHECK(nng_dialer_id(d) > 0);
+
+ TEST_NNG_PASS(nng_close(s1));
+ TEST_NNG_PASS(nng_close(s2));
+}
+
+void
+test_endpoint_types(void)
+{
+ nng_socket s1;
+ nng_dialer d = NNG_DIALER_INITIALIZER;
+ nng_listener l = NNG_LISTENER_INITIALIZER;
+ nng_dialer d2;
+ nng_listener l2;
+ char * a = "inproc://mumble...";
+ bool b;
+
+ TEST_NNG_PASS(nng_pair1_open(&s1));
+
+ TEST_CHECK(nng_dialer_id(d) < 0);
+ TEST_NNG_PASS(nng_dialer_create(&d, s1, a));
+ TEST_CHECK(nng_dialer_id(d) > 0);
+
+ // Forge a listener
+ l2.id = nng_dialer_id(d);
+ TEST_NNG_FAIL(nng_listener_get_bool(l2, NNG_OPT_RAW, &b), NNG_ENOENT);
+ TEST_NNG_FAIL(nng_listener_close(l2), NNG_ENOENT);
+ TEST_NNG_PASS(nng_dialer_close(d));
+
+ TEST_CHECK(nng_listener_id(l) < 0);
+ TEST_NNG_PASS(nng_listener_create(&l, s1, a));
+ TEST_CHECK(nng_listener_id(l) > 0);
+
+ // Forge a dialer
+ d2.id = nng_listener_id(l);
+ TEST_NNG_FAIL(nng_dialer_get_bool(d2, NNG_OPT_RAW, &b), NNG_ENOENT);
+ TEST_NNG_FAIL(nng_dialer_close(d2), NNG_ENOENT);
+ TEST_NNG_PASS(nng_listener_close(l));
+
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_bad_url(void)
+{
+ nng_socket s1;
+
+ TEST_NNG_PASS(nng_pair1_open(&s1));
+ TEST_NNG_FAIL(nng_dial(s1, "bogus://1", NULL, 0), NNG_ENOTSUP);
+ TEST_NNG_FAIL(nng_listen(s1, "bogus://2", NULL, 0), NNG_ENOTSUP);
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_url_option(void)
+{
+ nng_socket s1;
+ char url[NNG_MAXADDRLEN];
+ nng_listener l;
+ nng_dialer d;
+ size_t sz;
+
+ TEST_NNG_PASS(nng_pair1_open(&s1));
+
+ // Listener
+ TEST_NNG_PASS(nng_listener_create(&l, s1, "inproc://url1"));
+ memset(url, 0, sizeof(url));
+ sz = sizeof(url);
+ TEST_NNG_PASS(nng_listener_get(l, NNG_OPT_URL, url, &sz));
+ TEST_STREQUAL(url, "inproc://url1");
+ TEST_NNG_FAIL(
+ nng_listener_set(l, NNG_OPT_URL, url, sz), NNG_EREADONLY);
+ sz = sizeof(url);
+
+ // Dialer
+ TEST_NNG_PASS(nng_dialer_create(&d, s1, "inproc://url2"));
+ TEST_NNG_PASS(nng_dialer_get(d, NNG_OPT_URL, url, &sz));
+ TEST_STREQUAL(url, "inproc://url2");
+ TEST_NNG_FAIL(nng_dialer_set(d, NNG_OPT_URL, url, sz), NNG_EREADONLY);
+
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_listener_options(void)
+{
+ nng_socket s1;
+ nng_listener l;
+ size_t sz;
+
+ TEST_NNG_PASS(nng_pair1_open(&s1));
+
+#ifndef NNG_ELIDE_DEPRECATED
+ // Create a listener with the specified options
+ TEST_NNG_PASS(nng_socket_set_size(s1, NNG_OPT_RECVMAXSZ, 543));
+ TEST_NNG_PASS(nng_listener_create(&l, s1, "inproc://listener_opts"));
+ TEST_NNG_PASS(nng_listener_get_size(l, NNG_OPT_RECVMAXSZ, &sz));
+ TEST_CHECK(sz == 543);
+
+ // Verify endpoint overrides
+ TEST_NNG_PASS(nng_listener_set_size(l, NNG_OPT_RECVMAXSZ, 678));
+ TEST_NNG_PASS(nng_listener_get_size(l, NNG_OPT_RECVMAXSZ, &sz));
+ TEST_CHECK(sz == 678);
+ TEST_NNG_PASS(nng_socket_get_size(s1, NNG_OPT_RECVMAXSZ, &sz));
+ TEST_CHECK(sz == 543);
+
+ // And socket overrides again
+ TEST_NNG_PASS(nng_socket_set_size(s1, NNG_OPT_RECVMAXSZ, 911));
+ TEST_NNG_PASS(nng_listener_get_size(l, NNG_OPT_RECVMAXSZ, &sz));
+ TEST_CHECK(sz == 911);
+#else
+ TEST_NNG_PASS(nng_listener_create(&l, s1, "inproc://listener_opts"));
+ TEST_NNG_PASS(nng_listener_set_size(l, NNG_OPT_RECVMAXSZ, 678));
+ TEST_NNG_PASS(nng_listener_get_size(l, NNG_OPT_RECVMAXSZ, &sz));
+ TEST_CHECK(sz == 678);
+#endif
+
+ // Cannot set invalid options
+ TEST_NNG_FAIL(nng_listener_set_size(l, "BAD_OPT", 1), NNG_ENOTSUP);
+ TEST_NNG_FAIL(
+ nng_listener_set_bool(l, NNG_OPT_RECVMAXSZ, true), NNG_EBADTYPE);
+ TEST_NNG_FAIL(
+ nng_listener_set(l, NNG_OPT_RECVMAXSZ, &sz, 1), NNG_EINVAL);
+
+ // Cannot set inappropriate options
+ TEST_NNG_FAIL(
+ nng_listener_set_string(l, NNG_OPT_SOCKNAME, "1"), NNG_ENOTSUP);
+
+ TEST_NNG_FAIL(
+ nng_listener_set_bool(l, NNG_OPT_RAW, true), NNG_ENOTSUP);
+ TEST_NNG_FAIL(
+ nng_listener_set_ms(l, NNG_OPT_RECONNMINT, 1), NNG_ENOTSUP);
+ TEST_NNG_FAIL(nng_listener_set_string(l, NNG_OPT_SOCKNAME, "bogus"),
+ NNG_ENOTSUP);
+
+ // Read only options
+ TEST_NNG_FAIL(nng_listener_set_string(l, NNG_OPT_URL, "inproc://junk"),
+ NNG_EREADONLY);
+
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_dialer_options(void)
+{
+ nng_socket s1;
+ nng_dialer d;
+ size_t sz;
+
+ TEST_NNG_PASS(nng_pair1_open(&s1));
+
+#ifndef NNG_ELIDE_DEPRECATED
+ // NOTE: This test will fail if eliding deprecated behavior.
+ // Create a dialer with the specified options
+ TEST_NNG_PASS(nng_socket_set_size(s1, NNG_OPT_RECVMAXSZ, 543));
+ TEST_NNG_PASS(nng_dialer_create(&d, s1, "inproc://dialer_opts"));
+ TEST_NNG_PASS(nng_dialer_get_size(d, NNG_OPT_RECVMAXSZ, &sz));
+ TEST_CHECK(sz == 543);
+
+ // Verify endpoint overrides
+ TEST_NNG_PASS(nng_dialer_set_size(d, NNG_OPT_RECVMAXSZ, 678));
+ TEST_NNG_PASS(nng_dialer_get_size(d, NNG_OPT_RECVMAXSZ, &sz));
+ TEST_CHECK(sz == 678);
+ TEST_NNG_PASS(nng_socket_get_size(s1, NNG_OPT_RECVMAXSZ, &sz));
+ TEST_CHECK(sz == 543);
+
+ // And socket overrides again
+ TEST_NNG_PASS(nng_socket_set_size(s1, NNG_OPT_RECVMAXSZ, 911));
+ TEST_NNG_PASS(nng_dialer_get_size(d, NNG_OPT_RECVMAXSZ, &sz));
+ TEST_CHECK(sz == 911);
+#else
+ TEST_NNG_PASS(nng_dialer_create(&d, s1, "inproc://dialer_opts"));
+ TEST_NNG_PASS(nng_dialer_set_size(d, NNG_OPT_RECVMAXSZ, 678));
+ TEST_NNG_PASS(nng_dialer_get_size(d, NNG_OPT_RECVMAXSZ, &sz));
+ TEST_CHECK(sz == 678);
+#endif
+
+ // Cannot set invalid options
+ TEST_NNG_FAIL(nng_dialer_set_size(d, "BAD_OPT", 1), NNG_ENOTSUP);
+ TEST_NNG_FAIL(
+ nng_dialer_set_bool(d, NNG_OPT_RECVMAXSZ, true), NNG_EBADTYPE);
+ TEST_NNG_FAIL(
+ nng_dialer_set(d, NNG_OPT_RECVMAXSZ, &sz, 1), NNG_EINVAL);
+
+ // Cannot set inappropriate options
+ TEST_NNG_FAIL(
+ nng_dialer_set_string(d, NNG_OPT_SOCKNAME, "1"), NNG_ENOTSUP);
+ TEST_NNG_FAIL(nng_dialer_set_bool(d, NNG_OPT_RAW, true), NNG_ENOTSUP);
+ TEST_NNG_FAIL(nng_dialer_set_ms(d, NNG_OPT_SENDTIMEO, 1), NNG_ENOTSUP);
+ TEST_NNG_FAIL(
+ nng_dialer_set_string(d, NNG_OPT_SOCKNAME, "bogus"), NNG_ENOTSUP);
+
+ // Read only options
+ TEST_NNG_FAIL(nng_dialer_set_string(d, NNG_OPT_URL, "inproc://junk"),
+ NNG_EREADONLY);
+
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_endpoint_absent_options(void)
+{
+ size_t s;
+ int i;
+ nng_duration t;
+ bool b;
+ nng_dialer d;
+ nng_listener l;
+ d.id = 1999;
+ l.id = 1999;
+
+ TEST_NNG_FAIL(
+ nng_dialer_set_size(d, NNG_OPT_RECVMAXSZ, 10), NNG_ENOENT);
+ TEST_NNG_FAIL(
+ nng_listener_set_size(l, NNG_OPT_RECVMAXSZ, 10), NNG_ENOENT);
+
+ TEST_NNG_FAIL(nng_dialer_get_bool(d, NNG_OPT_RAW, &b), NNG_ENOENT);
+ TEST_NNG_FAIL(nng_listener_get_bool(l, NNG_OPT_RAW, &b), NNG_ENOENT);
+
+ TEST_NNG_FAIL(
+ nng_dialer_get_size(d, NNG_OPT_RECVMAXSZ, &s), NNG_ENOENT);
+ TEST_NNG_FAIL(
+ nng_listener_get_size(l, NNG_OPT_RECVMAXSZ, &s), NNG_ENOENT);
+
+ TEST_NNG_FAIL(nng_dialer_get_int(d, NNG_OPT_RAW, &i), NNG_ENOENT);
+ TEST_NNG_FAIL(nng_listener_get_int(l, NNG_OPT_RAW, &i), NNG_ENOENT);
+
+ TEST_NNG_FAIL(nng_dialer_get_ms(d, NNG_OPT_RECVTIMEO, &t), NNG_ENOENT);
+ TEST_NNG_FAIL(
+ nng_listener_get_ms(l, NNG_OPT_SENDTIMEO, &t), NNG_ENOENT);
+}
+
+void
+test_timeout_options(void)
+{
+ nng_socket s1;
+ nng_duration to;
+ size_t sz;
+
+ char *cases[] = {
+ NNG_OPT_RECVTIMEO,
+ NNG_OPT_SENDTIMEO,
+ NNG_OPT_RECONNMAXT,
+ NNG_OPT_RECONNMINT,
+ NULL,
+ };
+
+ TEST_NNG_PASS(nng_pair1_open(&s1));
+ for (int i = 0; cases[i] != NULL; i++) {
+ bool b;
+ TEST_CASE(cases[i]);
+
+ // Can't receive a duration into zero bytes.
+ sz = 0;
+ TEST_NNG_FAIL(
+ nng_socket_get(s1, cases[i], &to, &sz), NNG_EINVAL);
+
+ // Type mismatches
+ TEST_NNG_FAIL(
+ nng_socket_get_bool(s1, cases[i], &b), NNG_EBADTYPE);
+ sz = 1;
+ TEST_NNG_FAIL(
+ nng_socket_get(s1, cases[i], &b, &sz), NNG_EINVAL);
+
+ // Can set a valid duration
+ TEST_NNG_PASS(nng_socket_set_ms(s1, cases[i], 1234));
+ TEST_NNG_PASS(nng_socket_get_ms(s1, cases[i], &to));
+ TEST_CHECK(to == 1234);
+
+ to = 0;
+ sz = sizeof(to);
+ TEST_NNG_PASS(nng_socket_get(s1, cases[i], &to, &sz));
+ TEST_CHECK(to == 1234);
+ TEST_CHECK(sz == sizeof(to));
+
+ // Can't set a negative duration
+ TEST_NNG_FAIL(nng_socket_set_ms(s1, cases[i], -5), NNG_EINVAL);
+
+ // Can't pass a buf too small for duration
+ sz = sizeof(to) - 1;
+ to = 1;
+ TEST_NNG_FAIL(
+ nng_socket_set(s1, cases[i], &to, sz), NNG_EINVAL);
+ }
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_size_options(void)
+{
+ nng_socket s1;
+ size_t val;
+ size_t sz;
+ char * opt;
+
+ char *cases[] = {
+ NNG_OPT_RECVMAXSZ,
+ NULL,
+ };
+
+ TEST_NNG_PASS(nng_pair1_open(&s1));
+ for (int i = 0; (opt = cases[i]) != NULL; i++) {
+ TEST_CASE(opt);
+
+ // Can't receive a size into zero bytes.
+ sz = 0;
+ TEST_NNG_FAIL(nng_socket_get(s1, opt, &val, &sz), NNG_EINVAL);
+
+ // Can set a valid duration
+ TEST_NNG_PASS(nng_socket_set_size(s1, opt, 1234));
+ TEST_NNG_PASS(nng_socket_get_size(s1, opt, &val));
+ TEST_CHECK(val == 1234);
+
+ val = 0;
+ sz = sizeof(val);
+ TEST_NNG_PASS(nng_socket_get(s1, opt, &val, &sz));
+ TEST_CHECK(val == 1234);
+ TEST_CHECK(sz == sizeof(val));
+
+ // Can't pass a buf too small for size
+ sz = sizeof(val) - 1;
+ val = 1;
+ TEST_NNG_FAIL(nng_socket_set(s1, opt, &val, sz), NNG_EINVAL);
+
+ // We limit the limit to 4GB. Clear it if you want to
+ // ship more than 4GB at a time.
+#if defined(_WIN64) || defined(_LP64)
+ val = 0x10000u;
+ val <<= 30u;
+ TEST_NNG_FAIL(nng_socket_set_size(s1, opt, val), NNG_EINVAL);
+ TEST_NNG_PASS(nng_socket_get_size(s1, opt, &val));
+ TEST_CHECK(val == 1234);
+#endif
+ }
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+TEST_LIST = {
+ { "recv timeout", test_recv_timeout },
+ { "recv non-block", test_recv_nonblock },
+ { "send timeout", test_send_timeout },
+ { "send non-block", test_send_nonblock },
+ { "read only options", test_readonly_options },
+ { "socket base", test_socket_base },
+ { "socket name", test_socket_name },
+ { "socket name oversize", test_socket_name_oversize },
+ { "send recv", test_send_recv },
+ { "send recv zero length", test_send_recv_zero_length },
+ { "connection refused", test_connection_refused },
+ { "late connection", test_late_connection },
+ { "address busy", test_address_busy },
+ { "bad url", test_bad_url },
+ { "url option", test_url_option },
+ { "listener options", test_listener_options },
+ { "dialer options", test_dialer_options },
+ { "timeout options", test_timeout_options },
+ { "size options", test_size_options },
+ { "endpoint absent options", test_endpoint_absent_options },
+ { "endpoint types", test_endpoint_types },
+
+ { NULL, NULL },
+};
diff --git a/src/core/url_test.c b/src/core/url_test.c
new file mode 100644
index 00000000..847b7df3
--- /dev/null
+++ b/src/core/url_test.c
@@ -0,0 +1,479 @@
+//
+// Copyright 2018 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.
+//
+
+
+#include "acutest.h"
+
+#include <string.h>
+
+#include <nng/nng.h>
+
+#include "core/url.h"
+
+#include "testutil.h"
+
+void
+test_url_host(void)
+{
+ nng_url *url;
+
+ TEST_NNG_PASS(nng_url_parse(&url, "http://www.google.com"));
+ TEST_ASSERT(url != NULL);
+ TEST_CHECK(strcmp(url->u_scheme, "http") == 0);
+ TEST_CHECK(strcmp(url->u_host, "www.google.com") == 0);
+ TEST_CHECK(strcmp(url->u_hostname, "www.google.com") == 0);
+ TEST_CHECK(strcmp(url->u_port, "80") == 0);
+ TEST_CHECK(strcmp(url->u_path, "") == 0);
+ TEST_CHECK(strcmp(url->u_requri, "") == 0);
+ TEST_CHECK(url->u_query == NULL);
+ TEST_CHECK(url->u_fragment == NULL);
+ TEST_CHECK(url->u_userinfo == NULL);
+ nng_url_free(url);
+}
+
+void
+test_url_host_port(void)
+{
+ nng_url *url;
+ TEST_NNG_PASS(nng_url_parse(&url, "http://www.google.com:1234"));
+ TEST_ASSERT(url != NULL);
+ TEST_CHECK(strcmp(url->u_scheme, "http") == 0);
+ TEST_CHECK(strcmp(url->u_host, "www.google.com:1234") == 0);
+ TEST_CHECK(strcmp(url->u_hostname, "www.google.com") == 0);
+ TEST_CHECK(strcmp(url->u_port, "1234") == 0);
+ TEST_CHECK(strcmp(url->u_path, "") == 0);
+ TEST_CHECK(strcmp(url->u_requri, "") == 0);
+ TEST_CHECK(url->u_query == NULL);
+ TEST_CHECK(url->u_fragment == NULL);
+ TEST_CHECK(url->u_userinfo == NULL);
+ nng_url_free(url);
+}
+
+void
+test_url_host_port_path(void)
+{
+ nng_url *url;
+
+ TEST_NNG_PASS(
+ nng_url_parse(&url, "http://www.google.com:1234/somewhere"));
+ TEST_ASSERT(url != NULL);
+ TEST_CHECK(strcmp(url->u_scheme, "http") == 0);
+ TEST_CHECK(strcmp(url->u_host, "www.google.com:1234") == 0);
+ TEST_CHECK(strcmp(url->u_hostname, "www.google.com") == 0);
+ TEST_CHECK(strcmp(url->u_port, "1234") == 0);
+ TEST_CHECK(strcmp(url->u_path, "/somewhere") == 0);
+ TEST_CHECK(strcmp(url->u_requri, "/somewhere") == 0);
+ TEST_CHECK(url->u_userinfo == NULL);
+ TEST_CHECK(url->u_query == NULL);
+ TEST_CHECK(url->u_fragment == NULL);
+ nng_url_free(url);
+}
+
+void
+test_url_user_info(void)
+{
+ nng_url *url;
+ TEST_NNG_PASS(nng_url_parse(
+ &url, "http://garrett@www.google.com:1234/somewhere"));
+ TEST_ASSERT(url != NULL);
+ TEST_STREQUAL(url->u_scheme, "http");
+ TEST_STREQUAL(url->u_userinfo, "garrett");
+ TEST_STREQUAL(url->u_host, "www.google.com:1234");
+ TEST_STREQUAL(url->u_hostname, "www.google.com");
+ TEST_STREQUAL(url->u_port, "1234");
+ TEST_STREQUAL(url->u_path, "/somewhere");
+ TEST_STREQUAL(url->u_requri, "/somewhere");
+ TEST_NULL(url->u_query);
+ TEST_NULL(url->u_fragment);
+ nng_url_free(url);
+}
+
+void
+test_url_path_query_param(void)
+{
+ nng_url *url;
+ TEST_NNG_PASS(
+ nng_url_parse(&url, "http://www.google.com/somewhere?result=yes"));
+ TEST_ASSERT(url != NULL);
+ TEST_STREQUAL(url->u_scheme, "http");
+ TEST_STREQUAL(url->u_host, "www.google.com");
+ TEST_STREQUAL(url->u_hostname, "www.google.com");
+ TEST_STREQUAL(url->u_port, "80");
+ TEST_STREQUAL(url->u_path, "/somewhere");
+ TEST_STREQUAL(url->u_query, "result=yes");
+ TEST_STREQUAL(url->u_requri, "/somewhere?result=yes");
+ TEST_NULL(url->u_userinfo);
+ TEST_NULL(url->u_fragment);
+ nng_url_free(url);
+}
+
+void
+test_url_query_param_anchor(void)
+{
+ nng_url *url;
+ TEST_NNG_PASS(nng_url_parse(&url,
+ "http://www.google.com/"
+ "somewhere?result=yes#chapter1"));
+ TEST_ASSERT(url != NULL);
+ TEST_STREQUAL(url->u_scheme, "http");
+ TEST_STREQUAL(url->u_host, "www.google.com");
+ TEST_STREQUAL(url->u_hostname, "www.google.com");
+ TEST_STREQUAL(url->u_port, "80");
+ TEST_STREQUAL(url->u_path, "/somewhere");
+ TEST_STREQUAL(url->u_query, "result=yes");
+ TEST_STREQUAL(url->u_fragment, "chapter1");
+ TEST_STREQUAL(url->u_requri, "/somewhere?result=yes#chapter1");
+ TEST_NULL(url->u_userinfo);
+ nng_url_free(url);
+}
+
+void
+test_url_path_anchor(void)
+{
+ nng_url *url;
+ TEST_NNG_PASS(
+ nng_url_parse(&url, "http://www.google.com/somewhere#chapter2"));
+ TEST_ASSERT(url != NULL);
+ TEST_STREQUAL(url->u_scheme, "http");
+ TEST_STREQUAL(url->u_host, "www.google.com");
+ TEST_STREQUAL(url->u_hostname, "www.google.com");
+ TEST_STREQUAL(url->u_port, "80");
+ TEST_STREQUAL(url->u_path, "/somewhere");
+ TEST_STREQUAL(url->u_fragment, "chapter2");
+ TEST_STREQUAL(url->u_requri, "/somewhere#chapter2");
+ TEST_NULL(url->u_query);
+ TEST_NULL(url->u_userinfo);
+ nng_url_free(url);
+}
+
+void
+test_url_anchor(void)
+{
+ nng_url *url;
+ TEST_NNG_PASS(nng_url_parse(&url, "http://www.google.com#chapter3"));
+ TEST_ASSERT(url != NULL);
+ TEST_STREQUAL(url->u_scheme, "http");
+ TEST_STREQUAL(url->u_host, "www.google.com");
+ TEST_STREQUAL(url->u_hostname, "www.google.com");
+ TEST_STREQUAL(url->u_path, "");
+ TEST_STREQUAL(url->u_port, "80");
+ TEST_STREQUAL(url->u_fragment, "chapter3");
+ TEST_STREQUAL(url->u_requri, "#chapter3");
+ TEST_NULL(url->u_query);
+ TEST_NULL(url->u_userinfo);
+ nng_url_free(url);
+}
+
+void
+test_url_query_param(void)
+{
+ nng_url *url;
+ TEST_NNG_PASS(nng_url_parse(&url, "http://www.google.com?color=red"));
+ TEST_ASSERT(url != NULL);
+ TEST_STREQUAL(url->u_scheme, "http");
+ TEST_STREQUAL(url->u_host, "www.google.com");
+ TEST_STREQUAL(url->u_hostname, "www.google.com");
+ TEST_STREQUAL(url->u_path, "");
+ TEST_STREQUAL(url->u_port, "80");
+ TEST_STREQUAL(url->u_query, "color=red");
+ TEST_STREQUAL(url->u_requri, "?color=red");
+ TEST_ASSERT(url != NULL);
+ TEST_NULL(url->u_userinfo);
+ nng_url_free(url);
+}
+
+void
+test_url_v6_host(void)
+{
+ nng_url *url;
+ TEST_NNG_PASS(nng_url_parse(&url, "http://[::1]"));
+ TEST_ASSERT(url != NULL);
+ TEST_STREQUAL(url->u_scheme, "http");
+ TEST_STREQUAL(url->u_host, "[::1]");
+ TEST_STREQUAL(url->u_hostname, "::1");
+ TEST_STREQUAL(url->u_path, "");
+ TEST_STREQUAL(url->u_port, "80");
+ TEST_NULL(url->u_query);
+ TEST_NULL(url->u_fragment);
+ TEST_NULL(url->u_userinfo);
+ nng_url_free(url);
+}
+
+void
+test_url_v6_host_port(void)
+{
+ nng_url *url;
+ TEST_NNG_PASS(nng_url_parse(&url, "http://[::1]:29"));
+ TEST_ASSERT(url != NULL);
+ TEST_STREQUAL(url->u_scheme, "http");
+ TEST_STREQUAL(url->u_host, "[::1]:29");
+ TEST_STREQUAL(url->u_hostname, "::1");
+ TEST_STREQUAL(url->u_path, "");
+ TEST_STREQUAL(url->u_port, "29");
+ TEST_NULL(url->u_query);
+ TEST_NULL(url->u_fragment);
+ TEST_NULL(url->u_userinfo);
+ nng_url_free(url);
+}
+
+void
+test_url_v6_host_port_path(void)
+{
+ nng_url *url;
+ TEST_NNG_PASS(nng_url_parse(&url, "http://[::1]:29/bottles"));
+ TEST_ASSERT(url != NULL);
+ TEST_STREQUAL(url->u_scheme, "http");
+ TEST_STREQUAL(url->u_host, "[::1]:29");
+ TEST_STREQUAL(url->u_hostname, "::1");
+ TEST_STREQUAL(url->u_path, "/bottles");
+ TEST_STREQUAL(url->u_port, "29");
+ TEST_NULL(url->u_query);
+ TEST_NULL(url->u_fragment);
+ TEST_NULL(url->u_userinfo);
+ nng_url_free(url);
+}
+
+void
+test_url_tcp_port(void)
+{
+ nng_url *url;
+ TEST_NNG_PASS(nng_url_parse(&url, "tcp://:9876/"));
+ TEST_ASSERT(url != NULL);
+ TEST_STREQUAL(url->u_scheme, "tcp");
+ TEST_STREQUAL(url->u_host, ":9876");
+ TEST_STREQUAL(url->u_hostname, "");
+ TEST_STREQUAL(url->u_path, "/");
+ TEST_STREQUAL(url->u_port, "9876");
+ TEST_NULL(url->u_query);
+ TEST_NULL(url->u_fragment);
+ TEST_NULL(url->u_userinfo);
+ nng_url_free(url);
+}
+
+void
+test_url_bare_ws(void)
+{
+ nng_url *url;
+
+ TEST_NNG_PASS(nng_url_parse(&url, "ws://"));
+ TEST_ASSERT(url != NULL);
+ TEST_STREQUAL(url->u_scheme, "ws");
+ TEST_STREQUAL(url->u_host, "");
+ TEST_STREQUAL(url->u_hostname, "");
+ TEST_STREQUAL(url->u_path, "");
+ TEST_STREQUAL(url->u_port, "80");
+ TEST_NULL(url->u_query);
+ TEST_NULL(url->u_fragment);
+ TEST_NULL(url->u_userinfo);
+ nng_url_free(url);
+}
+
+void
+test_url_ws_wildcard(void)
+{
+ nng_url *url;
+ TEST_NNG_PASS(nng_url_parse(&url, "ws://*:12345/foobar"));
+ TEST_ASSERT(url != NULL);
+ TEST_STREQUAL(url->u_scheme, "ws");
+ TEST_STREQUAL(url->u_host, ":12345");
+ TEST_STREQUAL(url->u_hostname, "");
+ TEST_STREQUAL(url->u_path, "/foobar");
+ TEST_STREQUAL(url->u_port, "12345");
+ TEST_NULL(url->u_query);
+ TEST_NULL(url->u_fragment);
+ TEST_NULL(url->u_userinfo);
+ nng_url_free(url);
+}
+
+void
+test_url_ssh(void)
+{
+ nng_url *url;
+ TEST_NNG_PASS(nng_url_parse(&url, "ssh://user@host.example.com"));
+ TEST_ASSERT(url != NULL);
+ TEST_STREQUAL(url->u_scheme, "ssh");
+ TEST_STREQUAL(url->u_host, "host.example.com");
+ TEST_STREQUAL(url->u_hostname, "host.example.com");
+ TEST_STREQUAL(url->u_path, "");
+ TEST_STREQUAL(url->u_port, "22");
+ TEST_NULL(url->u_query);
+ TEST_NULL(url->u_fragment);
+ TEST_STREQUAL(url->u_userinfo, "user");
+ nng_url_free(url);
+}
+
+void
+test_url_bad_scheme(void)
+{
+ nng_url *url = NULL;
+ TEST_NNG_FAIL(nng_url_parse(&url, "www.google.com"), NNG_EINVAL);
+ TEST_NULL(url);
+ TEST_NNG_FAIL(nng_url_parse(&url, "http:www.google.com"), NNG_EINVAL);
+ TEST_NULL(url);
+}
+
+void
+test_url_bad_ipv6(void)
+{
+ nng_url *url = NULL;
+ TEST_NNG_FAIL(nng_url_parse(&url, "http://[::1"), NNG_EINVAL);
+ TEST_NULL(url);
+ TEST_NNG_FAIL(nng_url_parse(&url, "http://[::1]bogus"), NNG_EINVAL);
+ TEST_NULL(url);
+}
+
+void
+test_url_canonify(void)
+{
+ nng_url *url = NULL;
+ TEST_NNG_PASS(nng_url_parse(
+ &url, "hTTp://www.EXAMPLE.com/bogus/.%2e/%7egarrett"));
+ TEST_ASSERT(url != NULL);
+ TEST_STREQUAL(url->u_scheme, "http");
+ TEST_STREQUAL(url->u_hostname, "www.example.com");
+ TEST_STREQUAL(url->u_port, "80");
+ TEST_STREQUAL(url->u_path, "/~garrett");
+ nng_url_free(url);
+}
+
+void
+test_url_path_resolve(void)
+{
+ nng_url *url = NULL;
+ TEST_NNG_PASS(
+ nng_url_parse(&url, "http://www.x.com//abc/def/./x/..///./../y"));
+ TEST_STREQUAL(url->u_scheme, "http");
+ TEST_STREQUAL(url->u_hostname, "www.x.com");
+ TEST_STREQUAL(url->u_port, "80");
+ TEST_STREQUAL(url->u_path, "/abc/y");
+ nng_url_free(url);
+}
+
+void
+test_url_query_info_pass(void)
+{
+ nng_url *url = NULL;
+ TEST_NNG_PASS(
+ nng_url_parse(&url, "http://www.x.com/?/abc/def/./x/.././../y"));
+ TEST_ASSERT(url != NULL);
+ TEST_STREQUAL(url->u_scheme, "http");
+ TEST_STREQUAL(url->u_hostname, "www.x.com");
+ TEST_STREQUAL(url->u_port, "80");
+ TEST_STREQUAL(url->u_path, "/");
+ TEST_STREQUAL(url->u_query, "/abc/def/./x/.././../y");
+ nng_url_free(url);
+}
+
+void
+test_url_bad_utf8(void)
+{
+ nng_url *url = NULL;
+ TEST_NNG_FAIL(nng_url_parse(&url, "http://x.com/x%80x"), NNG_EINVAL);
+ TEST_NULL(url);
+ TEST_NNG_FAIL(nng_url_parse(&url, "http://x.com/x%c0%81"), NNG_EINVAL);
+ TEST_NULL(url);
+}
+
+void
+test_url_good_utf8(void)
+{
+ nng_url *url = NULL;
+ TEST_NNG_PASS(nng_url_parse(&url, "http://www.x.com/%c2%a2_cents"));
+ TEST_ASSERT(url != NULL);
+ TEST_STREQUAL(url->u_scheme, "http");
+ TEST_STREQUAL(url->u_hostname, "www.x.com");
+ TEST_STREQUAL(url->u_port, "80");
+ TEST_STREQUAL(url->u_path, "/\xc2\xa2_cents");
+ nng_url_free(url);
+}
+
+void
+test_url_decode(void)
+{
+ uint8_t out[16];
+ size_t len;
+
+ out[3] = 'x';
+ len = nni_url_decode(out, "abc", 3);
+ TEST_CHECK(len == 3);
+ TEST_CHECK(memcmp(out, "abc", 3) == 0);
+ TEST_CHECK(out[3] == 'x');
+
+ len = nni_url_decode(out, "x%00y", 3); // embedded NULL
+ TEST_CHECK(len == 3);
+ TEST_CHECK(memcmp(out, "x\x00y", 3) == 0);
+ TEST_CHECK(out[3] == 'x');
+
+ len = nni_url_decode(out, "%3987", 3);
+ TEST_CHECK(len == 3);
+ TEST_CHECK(memcmp(out, "987", 3) == 0);
+ TEST_CHECK(out[3] == 'x');
+
+ len = nni_url_decode(out, "78%39", 3);
+ TEST_CHECK(len == 3);
+ TEST_CHECK(memcmp(out, "789", 3) == 0);
+ TEST_CHECK(out[3] == 'x');
+
+ len = nni_url_decode(out, "", 5);
+ TEST_CHECK(len == 0);
+ TEST_CHECK(memcmp(out, "789", 3) == 0);
+ TEST_CHECK(out[3] == 'x');
+
+ len = nni_url_decode(out, "be", 2);
+ TEST_CHECK(len == 2);
+ TEST_CHECK(memcmp(out, "be9", 3) == 0);
+ TEST_CHECK(out[3] == 'x');
+
+ len = nni_url_decode(out, "78%39", 2);
+ TEST_CHECK(len == (size_t) -1);
+
+ len = nni_url_decode(out, "", 2);
+ TEST_CHECK(len == 0);
+
+ len = nni_url_decode(out, "78%", 5);
+ TEST_CHECK(len == (size_t) -1);
+
+ len = nni_url_decode(out, "78%xy", 5);
+ TEST_CHECK(len == (size_t) -1);
+
+ len = nni_url_decode(out, "78%1$", 5);
+ TEST_CHECK(len == (size_t) -1);
+
+ len = nni_url_decode(out, "%%20", 5);
+ TEST_CHECK(len == (size_t) -1);
+}
+
+TEST_LIST = {
+ { "url host", test_url_host },
+ { "url host port", test_url_host_port },
+ { "url host port path", test_url_host_port_path },
+ { "url user info", test_url_user_info },
+ { "url path query param", test_url_path_query_param },
+ { "url query param anchor", test_url_query_param_anchor },
+ { "url path anchor", test_url_path_anchor },
+ { "url anchor", test_url_anchor },
+ { "url query param", test_url_query_param },
+ { "url v6 host", test_url_v6_host },
+ { "url v6 host port", test_url_v6_host_port },
+ { "url v6 host port path", test_url_v6_host_port_path },
+ { "url tcp port", test_url_tcp_port },
+ { "url bare ws", test_url_bare_ws },
+ { "url ws wildcard", test_url_ws_wildcard },
+ { "url ssh", test_url_ssh },
+ { "url bad scheme", test_url_bad_scheme },
+ { "url bad v6", test_url_bad_ipv6 },
+ { "url canonify", test_url_canonify },
+ { "url path resolve", test_url_path_resolve },
+ { "url query info pass", test_url_query_info_pass },
+ { "url bad utf8", test_url_bad_utf8 },
+ { "url good utf8", test_url_good_utf8 },
+ { "url decode", test_url_decode },
+ { NULL, NULL },
+}; \ No newline at end of file
diff --git a/src/platform/CMakeLists.txt b/src/platform/CMakeLists.txt
new file mode 100644
index 00000000..2b2288e1
--- /dev/null
+++ b/src/platform/CMakeLists.txt
@@ -0,0 +1,17 @@
+#
+# Copyright 2020 Staysail Systems, Inc. <info@staystail.tech>
+#
+# 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.
+#
+
+# Platforms.
+nng_directory(platform)
+
+add_subdirectory(posix)
+add_subdirectory(windows)
+
+nng_test(platform_test)
+nng_test(resolver_test) \ No newline at end of file
diff --git a/src/platform/platform_test.c b/src/platform/platform_test.c
new file mode 100644
index 00000000..e7dcabaa
--- /dev/null
+++ b/src/platform/platform_test.c
@@ -0,0 +1,181 @@
+//
+// Copyright 2020 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.
+//
+
+#include "testutil.h"
+
+#include <nng/nng.h>
+#include <nng/supplemental/util/platform.h>
+
+#include "acutest.h"
+
+struct add_arg {
+ int cnt;
+ nng_mtx *mx;
+ nng_cv * cv;
+};
+
+void
+add(void *arg)
+{
+ struct add_arg *aa = arg;
+
+ nng_mtx_lock(aa->mx);
+ aa->cnt++;
+ nng_cv_wake(aa->cv);
+ nng_mtx_unlock(aa->mx);
+}
+
+void
+test_sleep(void)
+{
+ uint64_t start, end;
+ start = testutil_clock();
+ nng_msleep(100);
+ end = testutil_clock();
+ TEST_CHECK((end - start) >= 100);
+#ifdef __has_feature
+#if !__has_feature(thread_sanitizer) && !__has_feature(memory_sanitizer)
+ TEST_CHECK((end - start) <= 500);
+#endif
+#endif
+}
+
+void
+test_clock(void)
+{
+ uint64_t mstart;
+ uint64_t msend;
+ nng_time usend;
+ nng_time usnow;
+
+ mstart = testutil_clock();
+ usnow = nng_clock();
+ nng_msleep(200);
+ usend = nng_clock();
+ msend = testutil_clock();
+
+ TEST_CHECK(usend > usnow);
+ TEST_CHECK(msend > mstart);
+
+#ifdef __has_feature
+#if !__has_feature(thread_sanitizer) && !__has_feature(memory_sanitizer)
+ uint64_t usdelta;
+ uint64_t msdelta;
+ usdelta = usend - usnow;
+ msdelta = msend - mstart;
+ TEST_CHECK(usdelta >= 200);
+ TEST_CHECK(usdelta < 500); // increased tolerance for CIs
+ if (msdelta > usdelta) {
+ TEST_CHECK((msdelta - usdelta) < 50);
+ } else {
+ TEST_CHECK((usdelta - msdelta) < 50);
+ }
+#endif
+#endif
+}
+
+void
+test_mutex(void)
+{
+ nng_mtx *mx, *mx2;
+
+ TEST_CHECK(nng_mtx_alloc(&mx) == 0);
+ nng_mtx_lock(mx);
+ nng_mtx_unlock(mx);
+
+ nng_mtx_lock(mx);
+ nng_mtx_unlock(mx);
+ nng_mtx_free(mx);
+
+ // Verify that the mutexes are not always the same!
+ TEST_CHECK(nng_mtx_alloc(&mx) == 0);
+ TEST_CHECK(nng_mtx_alloc(&mx2) == 0);
+ TEST_CHECK(mx != mx2);
+ nng_mtx_free(mx);
+ nng_mtx_free(mx2);
+}
+
+void
+test_thread(void)
+{
+ nng_thread * thr;
+ int rv;
+ struct add_arg aa;
+
+ TEST_CHECK(nng_mtx_alloc(&aa.mx) == 0);
+ TEST_CHECK(nng_cv_alloc(&aa.cv, aa.mx) == 0);
+ aa.cnt = 0;
+
+ TEST_CHECK((rv = nng_thread_create(&thr, add, &aa)) == 0);
+ nng_thread_destroy(thr);
+ TEST_CHECK(aa.cnt == 1);
+
+ nng_cv_free(aa.cv);
+ nng_mtx_free(aa.mx);
+}
+
+void
+test_cond_var(void)
+{
+ nng_thread * thr;
+ int rv;
+ struct add_arg aa;
+
+ TEST_CHECK(nng_mtx_alloc(&aa.mx) == 0);
+ TEST_CHECK(nng_cv_alloc(&aa.cv, aa.mx) == 0);
+ aa.cnt = 0;
+
+ TEST_CHECK((rv = nng_thread_create(&thr, add, &aa)) == 0);
+
+ nng_mtx_lock(aa.mx);
+ while (aa.cnt == 0) {
+ nng_cv_wait(aa.cv);
+ }
+ nng_mtx_unlock(aa.mx);
+ nng_thread_destroy(thr);
+ TEST_CHECK(aa.cnt == 1);
+
+ nng_cv_free(aa.cv);
+ nng_mtx_free(aa.mx);
+}
+
+void
+test_random(void)
+{
+ int same = 0;
+ uint32_t values[1000];
+
+ for (int i = 0; i < 1000; i++) {
+ values[i] = nng_random();
+ }
+ for (int i = 0; i < 1000; i++) {
+ for (int j = 0; j < i; j++) {
+ if (values[j] == values[i]) {
+ same++;
+ }
+ }
+ }
+
+ // 1% reproduction is *highly* unlikely.
+ // There are 4 billion possible options, we are only looking at
+ // 1000 of them. In general, it would be an extreme outlier
+ // to see more than 2 repeats, unless you RNG is biased.
+ TEST_CHECK_(same < 5, "fewer than 5 in 1000 repeats: %d", same);
+}
+
+TEST_LIST = {
+ { "sleep", test_sleep },
+ { "clock", test_clock },
+ { "mutex", test_mutex },
+ { "thread", test_thread },
+ { "cond var", test_cond_var },
+ { "random", test_random },
+ { NULL, NULL },
+};
diff --git a/src/platform/posix/posix_file.c b/src/platform/posix/posix_file.c
index 5d918d6b..d5fb5016 100644
--- a/src/platform/posix/posix_file.c
+++ b/src/platform/posix/posix_file.c
@@ -1,5 +1,5 @@
//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2020 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
@@ -323,15 +323,12 @@ nni_plat_temp_dir(void)
char *
nni_plat_join_dir(const char *prefix, const char *suffix)
{
- char * newdir;
- size_t len;
+ char *result;
- len = strlen(prefix) + strlen(suffix) + 2;
- newdir = nni_alloc(strlen(prefix) + strlen(suffix) + 2);
- if (newdir != NULL) {
- (void) snprintf(newdir, len, "%s/%s", prefix, suffix);
+ if (nni_asprintf(&result, "%s/%s", prefix, suffix) == 0) {
+ return (result);
}
- return (newdir);
+ return (NULL);
}
#endif // NNG_PLATFORM_POSIX
diff --git a/src/platform/resolver_test.c b/src/platform/resolver_test.c
new file mode 100644
index 00000000..43168cdb
--- /dev/null
+++ b/src/platform/resolver_test.c
@@ -0,0 +1,199 @@
+//
+// Copyright 2020 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.
+//
+
+#include "testutil.h"
+
+#include <string.h>
+
+#include "core/nng_impl.h"
+#include "stubs.h"
+
+#include "acutest.h"
+
+#ifndef _WIN32
+#include <arpa/inet.h> // for htons, htonl
+#endif
+
+uint8_t v6loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
+
+void
+test_google_dns(void)
+{
+ nng_aio * aio;
+ nng_sockaddr sa;
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ nni_resolv_ip("google-public-dns-a.google.com", "80", NNG_AF_INET,
+ true, &sa, aio);
+ nng_aio_wait(aio);
+ TEST_NNG_PASS(nng_aio_result(aio));
+ TEST_CHECK(sa.s_in.sa_family == NNG_AF_INET);
+ TEST_CHECK(sa.s_in.sa_port == ntohs(80));
+ TEST_CHECK(sa.s_in.sa_addr == 0x08080808); // aka 8.8.8.8
+ nng_aio_free(aio);
+}
+
+void
+test_numeric_addr(void)
+{
+ nng_aio * aio;
+ nng_sockaddr sa;
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ nni_resolv_ip("8.8.4.4", "69", NNG_AF_INET, true, &sa, aio);
+ nng_aio_wait(aio);
+ TEST_NNG_PASS(nng_aio_result(aio));
+ TEST_CHECK(sa.s_in.sa_family == NNG_AF_INET);
+ TEST_CHECK(sa.s_in.sa_port == ntohs(69));
+ TEST_CHECK(sa.s_in.sa_addr == ntohl(0x08080404)); // 8.8.4.4.
+ nng_aio_free(aio);
+}
+
+void
+test_numeric_v6(void)
+{
+ nng_aio * aio;
+ nng_sockaddr sa;
+
+ // Travis CI has moved some of their services to host that
+ // apparently don't support IPv6 at all. This is very sad.
+ // CircleCI 2.0 is in the same boat. (Amazon to blame.)
+ if ((getenv("TRAVIS") != NULL) || (getenv("CIRCLECI") != NULL)) {
+ return; // skip this one.
+ }
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ nni_resolv_ip("::1", "80", NNG_AF_INET6, true, &sa, aio);
+ nng_aio_wait(aio);
+ TEST_NNG_PASS(nng_aio_result(aio));
+ TEST_CHECK(sa.s_in6.sa_family == NNG_AF_INET6);
+ TEST_CHECK(sa.s_in6.sa_port == ntohs(80));
+ TEST_CHECK(memcmp(sa.s_in6.sa_addr, v6loop, 16) == 0);
+ nng_aio_free(aio);
+}
+
+void
+test_service_names(void)
+{
+ nng_aio * aio;
+ nng_sockaddr sa;
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ nni_resolv_ip("8.8.4.4", "http", NNG_AF_INET, true, &sa, aio);
+ nng_aio_wait(aio);
+ TEST_NNG_PASS(nng_aio_result(aio));
+ TEST_CHECK(sa.s_in.sa_port == ntohs(80));
+ TEST_CHECK(sa.s_in.sa_addr = ntohl(0x08080404));
+ nng_aio_free(aio);
+}
+
+void
+test_localhost_v4(void)
+{
+ nng_aio * aio;
+ nng_sockaddr sa;
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ nni_resolv_ip("localhost", "80", NNG_AF_INET, true, &sa, aio);
+ nng_aio_wait(aio);
+ TEST_NNG_PASS(nng_aio_result(aio));
+ TEST_CHECK(sa.s_in.sa_family == NNG_AF_INET);
+ TEST_CHECK(sa.s_in.sa_port == ntohs(80));
+ TEST_CHECK(sa.s_in.sa_addr == ntohl(0x7f000001));
+ nng_aio_free(aio);
+}
+
+void
+test_localhost_unspec(void)
+{
+ nng_aio * aio;
+ nng_sockaddr sa;
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ nni_resolv_ip("localhost", "80", NNG_AF_UNSPEC, true, &sa, aio);
+ nng_aio_wait(aio);
+ TEST_NNG_PASS(nng_aio_result(aio));
+ TEST_CHECK(
+ (sa.s_family == NNG_AF_INET) || (sa.s_family == NNG_AF_INET6));
+ switch (sa.s_family) {
+ case NNG_AF_INET:
+ TEST_CHECK(sa.s_in.sa_port == ntohs(80));
+ TEST_CHECK(sa.s_in.sa_addr == ntohl(0x7f000001));
+ break;
+ case NNG_AF_INET6:
+ TEST_CHECK(sa.s_in6.sa_port == ntohs(80));
+ TEST_CHECK(memcmp(sa.s_in6.sa_addr, v6loop, 16) == 0);
+ break;
+ }
+ nng_aio_free(aio);
+}
+
+void
+test_null_passive(void)
+{
+ nng_aio * aio;
+ nng_sockaddr sa;
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ nni_resolv_ip(NULL, "80", NNG_AF_INET, true, &sa, aio);
+ nng_aio_wait(aio);
+ TEST_NNG_PASS(nng_aio_result(aio));
+ TEST_CHECK(sa.s_in.sa_family == NNG_AF_INET);
+ TEST_CHECK(sa.s_in.sa_port == ntohs(80));
+ TEST_CHECK(sa.s_in.sa_addr == 0); // INADDR_ANY
+ nng_aio_free(aio);
+}
+
+void
+test_null_not_passive(void)
+{
+ nng_aio * aio;
+ nng_sockaddr sa;
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ nni_resolv_ip(NULL, "80", NNG_AF_INET, false, &sa, aio);
+ nng_aio_wait(aio);
+ // We can either get NNG_EADDRINVAL, or a loopback address.
+ // Most systems do the former, but Linux does the latter.
+ if (nng_aio_result(aio) == 0) {
+ TEST_CHECK(sa.s_family == NNG_AF_INET);
+ TEST_CHECK(sa.s_in.sa_addr == htonl(0x7f000001));
+ TEST_CHECK(sa.s_in.sa_port == htons(80));
+ } else {
+ TEST_NNG_FAIL(nng_aio_result(aio), NNG_EADDRINVAL);
+ }
+ nng_aio_free(aio);
+}
+
+void
+test_bad_port_number(void)
+{
+ nng_aio * aio;
+ nng_sockaddr sa;
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ nni_resolv_ip("1.1.1.1", "1000000", NNG_AF_INET, true, &sa, aio);
+ nng_aio_wait(aio);
+ TEST_NNG_FAIL(nng_aio_result(aio), NNG_EADDRINVAL);
+ nng_aio_free(aio);
+}
+
+TEST_LIST = {
+ { "resolve google dns", test_google_dns },
+ { "resolve numeric addr", test_numeric_addr },
+ { "resolve numeric v6", test_numeric_v6 },
+ { "resolve service names", test_service_names },
+ { "resolve localhost v4", test_localhost_v4 },
+ { "resolve localhost unspec", test_localhost_unspec },
+ { "resolve null passive", test_null_passive },
+ { "resolve null not passive", test_null_not_passive },
+ { "resolve bad port number", test_bad_port_number },
+ { NULL, NULL },
+};
diff --git a/src/protocol/CMakeLists.txt b/src/protocol/CMakeLists.txt
new file mode 100644
index 00000000..fd480523
--- /dev/null
+++ b/src/protocol/CMakeLists.txt
@@ -0,0 +1,20 @@
+#
+# Copyright 2020 Staysail Systems, Inc. <info@staystail.tech>
+#
+# 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.
+#
+
+# Protocols.
+nng_directory(protocol)
+
+add_subdirectory(bus0)
+add_subdirectory(pair0)
+add_subdirectory(pair1)
+add_subdirectory(pipeline0)
+add_subdirectory(pubsub0)
+add_subdirectory(reqrep0)
+add_subdirectory(survey0)
+
diff --git a/src/protocol/bus0/CMakeLists.txt b/src/protocol/bus0/CMakeLists.txt
index 1115e2ec..01c0b05b 100644
--- a/src/protocol/bus0/CMakeLists.txt
+++ b/src/protocol/bus0/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+# Copyright 2020 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
@@ -9,9 +9,10 @@
#
# Bus protocol
-option (NNG_PROTO_BUS0 "Enable BUSv0 protocol." ON)
-mark_as_advanced(NNG_PROTO_BUS0)
+nng_directory(bus0)
nng_sources_if(NNG_PROTO_BUS0 bus.c)
nng_headers_if(NNG_PROTO_BUS0 nng/protocol/bus0/bus.h)
-nng_defines_if(NNG_PROTO_BUS0 NNG_HAVE_BUS0) \ No newline at end of file
+nng_defines_if(NNG_PROTO_BUS0 NNG_HAVE_BUS0)
+
+nng_test(bug1247_test) \ No newline at end of file
diff --git a/src/protocol/bus0/bug1247_test.c b/src/protocol/bus0/bug1247_test.c
new file mode 100644
index 00000000..6f418f53
--- /dev/null
+++ b/src/protocol/bus0/bug1247_test.c
@@ -0,0 +1,39 @@
+//
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
+//
+// 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.
+//
+
+#include <string.h>
+
+#include <nng/nng.h>
+#include <nng/protocol/bus0/bus.h>
+
+#include "acutest.h"
+#include "testutil.h"
+
+void
+test_bug1247(void)
+{
+ nng_socket bus1, bus2;
+ char addr[64];
+
+ testutil_scratch_addr("tcp", sizeof(addr), addr);
+
+ TEST_NNG_PASS(nng_bus0_open(&bus1));
+ TEST_NNG_PASS(nng_bus0_open(&bus2));
+
+ TEST_NNG_PASS(nng_listen(bus1, addr, NULL, 0));
+ TEST_NNG_FAIL(nng_listen(bus2, addr, NULL, 0), NNG_EADDRINUSE);
+
+ TEST_NNG_PASS(nng_close(bus2));
+ TEST_NNG_PASS(nng_close(bus1));
+}
+
+TEST_LIST = {
+ { "bug1247", test_bug1247 },
+ { NULL, NULL },
+};
diff --git a/src/protocol/pair0/CMakeLists.txt b/src/protocol/pair0/CMakeLists.txt
index c3da1b07..b12583ab 100644
--- a/src/protocol/pair0/CMakeLists.txt
+++ b/src/protocol/pair0/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+# Copyright 2020 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
@@ -9,8 +9,7 @@
#
# PAIRv0 protocol
-option (NNG_PROTO_PAIR0 "Enable PAIRv0 protocol." ON)
-mark_as_advanced(NNG_PROTO_PAIR0)
+nng_directory(pair0)
nng_sources_if(NNG_PROTO_PAIR0 pair.c)
nng_headers_if(NNG_PROTO_PAIR0 nng/protocol/pair0/pair.h)
diff --git a/src/protocol/pair1/CMakeLists.txt b/src/protocol/pair1/CMakeLists.txt
index f586fabe..12e12607 100644
--- a/src/protocol/pair1/CMakeLists.txt
+++ b/src/protocol/pair1/CMakeLists.txt
@@ -9,12 +9,12 @@
#
# PAIRv1 protocol
-option (NNG_PROTO_PAIR1 "Enable PAIRv1 protocol." ON)
-mark_as_advanced(NNG_PROTO_PAIR1)
+nng_directory(pair1)
# XXX: break pair1_poly into an ifdef.
nng_sources_if(NNG_PROTO_PAIR1 pair.c pair1_poly.c)
nng_headers_if(NNG_PROTO_PAIR1 nng/protocol/pair1/pair.h)
nng_defines_if(NNG_PROTO_PAIR1 NNG_HAVE_PAIR1)
+
nng_test(pair1_test)
nng_test(pair1_poly_test) \ No newline at end of file
diff --git a/src/protocol/pipeline0/CMakeLists.txt b/src/protocol/pipeline0/CMakeLists.txt
index 0e211cf5..4f591450 100644
--- a/src/protocol/pipeline0/CMakeLists.txt
+++ b/src/protocol/pipeline0/CMakeLists.txt
@@ -9,11 +9,7 @@
#
# Pipeline protocol
-option (NNG_PROTO_PUSH0 "Enable PUSHv0 protocol." ON)
-mark_as_advanced(NNG_PROTO_PUSH0)
-
-option (NNG_PROTO_PULL0 "Enable PULLv0 protocol." ON)
-mark_as_advanced(NNG_PROTO_PULL0)
+nng_directory(pipeline0)
nng_sources_if(NNG_PROTO_PUSH0 push.c)
nng_headers_if(NNG_PROTO_PUSH0 nng/protocol/pipeline0/push.h)
diff --git a/src/protocol/pubsub0/CMakeLists.txt b/src/protocol/pubsub0/CMakeLists.txt
index 8687de4e..160b7462 100644
--- a/src/protocol/pubsub0/CMakeLists.txt
+++ b/src/protocol/pubsub0/CMakeLists.txt
@@ -9,11 +9,7 @@
#
# Pub/Sub protocol
-option (NNG_PROTO_PUB0 "Enable PUBv0 protocol." ON)
-mark_as_advanced(NNG_PROTO_PUB0)
-
-option (NNG_PROTO_SUB0 "Enable SUBv0 protocol." ON)
-mark_as_advanced(NNG_PROTO_SUB0)
+nng_directory(pubsub0)
nng_sources_if(NNG_PROTO_PUB0 pub.c)
nng_headers_if(NNG_PROTO_PUB0 nng/protocol/pubsub0/pub.h)
diff --git a/src/protocol/reqrep0/CMakeLists.txt b/src/protocol/reqrep0/CMakeLists.txt
index 46eb7abf..a3cecfd0 100644
--- a/src/protocol/reqrep0/CMakeLists.txt
+++ b/src/protocol/reqrep0/CMakeLists.txt
@@ -9,11 +9,7 @@
#
# Req/Rep protocol
-option(NNG_PROTO_REQ0 "Enable REQv0 protocol." ON)
-mark_as_advanced(NNG_PROTO_REQ0)
-
-option(NNG_PROTO_REP0 "Enable REPv0 protocol." ON)
-mark_as_advanced(NNG_PROTO_REP0)
+nng_directory(reqrep0)
nng_sources_if(NNG_PROTO_REQ0 req.c xreq.c)
nng_headers_if(NNG_PROTO_REQ0 nng/protocol/reqrep0/req.h)
diff --git a/src/protocol/survey0/CMakeLists.txt b/src/protocol/survey0/CMakeLists.txt
index 6b3c8277..b5daca41 100644
--- a/src/protocol/survey0/CMakeLists.txt
+++ b/src/protocol/survey0/CMakeLists.txt
@@ -9,11 +9,7 @@
#
# Surveyor/Respondent protocol
-option (NNG_PROTO_RESPONDENT0 "Enable RESPONDENTv0 protocol." ON)
-mark_as_advanced(NNG_PROTO_RESPONDENT0)
-
-option (NNG_PROTO_SURVEYOR0 "Enable SURVEYORv0 protocol." ON)
-mark_as_advanced(NNG_PROTO_SURVEYOR0)
+nng_directory(survey0)
nng_sources_if(NNG_PROTO_SURVEYOR0 survey.c xsurvey.c)
nng_headers_if(NNG_PROTO_SURVEYOR0 nng/protocol/survey0/survey.h)
diff --git a/src/supplemental/websocket/wssfile_test.c b/src/supplemental/websocket/wssfile_test.c
index 8a0f95b2..3f69cadc 100644
--- a/src/supplemental/websocket/wssfile_test.c
+++ b/src/supplemental/websocket/wssfile_test.c
@@ -137,7 +137,7 @@ init_listener_wss_file(nng_listener l)
nni_strfree(pth);
}
-void
+static void
test_invalid_verify(void)
{
uint16_t port = testutil_next_port();
@@ -180,14 +180,14 @@ test_invalid_verify(void)
TEST_NNG_PASS(nng_close(s2));
}
-void
+static void
test_no_verify(void)
{
nng_socket s1;
nng_socket s2;
nng_listener l;
nng_dialer d;
- char addr[NNG_MAXADDRLEN];
+ char addr[64];
nng_msg * msg;
nng_pipe p;
bool b;
@@ -232,7 +232,7 @@ test_no_verify(void)
TEST_NNG_PASS(nng_close(s2));
}
-void
+static void
test_verify_works(void)
{
nng_socket s1;
@@ -280,7 +280,7 @@ test_verify_works(void)
TEST_NNG_PASS(nng_close(s2));
}
-void
+static void
test_cert_file_not_present(void)
{
nng_socket s1;
diff --git a/src/transport/CMakeLists.txt b/src/transport/CMakeLists.txt
new file mode 100644
index 00000000..add8a9c9
--- /dev/null
+++ b/src/transport/CMakeLists.txt
@@ -0,0 +1,19 @@
+#
+# Copyright 2020 Staysail Systems, Inc. <info@staystail.tech>
+#
+# 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.
+#
+
+# Transports.
+nng_directory(transport)
+
+add_subdirectory(inproc)
+add_subdirectory(ipc)
+add_subdirectory(tcp)
+add_subdirectory(tls)
+add_subdirectory(ws)
+add_subdirectory(zerotier)
+
diff --git a/src/transport/inproc/CMakeLists.txt b/src/transport/inproc/CMakeLists.txt
index e440fe31..317686bb 100644
--- a/src/transport/inproc/CMakeLists.txt
+++ b/src/transport/inproc/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+# Copyright 2020 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
@@ -9,8 +9,7 @@
#
# inproc protocol
-option (NNG_TRANSPORT_INPROC "Enable inproc transport." ON)
-mark_as_advanced(NNG_TRANSPORT_INPROC)
+nng_directory(inproc)
nng_sources_if(NNG_TRANSPORT_INPROC inproc.c)
nng_headers_if(NNG_TRANSPORT_INPROC nng/transport/inproc/inproc.h)
diff --git a/src/transport/ipc/CMakeLists.txt b/src/transport/ipc/CMakeLists.txt
index 00e81d54..c9927f75 100644
--- a/src/transport/ipc/CMakeLists.txt
+++ b/src/transport/ipc/CMakeLists.txt
@@ -9,8 +9,7 @@
#
# ipc protocol
-option (NNG_TRANSPORT_IPC "Enable IPC transport." ON)
-mark_as_advanced(NNG_TRANSPORT_IPC)
+nng_directory(ipc)
nng_sources_if(NNG_TRANSPORT_IPC ipc.c)
nng_headers_if(NNG_TRANSPORT_IPC nng/transport/ipc/ipc.h)
diff --git a/src/transport/ipc/ipc_test.c b/src/transport/ipc/ipc_test.c
index 7bf3d2ec..3240b21d 100644
--- a/src/transport/ipc/ipc_test.c
+++ b/src/transport/ipc/ipc_test.c
@@ -1,5 +1,6 @@
//
// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Cody Piersall <cody.piersall@gmail.com>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -107,27 +108,24 @@ test_ipc_listener_perms(void)
TEST_NNG_PASS(nng_listener_create(&l, s, addr));
#ifdef _WIN32
- TEST_NNG_FAIL(
- nng_listener_setopt_int(l, NNG_OPT_IPC_PERMISSIONS, 0444),
+ TEST_NNG_FAIL(nng_listener_set_int(l, NNG_OPT_IPC_PERMISSIONS, 0444),
NNG_ENOTSUP);
#else
path = &addr[strlen("ipc://")];
// Attempt to set invalid permissions fails.
TEST_NNG_FAIL(
- nng_listener_setopt_int(l, NNG_OPT_IPC_PERMISSIONS, S_IFREG),
+ nng_listener_set_int(l, NNG_OPT_IPC_PERMISSIONS, S_IFREG),
NNG_EINVAL);
- TEST_NNG_PASS(
- nng_listener_setopt_int(l, NNG_OPT_IPC_PERMISSIONS, 0444));
+ TEST_NNG_PASS(nng_listener_set_int(l, NNG_OPT_IPC_PERMISSIONS, 0444));
TEST_NNG_PASS(nng_listener_start(l, 0));
TEST_CHECK(stat(path, &st) == 0);
TEST_CHECK((st.st_mode & 0777) == 0444);
// Now that it's running, we cannot set it.
TEST_NNG_FAIL(
- nng_listener_setopt_int(l, NNG_OPT_IPC_PERMISSIONS, 0644),
- NNG_EBUSY);
+ nng_listener_set_int(l, NNG_OPT_IPC_PERMISSIONS, 0644), NNG_EBUSY);
#endif
TEST_NNG_PASS(nng_close(s));
@@ -146,19 +144,19 @@ test_ipc_listener_properties(void)
TEST_NNG_PASS(nng_pair0_open(&s));
TEST_NNG_PASS(nng_listen(s, addr, &l, 0));
- TEST_NNG_PASS(nng_listener_getopt_sockaddr(l, NNG_OPT_LOCADDR, &sa));
+ TEST_NNG_PASS(nng_listener_get_addr(l, NNG_OPT_LOCADDR, &sa));
TEST_CHECK(sa.s_ipc.sa_family == NNG_AF_IPC);
TEST_STREQUAL(sa.s_ipc.sa_path, addr + strlen("ipc://"));
- TEST_NNG_FAIL(nng_listener_setopt(l, NNG_OPT_LOCADDR, &sa, sizeof(sa)),
+ TEST_NNG_FAIL(nng_listener_set(l, NNG_OPT_LOCADDR, &sa, sizeof(sa)),
NNG_EREADONLY);
z = 8192;
- TEST_NNG_PASS(nng_listener_setopt_size(l, NNG_OPT_RECVMAXSZ, z));
+ TEST_NNG_PASS(nng_listener_set_size(l, NNG_OPT_RECVMAXSZ, z));
z = 0;
- TEST_NNG_PASS(nng_listener_getopt_size(l, NNG_OPT_RECVMAXSZ, &z));
+ TEST_NNG_PASS(nng_listener_get_size(l, NNG_OPT_RECVMAXSZ, &z));
TEST_CHECK(z == 8192);
TEST_NNG_FAIL(
- nng_listener_setopt_bool(l, NNG_OPT_RAW, true), NNG_ENOTSUP);
+ nng_listener_set_bool(l, NNG_OPT_RAW, true), NNG_ENOTSUP);
TEST_NNG_PASS(nng_close(s));
}
@@ -242,10 +240,10 @@ test_abstract_auto_bind(void)
TEST_NNG_PASS(nng_pair0_open(&s1));
TEST_NNG_PASS(nng_pair0_open(&s2));
- TEST_NNG_PASS(nng_setopt_ms(s1, NNG_OPT_SENDTIMEO, 1000));
- TEST_NNG_PASS(nng_setopt_ms(s2, NNG_OPT_SENDTIMEO, 1000));
- TEST_NNG_PASS(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, 1000));
- TEST_NNG_PASS(nng_setopt_ms(s2, NNG_OPT_RECVTIMEO, 1000));
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 1000));
+ TEST_NNG_PASS(nng_socket_set_ms(s2, NNG_OPT_SENDTIMEO, 1000));
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 1000));
+ TEST_NNG_PASS(nng_socket_set_ms(s2, NNG_OPT_RECVTIMEO, 1000));
TEST_NNG_PASS(nng_listen(s1, addr, &l, 0));
TEST_NNG_PASS(nng_listener_get_addr(l, NNG_OPT_LOCADDR, &sa));
@@ -287,8 +285,8 @@ test_abstract_too_long(void)
TEST_ASSERT(strlen(addr) == 255);
TEST_NNG_PASS(nng_pair0_open(&s1));
- TEST_NNG_PASS(nng_setopt_ms(s1, NNG_OPT_SENDTIMEO, 1000));
- TEST_NNG_PASS(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, 1000));
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 1000));
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 1000));
TEST_NNG_FAIL(nng_listen(s1, addr, NULL, 0), NNG_EADDRINVAL);
TEST_NNG_FAIL(
nng_dial(s1, addr, NULL, NNG_FLAG_NONBLOCK), NNG_EADDRINVAL);
@@ -317,10 +315,10 @@ test_abstract_null(void)
TEST_NNG_PASS(nng_pair0_open(&s1));
TEST_NNG_PASS(nng_pair0_open(&s2));
- TEST_NNG_PASS(nng_setopt_ms(s1, NNG_OPT_SENDTIMEO, 1000));
- TEST_NNG_PASS(nng_setopt_ms(s2, NNG_OPT_SENDTIMEO, 1000));
- TEST_NNG_PASS(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, 1000));
- TEST_NNG_PASS(nng_setopt_ms(s2, NNG_OPT_RECVTIMEO, 1000));
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 1000));
+ TEST_NNG_PASS(nng_socket_set_ms(s2, NNG_OPT_SENDTIMEO, 1000));
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 1000));
+ TEST_NNG_PASS(nng_socket_set_ms(s2, NNG_OPT_RECVTIMEO, 1000));
TEST_NNG_PASS(nng_listen(s1, addr, &l, 0));
TEST_NNG_PASS(nng_listener_get_addr(l, NNG_OPT_LOCADDR, &sa));
@@ -372,10 +370,10 @@ test_unix_alias(void)
TEST_NNG_PASS(nng_pair0_open(&s1));
TEST_NNG_PASS(nng_pair0_open(&s2));
- TEST_NNG_PASS(nng_setopt_ms(s1, NNG_OPT_SENDTIMEO, 1000));
- TEST_NNG_PASS(nng_setopt_ms(s2, NNG_OPT_SENDTIMEO, 1000));
- TEST_NNG_PASS(nng_setopt_ms(s1, NNG_OPT_RECVTIMEO, 1000));
- TEST_NNG_PASS(nng_setopt_ms(s2, NNG_OPT_RECVTIMEO, 1000));
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 1000));
+ TEST_NNG_PASS(nng_socket_set_ms(s2, NNG_OPT_SENDTIMEO, 1000));
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 1000));
+ TEST_NNG_PASS(nng_socket_set_ms(s2, NNG_OPT_RECVTIMEO, 1000));
TEST_NNG_PASS(nng_listen(s1, addr1, NULL, 0));
TEST_NNG_PASS(nng_dial(s2, addr2, NULL, 0));
diff --git a/src/transport/tcp/CMakeLists.txt b/src/transport/tcp/CMakeLists.txt
index f3daa0a4..d6022329 100644
--- a/src/transport/tcp/CMakeLists.txt
+++ b/src/transport/tcp/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+# Copyright 2020 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
@@ -9,9 +9,9 @@
#
# TCP protocol
-option (NNG_TRANSPORT_TCP "Enable TCP transport." ON)
-mark_as_advanced(NNG_TRANSPORT_TCP)
+nng_directory(tcp)
nng_sources_if(NNG_TRANSPORT_TCP tcp.c)
nng_headers_if(NNG_TRANSPORT_TCP nng/transport/tcp/tcp.h)
-nng_defines_if(NNG_TRANSPORT_TCP NNG_TRANSPORT_TCP) \ No newline at end of file
+nng_defines_if(NNG_TRANSPORT_TCP NNG_TRANSPORT_TCP)
+nng_test(tcp_test) \ No newline at end of file
diff --git a/src/transport/tcp/tcp_test.c b/src/transport/tcp/tcp_test.c
new file mode 100644
index 00000000..88b77ab4
--- /dev/null
+++ b/src/transport/tcp/tcp_test.c
@@ -0,0 +1,304 @@
+//
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+// Copyright 2018 Devolutions <info@devolutions.net>
+// Copyright 2018 Cody Piersall <cody.piersall@gmail.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.
+//
+
+#include <nng/nng.h>
+#include <nng/protocol/pair0/pair.h>
+#include <nng/supplemental/util/platform.h>
+
+#include <acutest.h>
+#include <testutil.h>
+
+// TCP tests.
+
+static void
+test_tcp_wild_card_connect_fail(void)
+{
+ nng_socket s;
+ char addr[NNG_MAXADDRLEN];
+
+ TEST_NNG_PASS(nng_pair0_open(&s));
+ (void) snprintf(
+ addr, sizeof(addr), "tcp://*:%u", testutil_next_port());
+ TEST_NNG_FAIL(nng_dial(s, addr, NULL, 0), NNG_EADDRINVAL);
+ TEST_NNG_PASS(nng_close(s));
+}
+
+void
+test_tcp_wild_card_bind(void)
+{
+ nng_socket s1;
+ nng_socket s2;
+ char addr[NNG_MAXADDRLEN];
+ uint16_t port;
+
+ port = testutil_next_port();
+
+ TEST_NNG_PASS(nng_pair0_open(&s1));
+ TEST_NNG_PASS(nng_pair0_open(&s2));
+ (void) snprintf(addr, sizeof(addr), "tcp4://*:%u", port);
+ TEST_NNG_PASS(nng_listen(s1, addr, NULL, 0));
+ // reset port back one
+ (void) snprintf(addr, sizeof(addr), "tcp://127.0.0.1:%u", port);
+ TEST_NNG_PASS(nng_dial(s2, addr, NULL, 0));
+ TEST_NNG_PASS(nng_close(s2));
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_tcp_local_address_connect(void)
+{
+
+ nng_socket s1;
+ nng_socket s2;
+ char addr[NNG_MAXADDRLEN];
+ uint16_t port;
+
+ TEST_NNG_PASS(nng_pair0_open(&s1));
+ TEST_NNG_PASS(nng_pair0_open(&s2));
+ port = testutil_next_port();
+ (void) snprintf(addr, sizeof(addr), "tcp://127.0.0.1:%u", port);
+ TEST_NNG_PASS(nng_listen(s1, addr, NULL, 0));
+ // reset port back one
+ (void) snprintf(
+ addr, sizeof(addr), "tcp://127.0.0.1;127.0.0.1:%u", port);
+ TEST_NNG_PASS(nng_dial(s2, addr, NULL, 0));
+ TEST_NNG_PASS(nng_close(s2));
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_tcp_port_zero_bind(void)
+{
+ nng_socket s1;
+ nng_socket s2;
+ nng_sockaddr sa;
+ nng_listener l;
+ char * addr;
+
+ TEST_NNG_PASS(nng_pair0_open(&s1));
+ TEST_NNG_PASS(nng_pair_open(&s2));
+ TEST_NNG_PASS(nng_listen(s1, "tcp://127.0.0.1:0", &l, 0));
+ TEST_NNG_PASS(nng_listener_get_string(l, NNG_OPT_URL, &addr));
+ TEST_CHECK(memcmp(addr, "tcp://", 6) == 0);
+ TEST_NNG_PASS(nng_listener_get_addr(l, NNG_OPT_LOCADDR, &sa));
+ TEST_CHECK(sa.s_in.sa_family == NNG_AF_INET);
+ TEST_CHECK(sa.s_in.sa_port != 0);
+ TEST_CHECK(sa.s_in.sa_addr = testutil_htonl(0x7f000001));
+ TEST_NNG_PASS(nng_dial(s2, addr, NULL, 0));
+ nng_strfree(addr);
+ TEST_NNG_PASS(nng_close(s2));
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_tcp_bad_local_interface(void)
+{
+ nng_socket s1;
+
+ TEST_NNG_PASS(nng_pair0_open(&s1));
+ TEST_NNG_FAIL(nng_dial(s1, "tcp://bogus1;127.0.0.1:80", NULL, 0),
+ NNG_EADDRINVAL);
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_tcp_non_local_address(void)
+{
+ nng_socket s1;
+
+ TEST_NNG_PASS(nng_pair0_open(&s1));
+ TEST_NNG_FAIL(nng_dial(s1, "tcp://8.8.8.8;127.0.0.1:80", NULL, 0),
+ NNG_EADDRINVAL);
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_tcp_malformed_address(void)
+{
+ nng_socket s1;
+
+ TEST_NNG_PASS(nng_pair0_open(&s1));
+ TEST_NNG_FAIL(
+ nng_dial(s1, "tcp://127.0.0.1", NULL, 0), NNG_EADDRINVAL);
+ TEST_NNG_FAIL(
+ nng_dial(s1, "tcp://127.0.0.1.32", NULL, 0), NNG_EADDRINVAL);
+ TEST_NNG_FAIL(
+ nng_dial(s1, "tcp://127.0.x.1.32", NULL, 0), NNG_EADDRINVAL);
+ TEST_NNG_FAIL(
+ nng_listen(s1, "tcp://127.0.0.1.32", NULL, 0), NNG_EADDRINVAL);
+ TEST_NNG_FAIL(
+ nng_listen(s1, "tcp://127.0.x.1.32", NULL, 0), NNG_EADDRINVAL);
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+void
+test_tcp_no_delay_option(void)
+{
+ nng_socket s;
+ nng_dialer d;
+ nng_listener l;
+ bool v;
+ int x;
+ char addr[64];
+
+ testutil_scratch_addr("tcp", sizeof(addr), addr);
+
+ TEST_NNG_PASS(nng_pair0_open(&s));
+#ifndef NNG_ELIDE_DEPRECATED
+ TEST_NNG_PASS(nng_socket_get_bool(s, NNG_OPT_TCP_NODELAY, &v));
+ TEST_CHECK(v == true);
+#endif
+ TEST_NNG_PASS(nng_dialer_create(&d, s, addr));
+ TEST_NNG_PASS(nng_dialer_get_bool(d, NNG_OPT_TCP_NODELAY, &v));
+ TEST_CHECK(v == true);
+ TEST_NNG_PASS(nng_dialer_set_bool(d, NNG_OPT_TCP_NODELAY, false));
+ TEST_NNG_PASS(nng_dialer_get_bool(d, NNG_OPT_TCP_NODELAY, &v));
+ TEST_CHECK(v == false);
+ TEST_NNG_FAIL(
+ nng_dialer_get_int(d, NNG_OPT_TCP_NODELAY, &x), NNG_EBADTYPE);
+ x = 0;
+ TEST_NNG_FAIL(
+ nng_dialer_set_int(d, NNG_OPT_TCP_NODELAY, x), NNG_EBADTYPE);
+ // This assumes sizeof (bool) != sizeof (int)
+ if (sizeof(bool) != sizeof(int)) {
+ TEST_NNG_FAIL(
+ nng_dialer_set(d, NNG_OPT_TCP_NODELAY, &x, sizeof(x)),
+ NNG_EINVAL);
+ }
+
+ TEST_NNG_PASS(nng_listener_create(&l, s, addr));
+ TEST_NNG_PASS(nng_listener_get_bool(l, NNG_OPT_TCP_NODELAY, &v));
+ TEST_CHECK(v == true);
+ x = 0;
+ TEST_NNG_FAIL(
+ nng_listener_set_int(l, NNG_OPT_TCP_NODELAY, x), NNG_EBADTYPE);
+ // This assumes sizeof (bool) != sizeof (int)
+ TEST_NNG_FAIL(nng_listener_set(l, NNG_OPT_TCP_NODELAY, &x, sizeof(x)),
+ NNG_EINVAL);
+
+ TEST_NNG_PASS(nng_dialer_close(d));
+ TEST_NNG_PASS(nng_listener_close(l));
+
+ // Make sure socket wide defaults apply.
+#ifndef NNG_ELIDE_DEPRECATED
+ TEST_NNG_PASS(nng_socket_set_bool(s, NNG_OPT_TCP_NODELAY, true));
+ v = false;
+ TEST_NNG_PASS(nng_socket_get_bool(s, NNG_OPT_TCP_NODELAY, &v));
+ TEST_CHECK(v == true);
+ TEST_NNG_PASS(nng_socket_set_bool(s, NNG_OPT_TCP_NODELAY, false));
+ TEST_NNG_PASS(nng_dialer_create(&d, s, addr));
+ TEST_NNG_PASS(nng_dialer_get_bool(d, NNG_OPT_TCP_NODELAY, &v));
+ TEST_CHECK(v == false);
+#endif
+ TEST_NNG_PASS(nng_close(s));
+}
+
+void
+test_tcp_keep_alive_option(void)
+{
+ nng_socket s;
+ nng_dialer d;
+ nng_listener l;
+ bool v;
+ int x;
+ char addr[64];
+
+ testutil_scratch_addr("tcp", sizeof(addr), addr);
+ TEST_NNG_PASS(nng_pair0_open(&s));
+#ifndef NNG_ELIDE_DEPRECATED
+ TEST_NNG_PASS(nng_socket_get_bool(s, NNG_OPT_TCP_KEEPALIVE, &v));
+ TEST_CHECK(v == false);
+#endif
+ TEST_NNG_PASS(nng_dialer_create(&d, s, addr));
+ TEST_NNG_PASS(nng_dialer_get_bool(d, NNG_OPT_TCP_KEEPALIVE, &v));
+ TEST_CHECK(v == false);
+ TEST_NNG_PASS(nng_dialer_set_bool(d, NNG_OPT_TCP_KEEPALIVE, true));
+ TEST_NNG_PASS(nng_dialer_get_bool(d, NNG_OPT_TCP_KEEPALIVE, &v));
+ TEST_CHECK(v == true);
+ TEST_NNG_FAIL(
+ nng_dialer_get_int(d, NNG_OPT_TCP_KEEPALIVE, &x), NNG_EBADTYPE);
+ x = 1;
+ TEST_NNG_FAIL(
+ nng_dialer_set_int(d, NNG_OPT_TCP_KEEPALIVE, x), NNG_EBADTYPE);
+
+ TEST_NNG_PASS(nng_listener_create(&l, s, addr));
+ TEST_NNG_PASS(nng_listener_get_bool(l, NNG_OPT_TCP_KEEPALIVE, &v));
+ TEST_CHECK(v == false);
+ x = 1;
+ TEST_NNG_FAIL(
+ nng_listener_set_int(l, NNG_OPT_TCP_KEEPALIVE, x), NNG_EBADTYPE);
+
+ TEST_NNG_PASS(nng_dialer_close(d));
+ TEST_NNG_PASS(nng_listener_close(l));
+
+ // Make sure socket wide defaults apply.
+#ifndef NNG_ELIDE_DEPRECATED
+ TEST_NNG_PASS(nng_socket_set_bool(s, NNG_OPT_TCP_KEEPALIVE, false));
+ v = true;
+ TEST_NNG_PASS(nng_socket_get_bool(s, NNG_OPT_TCP_KEEPALIVE, &v));
+ TEST_CHECK(v == false);
+ TEST_NNG_PASS(nng_socket_set_bool(s, NNG_OPT_TCP_KEEPALIVE, true));
+ TEST_NNG_PASS(nng_dialer_create(&d, s, addr));
+ TEST_NNG_PASS(nng_dialer_get_bool(d, NNG_OPT_TCP_KEEPALIVE, &v));
+ TEST_CHECK(v == true);
+#endif
+ TEST_NNG_PASS(nng_close(s));
+}
+
+void
+test_tcp_recv_max(void)
+{
+ char msg[256];
+ char buf[256];
+ nng_socket s0;
+ nng_socket s1;
+ nng_listener l;
+ size_t sz;
+ char addr[64];
+
+ testutil_scratch_addr("tcp", sizeof(addr), addr);
+
+ TEST_NNG_PASS(nng_pair0_open(&s0));
+ TEST_NNG_PASS(nng_socket_set_ms(s0, NNG_OPT_RECVTIMEO, 100));
+ TEST_NNG_PASS(nng_socket_set_size(s0, NNG_OPT_RECVMAXSZ, 200));
+ TEST_NNG_PASS(nng_listener_create(&l, s0, addr));
+ TEST_NNG_PASS(nng_socket_get_size(s0, NNG_OPT_RECVMAXSZ, &sz));
+ TEST_CHECK(sz == 200);
+ TEST_NNG_PASS(nng_listener_set_size(l, NNG_OPT_RECVMAXSZ, 100));
+ TEST_NNG_PASS(nng_listener_start(l, 0));
+
+ TEST_NNG_PASS(nng_pair0_open(&s1));
+ TEST_NNG_PASS(nng_dial(s1, addr, NULL, 0));
+ TEST_NNG_PASS(nng_send(s1, msg, 95, 0));
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 100));
+ TEST_NNG_PASS(nng_recv(s0, buf, &sz, 0));
+ TEST_CHECK(sz == 95);
+ TEST_NNG_PASS(nng_send(s1, msg, 150, 0));
+ TEST_NNG_FAIL(nng_recv(s0, buf, &sz, 0), NNG_ETIMEDOUT);
+ TEST_NNG_PASS(nng_close(s0));
+ TEST_NNG_PASS(nng_close(s1));
+}
+
+TEST_LIST = {
+
+ { "tcp wild card connect fail", test_tcp_wild_card_connect_fail },
+ { "tcp wild card bind", test_tcp_wild_card_bind },
+ { "tcp port zero bind", test_tcp_port_zero_bind },
+ { "tcp local address connect", test_tcp_local_address_connect },
+ { "tcp bad local interface", test_tcp_bad_local_interface },
+ { "tcp non-local address", test_tcp_non_local_address },
+ { "tcp malformed address", test_tcp_malformed_address },
+ { "tcp no delay option", test_tcp_no_delay_option },
+ { "tcp keep alive option", test_tcp_keep_alive_option },
+ { "tcp recv max", test_tcp_recv_max },
+ { NULL, NULL },
+}; \ No newline at end of file
diff --git a/src/transport/tls/CMakeLists.txt b/src/transport/tls/CMakeLists.txt
index d77a67cd..82f24c79 100644
--- a/src/transport/tls/CMakeLists.txt
+++ b/src/transport/tls/CMakeLists.txt
@@ -9,8 +9,7 @@
#
# TLS transport
-option (NNG_TRANSPORT_TLS "Enable TLS transport." ON)
-mark_as_advanced(NNG_TRANSPORT_TLS)
+nng_directory(tls)
nng_sources_if(NNG_TRANSPORT_TLS tls.c)
nng_headers_if(NNG_TRANSPORT_TLS nng/transport/tls/tls.h)
diff --git a/src/transport/ws/CMakeLists.txt b/src/transport/ws/CMakeLists.txt
index 8d8b5965..6e409b43 100644
--- a/src/transport/ws/CMakeLists.txt
+++ b/src/transport/ws/CMakeLists.txt
@@ -9,19 +9,9 @@
#
# WebSocket transport
-option (NNG_TRANSPORT_WS "Enable WebSocket transport." ON)
-mark_as_advanced(NNG_TRANSPORT_WS)
-
-CMAKE_DEPENDENT_OPTION(NNG_TRANSPORT_WSS "Enable WSS transport" ON
- "NNG_ENABLE_TLS" OFF)
-mark_as_advanced(NNG_TRANSPORT_WSS)
+nng_directory(ws)
if (NNG_TRANSPORT_WS OR NNG_TRANSPORT_WSS)
- # Make sure things we *MUST* have are enabled.
- set(NNG_SUPP_WEBSOCKET ON PARENT_SCOPE)
- set(NNG_SUPP_HTTP ON PARENT_SCOPE)
- set(NNG_SUPP_BASE64 ON PARENT_SCOPE)
- set(NNG_SUPP_SHA1 ON PARENT_SCOPE)
set(WS_ON ON)
endif()
diff --git a/src/transport/ws/ws_test.c b/src/transport/ws/ws_test.c
index 3a6e7fdf..f8f122a1 100644
--- a/src/transport/ws/ws_test.c
+++ b/src/transport/ws/ws_test.c
@@ -1,5 +1,6 @@
//
// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Cody Piersall <cody.piersall@gmail.com>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -60,18 +61,18 @@ test_wild_card_port(void)
TEST_NNG_PASS(nng_pair0_open(&s6));
TEST_NNG_PASS(nng_listen(s1, "ws://127.0.0.1:0/one", &l1, 0));
TEST_NNG_PASS(
- nng_listener_getopt_int(l1, NNG_OPT_TCP_BOUND_PORT, &port1));
+ nng_listener_get_int(l1, NNG_OPT_TCP_BOUND_PORT, &port1));
TEST_CHECK(port1 != 0);
snprintf(ws_url, sizeof(ws_url), "ws4://127.0.0.1:%d/two", port1);
TEST_NNG_PASS(nng_listen(s2, ws_url, &l2, 0));
TEST_NNG_PASS(
- nng_listener_getopt_int(l2, NNG_OPT_TCP_BOUND_PORT, &port2));
+ nng_listener_get_int(l2, NNG_OPT_TCP_BOUND_PORT, &port2));
TEST_CHECK(port1 != 0);
TEST_CHECK(port1 == port2);
// Now try a different wild card port.
TEST_NNG_PASS(nng_listen(s3, "ws4://127.0.0.1:0/three", &l3, 0));
TEST_NNG_PASS(
- nng_listener_getopt_int(l3, NNG_OPT_TCP_BOUND_PORT, &port3));
+ nng_listener_get_int(l3, NNG_OPT_TCP_BOUND_PORT, &port3));
TEST_CHECK(port3 != 0);
TEST_CHECK(port3 != port1);
@@ -141,10 +142,45 @@ test_empty_host(void)
TEST_NNG_PASS(nng_close(s2));
}
+void
+test_ws_recv_max(void)
+{
+ char msg[256];
+ char buf[256];
+ nng_socket s0;
+ nng_socket s1;
+ nng_listener l;
+ size_t sz;
+ char addr[64];
+
+ testutil_scratch_addr("ws", sizeof(addr), addr);
+
+ TEST_NNG_PASS(nng_pair0_open(&s0));
+ TEST_NNG_PASS(nng_socket_set_ms(s0, NNG_OPT_RECVTIMEO, 100));
+ TEST_NNG_PASS(nng_socket_set_size(s0, NNG_OPT_RECVMAXSZ, 200));
+ TEST_NNG_PASS(nng_listener_create(&l, s0, addr));
+ TEST_NNG_PASS(nng_socket_get_size(s0, NNG_OPT_RECVMAXSZ, &sz));
+ TEST_CHECK(sz == 200);
+ TEST_NNG_PASS(nng_listener_set_size(l, NNG_OPT_RECVMAXSZ, 100));
+ TEST_NNG_PASS(nng_listener_start(l, 0));
+
+ TEST_NNG_PASS(nng_pair0_open(&s1));
+ TEST_NNG_PASS(nng_dial(s1, addr, NULL, 0));
+ TEST_NNG_PASS(nng_send(s1, msg, 95, 0));
+ TEST_NNG_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 100));
+ TEST_NNG_PASS(nng_recv(s0, buf, &sz, 0));
+ TEST_CHECK(sz == 95);
+ TEST_NNG_PASS(nng_send(s1, msg, 150, 0));
+ TEST_NNG_FAIL(nng_recv(s0, buf, &sz, 0), NNG_ETIMEDOUT);
+ TEST_NNG_PASS(nng_close(s0));
+ TEST_NNG_PASS(nng_close(s1));
+}
+
TEST_LIST = {
{ "ws url path filters", test_ws_url_path_filters },
{ "ws wild card port", test_wild_card_port },
{ "ws wild card host", test_wild_card_host },
{ "ws empty host", test_empty_host },
+ { "ws recv max", test_ws_recv_max },
{ NULL, NULL },
}; \ No newline at end of file
diff --git a/src/transport/zerotier/CMakeLists.txt b/src/transport/zerotier/CMakeLists.txt
index 167a98c0..903b7f56 100644
--- a/src/transport/zerotier/CMakeLists.txt
+++ b/src/transport/zerotier/CMakeLists.txt
@@ -13,6 +13,8 @@
option (NNG_TRANSPORT_ZEROTIER "Enable ZeroTier transport (requires libzerotiercore)." OFF)
mark_as_advanced(NNG_TRANSPORT_ZEROTIER)
+nng_directory(zerotier)
+
if (NNG_TRANSPORT_ZEROTIER)
# NB: As we wind up linking libzerotiercore.a into the application,