This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
commit 0a7b4518ce3491d383b0647c2db1354c6a211a74 Author: Marco Casaroli <[email protected]> AuthorDate: Tue Nov 3 19:41:17 2026 +0100 testing/nettest: Add a test of Unix domain datagram sockets. No test in apps covers connect() and poll() of Unix domain datagram sockets. Add the cmocka test cmocka_net_local_dgram (CONFIG_TESTING_NET_LOCAL_DGRAM). It has 20 cases: - connect() sets the destination, connect(AF_UNSPEC) removes it and a second connect() changes it. - send(), write() and sendto() with a NULL address go to the destination. getpeername() gives its name. - A connected socket takes datagrams from its peer only. - poll() and select() report POLLIN and POLLOUT. poll() wakes up when a datagram arrives. A datagram that is too large causes no POLLHUP. - recv() with MSG_DONTWAIT or O_NONBLOCK fails with EAGAIN. - connect() to a missing name fails with ENOENT, connect() to a regular file with ECONNREFUSED. send() after the receiver is closed fails with ECONNREFUSED. - connect() and send() to an abstract name. A watchdog (alarm()) stops the program if a case does not end. The optional argument is a writable directory for the socket names. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <[email protected]> --- testing/nettest/CMakeLists.txt | 22 ++ testing/nettest/Kconfig | 11 + testing/nettest/Makefile | 7 + testing/nettest/local/test_local_dgram.c | 92 +++++++ testing/nettest/local/test_local_dgram.h | 261 ++++++++++++++++++ testing/nettest/local/test_local_dgram_common.c | 335 +++++++++++++++++++++++ testing/nettest/local/test_local_dgram_connect.c | 321 ++++++++++++++++++++++ testing/nettest/local/test_local_dgram_poll.c | 298 ++++++++++++++++++++ 8 files changed, 1347 insertions(+) diff --git a/testing/nettest/CMakeLists.txt b/testing/nettest/CMakeLists.txt index 9ee84b486..9a679f494 100644 --- a/testing/nettest/CMakeLists.txt +++ b/testing/nettest/CMakeLists.txt @@ -73,6 +73,28 @@ if(CONFIG_TESTING_NET_TEST) ${SRCS}) endif() + if(CONFIG_TESTING_NET_LOCAL_DGRAM) + set(SRCS + ${CMAKE_CURRENT_LIST_DIR}/local/test_local_dgram.c + ${CMAKE_CURRENT_LIST_DIR}/local/test_local_dgram_common.c + ${CMAKE_CURRENT_LIST_DIR}/local/test_local_dgram_connect.c + ${CMAKE_CURRENT_LIST_DIR}/local/test_local_dgram_poll.c) + + nuttx_add_application( + NAME + cmocka_net_local_dgram + PRIORITY + ${CONFIG_TESTING_NET_TEST_PRIORITY} + STACKSIZE + ${CONFIG_TESTING_NET_TEST_STACKSIZE} + MODULE + ${CONFIG_TESTING_NET_TEST} + DEPENDS + cmocka + SRCS + ${SRCS}) + endif() + if(CONFIG_TESTING_NET_OTHERS) set(SRCS ${CMAKE_CURRENT_LIST_DIR}/others/test_others.c diff --git a/testing/nettest/Kconfig b/testing/nettest/Kconfig index 23171814f..8d6c0a3b8 100644 --- a/testing/nettest/Kconfig +++ b/testing/nettest/Kconfig @@ -40,6 +40,17 @@ config TESTING_NET_LOCAL depends on NET_LOCAL && NET_LOCAL_SCM default y +config TESTING_NET_LOCAL_DGRAM + bool "Enable cmocka net local datagram test" + depends on NET_LOCAL && NET_LOCAL_DGRAM + depends on !DISABLE_PTHREAD && !DISABLE_POSIX_TIMERS + default y + ---help--- + Test connect(), send(), getpeername(), poll() and select() of + Unix domain datagram sockets (cmocka_net_local_dgram). The + optional argument of the program is a writable directory for + the socket names (default P_tmpdir). + config TESTING_NET_OTHERS bool "Enable cmocka net other test" default y diff --git a/testing/nettest/Makefile b/testing/nettest/Makefile index fb5f5e5f7..642ba2009 100644 --- a/testing/nettest/Makefile +++ b/testing/nettest/Makefile @@ -51,6 +51,13 @@ PROGNAME += cmocka_net_local CSRCS += local/test_local_common.c local/test_local_scm_rights.c endif +ifeq ($(CONFIG_TESTING_NET_LOCAL_DGRAM),y) +MAINSRC += local/test_local_dgram.c +PROGNAME += cmocka_net_local_dgram +CSRCS += local/test_local_dgram_common.c local/test_local_dgram_connect.c \ + local/test_local_dgram_poll.c +endif + ifeq ($(CONFIG_TESTING_NET_OTHERS),y) MAINSRC += others/test_others.c PROGNAME += cmocka_net_others diff --git a/testing/nettest/local/test_local_dgram.c b/testing/nettest/local/test_local_dgram.c new file mode 100644 index 000000000..fe388ec49 --- /dev/null +++ b/testing/nettest/local/test_local_dgram.c @@ -0,0 +1,92 @@ +/**************************************************************************** + * apps/testing/nettest/local/test_local_dgram.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <setjmp.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <cmocka.h> + +#include "test_local_dgram.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define DGRAM_TEST(f) \ + cmocka_unit_test_setup_teardown(f, test_local_dgram_setup, \ + test_local_dgram_teardown) +#define DGRAM_TEST_CONNECTED(f) \ + cmocka_unit_test_setup_teardown(f, test_local_dgram_connected_setup, \ + test_local_dgram_teardown) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: main + * + * Description: + * The optional argument is a writable directory for the socket names. + * + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + const struct CMUnitTest local_dgram_tests[] = + { + DGRAM_TEST(test_local_dgram_connect), + DGRAM_TEST_CONNECTED(test_local_dgram_peername), + DGRAM_TEST_CONNECTED(test_local_dgram_send), + DGRAM_TEST_CONNECTED(test_local_dgram_write), + DGRAM_TEST_CONNECTED(test_local_dgram_sendto_null), + DGRAM_TEST(test_local_dgram_pollin0), + DGRAM_TEST_CONNECTED(test_local_dgram_pollin), + DGRAM_TEST_CONNECTED(test_local_dgram_nohup), + DGRAM_TEST_CONNECTED(test_local_dgram_pollout), + DGRAM_TEST_CONNECTED(test_local_dgram_pollwait), + DGRAM_TEST_CONNECTED(test_local_dgram_select), + DGRAM_TEST(test_local_dgram_dontwait), + DGRAM_TEST(test_local_dgram_nonblock), + DGRAM_TEST(test_local_dgram_peeronly), + DGRAM_TEST_CONNECTED(test_local_dgram_unspec), + DGRAM_TEST_CONNECTED(test_local_dgram_reconnect), + DGRAM_TEST(test_local_dgram_missing), + DGRAM_TEST(test_local_dgram_notsock), + DGRAM_TEST_CONNECTED(test_local_dgram_closed), + DGRAM_TEST(test_local_dgram_abstract), + }; + + if (argc > 1) + { + g_local_dgram_dir = argv[1]; + } + + return cmocka_run_group_tests(local_dgram_tests, + test_local_dgram_group_setup, + test_local_dgram_group_teardown); +} diff --git a/testing/nettest/local/test_local_dgram.h b/testing/nettest/local/test_local_dgram.h new file mode 100644 index 000000000..b17099a83 --- /dev/null +++ b/testing/nettest/local/test_local_dgram.h @@ -0,0 +1,261 @@ +/**************************************************************************** + * apps/testing/nettest/local/test_local_dgram.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __APPS_TESTING_NETTEST_LOCAL_TEST_LOCAL_DGRAM_H +#define __APPS_TESTING_NETTEST_LOCAL_TEST_LOCAL_DGRAM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/compiler.h> + +#include <stdbool.h> +#include <sys/socket.h> +#include <sys/un.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define LOCAL_DGRAM_PATHLEN 96 +#define LOCAL_DGRAM_BIGLEN 60000 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct nettest_local_dgram_state_s +{ + char p1[LOCAL_DGRAM_PATHLEN]; /* Name of r1 */ + char p2[LOCAL_DGRAM_PATHLEN]; /* Name of r2 */ + char p3[LOCAL_DGRAM_PATHLEN]; /* Name of r3 */ + char pf[LOCAL_DGRAM_PATHLEN]; /* Name of a regular file */ + char abs[LOCAL_DGRAM_PATHLEN]; /* An abstract name */ + FAR char *big; /* LOCAL_DGRAM_BIGLEN bytes */ + int r1; /* Receiver bound to p1 */ + int r2; + int r3; + int s; /* Sender */ + int u; +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* The directory of the socket names (default P_tmpdir) */ + +extern FAR const char *g_local_dgram_dir; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: local_dgram_bind + ****************************************************************************/ + +int local_dgram_bind(FAR const char *path, bool abstract); + +/**************************************************************************** + * Name: local_dgram_connect_to + ****************************************************************************/ + +int local_dgram_connect_to(int fd, FAR const char *path, bool abstract); + +/**************************************************************************** + * Name: local_dgram_addr + ****************************************************************************/ + +socklen_t local_dgram_addr(FAR struct sockaddr_un *addr, + FAR const char *path, bool abstract); + +/**************************************************************************** + * Name: local_dgram_readable + ****************************************************************************/ + +bool local_dgram_readable(int fd, int ms); + +/**************************************************************************** + * Name: local_dgram_expect + ****************************************************************************/ + +void local_dgram_expect(int fd, FAR const char *want); + +/**************************************************************************** + * Name: local_dgram_drain + ****************************************************************************/ + +void local_dgram_drain(int fd, FAR char *buf, size_t size); + +/**************************************************************************** + * Name: test_local_dgram_group_setup + ****************************************************************************/ + +int test_local_dgram_group_setup(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_group_teardown + ****************************************************************************/ + +int test_local_dgram_group_teardown(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_setup + ****************************************************************************/ + +int test_local_dgram_setup(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_connected_setup + ****************************************************************************/ + +int test_local_dgram_connected_setup(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_teardown + ****************************************************************************/ + +int test_local_dgram_teardown(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_connect + ****************************************************************************/ + +void test_local_dgram_connect(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_peername + ****************************************************************************/ + +void test_local_dgram_peername(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_send + ****************************************************************************/ + +void test_local_dgram_send(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_write + ****************************************************************************/ + +void test_local_dgram_write(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_sendto_null + ****************************************************************************/ + +void test_local_dgram_sendto_null(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_peeronly + ****************************************************************************/ + +void test_local_dgram_peeronly(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_unspec + ****************************************************************************/ + +void test_local_dgram_unspec(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_reconnect + ****************************************************************************/ + +void test_local_dgram_reconnect(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_missing + ****************************************************************************/ + +void test_local_dgram_missing(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_notsock + ****************************************************************************/ + +void test_local_dgram_notsock(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_closed + ****************************************************************************/ + +void test_local_dgram_closed(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_abstract + ****************************************************************************/ + +void test_local_dgram_abstract(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_pollin0 + ****************************************************************************/ + +void test_local_dgram_pollin0(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_pollin + ****************************************************************************/ + +void test_local_dgram_pollin(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_nohup + ****************************************************************************/ + +void test_local_dgram_nohup(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_pollout + ****************************************************************************/ + +void test_local_dgram_pollout(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_pollwait + ****************************************************************************/ + +void test_local_dgram_pollwait(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_select + ****************************************************************************/ + +void test_local_dgram_select(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_dontwait + ****************************************************************************/ + +void test_local_dgram_dontwait(FAR void **state); + +/**************************************************************************** + * Name: test_local_dgram_nonblock + ****************************************************************************/ + +void test_local_dgram_nonblock(FAR void **state); + +#endif /* __APPS_TESTING_NETTEST_LOCAL_TEST_LOCAL_DGRAM_H */ diff --git a/testing/nettest/local/test_local_dgram_common.c b/testing/nettest/local/test_local_dgram_common.c new file mode 100644 index 000000000..1d527ddf2 --- /dev/null +++ b/testing/nettest/local/test_local_dgram_common.c @@ -0,0 +1,335 @@ +/**************************************************************************** + * apps/testing/nettest/local/test_local_dgram_common.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <errno.h> +#include <poll.h> +#include <setjmp.h> +#include <signal.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <cmocka.h> + +#include "test_local_dgram.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* A case that does not end in this time stops the program */ + +#define LOCAL_DGRAM_WATCHDOG 10 + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +FAR const char *g_local_dgram_dir = P_tmpdir; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void local_dgram_watchdog(int signo) +{ + static const char msg[] = "cmocka_net_local_dgram: watchdog: " + "the test case does not end\n"; + + write(STDOUT_FILENO, msg, sizeof(msg) - 1); + _exit(EXIT_FAILURE); +} + +static void local_dgram_close(FAR int *fd) +{ + if (*fd >= 0) + { + close(*fd); + *fd = -1; + } +} + +static void local_dgram_cleanup(FAR struct nettest_local_dgram_state_s *st) +{ + local_dgram_close(&st->r1); + local_dgram_close(&st->r2); + local_dgram_close(&st->r3); + local_dgram_close(&st->s); + local_dgram_close(&st->u); + unlink(st->p1); + unlink(st->p2); + unlink(st->p3); + unlink(st->pf); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: local_dgram_addr + ****************************************************************************/ + +socklen_t local_dgram_addr(FAR struct sockaddr_un *addr, + FAR const char *path, bool abstract) +{ + memset(addr, 0, sizeof(*addr)); + addr->sun_family = AF_UNIX; + if (abstract) + { + strlcpy(addr->sun_path + 1, path, sizeof(addr->sun_path) - 1); + return sizeof(sa_family_t) + 1 + strlen(path); + } + + strlcpy(addr->sun_path, path, sizeof(addr->sun_path)); + return sizeof(sa_family_t) + strlen(path) + 1; +} + +/**************************************************************************** + * Name: local_dgram_bind + * + * Description: + * Return a datagram socket bound to path, or -1. + * + ****************************************************************************/ + +int local_dgram_bind(FAR const char *path, bool abstract) +{ + struct sockaddr_un addr; + socklen_t len = local_dgram_addr(&addr, path, abstract); + int fd; + + fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (fd < 0) + { + return -1; + } + + if (!abstract) + { + unlink(path); + } + + if (bind(fd, (FAR struct sockaddr *)&addr, len) < 0) + { + close(fd); + return -1; + } + + return fd; +} + +/**************************************************************************** + * Name: local_dgram_connect_to + ****************************************************************************/ + +int local_dgram_connect_to(int fd, FAR const char *path, bool abstract) +{ + struct sockaddr_un addr; + socklen_t len = local_dgram_addr(&addr, path, abstract); + + return connect(fd, (FAR struct sockaddr *)&addr, len); +} + +/**************************************************************************** + * Name: local_dgram_readable + * + * Description: + * Return true if poll() reports POLLIN on fd within ms milliseconds. + * + ****************************************************************************/ + +bool local_dgram_readable(int fd, int ms) +{ + struct pollfd pfd; + struct timespec t0; + struct timespec t1; + long left = ms; + + clock_gettime(CLOCK_MONOTONIC, &t0); + for (; ; ) + { + pfd.fd = fd; + pfd.events = POLLIN; + pfd.revents = 0; + if (poll(&pfd, 1, left) > 0 && (pfd.revents & POLLIN) != 0) + { + return true; + } + + clock_gettime(CLOCK_MONOTONIC, &t1); + left = ms - ((t1.tv_sec - t0.tv_sec) * 1000 + + (t1.tv_nsec - t0.tv_nsec) / 1000000); + if (left <= 0) + { + return false; + } + } +} + +/**************************************************************************** + * Name: local_dgram_expect + * + * Description: + * Wait up to 1 s for one datagram on fd and check that it is "want". + * + ****************************************************************************/ + +void local_dgram_expect(int fd, FAR const char *want) +{ + char buf[128]; + ssize_t n; + + assert_true(local_dgram_readable(fd, 1000)); + n = recv(fd, buf, sizeof(buf) - 1, 0); + assert_return_code(n, errno); + buf[n] = '\0'; + assert_string_equal(buf, want); +} + +/**************************************************************************** + * Name: local_dgram_drain + ****************************************************************************/ + +void local_dgram_drain(int fd, FAR char *buf, size_t size) +{ + while (local_dgram_readable(fd, 0)) + { + if (recv(fd, buf, size, 0) < 0) + { + break; + } + } +} + +/**************************************************************************** + * Name: test_local_dgram_group_setup + ****************************************************************************/ + +int test_local_dgram_group_setup(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st; + FAR const char *dir = g_local_dgram_dir; + int pid = getpid(); + + st = zalloc(sizeof(*st)); + assert_non_null(st); + + st->big = malloc(LOCAL_DGRAM_BIGLEN); + assert_non_null(st->big); + memset(st->big, 'b', LOCAL_DGRAM_BIGLEN); + + snprintf(st->p1, sizeof(st->p1), "%s/dgram1-%d", dir, pid); + snprintf(st->p2, sizeof(st->p2), "%s/dgram2-%d", dir, pid); + snprintf(st->p3, sizeof(st->p3), "%s/dgram3-%d", dir, pid); + snprintf(st->pf, sizeof(st->pf), "%s/dgramf-%d", dir, pid); + snprintf(st->abs, sizeof(st->abs), "dgramabs-%d", pid); + + st->r1 = -1; + st->r2 = -1; + st->r3 = -1; + st->s = -1; + st->u = -1; + + signal(SIGALRM, local_dgram_watchdog); + *state = st; + return 0; +} + +/**************************************************************************** + * Name: test_local_dgram_group_teardown + ****************************************************************************/ + +int test_local_dgram_group_teardown(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + + alarm(0); + signal(SIGALRM, SIG_DFL); + local_dgram_cleanup(st); + free(st->big); + free(st); + return 0; +} + +/**************************************************************************** + * Name: test_local_dgram_setup + * + * Description: + * Make r1, a socket bound to p1, and s, a socket that is not connected. + * + ****************************************************************************/ + +int test_local_dgram_setup(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + + local_dgram_cleanup(st); + alarm(LOCAL_DGRAM_WATCHDOG); + + st->r1 = local_dgram_bind(st->p1, false); + assert_return_code(st->r1, errno); + + st->s = socket(AF_UNIX, SOCK_DGRAM, 0); + assert_return_code(st->s, errno); + return 0; +} + +/**************************************************************************** + * Name: test_local_dgram_connected_setup + * + * Description: + * As test_local_dgram_setup(), and connect s to p1. + * + ****************************************************************************/ + +int test_local_dgram_connected_setup(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + int ret; + + test_local_dgram_setup(state); + ret = local_dgram_connect_to(st->s, st->p1, false); + assert_return_code(ret, errno); + return 0; +} + +/**************************************************************************** + * Name: test_local_dgram_teardown + ****************************************************************************/ + +int test_local_dgram_teardown(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + + alarm(0); + local_dgram_cleanup(st); + return 0; +} diff --git a/testing/nettest/local/test_local_dgram_connect.c b/testing/nettest/local/test_local_dgram_connect.c new file mode 100644 index 000000000..47b668c7a --- /dev/null +++ b/testing/nettest/local/test_local_dgram_connect.c @@ -0,0 +1,321 @@ +/**************************************************************************** + * apps/testing/nettest/local/test_local_dgram_connect.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <errno.h> +#include <fcntl.h> +#include <setjmp.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <cmocka.h> + +#include "test_local_dgram.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: test_local_dgram_connect + * + * Description: + * connect() to a bound datagram socket returns 0. + * + ****************************************************************************/ + +void test_local_dgram_connect(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + int ret; + + ret = local_dgram_connect_to(st->s, st->p1, false); + assert_return_code(ret, errno); +} + +/**************************************************************************** + * Name: test_local_dgram_peername + * + * Description: + * getpeername() gives the name of the receiver. + * + ****************************************************************************/ + +void test_local_dgram_peername(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + struct sockaddr_un addr; + socklen_t len = sizeof(addr); + int ret; + + memset(&addr, 0, sizeof(addr)); + ret = getpeername(st->s, (FAR struct sockaddr *)&addr, &len); + assert_return_code(ret, errno); + assert_int_equal(addr.sun_family, AF_UNIX); + assert_string_equal(addr.sun_path, st->p1); +} + +/**************************************************************************** + * Name: test_local_dgram_send + * + * Description: + * send() without an address reaches the receiver. + * + ****************************************************************************/ + +void test_local_dgram_send(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + ssize_t ret; + + ret = send(st->s, "one", 3, 0); + assert_return_code(ret, errno); + assert_int_equal(ret, 3); + local_dgram_expect(st->r1, "one"); +} + +/**************************************************************************** + * Name: test_local_dgram_write + * + * Description: + * write() reaches the receiver. + * + ****************************************************************************/ + +void test_local_dgram_write(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + ssize_t ret; + + ret = write(st->s, "two", 3); + assert_return_code(ret, errno); + assert_int_equal(ret, 3); + local_dgram_expect(st->r1, "two"); +} + +/**************************************************************************** + * Name: test_local_dgram_sendto_null + * + * Description: + * sendto() with a NULL address reaches the receiver. + * + ****************************************************************************/ + +void test_local_dgram_sendto_null(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + ssize_t ret; + + ret = sendto(st->s, "three", 5, 0, NULL, 0); + assert_return_code(ret, errno); + assert_int_equal(ret, 5); + local_dgram_expect(st->r1, "three"); +} + +/**************************************************************************** + * Name: test_local_dgram_peeronly + * + * Description: + * A connected socket takes datagrams from its peer only. + * + ****************************************************************************/ + +void test_local_dgram_peeronly(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + struct sockaddr_un addr; + socklen_t len; + ssize_t ret; + + /* r2 at p2 is connected to r3 at p3; u is a stranger */ + + st->r2 = local_dgram_bind(st->p2, false); + assert_return_code(st->r2, errno); + st->r3 = local_dgram_bind(st->p3, false); + assert_return_code(st->r3, errno); + st->u = socket(AF_UNIX, SOCK_DGRAM, 0); + assert_return_code(st->u, errno); + ret = local_dgram_connect_to(st->r2, st->p3, false); + assert_return_code(ret, errno); + + /* The sendto() of the stranger can fail (EPERM) or not, but the + * datagram must not arrive. + */ + + len = local_dgram_addr(&addr, st->p2, false); + sendto(st->u, "stranger", 8, 0, (FAR struct sockaddr *)&addr, len); + ret = sendto(st->r3, "peer", 4, 0, (FAR struct sockaddr *)&addr, len); + assert_return_code(ret, errno); + assert_int_equal(ret, 4); + local_dgram_expect(st->r2, "peer"); + assert_false(local_dgram_readable(st->r2, 50)); +} + +/**************************************************************************** + * Name: test_local_dgram_unspec + * + * Description: + * connect(AF_UNSPEC) removes the destination: send() fails. + * + ****************************************************************************/ + +void test_local_dgram_unspec(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + struct sockaddr_un addr; + ssize_t ret; + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNSPEC; + ret = connect(st->s, (FAR struct sockaddr *)&addr, sizeof(sa_family_t)); + assert_return_code(ret, errno); + + errno = 0; + ret = send(st->s, "x", 1, 0); + assert_int_equal(ret, -1); + assert_true(errno == EDESTADDRREQ || errno == ENOTCONN); +} + +/**************************************************************************** + * Name: test_local_dgram_reconnect + * + * Description: + * connect() to a second receiver: send() goes there. + * + ****************************************************************************/ + +void test_local_dgram_reconnect(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + ssize_t ret; + + st->r3 = local_dgram_bind(st->p3, false); + assert_return_code(st->r3, errno); + ret = local_dgram_connect_to(st->s, st->p3, false); + assert_return_code(ret, errno); + + ret = send(st->s, "seven", 5, 0); + assert_return_code(ret, errno); + assert_int_equal(ret, 5); + local_dgram_expect(st->r3, "seven"); + assert_false(local_dgram_readable(st->r1, 50)); +} + +/**************************************************************************** + * Name: test_local_dgram_missing + * + * Description: + * connect() to a name that does not exist fails with ENOENT. + * + ****************************************************************************/ + +void test_local_dgram_missing(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + int ret; + + errno = 0; + ret = local_dgram_connect_to(st->s, st->pf, false); + assert_int_equal(ret, -1); + assert_int_equal(errno, ENOENT); +} + +/**************************************************************************** + * Name: test_local_dgram_notsock + * + * Description: + * connect() to a regular file fails with ECONNREFUSED. + * + ****************************************************************************/ + +void test_local_dgram_notsock(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + int ret; + + ret = open(st->pf, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (ret < 0) + { + skip(); + } + + close(ret); + errno = 0; + ret = local_dgram_connect_to(st->s, st->pf, false); + assert_int_equal(ret, -1); + assert_int_equal(errno, ECONNREFUSED); +} + +/**************************************************************************** + * Name: test_local_dgram_closed + * + * Description: + * send() after the receiver is closed fails with ECONNREFUSED. + * + ****************************************************************************/ + +void test_local_dgram_closed(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + ssize_t ret; + + close(st->r1); + st->r1 = -1; + unlink(st->p1); + + errno = 0; + ret = send(st->s, "x", 1, 0); + assert_int_equal(ret, -1); + assert_int_equal(errno, ECONNREFUSED); +} + +/**************************************************************************** + * Name: test_local_dgram_abstract + * + * Description: + * connect() and send() to an abstract name. + * + ****************************************************************************/ + +void test_local_dgram_abstract(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + ssize_t ret; + + st->r2 = local_dgram_bind(st->abs, true); + if (st->r2 < 0) + { + skip(); + } + + ret = local_dgram_connect_to(st->s, st->abs, true); + assert_return_code(ret, errno); + ret = send(st->s, "eight", 5, 0); + assert_return_code(ret, errno); + assert_int_equal(ret, 5); + local_dgram_expect(st->r2, "eight"); +} diff --git a/testing/nettest/local/test_local_dgram_poll.c b/testing/nettest/local/test_local_dgram_poll.c new file mode 100644 index 000000000..d1441f1d7 --- /dev/null +++ b/testing/nettest/local/test_local_dgram_poll.c @@ -0,0 +1,298 @@ +/**************************************************************************** + * apps/testing/nettest/local/test_local_dgram_poll.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <errno.h> +#include <fcntl.h> +#include <poll.h> +#include <pthread.h> +#include <setjmp.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <time.h> +#include <unistd.h> +#include <sys/select.h> +#include <cmocka.h> + +#include "test_local_dgram.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct local_dgram_later_s +{ + int fd; + FAR const char *msg; + size_t len; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* Send one datagram after 200 ms */ + +static FAR void *local_dgram_send_later(FAR void *arg) +{ + FAR struct local_dgram_later_s *later = arg; + + usleep(200000); + send(later->fd, later->msg, later->len, 0); + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: test_local_dgram_pollin0 + * + * Description: + * poll(POLLIN) of a receiver with no datagram reports no event. + * + ****************************************************************************/ + +void test_local_dgram_pollin0(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + struct pollfd pfd; + int ret; + + pfd.fd = st->r1; + pfd.events = POLLIN; + pfd.revents = 0; + ret = poll(&pfd, 1, 0); + assert_return_code(ret, errno); + assert_int_equal(ret, 0); +} + +/**************************************************************************** + * Name: test_local_dgram_pollin + * + * Description: + * poll(POLLIN) after a send() reports POLLIN. + * + ****************************************************************************/ + +void test_local_dgram_pollin(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + struct pollfd pfd; + int ret; + + ret = send(st->s, "four", 4, 0); + assert_int_equal(ret, 4); + + pfd.fd = st->r1; + pfd.events = POLLIN; + pfd.revents = 0; + ret = poll(&pfd, 1, 1000); + assert_return_code(ret, errno); + assert_int_equal(ret, 1); + assert_true((pfd.revents & POLLIN) != 0); + local_dgram_expect(st->r1, "four"); +} + +/**************************************************************************** + * Name: test_local_dgram_nohup + * + * Description: + * A datagram that is too large for the receiver does not make poll() + * of the receiver report POLLHUP. + * + ****************************************************************************/ + +void test_local_dgram_nohup(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + struct local_dgram_later_s later; + struct pollfd pfd; + pthread_t thread; + int ret; + + later.fd = st->s; + later.msg = st->big; + later.len = LOCAL_DGRAM_BIGLEN; + ret = pthread_create(&thread, NULL, local_dgram_send_later, &later); + assert_int_equal(ret, 0); + + pfd.fd = st->r1; + pfd.events = POLLIN; + pfd.revents = 0; + ret = poll(&pfd, 1, 600); + pthread_join(thread, NULL); + local_dgram_drain(st->r1, st->big, LOCAL_DGRAM_BIGLEN); + + assert_return_code(ret, errno); + assert_true((pfd.revents & POLLHUP) == 0); +} + +/**************************************************************************** + * Name: test_local_dgram_pollout + * + * Description: + * poll(POLLOUT) of a connected sender reports POLLOUT. + * + ****************************************************************************/ + +void test_local_dgram_pollout(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + struct pollfd pfd; + int ret; + + pfd.fd = st->s; + pfd.events = POLLOUT; + pfd.revents = 0; + ret = poll(&pfd, 1, 0); + assert_return_code(ret, errno); + assert_int_equal(ret, 1); + assert_true((pfd.revents & POLLOUT) != 0); +} + +/**************************************************************************** + * Name: test_local_dgram_pollwait + * + * Description: + * poll(POLLIN) wakes up when another thread sends a datagram. + * + ****************************************************************************/ + +void test_local_dgram_pollwait(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + struct local_dgram_later_s later; + struct pollfd pfd; + struct timespec t0; + struct timespec t1; + pthread_t thread; + long ms; + int ret; + + later.fd = st->s; + later.msg = "five"; + later.len = 4; + + pfd.fd = st->r1; + pfd.events = POLLIN; + pfd.revents = 0; + clock_gettime(CLOCK_MONOTONIC, &t0); + ret = pthread_create(&thread, NULL, local_dgram_send_later, &later); + assert_int_equal(ret, 0); + + ret = poll(&pfd, 1, 3000); + clock_gettime(CLOCK_MONOTONIC, &t1); + pthread_join(thread, NULL); + + ms = (t1.tv_sec - t0.tv_sec) * 1000 + + (t1.tv_nsec - t0.tv_nsec) / 1000000; + assert_return_code(ret, errno); + assert_int_equal(ret, 1); + assert_true((pfd.revents & POLLIN) != 0); + assert_in_range(ms, 100, 2500); + local_dgram_expect(st->r1, "five"); +} + +/**************************************************************************** + * Name: test_local_dgram_select + * + * Description: + * select() reports the receiver readable after a send(). + * + ****************************************************************************/ + +void test_local_dgram_select(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + struct timeval tv; + fd_set rset; + int ret; + + ret = send(st->s, "six", 3, 0); + assert_int_equal(ret, 3); + + FD_ZERO(&rset); + FD_SET(st->r1, &rset); + tv.tv_sec = 1; + tv.tv_usec = 0; + ret = select(st->r1 + 1, &rset, NULL, NULL, &tv); + assert_return_code(ret, errno); + assert_int_equal(ret, 1); + assert_true(FD_ISSET(st->r1, &rset)); + local_dgram_expect(st->r1, "six"); +} + +/**************************************************************************** + * Name: test_local_dgram_dontwait + * + * Description: + * recv(MSG_DONTWAIT) of an empty socket fails with EAGAIN. + * + ****************************************************************************/ + +void test_local_dgram_dontwait(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + char buf[16]; + ssize_t ret; + + errno = 0; + ret = recv(st->r1, buf, sizeof(buf), MSG_DONTWAIT); + assert_int_equal(ret, -1); + assert_true(errno == EAGAIN || errno == EWOULDBLOCK); +} + +/**************************************************************************** + * Name: test_local_dgram_nonblock + * + * Description: + * recv() of an empty socket with O_NONBLOCK set after bind() fails with + * EAGAIN. + * + ****************************************************************************/ + +void test_local_dgram_nonblock(FAR void **state) +{ + FAR struct nettest_local_dgram_state_s *st = *state; + char buf[16]; + ssize_t ret; + int flags; + + st->r2 = local_dgram_bind(st->p2, false); + assert_return_code(st->r2, errno); + + flags = fcntl(st->r2, F_GETFL); + assert_return_code(flags, errno); + ret = fcntl(st->r2, F_SETFL, flags | O_NONBLOCK); + assert_return_code(ret, errno); + + errno = 0; + ret = recv(st->r2, buf, sizeof(buf), 0); + assert_int_equal(ret, -1); + assert_true(errno == EAGAIN || errno == EWOULDBLOCK); +}
