nuttx icon indicating copy to clipboard operation
nuttx copied to clipboard

[BUG] Unix datagram sockets seems broken

Open michallenc opened this issue 6 months ago • 2 comments

Description / Steps to reproduce the issue

Unix local datagram sockets seems to be broken on NuttX. The following code doesn't work on sim:udgram configuration (nor other configurations with CONFIG_NET=y, including real hardware). The code basically creates a local unix socket and then polls for POLLIN. However, the poll fails on POLLERR, but no errno is set during subsequent read call (and read returns 0). I think the POSIX states that subsequent read should return -1 and set errno in this case. You can compile it on both Linux and NuttX to reproduce, just run the application without argument (or with 's') for server and with 'c' for a client). The code works on Linux as expected - server polls, client sends 10 and server receives and prints the value. No POLLERR occurs.

#include <errno.h>
#include <poll.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

#define SOCKET_PATH "/tmp/socket.sock"

void run_client(void) {
  int sock = socket(AF_UNIX, SOCK_DGRAM, 0);
  if (sock < 0) {
    printf("Failed to open socket.");
    return;
  }

  struct sockaddr_un name;
  name.sun_family = AF_UNIX;
  strcpy(name.sun_path, SOCKET_PATH);

  uint8_t data = 10;
  if (sendto(sock, &data, sizeof data, 0, (const struct sockaddr *)&name,
             sizeof name) < 0) {
    printf("Failed to send data.");
  }

  close(sock);
}

void run_server(void) {
  int sock = socket(AF_UNIX, SOCK_DGRAM, 0);
  if (sock == -1) {
    printf("Failed to create a socket: %d", errno);
    return;
  }

  struct sockaddr_un addr;
  memset(&addr, 0, sizeof addr);
  addr.sun_family = AF_UNIX;
  strcpy(addr.sun_path, SOCKET_PATH);

  if (bind(sock, (const struct sockaddr *)&addr, sizeof addr) == -1) {
    printf("Failed to bind a socket: %d", errno);
    close(sock);
    return;
  }

  struct pollfd pfd = {.fd = sock, .events = POLLIN};

  uint8_t data;
  while (true) {
    int ret = poll(&pfd, 1, 10000);
    if (ret == -1 || ret == 0) {
      printf("timeout\n");
      continue;
    } else if (pfd.revents & POLLIN) {
      read(sock, &data, sizeof data);
      printf("data = %d\n", data);
    } else if (pfd.revents & POLLERR) {
      read(sock, &data, sizeof data);
      printf("pollerr = %d\n", errno);
      break;
    }
  }

  close(sock);
}

int main(int argc, char *argv[]) {
  bool server = true;
  if (argc > 1) {
    server = argv[1][0] == 's';
  }

  if (server)
    run_server();
  else
    run_client();

  return 0;
}

The example application CONFIG_EXAMPLES_UDGRAM without polling doesn't work as well. Running server (sim:udgram config as well) results in

nsh> server
server: 0. Receiving up 1024 bytes
server: 0. Received 0 bytes from a pathname client 
server: 0. ERROR recv size incorrect: 0 vs 96

This seems like recv on socket returns immediately even when it's set as a blocking socket. And this is AF_LOCAL socket, not AF_UNIX.

I will get to this issue in few days, just putting it here now to see if anyone hasn't already encountered this problem. Maybe it is some kind of an issue in a configuration? Btw, I checked citests and we don't seem to test this at all, both CM_SOCKET_TEST and CM_SYSCALL_TEST are not selected in sim:citest configuration. I invested few minutes into running them, but there seem to be many more issues, basically wasn't able to run CM_SYSCALL_TEST, where unix datagram test is located, at all.

On which OS does this issue occur?

[OS: Linux]

What is the version of your OS?

Ubuntu 22.04.5 LTS Linux 6.8.0-60-generic

NuttX Version

master

Issue Architecture

[Arch: all]

Issue Area

[Area: Networking], [Area: Posix], [Area: Kernel]

Host information

file sysinfo.h not exists
NuttX CFLAGS:
  --g\
  -fomit-frame-pointer
  -fno-common
  -fvisibility=hidden
  -ffunction-sections
  -fdata-sections
  -Wall
  -Wstrict-prototypes
  -Wshadow
  -Wundef
  -Wno-attributes
  -Wno-unknown-pragmas
  -fno-pic
  -mcmodel=medium
  -isystem /home/michal/Michal/GIT/nuttx-fork/samv7/include
  -D__NuttX__
  -DNDEBUG
  -U_AIX
  -U_WIN32
  -U__APPLE__
  -U__FreeBSD__
  -U__NetBSD__
  -U__linux__
  -U__sun__
  -U__unix__
  -U__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ 


NuttX CXXFLAGS:
  --g\
  -fomit-frame-pointer
  -fno-common
  -fvisibility=hidden
  -ffunction-sections
  -fdata-sections
  -Wall
  -Wshadow
  -Wundef
  -Wno-attributes
  -Wno-unknown-pragmas
  -nostdinc++
  -fno-exceptions
  -fcheck-new
  -fno-rtti
  -fno-pic
  -mcmodel=medium
  -isystem /home/michal/Michal/GIT/nuttx-fork/samv7/include/cxx
  -isystem /home/michal/Michal/GIT/nuttx-fork/samv7/include
  -D__NuttX__
  -DNDEBUG
  -U_AIX
  -U_WIN32
  -U__APPLE__
  -U__FreeBSD__
  -U__NetBSD__
  -U__linux__
  -U__sun__
  -U__unix__
  -U__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ 


NuttX LDFLAGS:
  -Wl--gc-sections
  -Wl-Ttext-segment=0x40000000
  -Wl-Map=/home/michal/Michal/GIT/nuttx-fork/samv7/nuttx.map
  -Wl-Map=/home/michal/Michal/GIT/nuttx-fork/samv7/nuttx.map
  -Wl-no-pie


NuttX configuration options:
  CONFIG_HOST_LINUX=y
  CONFIG_APPS_DIR=\../apps\
  CONFIG_BASE_DEFCONFIG=\sim:udgram\
  CONFIG_BUILD_FLAT=y
  CONFIG_OUTPUT_STRIP_PATHS=y
  CONFIG_ARCH_HAVE_MATH_H=y
  CONFIG_ARCH_HAVE_SETJMP=y
  CONFIG_ARCH_SETJMP_H=y
  CONFIG_ARCH_NONE_DEBUG_H=y
  CONFIG_FORTIFY_SOURCE=0
  CONFIG_NDEBUG=y
  CONFIG_ARCH_HAVE_STACKCHECK=y
  CONFIG_STACK_USAGE_WARNING=0
  CONFIG_DEBUG_SYMBOLS=y
  CONFIG_DEBUG_SYMBOLS_LEVEL=\-g\
  CONFIG_ARCH_HAVE_CUSTOMOPT=y
  CONFIG_DEBUG_NOOPT=y
  CONFIG_LTO_NONE=y
  CONFIG_DEBUG_OPT_UNUSED_SECTIONS=y
  CONFIG_DEBUG_LINK_MAP=y
  CONFIG_ARCH_SIM=y
  CONFIG_ARCH=\sim\
  CONFIG_ARCH_CHIP=\sim\
  CONFIG_HOST_X86_64=y
  CONFIG_SIM_TOOLCHAIN_GCC=y
  CONFIG_SIM_X8664_SYSTEMV=y
  CONFIG_SIM_WALLTIME_SLEEP=y
  CONFIG_SIM_LOOPTASK_PRIORITY=224
  CONFIG_SIM_LOOPTASK_INTERVAL=10000
  CONFIG_SIM_STACKSIZE_ADJUSTMENT=65536
  CONFIG_SIM_OFFLOAD_NUM_BUFFERS=2
  CONFIG_SIM_OFFLOAD_BUFFER_NUMBYTES=32767
  CONFIG_SIM_UART_DMA=y
  CONFIG_SIM_UART_NUMBER=0
  CONFIG_SIM_CUSTOM_DATA_SECTION=\\
  CONFIG_ARCH_TOOLCHAIN_GNU=y
  CONFIG_ARCH_TOOLCHAIN_GCC=y
  CONFIG_ARCH_HAVE_TEXT_HEAP=y
  CONFIG_ARCH_HAVE_MULTICPU=y
  CONFIG_ARCH_HAVE_FORK=y
  CONFIG_ARCH_HAVE_POWEROFF=y
  CONFIG_ARCH_HAVE_TESTSET=y
  CONFIG_ARCH_HAVE_RTC_SUBSECONDS=y
  CONFIG_ARCH_HAVE_SYSCALL_HOOKS=y
  CONFIG_ARCH_HAVE_BACKTRACE=y
  CONFIG_ARCH_HAVE_CPUINFO=y
  CONFIG_ARCH_CPUINFO_FREQ_KHZ=0
  CONFIG_ARCH_HAVE_TCBINFO=y
  CONFIG_BOARD_LOOPSPERMSEC=0
  CONFIG_BOOT_RUNFROMEXTSRAM=y
  CONFIG_RAM_START=0x0
  CONFIG_RAM_SIZE=0
  CONFIG_ARCH_BOARD_SIM=y
  CONFIG_ARCH_BOARD=\sim\
  CONFIG_ARCH_HAVE_BUTTONS=y
  CONFIG_ARCH_HAVE_IRQBUTTONS=y
  CONFIG_BOARD_CRASHDUMP_NONE=y
  CONFIG_BOARDCTL=y
  CONFIG_BOARDCTL_MKRD=y
  CONFIG_BOARD_MEMORY_RANGE=\\
  CONFIG_DISABLE_OS_API=y
  CONFIG_ARCH_HAVE_TICKLESS=y
  CONFIG_USEC_PER_TICK=10000
  CONFIG_TIMER_ADJUST_USEC=0
  CONFIG_ARCH_HAVE_TIMEKEEPING=y
  CONFIG_START_YEAR=2008
  CONFIG_START_MONTH=6
  CONFIG_START_DAY=1
  CONFIG_PREALLOC_TIMERS=8
  CONFIG_IRQ_NWORKS=8
  CONFIG_IRQ_WORK_SECTION=\\
  CONFIG_IRQ_WORK_STACKSIZE=2048
  CONFIG_INIT_ENTRY=y
  CONFIG_INIT_ARGS=\\
  CONFIG_INIT_STACKSIZE=2048
  CONFIG_INIT_PRIORITY=100
  CONFIG_INIT_ENTRYPOINT=\nsh_main\
  CONFIG_INIT_ENTRYNAME=\nsh_main\
  CONFIG_ETC_ROMFS=y
  CONFIG_ETC_ROMFSMOUNTPT=\/etc\
  CONFIG_ETC_ROMFSDEVNO=1
  CONFIG_ETC_ROMFSSECTSIZE=64
  CONFIG_ETC_FATDEVNO=2
  CONFIG_ETC_FATSECTSIZE=512
  CONFIG_ETC_FATNSECTORS=1024
  CONFIG_ETC_FATMOUNTPT=\/tmp\
  CONFIG_RR_INTERVAL=0
  CONFIG_TASK_NAME_SIZE=31
  CONFIG_SCHED_HAVE_PARENT=y
  CONFIG_SCHED_WAITPID=y
  CONFIG_PTHREAD_MUTEX_ROBUST=y
  CONFIG_PTHREAD_MUTEX_DEFAULT_PRIO_NONE=y
  CONFIG_SCHED_CPULOAD_NONE=y
  CONFIG_SCHED_CPULOAD_TICKSPERSEC=100
  CONFIG_SCHED_PROFILE_TICKSPERSEC=1000
  CONFIG_SCHED_STACK_RECORD=0
  CONFIG_DEV_CONSOLE=y
  CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=8
  CONFIG_FILE_STREAM=y
  CONFIG_SIG_PREALLOC_ACTIONS=4
  CONFIG_SIG_ALLOC_ACTIONS=1
  CONFIG_SIG_PREALLOC_IRQ_ACTIONS=8
  CONFIG_PREALLOC_MQ_MSGS=8
  CONFIG_PREALLOC_MQ_IRQ_MSGS=8
  CONFIG_MQ_MAXMSGSIZE=32
  CONFIG_SCHED_WORKQUEUE=y
  CONFIG_SCHED_HPWORK=y
  CONFIG_SCHED_HPNTHREADS=1
  CONFIG_SCHED_HPWORKPRIORITY=224
  CONFIG_SCHED_HPWORKSTACKSIZE=2048
  CONFIG_DEFAULT_TASK_STACKSIZE=2048
  CONFIG_IDLETHREAD_STACKSIZE=8192
  CONFIG_PTHREAD_STACK_MIN=256
  CONFIG_PTHREAD_STACK_DEFAULT=2048
  CONFIG_PID_INITIAL_COUNT=16
  CONFIG_ONESHOT=y
  CONFIG_ALARM_ARCH=y
  CONFIG_BCH=y
  CONFIG_BCH_BUFFER_ALIGNMENT=0
  CONFIG_DEV_NULL=y
  CONFIG_DEV_ZERO=y
  CONFIG_DEV_OPTEE_NONE=y
  CONFIG_DRVR_MKRD=y
  CONFIG_NETDEVICES=y
  CONFIG_NETDEV_HPWORK_THREAD=y
  CONFIG_NET_IGC_TXDESC=256
  CONFIG_NET_IGC_RXDESC=256
  CONFIG_PIPES=y
  CONFIG_DEV_PIPE_MAXSIZE=65535
  CONFIG_DEV_PIPE_SIZE=1024
  CONFIG_DEV_FIFO_SIZE=1024
  CONFIG_DEV_PIPE_VFS_PATH=\/var/pipe\
  CONFIG_DEV_PIPE_NPOLLWAITERS=4
  CONFIG_ARCH_HAVE_SERIAL_TERMIOS=y
  CONFIG_SERIAL=y
  CONFIG_SERIAL_CONSOLE=y
  CONFIG_SERIAL_NPOLLWAITERS=4
  CONFIG_SERIAL_IFLOWCONTROL=y
  CONFIG_SERIAL_TXDMA=y
  CONFIG_SERIAL_RXDMA=y
  CONFIG_SYSLOG=y
  CONFIG_SYSLOG_DEFAULT_MASK=0xff
  CONFIG_SYSLOG_CRLF=y
  CONFIG_SYSLOG_MAX_CHANNELS=1
  CONFIG_SYSLOG_DEVPATH=\/dev/ttyS1\
  CONFIG_SYSLOG_DEFAULT=y
  CONFIG_ARCH_HAVE_NET=y
  CONFIG_NET=y
  CONFIG_NET_DEFAULT_MIN_PORT=4096
  CONFIG_NET_DEFAULT_MAX_PORT=32000
  CONFIG_NET_GUARDSIZE=2
  CONFIG_NET_LL_GUARDSIZE=0
  CONFIG_NET_RECV_BUFSIZE=0
  CONFIG_NET_IPFORWARD_ALLOC_STRUCT=1
  CONFIG_NET_PREALLOC_DEVIF_CALLBACKS=16
  CONFIG_NET_ALLOC_DEVIF_CALLBACKS=0
  CONFIG_NET_IPV4_CHECKSUMS=y
  CONFIG_NET_LOCAL=y
  CONFIG_NET_LOCAL_VFS_PATH=\/var/run\
  CONFIG_NET_LOCAL_DGRAM=y
  CONFIG_NET_IGMP_CHECKSUMS=y
  CONFIG_NET_SNOOP_BUFSIZE=4096
  CONFIG_NET_RECV_PACK=y
  CONFIG_FS_NEPOLL_DESCRIPTORS=8
  CONFIG_FS_LOCK_BUCKET_SIZE=0
  CONFIG_SENDFILE_BUFSIZE=512
  CONFIG_FS_BACKTRACE=0
  CONFIG_FS_MQUEUE_VFS_PATH=\/var/mqueue\
  CONFIG_FS_MQUEUE_NPOLLWAITERS=4
  CONFIG_FS_ANONMAP=y
  CONFIG_FS_FAT=y
  CONFIG_FAT_LCNAMES=y
  CONFIG_FAT_LFN=y
  CONFIG_FAT_MAXFNAME=32
  CONFIG_FAT_LFN_ALIAS_TRAILCHARS=0
  CONFIG_FS_ROMFS=y
  CONFIG_FS_ROMFS_CACHE_NODE=y
  CONFIG_FS_ROMFS_CACHE_FILE_NSECTORS=1
  CONFIG_FS_PROCFS=y
  CONFIG_NXFONTS_PACKEDMSFIRST=y
  CONFIG_MM_DEFAULT_MANAGER=y
  CONFIG_MM_DEFAULT_ALIGNMENT=8
  CONFIG_MM_REGIONS=1
  CONFIG_MM_MAP_COUNT_MAX=1024
  CONFIG_MM_BACKTRACE=-1
  CONFIG_MM_FREE_DELAYCOUNT_MAX=0
  CONFIG_MM_HEAP_BIGGEST_COUNT=30
  CONFIG_MM_HEAP_MEMPOOL_THRESHOLD=-1
  CONFIG_PATH_INITIAL=\/bin\
  CONFIG_BINFMT_ELF_RELOCATABLE=y
  CONFIG_STDIO_BUFFER_SIZE=64
  CONFIG_STDIO_LINEBUFFER=y
  CONFIG_NUNGET_CHARS=2
  CONFIG_LIBC_LONG_LONG=y
  CONFIG_ARCH_LOWPUTC=y
  CONFIG_LIBC_RAND_ORDER=1
  CONFIG_LIBC_HOMEDIR=\/\
  CONFIG_LIBC_TMPDIR=\/tmp\
  CONFIG_LIBC_MAX_TMPFILE=32
  CONFIG_LIBC_MAX_EXITFUNS=1
  CONFIG_LIBC_EXECFUNCS=y
  CONFIG_POSIX_SPAWN_DEFAULT_STACKSIZE=2048
  CONFIG_LIBC_HOSTNAME=\\
  CONFIG_LIBC_OPEN_MAX=256
  CONFIG_NAME_MAX=32
  CONFIG_PATH_MAX=256
  CONFIG_LINE_MAX=80
  CONFIG_LIBC_STRERROR_ERRNUM=y
  CONFIG_LIBC_STRSIGNAL=y
  CONFIG_TLS_NELEM=0
  CONFIG_TLS_TASK_NELEM=0
  CONFIG_TLS_NCLEANUP=0
  CONFIG_LIBC_GAISTRERROR_ERRNUM=y
  CONFIG_LIBC_ENVPATH=y
  CONFIG_LIBC_FTOK_VFS_PATH=\/var/ftok\
  CONFIG_LIBC_MEMFD_ERROR=y
  CONFIG_LIBC_TEMPBUFFER=y
  CONFIG_LIBC_MAX_TEMPBUFFER=2
  CONFIG_LIBC_TEMPBUFFER_MALLOC=y
  CONFIG_LIBC_MUTEX_BACKTRACE=0
  CONFIG_BUILTIN=y
  CONFIG_STREAM_OUT_BUFFER_SIZE=64
  CONFIG_STREAM_HEXDUMP_BUFFER_SIZE=128
  CONFIG_STREAM_BASE64_BUFFER_SIZE=128
  CONFIG_LIBC_INLINE_QUEUE=y
  CONFIG_LIBM_TOOLCHAIN=y
  CONFIG_BUILTIN_TOOLCHAIN=y
  CONFIG_COVERAGE_NONE=y
  CONFIG_COVERAGE_DEFAULT_PREFIX_STRIP=\99\
  CONFIG_COVERAGE_DEFAULT_PREFIX=\/data\
  CONFIG_PROFILE_NONE=y
  CONFIG_EXAMPLES_HELLO=y
  CONFIG_EXAMPLES_HELLO_PROGNAME=\hello\
  CONFIG_EXAMPLES_HELLO_PRIORITY=100
  CONFIG_EXAMPLES_HELLO_STACKSIZE=2048
  CONFIG_EXAMPLES_UDGRAM=y
  CONFIG_EXAMPLES_UDGRAM_ADDR=\/dev/fifo\
  CONFIG_EXAMPLES_UDGRAM_SERVER_STACKSIZE=8192
  CONFIG_EXAMPLES_UDGRAM_SERVER_PRIORITY=100
  CONFIG_EXAMPLES_UDGRAM_SERVER_PROGNAME=\server\
  CONFIG_EXAMPLES_UDGRAM_CLIENT_STACKSIZE=8192
  CONFIG_EXAMPLES_UDGRAM_CLIENT_PRIORITY=100
  CONFIG_EXAMPLES_UDGRAM_CLIENT_PROGNAME=\client\
  CONFIG_FSUTILS_MKFATFS=y
  CONFIG_MKFATFS_BUFFER_ALIGNMENT=0
  CONFIG_NETUTILS_NETINIT=y
  CONFIG_NETUTILS_NETLIB=y
  CONFIG_NSH_LIBRARY=y
  CONFIG_NSH_PROMPT_STRING=\nsh> \
  CONFIG_NSH_PROMPT_MAX=32
  CONFIG_NSH_PROMPT_ENV=\PS1\
  CONFIG_NSH_PROMPT_SUFFIX=\> \
  CONFIG_NSH_READLINE=y
  CONFIG_NSH_QUOTE=y
  CONFIG_NSH_MAXARGUMENTS=7
  CONFIG_NSH_ARGCAT=y
  CONFIG_NSH_NESTDEPTH=3
  CONFIG_NSH_ALIAS=y
  CONFIG_NSH_ALIAS_MAX_AMOUNT=1
  CONFIG_NSH_PIPELINE=y
  CONFIG_NSH_BUILTIN_APPS=y
  CONFIG_NSH_FILE_APPS=y
  CONFIG_NSH_DISABLE_DATE=y
  CONFIG_NSH_DISABLE_LOSMART=y
  CONFIG_NSH_DISABLE_LOMTD=y
  CONFIG_NSH_DISABLE_MB=y
  CONFIG_NSH_DISABLE_MH=y
  CONFIG_NSH_DISABLE_MW=y
  CONFIG_NSH_DISABLE_TIMEDATECTL=y
  CONFIG_NSH_CODECS_BUFSIZE=128
  CONFIG_NSH_PROC_MOUNTPOINT=\/proc\
  CONFIG_NSH_FILEIOSIZE=1024
  CONFIG_NSH_SYSINITSCRIPT=\init.d/rc.sysinit\
  CONFIG_NSH_INITSCRIPT=\init.d/rcS\
  CONFIG_NSH_SCRIPT_REDIRECT_PATH=\\
  CONFIG_NSH_CONSOLE=y
  CONFIG_NSH_ARCHINIT=y
  CONFIG_NSH_NETINIT=y
  CONFIG_NSH_WGET_BUFF_SIZE=512
  CONFIG_SYSTEM_DD=y
  CONFIG_SYSTEM_DD_PROGNAME=\dd\
  CONFIG_SYSTEM_DD_PRIORITY=100
  CONFIG_SYSTEM_DD_STACKSIZE=2048
  CONFIG_SYSTEM_DD_STATS=y
  CONFIG_SYSTEM_NSH=y
  CONFIG_SYSTEM_NSH_PRIORITY=100
  CONFIG_SYSTEM_NSH_STACKSIZE=2048
  CONFIG_SYSTEM_NSH_PROGNAME=\nsh\
  CONFIG_SYSTEM_READLINE=y
  CONFIG_READLINE_HAVE_EXTMATCH=y
  CONFIG_READLINE_ECHO=

Verification

  • [x] I have verified before submitting the report.

michallenc avatar Jun 19 '25 07:06 michallenc

So it seems there are two problems. The first one is pretty obvious after looking to the code, we simply don't support poll on SOCK_DGRAM 😅 See https://github.com/apache/nuttx/blob/master/net/local/local_netpoll.c#L162

The other problem is in local_recvmsg and local_sendmsg in the first check (https://github.com/apache/nuttx/blob/master/net/local/local_sendmsg.c#L442)

  if (conn->lc_outfile.f_inode == NULL)
    {
      return -EPIPE;
    }

added in #14103. For some reason, this seems to be always NULL for datagram in our case. With few hacks, I was able to send/receive data with SOCK_DGRAM, but the behavior is still weird.

michallenc avatar Jun 19 '25 15:06 michallenc

@wengzhe please take a look. Do you think it is possible to add poll support to SOCK_DGRAM ?

@GUIDINGLI since you created the PR https://github.com/apache/nuttx/pull/14103 could you please take a look too?

acassis avatar Jun 19 '25 21:06 acassis

Standard send/receive can be fixed by this.

diff --git a/net/local/local_recvmsg.c b/net/local/local_recvmsg.c
index 7f44907650..05baeaba48 100644
--- a/net/local/local_recvmsg.c
+++ b/net/local/local_recvmsg.c
@@ -547,7 +547,7 @@ ssize_t local_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
 
   /* Check shutdown state */
 
-  if (conn->lc_infile.f_inode == NULL)
+  if (psock->s_type != SOCK_DGRAM && conn->lc_infile.f_inode == NULL)
     {
       return 0;
     }
diff --git a/net/local/local_sendmsg.c b/net/local/local_sendmsg.c
index b64bdf5b3b..8a43798709 100644
--- a/net/local/local_sendmsg.c
+++ b/net/local/local_sendmsg.c
@@ -439,7 +439,7 @@ ssize_t local_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
 
   /* Check shutdown state */
 
-  if (conn->lc_outfile.f_inode == NULL)
+  if (psock->s_type != SOCK_DGRAM && conn->lc_outfile.f_inode == NULL)
     {
       return -EPIPE;
     }

The check for conn->lc_infile.f_inode == NULL is not required for DGRAM socket because psock_dgram_recvfrom creates half duplex FIFO itself if it doesn't exist (here https://github.com/apache/nuttx/blob/master/net/local/local_recvmsg.c#L390) and local_sendto used for datagrams (as there is no connection) creates it as well.

The question is why the check is in a common code now. It seems just like an unnecessary duplication, because psock_stream_recvfrom and local_send already check if inode is not NULL. We can either add a condition as showed in the diff or revert PR https://github.com/apache/nuttx/pull/14103 as the check should not be needed. @GUIDINGLI Could you share some info what was the goal of the additional check?

michallenc avatar Jun 23 '25 13:06 michallenc

@xiaoxiang781216 @wengzhe could you please comment here?

acassis avatar Jun 23 '25 14:06 acassis

Taking another look at polling... The implementation to local_netpoll.c seems pretty straightforward, just create receiver if it doesn't exist (default state for the datagram, basically the same as in psock_dgram_recvfrom and call file_poll. The behavior of poll is still not as expected though, because it returns POLLHUP right after the poll is called. But this event should not return on datagram sockets as they are not connection oriented.

I think this bring us back to the same issue @Cynerd already faced with stream sockets in #14667. NuttX sockets are implemented with fifos and pipes, but the expected behavior of local sockets (both stream and dgram) is a bit different from pipes.

Diff for poll. Just for tests, expects only listening to POLLIN event.

diff --git a/net/local/local_netpoll.c b/net/local/local_netpoll.c
index e68833aa9a..264c59c28a 100644
--- a/net/local/local_netpoll.c
+++ b/net/local/local_netpoll.c
@@ -161,7 +161,29 @@ int local_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
 
   if (conn->lc_proto == SOCK_DGRAM)
     {
-      return -ENOSYS;
+      if (conn->lc_infile.f_inode == NULL)
+        {
+          ret = local_create_halfduplex(conn, conn->lc_path, conn->lc_rcvsize);
+          if (ret < 0)
+            {
+              nerr("ERROR: Failed to create FIFO for %s: %d\n",
+                   conn->lc_path, ret);
+              return ret;
+            }
+
+          /* Open the receiving side of the transfer */
+
+          ret = local_open_receiver(conn, false);
+          if (ret < 0)
+            {
+              nerr("ERROR: Failed to open FIFO for %s: %d\n",
+                   conn->lc_path, ret);
+              local_release_halfduplex(conn);
+              return ret;
+            }
+        }
+
+      return file_poll(&conn->lc_infile, fds, true);
     }
 
 #ifdef CONFIG_NET_LOCAL_STREAM
@@ -310,7 +332,7 @@ int local_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds)
 
   if (conn->lc_proto == SOCK_DGRAM)
     {
-      return -ENOSYS;
+      return file_poll(&conn->lc_infile, fds, false);
     }
 
 #ifdef CONFIG_NET_LOCAL_STREAM

michallenc avatar Jun 27 '25 09:06 michallenc

@xiaoxiang781216 is @GUIDINGLI actively working on this? I would at least merge the conn->lc_infile.f_inode == NULL for now, to at least get datagrams working. Polling can be solved later.

michallenc avatar Jul 06 '25 17:07 michallenc

@michallenc Can you try this ? https://github.com/apache/nuttx/pull/16682

GUIDINGLI avatar Jul 07 '25 03:07 GUIDINGLI