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 <sys/param.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@ -39,6 +40,7 @@
#include <syslog.h> #include <syslog.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/un.h>
#include "sim_internal.h" #include "sim_internal.h"
#include "sim_hostusrsock.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, static int sockaddr_to_native(const struct nuttx_sockaddr *addr,
const nuttx_socklen_t addrlen, nuttx_socklen_t addrlen,
struct sockaddr *naddr, struct sockaddr_storage *naddr,
socklen_t *naddrlen) socklen_t *naddrlen)
{ {
naddr->sa_family = addr->sa_family; if (addr == NULL || naddr == NULL || naddrlen == NULL)
memcpy(naddr->sa_data, addr->sa_data, sizeof(naddr->sa_data)); {
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; *naddrlen = addrlen;
return 0;
} }
static void sockaddr_to_nuttx(const struct sockaddr *naddr, static int sockaddr_to_nuttx(const struct sockaddr_storage *naddr,
const socklen_t naddrlen, socklen_t naddrlen,
struct nuttx_sockaddr *addr, struct nuttx_sockaddr *addr,
nuttx_socklen_t *addrlen) nuttx_socklen_t *addrlen)
{ {
addr->sa_family = naddr->sa_family; if (naddr == NULL || addr == NULL || addrlen == NULL)
memcpy(addr->sa_data, naddr->sa_data, sizeof(addr->sa_data)); {
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; *addrlen = naddrlen;
return 0;
} }
static void sock_nonblock(int socket, int enable) 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 host_usrsock_socket(int domain, int type, int protocol)
{ {
int opt = 1; int opt = 1;
int sockflags = 0;
int ret; int ret;
if (domain == NUTTX_PF_INET) switch (domain)
{ {
domain = PF_INET; case NUTTX_PF_INET:
} domain = PF_INET;
else break;
{
return -EINVAL; #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; sockflags |= SOCK_NONBLOCK;
}
else
{
return -EINVAL;
} }
#endif
if (protocol == NUTTX_IPPROTO_IP) if (protocol == NUTTX_IPPROTO_IP)
{ {
@ -297,7 +401,7 @@ int host_usrsock_socket(int domain, int type, int protocol)
return -EINVAL; return -EINVAL;
} }
ret = socket(domain, type, protocol); ret = socket(domain, sockflags, protocol);
if (ret < 0) if (ret < 0)
{ {
return -errno; return -errno;
@ -327,17 +431,26 @@ int host_usrsock_connect(int sockfd,
const struct nuttx_sockaddr *addr, const struct nuttx_sockaddr *addr,
nuttx_socklen_t addrlen) nuttx_socklen_t addrlen)
{ {
struct sockaddr naddr; struct sockaddr_storage naddr;
socklen_t naddrlen; socklen_t naddrlen;
int ret; int ret;
sockaddr_to_native(addr, addrlen, &naddr, &naddrlen); ret = sockaddr_to_native(addr, addrlen, &naddr, &naddrlen);
sock_nonblock(sockfd, false);
ret = connect(sockfd, &naddr, naddrlen);
sock_nonblock(sockfd, true);
if (ret < 0) 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; return -errno;
} }
@ -351,14 +464,20 @@ ssize_t host_usrsock_sendto(int sockfd, const void *buf,
const struct nuttx_sockaddr *dest_addr, const struct nuttx_sockaddr *dest_addr,
nuttx_socklen_t addrlen) nuttx_socklen_t addrlen)
{ {
struct sockaddr naddr; struct sockaddr_storage naddr;
socklen_t naddrlen; socklen_t naddrlen;
int ret; int ret;
if (dest_addr && addrlen >= sizeof(*dest_addr)) if (dest_addr && addrlen >= sizeof(*dest_addr))
{ {
sockaddr_to_native(dest_addr, addrlen, &naddr, &naddrlen); ret = sockaddr_to_native(dest_addr, addrlen, &naddr, &naddrlen);
ret = sendto(sockfd, buf, len, flags, &naddr, naddrlen); if (ret < 0)
{
return ret;
}
ret = sendto(sockfd, buf, len, flags,
(struct sockaddr *)&naddr, naddrlen);
} }
else else
{ {
@ -384,14 +503,14 @@ ssize_t host_usrsock_recvfrom(int sockfd, void *buf, size_t len, int flags,
struct nuttx_sockaddr *src_addr, struct nuttx_sockaddr *src_addr,
nuttx_socklen_t *addrlen) nuttx_socklen_t *addrlen)
{ {
struct sockaddr naddr; struct sockaddr_storage naddr;
socklen_t naddrlen; socklen_t naddrlen = sizeof(naddr);
int ret; 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,
ret = recvfrom(sockfd, buf, len, flags, &naddr, &naddrlen); (struct sockaddr *)&naddr, &naddrlen);
} }
else else
{ {
@ -408,7 +527,7 @@ ssize_t host_usrsock_recvfrom(int sockfd, void *buf, size_t len, int flags,
return -errno; return -errno;
} }
if (src_addr && addrlen && *addrlen >= sizeof(*src_addr)) if (src_addr && addrlen)
{ {
sockaddr_to_nuttx(&naddr, naddrlen, 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, struct nuttx_sockaddr *addr,
nuttx_socklen_t *addrlen) nuttx_socklen_t *addrlen)
{ {
socklen_t naddrlen = sizeof(struct sockaddr); socklen_t naddrlen = sizeof(struct sockaddr_storage);
struct sockaddr naddr; struct sockaddr_storage naddr;
int ret; int ret;
ret = getsockname(sockfd, &naddr, &naddrlen); ret = getsockname(sockfd, (struct sockaddr *)&naddr, &naddrlen);
if (ret < 0) if (ret < 0)
{ {
return -errno; 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; return ret;
@ -458,19 +577,19 @@ int host_usrsock_getpeername(int sockfd,
struct nuttx_sockaddr *addr, struct nuttx_sockaddr *addr,
nuttx_socklen_t *addrlen) nuttx_socklen_t *addrlen)
{ {
socklen_t naddrlen = sizeof(struct sockaddr); socklen_t naddrlen = sizeof(struct sockaddr_storage);
struct sockaddr naddr; struct sockaddr_storage naddr;
int ret; int ret;
ret = getpeername(sockfd, &naddr, &naddrlen); ret = getpeername(sockfd, (struct sockaddr *)&naddr, &naddrlen);
if (ret < 0) if (ret < 0)
{ {
return -errno; 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; return ret;
@ -480,12 +599,17 @@ int host_usrsock_bind(int sockfd,
const struct nuttx_sockaddr *addr, const struct nuttx_sockaddr *addr,
nuttx_socklen_t addrlen) nuttx_socklen_t addrlen)
{ {
struct sockaddr naddr; struct sockaddr_storage naddr;
socklen_t naddrlen; 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) 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, int host_usrsock_accept(int sockfd, struct nuttx_sockaddr *addr,
nuttx_socklen_t *addrlen) nuttx_socklen_t *addrlen)
{ {
socklen_t naddrlen = sizeof(socklen_t); socklen_t naddrlen = sizeof(struct sockaddr_storage);
struct sockaddr naddr; struct sockaddr_storage naddr;
int ret; int ret;
ret = accept(sockfd, &naddr, &naddrlen); ret = accept(sockfd, (struct sockaddr *)&naddr, &naddrlen);
if (ret <= 0) if (ret < 0)
{ {
return -errno; return -errno;
} }
if (addr && addrlen && *addrlen >= sizeof(*addr)) if (addr && addrlen)
{ {
sockaddr_to_nuttx(&naddr, naddrlen, addr, addrlen); sockaddr_to_nuttx(&naddr, naddrlen, addr, addrlen);
} }
@ -562,7 +686,7 @@ void host_usrsock_loop(void)
int ret; int ret;
int i; int i;
if (g_active_maxfd <= 0) if (g_active_maxfd < 0)
{ {
return; return;
} }

View file

@ -83,6 +83,8 @@
#define NUTTX_PF_PKTRADIO 64 #define NUTTX_PF_PKTRADIO 64
#define NUTTX_PF_RPMSG 65 #define NUTTX_PF_RPMSG 65
#define NUTTX_UNIX_PATH_MAX 108
#define NUTTX_AF_UNSPEC NUTTX_PF_UNSPEC #define NUTTX_AF_UNSPEC NUTTX_PF_UNSPEC
#define NUTTX_AF_UNIX NUTTX_PF_UNIX #define NUTTX_AF_UNIX NUTTX_PF_UNIX
#define NUTTX_AF_LOCAL NUTTX_PF_LOCAL #define NUTTX_AF_LOCAL NUTTX_PF_LOCAL
@ -219,6 +221,12 @@ struct nuttx_sockaddr
char sa_data[14]; /* 14-bytes data (actually variable length) */ 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 struct nuttx_linger
{ {
int l_onoff; /* Indicates whether linger option is enabled. */ 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) static void sim_usrsock_work(void *arg)
{ {
host_usrsock_loop();
work_queue_next_wq(g_work_queue, &g_usrsock.work, sim_usrsock_work, work_queue_next_wq(g_work_queue, &g_usrsock.work, sim_usrsock_work,
NULL, SIM_USRSOCK_PERIOD); NULL, SIM_USRSOCK_PERIOD);
} }

View file

@ -103,10 +103,14 @@ static int usrsock_sockif_setup(FAR struct socket *psock)
int ret; int ret;
if (psock->s_domain != PF_INET && psock->s_domain != PF_INET6 && 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... /* Let the user socket logic handle the setup...
* *