// // Copyright 2020 Staysail Systems, Inc. // Copyright 2018 Cody Piersall // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this // file was obtained (LICENSE.txt). A copy of the license may also be // found online at https://opensource.org/licenses/MIT. // #include #ifdef NNG_PLATFORM_POSIX #include #include #include #endif void test_path_too_long(void) { nng_socket s1; char addr[256]; // All our names have to be less than 128 bytes. memset(addr, 'a', 255); addr[255] = 0; memcpy(addr, "ipc://", strlen("ipc://")); NUTS_ASSERT(strlen(addr) == 255); NUTS_OPEN(s1); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 1000)); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 1000)); NUTS_FAIL(nng_listen(s1, addr, NULL, 0), NNG_EADDRINVAL); NUTS_FAIL(nng_dial(s1, addr, NULL, NNG_FLAG_NONBLOCK), NNG_EADDRINVAL); NUTS_CLOSE(s1); } void test_ipc_dialer_perms(void) { nng_socket s; nng_dialer d; char * addr; NUTS_ADDR(addr, "ipc"); NUTS_OPEN(s); NUTS_PASS(nng_dialer_create(&d, s, addr)); NUTS_FAIL( nng_dialer_set_int(d, NNG_OPT_IPC_PERMISSIONS, 0444), NNG_ENOTSUP); NUTS_CLOSE(s); } void test_ipc_dialer_properties(void) { nng_socket s; nng_dialer d; nng_sockaddr sa; size_t z; char *addr; NUTS_ADDR(addr, "ipc"); NUTS_OPEN(s); NUTS_PASS(nng_dial(s, addr, &d, NNG_FLAG_NONBLOCK)); // Dialers don't have local addresses. NUTS_FAIL(nng_dialer_get_addr(d, NNG_OPT_LOCADDR, &sa), NNG_ENOTSUP); NUTS_FAIL( nng_dialer_set(d, NNG_OPT_LOCADDR, &sa, sizeof(sa)), NNG_ENOTSUP); z = 8192; NUTS_PASS(nng_dialer_set_size(d, NNG_OPT_RECVMAXSZ, z)); z = 0; NUTS_PASS(nng_dialer_get_size(d, NNG_OPT_RECVMAXSZ, &z)); NUTS_TRUE(z == 8192); NUTS_FAIL(nng_dialer_set_bool(d, NNG_OPT_RAW, true), NNG_ENOTSUP); NUTS_CLOSE(s); } void test_ipc_listener_perms(void) { nng_socket s; nng_listener l; char *addr; #ifndef _WIN32 char * path; struct stat st; #endif NUTS_ADDR(addr, "ipc"); NUTS_OPEN(s); NUTS_PASS(nng_listener_create(&l, s, addr)); #ifdef _WIN32 NUTS_FAIL(nng_listener_set_int(l, NNG_OPT_IPC_PERMISSIONS, 0444), NNG_ENOTSUP); #else path = &addr[strlen("ipc://")]; // Attempt to set invalid permissions fails. NUTS_FAIL(nng_listener_set_int(l, NNG_OPT_IPC_PERMISSIONS, S_IFREG), NNG_EINVAL); NUTS_PASS(nng_listener_set_int(l, NNG_OPT_IPC_PERMISSIONS, 0444)); NUTS_PASS(nng_listener_start(l, 0)); NUTS_TRUE(stat(path, &st) == 0); NUTS_TRUE((st.st_mode & 0777) == 0444); // Now that it's running, we cannot set it. NUTS_FAIL( nng_listener_set_int(l, NNG_OPT_IPC_PERMISSIONS, 0644), NNG_EBUSY); #endif NUTS_CLOSE(s); } void test_ipc_listener_properties(void) { nng_socket s; nng_listener l; nng_sockaddr sa; size_t z; char *addr; NUTS_ADDR(addr, "ipc"); NUTS_OPEN(s); NUTS_PASS(nng_listen(s, addr, &l, 0)); NUTS_PASS(nng_listener_get_addr(l, NNG_OPT_LOCADDR, &sa)); NUTS_TRUE(sa.s_ipc.sa_family == NNG_AF_IPC); NUTS_MATCH(sa.s_ipc.sa_path, addr + strlen("ipc://")); NUTS_FAIL(nng_listener_set(l, NNG_OPT_LOCADDR, &sa, sizeof(sa)), NNG_EREADONLY); z = 8192; NUTS_PASS(nng_listener_set_size(l, NNG_OPT_RECVMAXSZ, z)); z = 0; NUTS_PASS(nng_listener_get_size(l, NNG_OPT_RECVMAXSZ, &z)); NUTS_TRUE(z == 8192); NUTS_FAIL(nng_listener_set_bool(l, NNG_OPT_RAW, true), NNG_ENOTSUP); NUTS_CLOSE(s); } void test_ipc_recv_max(void) { char msg[256]; char rcvbuf[256]; nng_socket s0; nng_socket s1; nng_listener l; size_t sz; char *addr; NUTS_ADDR(addr, "ipc"); NUTS_OPEN(s0); NUTS_PASS(nng_socket_set_ms(s0, NNG_OPT_RECVTIMEO, 100)); NUTS_PASS(nng_socket_set_size(s0, NNG_OPT_RECVMAXSZ, 200)); NUTS_PASS(nng_listener_create(&l, s0, addr)); NUTS_PASS(nng_socket_get_size(s0, NNG_OPT_RECVMAXSZ, &sz)); NUTS_TRUE(sz == 200); NUTS_PASS(nng_listener_set_size(l, NNG_OPT_RECVMAXSZ, 100)); NUTS_PASS(nng_listener_start(l, 0)); NUTS_OPEN(s1); NUTS_PASS(nng_dial(s1, addr, NULL, 0)); NUTS_PASS(nng_send(s1, msg, 95, 0)); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 100)); NUTS_PASS(nng_recv(s0, rcvbuf, &sz, 0)); NUTS_TRUE(sz == 95); NUTS_PASS(nng_send(s1, msg, 150, 0)); NUTS_FAIL(nng_recv(s0, rcvbuf, &sz, 0), NNG_ETIMEDOUT); NUTS_CLOSE(s0); NUTS_CLOSE(s1); } void test_abstract_sockets(void) { #ifdef NNG_HAVE_ABSTRACT_SOCKETS nng_socket s1; nng_socket s2; char *addr; nng_pipe p1; nng_pipe p2; nng_sockaddr sa1; nng_sockaddr sa2; char * prefix = "abstract://"; NUTS_ADDR(addr, "abstract"); NUTS_OPEN(s1); NUTS_OPEN(s2); NUTS_MARRY_EX(s1, s2, addr, &p1, &p2); NUTS_PASS(nng_pipe_get_addr(p1, NNG_OPT_REMADDR, &sa1)); NUTS_PASS(nng_pipe_get_addr(p2, NNG_OPT_LOCADDR, &sa2)); NUTS_TRUE(sa1.s_family == sa2.s_family); NUTS_TRUE(sa1.s_family == NNG_AF_ABSTRACT); NUTS_TRUE(sa1.s_abstract.sa_len == strlen(addr) - strlen(prefix)); NUTS_TRUE(sa2.s_abstract.sa_len == strlen(addr) - strlen(prefix)); NUTS_SEND(s1, "ping"); NUTS_RECV(s2, "ping"); NUTS_CLOSE(s1); NUTS_CLOSE(s2); #endif } void test_abstract_auto_bind(void) { #ifdef NNG_HAVE_ABSTRACT_SOCKETS nng_socket s1; nng_socket s2; char addr[40]; char name[12]; nng_sockaddr sa; nng_listener l; size_t len; snprintf(addr, sizeof(addr), "abstract://"); NUTS_OPEN(s1); NUTS_OPEN(s2); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 1000)); NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_SENDTIMEO, 1000)); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 1000)); NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_RECVTIMEO, 1000)); NUTS_PASS(nng_listen(s1, addr, &l, 0)); NUTS_PASS(nng_listener_get_addr(l, NNG_OPT_LOCADDR, &sa)); // Under linux there are either 8 or 5 hex characters. NUTS_TRUE(sa.s_family == NNG_AF_ABSTRACT); NUTS_TRUE(sa.s_abstract.sa_len < 10); len = sa.s_abstract.sa_len; memcpy(name, sa.s_abstract.sa_name, len); name[len] = '\0'; NUTS_TRUE(strlen(name) == len); (void) snprintf(addr, sizeof(addr), "abstract://%s", name); NUTS_PASS(nng_dial(s2, addr, NULL, 0)); // first send the ping NUTS_SEND(s1, "ping"); NUTS_RECV(s2, "ping"); NUTS_SEND(s2, "pong"); NUTS_RECV(s1, "pong"); NUTS_CLOSE(s1); NUTS_CLOSE(s2); #endif } void test_abstract_too_long(void) { #ifdef NNG_HAVE_ABSTRACT_SOCKETS nng_socket s1; char addr[256]; // All our names have to be less than 128 bytes. memset(addr, 'a', 255); addr[255] = 0; memcpy(addr, "abstract://", strlen("abstract://")); NUTS_ASSERT(strlen(addr) == 255); NUTS_OPEN(s1); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 1000)); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 1000)); NUTS_FAIL(nng_listen(s1, addr, NULL, 0), NNG_EADDRINVAL); NUTS_FAIL(nng_dial(s1, addr, NULL, NNG_FLAG_NONBLOCK), NNG_EADDRINVAL); NUTS_CLOSE(s1); #endif } void test_abstract_null(void) { #ifdef NNG_HAVE_ABSTRACT_SOCKETS nng_socket s1; nng_socket s2; char addr[64]; char name[40]; char rng[20]; nng_sockaddr sa; nng_listener l; size_t len; snprintf(rng, sizeof(rng), "%08x%08x", nng_random(), nng_random()); snprintf(name, sizeof(name), "a%%00b_%s", rng); snprintf(addr, sizeof(addr), "abstract://%s", name); NUTS_OPEN(s1); NUTS_OPEN(s2); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 1000)); NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_SENDTIMEO, 1000)); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 1000)); NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_RECVTIMEO, 1000)); NUTS_PASS(nng_listen(s1, addr, &l, 0)); NUTS_PASS(nng_listener_get_addr(l, NNG_OPT_LOCADDR, &sa)); // Under linux there are either 8 or 5 hex characters. NUTS_TRUE(sa.s_family == NNG_AF_ABSTRACT); NUTS_TRUE(sa.s_abstract.sa_len < 32); len = sa.s_abstract.sa_len; NUTS_TRUE(len == 20); NUTS_TRUE(sa.s_abstract.sa_name[0] == 'a'); NUTS_TRUE(sa.s_abstract.sa_name[1] == '\0'); NUTS_TRUE(sa.s_abstract.sa_name[2] == 'b'); NUTS_TRUE(sa.s_abstract.sa_name[3] == '_'); NUTS_TRUE(memcmp(&sa.s_abstract.sa_name[4], rng, 16) == 0); NUTS_PASS(nng_dial(s2, addr, NULL, 0)); // first send the ping NUTS_SEND(s1, "1234"); NUTS_RECV(s2, "1234"); NUTS_SEND(s2, "5678"); NUTS_RECV(s1, "5678"); NUTS_CLOSE(s1); NUTS_CLOSE(s2); #endif } void test_unix_alias(void) { #ifdef NNG_PLATFORM_POSIX nng_socket s1; nng_socket s2; char addr1[32]; char addr2[32]; char rng[20]; nng_sockaddr sa1; nng_sockaddr sa2; nng_msg * msg; nng_pipe p; // Presumes /tmp. (void) snprintf( rng, sizeof(rng), "%08x%08x", nng_random(), nng_random()); snprintf(addr1, sizeof(addr1), "ipc:///tmp/%s", rng); snprintf(addr2, sizeof(addr2), "unix:///tmp/%s", rng); NUTS_OPEN(s1); NUTS_OPEN(s2); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 1000)); NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_SENDTIMEO, 1000)); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 1000)); NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_RECVTIMEO, 1000)); NUTS_PASS(nng_listen(s1, addr1, NULL, 0)); NUTS_PASS(nng_dial(s2, addr2, NULL, 0)); // first send the ping NUTS_SEND(s1, "ping"); NUTS_PASS(nng_recvmsg(s2, &msg, 0)); NUTS_ASSERT(msg != NULL); NUTS_TRUE(nng_msg_len(msg) == 5); NUTS_MATCH(nng_msg_body(msg), "ping"); p = nng_msg_get_pipe(msg); NUTS_PASS(nng_pipe_get_addr(p, NNG_OPT_REMADDR, &sa1)); NUTS_PASS(nng_pipe_get_addr(p, NNG_OPT_REMADDR, &sa2)); NUTS_TRUE(sa1.s_family == sa2.s_family); NUTS_TRUE(sa1.s_family == NNG_AF_IPC); NUTS_MATCH(sa1.s_ipc.sa_path, sa2.s_ipc.sa_path); nng_msg_free(msg); NUTS_CLOSE(s1); NUTS_CLOSE(s2); #endif } TEST_LIST = { { "ipc path too long", test_path_too_long }, { "ipc dialer perms", test_ipc_dialer_perms }, { "ipc dialer props", test_ipc_dialer_properties }, { "ipc listener perms", test_ipc_listener_perms }, { "ipc listener props", test_ipc_listener_properties }, { "ipc recv max", test_ipc_recv_max }, { "ipc abstract sockets", test_abstract_sockets }, { "ipc abstract auto bind", test_abstract_auto_bind }, { "ipc abstract name too long", test_abstract_too_long }, { "ipc abstract embedded null", test_abstract_null }, { "ipc unix alias", test_unix_alias }, { NULL, NULL }, };