From 31342e02cee863f11247601433920b1235190cbc Mon Sep 17 00:00:00 2001 From: Bogdan Date: Thu, 20 Aug 2026 17:08:54 +0300 Subject: [PATCH] testing/nettest: add cmocka test for local socket SCM_RIGHTS Add CMocka regression test case to verify local socket SCM_RIGHTS behavior when the file descriptor table is exhausted. Signed-off-by: Bogdan --- testing/nettest/CMakeLists.txt | 23 +++ testing/nettest/Kconfig | 5 + testing/nettest/Makefile | 6 + testing/nettest/local/test_local.c | 46 ++++++ testing/nettest/local/test_local.h | 52 ++++++ testing/nettest/local/test_local_common.c | 47 ++++++ testing/nettest/local/test_local_scm_rights.c | 154 ++++++++++++++++++ 7 files changed, 333 insertions(+) create mode 100644 testing/nettest/local/test_local.c create mode 100644 testing/nettest/local/test_local.h create mode 100644 testing/nettest/local/test_local_common.c create mode 100644 testing/nettest/local/test_local_scm_rights.c diff --git a/testing/nettest/CMakeLists.txt b/testing/nettest/CMakeLists.txt index 6a36708da..94fa4557f 100644 --- a/testing/nettest/CMakeLists.txt +++ b/testing/nettest/CMakeLists.txt @@ -50,6 +50,29 @@ if(CONFIG_TESTING_NET_TEST) ${SRCS}) endif() + if(CONFIG_TESTING_NET_LOCAL) + set(SRCS + ${CMAKE_CURRENT_LIST_DIR}/local/test_local.c + ${CMAKE_CURRENT_LIST_DIR}/local/test_local_common.c + ${CMAKE_CURRENT_LIST_DIR}/local/test_local_scm_rights.c) + + nuttx_add_application( + NAME + cmocka_net_local + PRIORITY + ${CONFIG_TESTING_NET_TEST_PRIORITY} + STACKSIZE + ${CONFIG_TESTING_NET_TEST_STACKSIZE} + MODULE + ${CONFIG_TESTING_NET_TEST} + DEPENDS + cmocka + INCLUDE_DIRECTORIES + ${CMAKE_CURRENT_LIST_DIR}/utils + 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 750b5796a..83e3ba722 100644 --- a/testing/nettest/Kconfig +++ b/testing/nettest/Kconfig @@ -35,6 +35,11 @@ config TESTING_NET_TCP_PORT endif +config TESTING_NET_LOCAL + bool "Enable cmocka net local test" + depends on NET_LOCAL && NET_LOCAL_SCM + default y + config TESTING_NET_OTHERS bool "Enable cmocka net other test" default y diff --git a/testing/nettest/Makefile b/testing/nettest/Makefile index 2abd410bc..6f10c3910 100644 --- a/testing/nettest/Makefile +++ b/testing/nettest/Makefile @@ -45,6 +45,12 @@ endif endif +ifeq ($(CONFIG_TESTING_NET_LOCAL),y) +MAINSRC += local/test_local.c +PROGNAME += cmocka_net_local +CSRCS += local/test_local_common.c local/test_local_scm_rights.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.c b/testing/nettest/local/test_local.c new file mode 100644 index 000000000..a0a0d3316 --- /dev/null +++ b/testing/nettest/local/test_local.c @@ -0,0 +1,46 @@ +/**************************************************************************** + * apps/testing/nettest/local/test_local.c + * + * 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 +#include +#include +#include +#include + +#include "test_local.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + const struct CMUnitTest local_tests[] = + { + cmocka_unit_test(test_local_scm_rights), + }; + + return cmocka_run_group_tests(local_tests, test_local_group_setup, + test_local_group_teardown); +} diff --git a/testing/nettest/local/test_local.h b/testing/nettest/local/test_local.h new file mode 100644 index 000000000..387104e27 --- /dev/null +++ b/testing/nettest/local/test_local.h @@ -0,0 +1,52 @@ +/**************************************************************************** + * apps/testing/nettest/local/test_local.h + * + * 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_H +#define __APPS_TESTING_NETTEST_LOCAL_TEST_LOCAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: test_local_group_setup + ****************************************************************************/ + +int test_local_group_setup(FAR void **state); + +/**************************************************************************** + * Name: test_local_group_teardown + ****************************************************************************/ + +int test_local_group_teardown(FAR void **state); + +/**************************************************************************** + * Name: test_local_scm_rights + ****************************************************************************/ + +void test_local_scm_rights(FAR void **state); + +#endif /* __APPS_TESTING_NETTEST_LOCAL_TEST_LOCAL_H */ diff --git a/testing/nettest/local/test_local_common.c b/testing/nettest/local/test_local_common.c new file mode 100644 index 000000000..ecfee701f --- /dev/null +++ b/testing/nettest/local/test_local_common.c @@ -0,0 +1,47 @@ +/**************************************************************************** + * apps/testing/nettest/local/test_local_common.c + * + * 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 "test_local.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: test_local_group_setup + ****************************************************************************/ + +int test_local_group_setup(FAR void **state) +{ + return 0; +} + +/**************************************************************************** + * Name: test_local_group_teardown + ****************************************************************************/ + +int test_local_group_teardown(FAR void **state) +{ + return 0; +} diff --git a/testing/nettest/local/test_local_scm_rights.c b/testing/nettest/local/test_local_scm_rights.c new file mode 100644 index 000000000..ebfc65268 --- /dev/null +++ b/testing/nettest/local/test_local_scm_rights.c @@ -0,0 +1,154 @@ +/**************************************************************************** + * apps/testing/nettest/local/test_local_scm_rights.c + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_local.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define SEND_FDS 3 + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: test_local_scm_rights + ****************************************************************************/ + +void test_local_scm_rights(FAR void **state) +{ + int sv[2]; + int p1[2]; + int p2[2]; + struct msghdr msg; + struct iovec iov; + char send_buf = 'X'; + char recv_buf; + char cmsgbuf[CMSG_SPACE(sizeof(int) * SEND_FDS)]; + struct cmsghdr *cmsg; + int send_fds[SEND_FDS]; + int junk[256]; + int n_open = 0; + int ret; + int i; + + ret = pipe(p1); + assert_return_code(ret, errno); + + ret = pipe(p2); + assert_return_code(ret, errno); + + ret = socketpair(AF_LOCAL, SOCK_STREAM, 0, sv); + assert_return_code(ret, errno); + + send_fds[0] = p1[0]; + send_fds[1] = p1[1]; + send_fds[2] = p2[0]; + + memset(&msg, 0, sizeof(msg)); + memset(cmsgbuf, 0, sizeof(cmsgbuf)); + + iov.iov_base = &send_buf; + iov.iov_len = 1; + + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsgbuf; + msg.msg_controllen = CMSG_SPACE(sizeof(int) * SEND_FDS); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int) * SEND_FDS); + memcpy(CMSG_DATA(cmsg), send_fds, sizeof(int) * SEND_FDS); + + ret = sendmsg(sv[0], &msg, 0); + assert_true(ret >= 0); + + for (i = 0; i < 256; i++) + { + junk[i] = open("/dev/null", O_RDONLY); + if (junk[i] < 0) + { + break; + } + + n_open++; + } + + if (n_open == 0) + { + /* If /dev/null is not available, try to dup p1[0] */ + + for (i = 0; i < 256; i++) + { + junk[i] = dup(p1[0]); + if (junk[i] < 0) + { + break; + } + + n_open++; + } + } + + memset(&msg, 0, sizeof(msg)); + memset(cmsgbuf, 0, sizeof(cmsgbuf)); + iov.iov_base = &recv_buf; + iov.iov_len = 1; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + + recvmsg(sv[1], &msg, 0); + + /* cleanup descriptors */ + + for (i = 0; i < n_open; i++) + { + close(junk[i]); + } + + close(sv[0]); + close(sv[1]); + close(p1[0]); + close(p1[1]); + close(p2[0]); + close(p2[1]); +}