arch/sim: Add AF_LOCAL support to host usrsock

The sim host usrsock backend only accepted INET/NETLINK domains and
translated socket addresses through plain struct sockaddr. That prevents
simulated applications from using POSIX AF_LOCAL sockets through the
standard socket API when CONFIG_NET_USRSOCK is used.

Add AF_LOCAL address conversion for struct sockaddr_un, allow PF_LOCAL
sockets through usrsock, handle NuttX socket type flags, and poll host
descriptors from the sim usrsock work item so nonblocking
connect/read/write readiness is reported back to NuttX. Use
sockaddr_storage for native address translation so larger address
structures are not truncated.

Testing:

  - Host: Ubuntu 22.04 x86_64.

  - Board/config: sim:nsh with CONFIG_NET_USRSOCK=y and
    CONFIG_EXAMPLES_HELLO=y.

  - make clean && make -j16.

  - Ran a temporary hello example that connected to host AF_UNIX
    SOCK_STREAM and SOCK_SEQPACKET sockets through NuttX socket(),
    connect(), write(), and read(). Both received pong and printed
    "AF_LOCAL usrsock test passed".

Assisted-by: Claude:Claude-Fable-5
Signed-off-by: Lingao Meng <menglingao@xiaomi.com>
This commit is contained in:
Lingao Meng 2026-07-16 15:14:59 +08:00 committed by Xiang Xiao
parent e84259cbcc
commit 3d20844903
4 changed files with 203 additions and 66 deletions

View file

@ -31,6 +31,7 @@
#include <sys/param.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@ -39,6 +40,7 @@
#include <syslog.h>
#include <netinet/in.h>
#include <sys/un.h>
#include "sim_internal.h"
#include "sim_hostusrsock.h"
@ -92,26 +94,93 @@ static void host_usrsock_set_fd(int fd, fd_set *fds)
}
}
static void sockaddr_to_native(const struct nuttx_sockaddr *addr,
const nuttx_socklen_t addrlen,
struct sockaddr *naddr,
socklen_t *naddrlen)
static int sockaddr_to_native(const struct nuttx_sockaddr *addr,
nuttx_socklen_t addrlen,
struct sockaddr_storage *naddr,
socklen_t *naddrlen)
{
naddr->sa_family = addr->sa_family;
memcpy(naddr->sa_data, addr->sa_data, sizeof(naddr->sa_data));
if (addr == NULL || naddr == NULL || naddrlen == NULL)
{
return -EINVAL;
}
memset(naddr, 0, sizeof(*naddr));
if (addr->sa_family == NUTTX_AF_LOCAL)
{
const struct nuttx_sockaddr_un *un =
(const struct nuttx_sockaddr_un *)addr;
struct sockaddr_un *native = (struct sockaddr_un *)naddr;
size_t pathlen;
if (addrlen < offsetof(struct nuttx_sockaddr_un, sun_path) + 1)
{
return -EINVAL;
}
pathlen = strnlen(un->sun_path, sizeof(un->sun_path));
if (pathlen >= sizeof(native->sun_path))
{
return -ENAMETOOLONG;
}
native->sun_family = AF_UNIX;
memcpy(native->sun_path, un->sun_path, pathlen + 1);
*naddrlen = offsetof(struct sockaddr_un, sun_path) + pathlen + 1;
return 0;
}
if (addrlen > sizeof(*naddr))
{
return -ENOSPC;
}
memcpy(naddr, addr, addrlen);
*naddrlen = addrlen;
return 0;
}
static void sockaddr_to_nuttx(const struct sockaddr *naddr,
const socklen_t naddrlen,
struct nuttx_sockaddr *addr,
nuttx_socklen_t *addrlen)
static int sockaddr_to_nuttx(const struct sockaddr_storage *naddr,
socklen_t naddrlen,
struct nuttx_sockaddr *addr,
nuttx_socklen_t *addrlen)
{
addr->sa_family = naddr->sa_family;
memcpy(addr->sa_data, naddr->sa_data, sizeof(addr->sa_data));
if (naddr == NULL || addr == NULL || addrlen == NULL)
{
return -EINVAL;
}
if (naddr->ss_family == AF_UNIX)
{
const struct sockaddr_un *native = (const struct sockaddr_un *)naddr;
struct nuttx_sockaddr_un *un = (struct nuttx_sockaddr_un *)addr;
size_t pathlen;
if (*addrlen < sizeof(*un))
{
return -ENOSPC;
}
memset(un, 0, sizeof(*un));
pathlen = strnlen(native->sun_path, sizeof(native->sun_path));
un->sun_family = NUTTX_AF_LOCAL;
memcpy(un->sun_path, native->sun_path, pathlen);
*addrlen = offsetof(struct nuttx_sockaddr_un, sun_path) + pathlen + 1;
return 0;
}
if (*addrlen < naddrlen)
{
return -ENOSPC;
}
memcpy(addr, naddr, naddrlen);
*addrlen = naddrlen;
return 0;
}
static void sock_nonblock(int socket, int enable)
@ -248,33 +317,68 @@ static int host_usrsock_sockopt(int sockfd, int level, int optname,
int host_usrsock_socket(int domain, int type, int protocol)
{
int opt = 1;
int sockflags = 0;
int ret;
if (domain == NUTTX_PF_INET)
switch (domain)
{
domain = PF_INET;
}
else
{
return -EINVAL;
case NUTTX_PF_INET:
domain = PF_INET;
break;
#ifdef CONFIG_NET_IPv6
case NUTTX_PF_INET6:
domain = PF_INET6;
break;
#endif
case NUTTX_PF_LOCAL:
domain = PF_UNIX;
break;
default:
return -EINVAL;
}
if (type == NUTTX_SOCK_STREAM)
switch (type & NUTTX_SOCK_TYPE_MASK)
{
type = SOCK_STREAM;
case NUTTX_SOCK_STREAM:
sockflags = SOCK_STREAM;
break;
case NUTTX_SOCK_DGRAM:
sockflags = SOCK_DGRAM;
break;
case NUTTX_SOCK_RAW:
sockflags = SOCK_RAW;
break;
case NUTTX_SOCK_SEQPACKET:
#ifdef SOCK_SEQPACKET
sockflags = SOCK_SEQPACKET;
break;
#else
return -EPROTONOSUPPORT;
#endif
default:
return -EINVAL;
}
else if (type == NUTTX_SOCK_DGRAM)
#ifdef SOCK_CLOEXEC
if ((type & NUTTX_SOCK_CLOEXEC) != 0)
{
type = SOCK_DGRAM;
sockflags |= SOCK_CLOEXEC;
}
else if (type == NUTTX_SOCK_RAW)
#endif
#ifdef SOCK_NONBLOCK
if ((type & NUTTX_SOCK_NONBLOCK) != 0)
{
type = SOCK_RAW;
}
else
{
return -EINVAL;
sockflags |= SOCK_NONBLOCK;
}
#endif
if (protocol == NUTTX_IPPROTO_IP)
{
@ -297,7 +401,7 @@ int host_usrsock_socket(int domain, int type, int protocol)
return -EINVAL;
}
ret = socket(domain, type, protocol);
ret = socket(domain, sockflags, protocol);
if (ret < 0)
{
return -errno;
@ -327,17 +431,26 @@ int host_usrsock_connect(int sockfd,
const struct nuttx_sockaddr *addr,
nuttx_socklen_t addrlen)
{
struct sockaddr naddr;
struct sockaddr_storage naddr;
socklen_t naddrlen;
int ret;
sockaddr_to_native(addr, addrlen, &naddr, &naddrlen);
sock_nonblock(sockfd, false);
ret = connect(sockfd, &naddr, naddrlen);
sock_nonblock(sockfd, true);
ret = sockaddr_to_native(addr, addrlen, &naddr, &naddrlen);
if (ret < 0)
{
return ret;
}
ret = connect(sockfd, (struct sockaddr *)&naddr, naddrlen);
if (ret < 0)
{
if (errno == EINPROGRESS || errno == EALREADY || errno == EWOULDBLOCK)
{
host_usrsock_set_fd(sockfd, &g_active_write_fds);
host_usrsock_set_fd(sockfd, &g_active_read_fds);
return -EINPROGRESS;
}
return -errno;
}
@ -351,14 +464,20 @@ ssize_t host_usrsock_sendto(int sockfd, const void *buf,
const struct nuttx_sockaddr *dest_addr,
nuttx_socklen_t addrlen)
{
struct sockaddr naddr;
struct sockaddr_storage naddr;
socklen_t naddrlen;
int ret;
if (dest_addr && addrlen >= sizeof(*dest_addr))
{
sockaddr_to_native(dest_addr, addrlen, &naddr, &naddrlen);
ret = sendto(sockfd, buf, len, flags, &naddr, naddrlen);
ret = sockaddr_to_native(dest_addr, addrlen, &naddr, &naddrlen);
if (ret < 0)
{
return ret;
}
ret = sendto(sockfd, buf, len, flags,
(struct sockaddr *)&naddr, naddrlen);
}
else
{
@ -384,14 +503,14 @@ ssize_t host_usrsock_recvfrom(int sockfd, void *buf, size_t len, int flags,
struct nuttx_sockaddr *src_addr,
nuttx_socklen_t *addrlen)
{
struct sockaddr naddr;
socklen_t naddrlen;
struct sockaddr_storage naddr;
socklen_t naddrlen = sizeof(naddr);
int ret;
if (src_addr && addrlen && *addrlen >= sizeof(*src_addr))
if (src_addr && addrlen)
{
sockaddr_to_native(src_addr, *addrlen, &naddr, &naddrlen);
ret = recvfrom(sockfd, buf, len, flags, &naddr, &naddrlen);
ret = recvfrom(sockfd, buf, len, flags,
(struct sockaddr *)&naddr, &naddrlen);
}
else
{
@ -408,7 +527,7 @@ ssize_t host_usrsock_recvfrom(int sockfd, void *buf, size_t len, int flags,
return -errno;
}
if (src_addr && addrlen && *addrlen >= sizeof(*src_addr))
if (src_addr && addrlen)
{
sockaddr_to_nuttx(&naddr, naddrlen, src_addr, addrlen);
}
@ -436,19 +555,19 @@ int host_usrsock_getsockname(int sockfd,
struct nuttx_sockaddr *addr,
nuttx_socklen_t *addrlen)
{
socklen_t naddrlen = sizeof(struct sockaddr);
struct sockaddr naddr;
socklen_t naddrlen = sizeof(struct sockaddr_storage);
struct sockaddr_storage naddr;
int ret;
ret = getsockname(sockfd, &naddr, &naddrlen);
ret = getsockname(sockfd, (struct sockaddr *)&naddr, &naddrlen);
if (ret < 0)
{
return -errno;
}
if (addr && addrlen && *addrlen >= sizeof(*addr))
if (addr && addrlen)
{
sockaddr_to_nuttx(&naddr, naddrlen, addr, addrlen);
ret = sockaddr_to_nuttx(&naddr, naddrlen, addr, addrlen);
}
return ret;
@ -458,19 +577,19 @@ int host_usrsock_getpeername(int sockfd,
struct nuttx_sockaddr *addr,
nuttx_socklen_t *addrlen)
{
socklen_t naddrlen = sizeof(struct sockaddr);
struct sockaddr naddr;
socklen_t naddrlen = sizeof(struct sockaddr_storage);
struct sockaddr_storage naddr;
int ret;
ret = getpeername(sockfd, &naddr, &naddrlen);
ret = getpeername(sockfd, (struct sockaddr *)&naddr, &naddrlen);
if (ret < 0)
{
return -errno;
}
if (addr && addrlen && *addrlen >= sizeof(*addr))
if (addr && addrlen)
{
sockaddr_to_nuttx(&naddr, naddrlen, addr, addrlen);
ret = sockaddr_to_nuttx(&naddr, naddrlen, addr, addrlen);
}
return ret;
@ -480,12 +599,17 @@ int host_usrsock_bind(int sockfd,
const struct nuttx_sockaddr *addr,
nuttx_socklen_t addrlen)
{
struct sockaddr naddr;
struct sockaddr_storage naddr;
socklen_t naddrlen;
int ret;
sockaddr_to_native(addr, addrlen, &naddr, &naddrlen);
ret = sockaddr_to_native(addr, addrlen, &naddr, &naddrlen);
if (ret < 0)
{
return ret;
}
return bind(sockfd, &naddr, naddrlen) < 0 ? -errno : 0;
return bind(sockfd, (struct sockaddr *)&naddr, naddrlen) < 0 ? -errno : 0;
}
int host_usrsock_listen(int sockfd, int backlog)
@ -506,17 +630,17 @@ int host_usrsock_listen(int sockfd, int backlog)
int host_usrsock_accept(int sockfd, struct nuttx_sockaddr *addr,
nuttx_socklen_t *addrlen)
{
socklen_t naddrlen = sizeof(socklen_t);
struct sockaddr naddr;
socklen_t naddrlen = sizeof(struct sockaddr_storage);
struct sockaddr_storage naddr;
int ret;
ret = accept(sockfd, &naddr, &naddrlen);
if (ret <= 0)
ret = accept(sockfd, (struct sockaddr *)&naddr, &naddrlen);
if (ret < 0)
{
return -errno;
}
if (addr && addrlen && *addrlen >= sizeof(*addr))
if (addr && addrlen)
{
sockaddr_to_nuttx(&naddr, naddrlen, addr, addrlen);
}
@ -562,7 +686,7 @@ void host_usrsock_loop(void)
int ret;
int i;
if (g_active_maxfd <= 0)
if (g_active_maxfd < 0)
{
return;
}

View file

@ -83,6 +83,8 @@
#define NUTTX_PF_PKTRADIO 64
#define NUTTX_PF_RPMSG 65
#define NUTTX_UNIX_PATH_MAX 108
#define NUTTX_AF_UNSPEC NUTTX_PF_UNSPEC
#define NUTTX_AF_UNIX NUTTX_PF_UNIX
#define NUTTX_AF_LOCAL NUTTX_PF_LOCAL
@ -219,6 +221,12 @@ struct nuttx_sockaddr
char sa_data[14]; /* 14-bytes data (actually variable length) */
};
struct nuttx_sockaddr_un
{
sa_family_t sun_family; /* Address family: AF_LOCAL */
char sun_path[NUTTX_UNIX_PATH_MAX];
};
struct nuttx_linger
{
int l_onoff; /* Indicates whether linger option is enabled. */

View file

@ -415,6 +415,7 @@ static const usrsock_handler_t g_usrsock_handler[] =
static void sim_usrsock_work(void *arg)
{
host_usrsock_loop();
work_queue_next_wq(g_work_queue, &g_usrsock.work, sim_usrsock_work,
NULL, SIM_USRSOCK_PERIOD);
}

View file

@ -103,10 +103,14 @@ static int usrsock_sockif_setup(FAR struct socket *psock)
int ret;
if (psock->s_domain != PF_INET && psock->s_domain != PF_INET6 &&
psock->s_domain != PF_NETLINK)
psock->s_domain != PF_NETLINK
#ifndef CONFIG_NET_LOCAL
&& psock->s_domain != PF_LOCAL
#endif
)
{
return -ENOTSUP; /* Only ipv4, ipv6 and netlink support the offload */
};
return -ENOTSUP; /* Only supported families can use usrsock offload */
}
/* Let the user socket logic handle the setup...
*