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);
+}

Reply via email to