mirror of
https://github.com/apache/nuttx.git
synced 2026-08-01 20:28:58 +00:00
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:
parent
e84259cbcc
commit
3d20844903
4 changed files with 203 additions and 66 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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...
|
||||
*
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue