From b90d0941380512ce81f36fb4ad68288dafa3e772 Mon Sep 17 00:00:00 2001 From: "chao.an" Date: Sun, 29 Aug 2021 17:52:02 +0800 Subject: [PATCH] arch/sim: add native socket support based on usrsock Signed-off-by: chao.an --- arch/sim/Kconfig | 17 +- arch/sim/src/Makefile | 5 + arch/sim/src/nuttx-names.in | 9 + arch/sim/src/sim/up_idle.c | 4 + arch/sim/src/sim/up_initialize.c | 6 + arch/sim/src/sim/up_internal.h | 7 + arch/sim/src/sim/up_usrsock.c | 443 +++++++++++++++++++++++++ arch/sim/src/sim/up_usrsock_host.c | 515 +++++++++++++++++++++++++++++ arch/sim/src/sim/up_usrsock_host.h | 317 ++++++++++++++++++ 9 files changed, 1321 insertions(+), 2 deletions(-) create mode 100644 arch/sim/src/sim/up_usrsock.c create mode 100644 arch/sim/src/sim/up_usrsock_host.c create mode 100644 arch/sim/src/sim/up_usrsock_host.h diff --git a/arch/sim/Kconfig b/arch/sim/Kconfig index 5cc6a33e12..ea2d9629b6 100644 --- a/arch/sim/Kconfig +++ b/arch/sim/Kconfig @@ -127,15 +127,28 @@ config SIM_WALLTIME_SIGNAL endchoice +choice + prompt "Simulated Network Interface" + default SIM_NETDEV + depends on NET + optional + config SIM_NETDEV bool "Simulated Network Device" - default y select ARCH_HAVE_NETDEV_STATISTICS select SCHED_LPWORK - depends on NET_ETHERNET + select NET_ETHERNET ---help--- Build in support for a simulated network device. +config SIM_NETUSRSOCK + bool "Simulated Network Device with Native Stack via usrsock" + select NET_USRSOCK + ---help--- + Built-in support for a simulated network device using native stack via usrsock + +endchoice + if SIM_NETDEV choice diff --git a/arch/sim/src/Makefile b/arch/sim/src/Makefile index a10611462b..71a8c4c921 100644 --- a/arch/sim/src/Makefile +++ b/arch/sim/src/Makefile @@ -170,6 +170,11 @@ else ifeq ($(CONFIG_SIM_NETDEV_VPNKIT),y) HOSTSRCS += protocol.c negotiate.c endif +ifeq ($(CONFIG_SIM_NETUSRSOCK),y) + HOSTSRCS += up_usrsock_host.c + CSRCS += up_usrsock.c +endif + ifeq ($(CONFIG_SIM_HCISOCKET),y) HOSTSRCS += up_hcisocket_host.c CSRCS += up_hcisocket.c diff --git a/arch/sim/src/nuttx-names.in b/arch/sim/src/nuttx-names.in index 4b576d208c..2c43b3a0bf 100644 --- a/arch/sim/src/nuttx-names.in +++ b/arch/sim/src/nuttx-names.in @@ -31,6 +31,7 @@ #endif NXSYMBOLS(__cxa_atexit) +NXSYMBOLS(accept) NXSYMBOLS(atexit) NXSYMBOLS(bind) NXSYMBOLS(calloc) @@ -45,13 +46,18 @@ NXSYMBOLS(dup) NXSYMBOLS(exit) NXSYMBOLS(fchmod) NXSYMBOLS(fchown) +NXSYMBOLS(fcntl) NXSYMBOLS(free) NXSYMBOLS(fstat) NXSYMBOLS(fsync) NXSYMBOLS(ftruncate) NXSYMBOLS(futimens) +NXSYMBOLS(getpeername) +NXSYMBOLS(getsockname) +NXSYMBOLS(getsockopt) NXSYMBOLS(if_nametoindex) NXSYMBOLS(ioctl) +NXSYMBOLS(listen) NXSYMBOLS(longjmp) NXSYMBOLS(lseek) NXSYMBOLS(malloc) @@ -87,14 +93,17 @@ NXSYMBOLS(read) NXSYMBOLS(readdir) NXSYMBOLS(readv) NXSYMBOLS(realloc) +NXSYMBOLS(recvfrom) NXSYMBOLS(rename) NXSYMBOLS(rewinddir) NXSYMBOLS(rmdir) NXSYMBOLS(sched_yield) NXSYMBOLS(select) NXSYMBOLS(sendmsg) +NXSYMBOLS(sendto) NXSYMBOLS(setitimer) NXSYMBOLS(setjmp) +NXSYMBOLS(setsockopt) NXSYMBOLS(shutdown) NXSYMBOLS(sigaction) NXSYMBOLS(sigaddset) diff --git a/arch/sim/src/sim/up_idle.c b/arch/sim/src/sim/up_idle.c index be6628730f..abd80f673a 100644 --- a/arch/sim/src/sim/up_idle.c +++ b/arch/sim/src/sim/up_idle.c @@ -90,6 +90,10 @@ void up_idle(void) netdriver_loop(); #endif +#ifdef CONFIG_SIM_NETUSRSOCK + usrsock_loop(); +#endif + #ifdef CONFIG_RPTUN up_rptun_loop(); #endif diff --git a/arch/sim/src/sim/up_initialize.c b/arch/sim/src/sim/up_initialize.c index ea5f0312bf..1af2c6a7e8 100644 --- a/arch/sim/src/sim/up_initialize.c +++ b/arch/sim/src/sim/up_initialize.c @@ -246,6 +246,12 @@ void up_initialize(void) netdriver_init(); /* Our "real" network driver */ #endif +#ifdef CONFIG_SIM_NETUSRSOCK + /* Register the usrsock native socket device */ + + usrsock_init(); +#endif + #ifdef CONFIG_NET_LOOPBACK /* Initialize the local loopback device */ diff --git a/arch/sim/src/sim/up_internal.h b/arch/sim/src/sim/up_internal.h index f8ef29cef1..c2ae3e2510 100644 --- a/arch/sim/src/sim/up_internal.h +++ b/arch/sim/src/sim/up_internal.h @@ -316,6 +316,13 @@ void netdriver_setmacaddr(unsigned char *macaddr); void netdriver_setmtu(int mtu); void netdriver_loop(void); +/* up_usrsock.c *************************************************************/ + +#ifdef CONFIG_SIM_NETUSRSOCK +int usrsock_init(void); +void usrsock_loop(void); +#endif + /* up_rptun.c ***************************************************************/ #ifdef CONFIG_RPTUN diff --git a/arch/sim/src/sim/up_usrsock.c b/arch/sim/src/sim/up_usrsock.c new file mode 100644 index 0000000000..5cd018569f --- /dev/null +++ b/arch/sim/src/sim/up_usrsock.c @@ -0,0 +1,443 @@ +/**************************************************************************** + * arch/sim/src/sim/up_usrsock.c + * + * 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 + +#include +#include +#include +#include +#include + +#include +#include + +#include "up_usrsock_host.h" + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +struct usrsock_s +{ + struct file usock; + uint8_t data[4096]; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +typedef int (*usrsock_handler_t)(FAR struct usrsock_s *usrsock, + FAR const void *data, size_t len); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct usrsock_s g_usrsock; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int usrsock_send(FAR struct usrsock_s *usrsock, + FAR const void *buf, size_t len) +{ + FAR uint8_t *data = (FAR uint8_t *)buf; + ssize_t ret; + + while (len > 0) + { + ret = file_write(&usrsock->usock, data, len); + if (ret < 0) + { + return ret; + } + + data += ret; + len -= ret; + } + + return 0; +} + +static int usrsock_send_ack(FAR struct usrsock_s *usrsock, + uint8_t xid, int32_t result) +{ + struct usrsock_message_req_ack_s ack; + + ack.head.msgid = USRSOCK_MESSAGE_RESPONSE_ACK; + ack.head.flags = (result == -EINPROGRESS); + + ack.xid = xid; + ack.result = result; + + return usrsock_send(usrsock, &ack, sizeof(ack)); +} + +static int usrsock_send_dack(FAR struct usrsock_s *usrsock, + FAR struct usrsock_message_datareq_ack_s *ack, + uint8_t xid, int32_t result, + uint16_t valuelen, + uint16_t valuelen_nontrunc) +{ + ack->reqack.head.msgid = USRSOCK_MESSAGE_RESPONSE_DATA_ACK; + ack->reqack.head.flags = 0; + + ack->reqack.xid = xid; + ack->reqack.result = result; + + if (result < 0) + { + result = 0; + valuelen = 0; + valuelen_nontrunc = 0; + } + else if (valuelen > valuelen_nontrunc) + { + valuelen = valuelen_nontrunc; + } + + ack->valuelen = valuelen; + ack->valuelen_nontrunc = valuelen_nontrunc; + + return usrsock_send(usrsock, ack, sizeof(*ack) + valuelen + result); +} + +static int usrsock_send_event(FAR struct usrsock_s *usrsock, + int16_t usockid, uint16_t events) +{ + struct usrsock_message_socket_event_s event; + + event.head.msgid = USRSOCK_MESSAGE_SOCKET_EVENT; + event.head.flags = USRSOCK_MESSAGE_FLAG_EVENT; + + event.usockid = usockid; + event.events = events; + + return usrsock_send(usrsock, &event, sizeof(event)); +} + +static int usrsock_socket_handler(FAR struct usrsock_s *usrsock, + FAR const void *data, size_t len) +{ + FAR const struct usrsock_request_socket_s *req = data; + int fd = usrsock_host_socket(req->domain, req->type, req->protocol); + + usrsock_send_ack(usrsock, req->head.xid, fd); + if (fd > 0) + { + usrsock_send_event(usrsock, fd, USRSOCK_EVENT_SENDTO_READY); + } + + return fd; +} + +static int usrsock_close_handler(FAR struct usrsock_s *usrsock, + FAR const void *data, size_t len) +{ + FAR const struct usrsock_request_close_s *req = data; + int ret = usrsock_host_close(req->usockid); + + return usrsock_send_ack(usrsock, req->head.xid, ret); +} + +static int usrsock_connect_handler(FAR struct usrsock_s *usrsock, + FAR const void *data, size_t len) +{ + FAR const struct usrsock_request_connect_s *req = data; + int ret = usrsock_host_connect(req->usockid, + (FAR const struct sockaddr *)(req + 1), + req->addrlen); + + return usrsock_send_ack(usrsock, req->head.xid, ret); +} + +static int usrsock_sendto_handler(FAR struct usrsock_s *usrsock, + FAR const void *data, size_t len) +{ + FAR const struct usrsock_request_sendto_s *req = data; + int ret = usrsock_host_sendto(req->usockid, + (FAR const void *)(req + 1) + req->addrlen, + req->buflen, req->flags, + req->addrlen ? + (FAR const struct sockaddr *)(req + 1) : + NULL, req->addrlen); + + usrsock_send_ack(usrsock, req->head.xid, ret); + if (ret > 0) + { + ret = usrsock_send_event(usrsock, req->usockid, + USRSOCK_EVENT_SENDTO_READY); + } + + return ret; +} + +static int usrsock_recvfrom_handler(FAR struct usrsock_s *usrsock, + FAR const void *data, size_t len) +{ + FAR const struct usrsock_request_recvfrom_s *req = data; + FAR struct usrsock_message_datareq_ack_s *ack; + socklen_t outaddrlen = req->max_addrlen; + socklen_t inaddrlen = req->max_addrlen; + size_t buflen = req->max_buflen; + int ret; + + ack = (struct usrsock_message_datareq_ack_s *)usrsock->data; + if (sizeof(*ack) + inaddrlen + buflen > sizeof(usrsock->data)) + { + buflen = sizeof(usrsock->data) - sizeof(*ack) - inaddrlen; + } + + ret = usrsock_host_recvfrom(req->usockid, + (FAR void *)(ack + 1) + inaddrlen, + buflen, req->flags, + outaddrlen ? + (FAR struct sockaddr *)(ack + 1) : NULL, + outaddrlen ? &outaddrlen : NULL); + if (ret > 0 && outaddrlen < inaddrlen) + { + memcpy((FAR void *)(ack + 1) + outaddrlen, + (FAR void *)(ack + 1) + inaddrlen, ret); + } + + return usrsock_send_dack(usrsock, ack, req->head.xid, + ret, inaddrlen, outaddrlen); +} + +static int usrsock_setsockopt_handler(FAR struct usrsock_s *usrsock, + FAR const void *data, size_t len) +{ + FAR const struct usrsock_request_setsockopt_s *req = data; + int ret = usrsock_host_setsockopt(req->usockid, req->level, + req->option, req + 1, req->valuelen); + + return usrsock_send_ack(usrsock, req->head.xid, ret); +} + +static int usrsock_getsockopt_handler(FAR struct usrsock_s *usrsock, + FAR const void *data, size_t len) +{ + FAR const struct usrsock_request_getsockopt_s *req = data; + FAR struct usrsock_message_datareq_ack_s *ack; + socklen_t optlen = req->max_valuelen; + int ret; + + ack = (FAR struct usrsock_message_datareq_ack_s *)usrsock->data; + ret = usrsock_host_getsockopt(req->usockid, + req->level, req->option, + ack + 1, &optlen); + + return usrsock_send_dack(usrsock, ack, req->head.xid, + ret, optlen, optlen); +} + +static int usrsock_getsockname_handler(FAR struct usrsock_s *usrsock, + FAR const void *data, size_t len) +{ + FAR const struct usrsock_request_getsockname_s *req = data; + FAR struct usrsock_message_datareq_ack_s *ack; + socklen_t outaddrlen = req->max_addrlen; + socklen_t inaddrlen = req->max_addrlen; + int ret; + + ack = (FAR struct usrsock_message_datareq_ack_s *)usrsock->data; + ret = usrsock_host_getsockname(req->usockid, + (FAR struct sockaddr *)(ack + 1), &outaddrlen); + + return usrsock_send_dack(usrsock, ack, req->head.xid, + ret, inaddrlen, outaddrlen); +} + +static int usrsock_getpeername_handler(FAR struct usrsock_s *usrsock, + FAR const void *data, size_t len) +{ + FAR const struct usrsock_request_getpeername_s *req = data; + FAR struct usrsock_message_datareq_ack_s *ack; + socklen_t outaddrlen = req->max_addrlen; + socklen_t inaddrlen = req->max_addrlen; + int ret; + + ack = (FAR struct usrsock_message_datareq_ack_s *)usrsock->data; + ret = usrsock_host_getpeername(req->usockid, + (FAR struct sockaddr *)(ack + 1), &outaddrlen); + + return usrsock_send_dack(usrsock, ack, req->head.xid, + ret, inaddrlen, outaddrlen); +} + +static int usrsock_bind_handler(FAR struct usrsock_s *usrsock, + FAR const void *data, size_t len) +{ + FAR const struct usrsock_request_bind_s *req = data; + int ret = usrsock_host_bind(req->usockid, + (FAR const struct sockaddr *)(req + 1), + req->addrlen); + + return usrsock_send_ack(usrsock, req->head.xid, ret); +} + +static int usrsock_listen_handler(FAR struct usrsock_s *usrsock, + FAR const void *data, size_t len) +{ + FAR const struct usrsock_request_listen_s *req = data; + int ret = usrsock_host_listen(req->usockid, req->backlog); + + return usrsock_send_ack(usrsock, req->head.xid, ret); +} + +static int usrsock_accept_handler(FAR struct usrsock_s *usrsock, + FAR const void *data, size_t len) +{ + FAR const struct usrsock_request_accept_s *req = data; + FAR struct usrsock_message_datareq_ack_s *ack; + socklen_t outaddrlen = req->max_addrlen; + socklen_t inaddrlen = req->max_addrlen; + int sockfd; + int ret; + + ack = (FAR struct usrsock_message_datareq_ack_s *)usrsock->data; + sockfd = usrsock_host_accept(req->usockid, + outaddrlen ? + (FAR struct sockaddr *)(ack + 1) : NULL, + outaddrlen ? &outaddrlen : NULL); + if (sockfd > 0) + { + /* Append index as usockid to the payload */ + + if (outaddrlen <= inaddrlen) + { + *(FAR int16_t *)((FAR void *)(ack + 1) + outaddrlen) = sockfd; + } + else + { + *(FAR int16_t *)((FAR void *)(ack + 1) + inaddrlen) = sockfd; + } + + ret = sizeof(int16_t); /* Return usockid size */ + } + else + { + ret = sockfd; + } + + usrsock_send_dack(usrsock, ack, req->head.xid, ret, + inaddrlen, outaddrlen); + if (ret > 0) + { + usrsock_send_event(usrsock, sockfd, USRSOCK_EVENT_SENDTO_READY); + } + + return ret; +} + +static int usrsock_ioctl_handler(FAR struct usrsock_s *usrsock, + FAR const void *data, size_t len) +{ + FAR const struct usrsock_request_ioctl_s *req = data; + FAR struct usrsock_message_datareq_ack_s *ack; + int ret; + + ack = (FAR struct usrsock_message_datareq_ack_s *)usrsock->data; + memcpy(ack + 1, req + 1, req->arglen); + ret = usrsock_host_ioctl(req->usockid, req->cmd, + (unsigned long)(ack + 1)); + + return usrsock_send_dack(usrsock, ack, req->head.xid, ret, + req->arglen, req->arglen); +} + +static const usrsock_handler_t g_usrsock_handler[] = +{ + [USRSOCK_REQUEST_SOCKET] = usrsock_socket_handler, + [USRSOCK_REQUEST_CLOSE] = usrsock_close_handler, + [USRSOCK_REQUEST_CONNECT] = usrsock_connect_handler, + [USRSOCK_REQUEST_SENDTO] = usrsock_sendto_handler, + [USRSOCK_REQUEST_RECVFROM] = usrsock_recvfrom_handler, + [USRSOCK_REQUEST_SETSOCKOPT] = usrsock_setsockopt_handler, + [USRSOCK_REQUEST_GETSOCKOPT] = usrsock_getsockopt_handler, + [USRSOCK_REQUEST_GETSOCKNAME] = usrsock_getsockname_handler, + [USRSOCK_REQUEST_GETPEERNAME] = usrsock_getpeername_handler, + [USRSOCK_REQUEST_BIND] = usrsock_bind_handler, + [USRSOCK_REQUEST_LISTEN] = usrsock_listen_handler, + [USRSOCK_REQUEST_ACCEPT] = usrsock_accept_handler, + [USRSOCK_REQUEST_IOCTL] = usrsock_ioctl_handler, +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int usrsock_event_callback(int16_t usockid, uint16_t events) +{ + return usrsock_send_event(&g_usrsock, usockid, events); +} + +int usrsock_init(void) +{ + return file_open(&g_usrsock.usock, "/dev/usrsock", O_RDWR); +} + +void usrsock_loop(void) +{ + FAR struct usrsock_request_common_s *common; + uint8_t data[4096]; + int ret; + struct pollfd pfd = + { + .ptr = &g_usrsock.usock, + .events = POLLIN | POLLFILE, + }; + + ret = poll(&pfd, 1, 0); + if (ret > 0) + { + ret = file_read(&g_usrsock.usock, data, sizeof(data)); + if (ret > 0) + { + common = (FAR struct usrsock_request_common_s *)data; + + if (common->reqid >= 0 && + common->reqid < USRSOCK_REQUEST__MAX) + { + ret = g_usrsock_handler[common->reqid](&g_usrsock, + data, ret); + if (ret < 0) + { + syslog(LOG_ERR, "Usrsock request %d failed: %d\n", + common->reqid, ret); + } + } + else + { + syslog(LOG_ERR, "Invalid request id: %d\n", + common->reqid); + } + } + } + + usrsock_host_loop(); +} diff --git a/arch/sim/src/sim/up_usrsock_host.c b/arch/sim/src/sim/up_usrsock_host.c new file mode 100644 index 0000000000..d6428fc399 --- /dev/null +++ b/arch/sim/src/sim/up_usrsock_host.c @@ -0,0 +1,515 @@ +/**************************************************************************** + * arch/sim/src/sim/up_usrsock_host.c + * + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "up_usrsock_host.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static int g_active_maxfd = -1; +static fd_set g_active_read_fds; +static fd_set g_active_write_fds; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void usrsock_host_clear_fd(int fd, fd_set *fds) +{ + if (FD_ISSET(fd, fds)) + { + FD_CLR(fd, fds); + + if (fd == g_active_maxfd) + { + while (fd--) + { + if (FD_ISSET(fd, &g_active_read_fds)) + { + break; + } + else if (FD_ISSET(fd, &g_active_write_fds)) + { + break; + } + } + + g_active_maxfd = fd; + } + } +} + +static void usrsock_host_set_fd(int fd, fd_set *fds) +{ + if (!FD_ISSET(fd, fds)) + { + FD_SET(fd, fds); + if (fd > g_active_maxfd) + { + g_active_maxfd = fd; + } + } +} + +static void sockaddr_to_native(const struct nuttx_sockaddr *addr, + const nuttx_socklen_t addrlen, + struct sockaddr *naddr, + socklen_t *naddrlen) +{ + naddr->sa_family = addr->sa_family; + memcpy(naddr->sa_data, addr->sa_data, sizeof(naddr->sa_data)); + + *naddrlen = addrlen; +} + +static void sockaddr_to_nuttx(const struct sockaddr *naddr, + const 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)); + + *addrlen = naddrlen; +} + +static void sock_nonblock(int socket, int enable) +{ + if (enable) + { + fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK); + } + else + { + fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) & ~O_NONBLOCK); + } +} + +static int usrsock_host_sockopt(int sockfd, int level, int optname, + const void *optval, nuttx_socklen_t *optlen, + bool set) +{ + int ret = -EINVAL; + + if (level == NUTTX_SOL_SOCKET) + { + level = SOL_SOCKET; + } + else if (level == NUTTX_IPPROTO_TCP) + { + level = IPPROTO_TCP; + } + else if (level == NUTTX_IPPROTO_UDP) + { + level = IPPROTO_UDP; + } + else if (level == NUTTX_IPPROTO_IP) + { + level = IPPROTO_IP; + } + else + { + return ret; + } + + if (optname == NUTTX_SO_REUSEADDR) + { + optname = SO_REUSEADDR; + } + else if (optname == NUTTX_SO_ERROR) + { + optname = SO_ERROR; + } + else + { + syslog(LOG_ERR, "Invalid optname: %x\n", optname); + return ret; + } + + if (set) + { + ret = setsockopt(sockfd, level, optname, optval, *optlen); + } + else + { + ret = getsockopt(sockfd, level, optname, (void *)optval, optlen); + } + + return ret < 0 ? -errno : 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int usrsock_host_socket(int domain, int type, int protocol) +{ + int ret; + + if (domain == NUTTX_PF_INET) + { + domain = PF_INET; + } + else + { + return -EINVAL; + } + + if (type == NUTTX_SOCK_STREAM) + { + type = SOCK_STREAM; + } + else if (type == NUTTX_SOCK_DGRAM) + { + type = SOCK_DGRAM; + } + else + { + return -EINVAL; + } + + if (protocol == NUTTX_IPPROTO_IP) + { + protocol = IPPROTO_IP; + } + else if (protocol == NUTTX_IPPROTO_ICMP) + { + protocol = IPPROTO_ICMP; + } + else if (protocol == NUTTX_IPPROTO_TCP) + { + protocol = IPPROTO_TCP; + } + else if (protocol == NUTTX_IPPROTO_UDP) + { + protocol = IPPROTO_UDP; + } + else + { + return -EINVAL; + } + + ret = socket(domain, type, protocol); + if (ret < 0) + { + return -errno; + } + + sock_nonblock(ret, true); + usrsock_host_set_fd(ret, &g_active_read_fds); + + return ret; +} + +int usrsock_host_close(int sockfd) +{ + usrsock_host_clear_fd(sockfd, &g_active_read_fds); + usrsock_host_clear_fd(sockfd, &g_active_write_fds); + + return close(sockfd); +} + +int usrsock_host_connect(int sockfd, + const struct nuttx_sockaddr *addr, + nuttx_socklen_t addrlen) +{ + struct sockaddr 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); + if (ret < 0) + { + return -errno; + } + + usrsock_host_set_fd(sockfd, &g_active_read_fds); + + return ret; +} + +ssize_t usrsock_host_sendto(int sockfd, const void *buf, + size_t len, int flags, + const struct nuttx_sockaddr *dest_addr, + nuttx_socklen_t addrlen) +{ + struct sockaddr 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); + } + else + { + ret = sendto(sockfd, buf, len, flags, NULL, 0); + } + + if (ret < 0) + { + if (errno == EAGAIN) + { + usrsock_host_set_fd(sockfd, &g_active_write_fds); + } + else + { + usrsock_event_callback(sockfd, NUTTX_USRSOCK_EVENT_REMOTE_CLOSED); + } + } + + return ret >= 0 ? ret : -errno; +} + +ssize_t usrsock_host_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; + int ret; + + if (src_addr && addrlen && *addrlen >= sizeof(*src_addr)) + { + sockaddr_to_native(src_addr, *addrlen, &naddr, &naddrlen); + ret = recvfrom(sockfd, buf, len, flags, &naddr, &naddrlen); + } + else + { + ret = recvfrom(sockfd, buf, len, flags, NULL, NULL); + } + + if (ret <= 0) + { + if (ret == 0 || errno != EAGAIN) + { + usrsock_event_callback(sockfd, NUTTX_USRSOCK_EVENT_REMOTE_CLOSED); + } + + return -errno; + } + + if (src_addr && addrlen && *addrlen >= sizeof(*src_addr)) + { + sockaddr_to_nuttx(&naddr, naddrlen, src_addr, addrlen); + } + + usrsock_host_set_fd(sockfd, &g_active_read_fds); + + return ret; +} + +int usrsock_host_setsockopt(int sockfd, int level, int optname, + const void *optval, nuttx_socklen_t optlen) +{ + return usrsock_host_sockopt(sockfd, level, optname, + optval, &optlen, true); +} + +int usrsock_host_getsockopt(int sockfd, int level, int optname, + void *optval, nuttx_socklen_t *optlen) +{ + return usrsock_host_sockopt(sockfd, level, optname, + optval, optlen, false); +} + +int usrsock_host_getsockname(int sockfd, + struct nuttx_sockaddr *addr, + nuttx_socklen_t *addrlen) +{ + socklen_t naddrlen = sizeof(struct sockaddr); + struct sockaddr naddr; + int ret; + + ret = getsockname(sockfd, &naddr, &naddrlen); + if (ret < 0) + { + return -errno; + } + + if (addr && addrlen && *addrlen >= sizeof(*addr)) + { + sockaddr_to_nuttx(&naddr, naddrlen, addr, addrlen); + } + + return ret; +} + +int usrsock_host_getpeername(int sockfd, + struct nuttx_sockaddr *addr, + nuttx_socklen_t *addrlen) +{ + socklen_t naddrlen = sizeof(struct sockaddr); + struct sockaddr naddr; + int ret; + + ret = getpeername(sockfd, &naddr, &naddrlen); + if (ret < 0) + { + return -errno; + } + + if (addr && addrlen && *addrlen >= sizeof(*addr)) + { + sockaddr_to_nuttx(&naddr, naddrlen, addr, addrlen); + } + + return ret; +} + +int usrsock_host_bind(int sockfd, + const struct nuttx_sockaddr *addr, + nuttx_socklen_t addrlen) +{ + struct sockaddr naddr; + socklen_t naddrlen; + + sockaddr_to_native(addr, addrlen, &naddr, &naddrlen); + + return bind(sockfd, &naddr, naddrlen) < 0 ? -errno : 0; +} + +int usrsock_host_listen(int sockfd, int backlog) +{ + int ret; + + ret = listen(sockfd, backlog); + if (ret < 0) + { + return -errno; + } + + usrsock_host_set_fd(sockfd, &g_active_read_fds); + + return ret; +} + +int usrsock_host_accept(int sockfd, struct nuttx_sockaddr *addr, + nuttx_socklen_t *addrlen) +{ + struct sockaddr naddr; + socklen_t naddrlen; + int ret; + + ret = accept(sockfd, &naddr, &naddrlen); + if (ret <= 0) + { + return -errno; + } + + if (addr && addrlen && *addrlen >= sizeof(*addr)) + { + sockaddr_to_nuttx(&naddr, naddrlen, addr, addrlen); + } + + sock_nonblock(ret, true); + usrsock_host_set_fd(ret, &g_active_read_fds); + usrsock_host_set_fd(sockfd, &g_active_read_fds); + + return ret; +} + +int usrsock_host_ioctl(int fd, unsigned long request, ...) +{ + return 0; +} + +void usrsock_host_loop(void) +{ + struct timeval timeout; + fd_set write_fds; + fd_set read_fds; + uint16_t events; + int ret; + int i; + + if (g_active_maxfd <= 0) + { + return; + } + + memset(&timeout, 0x0, sizeof(timeout)); + memcpy(&read_fds, &g_active_read_fds, sizeof(read_fds)); + memcpy(&write_fds, &g_active_write_fds, sizeof(write_fds)); + + ret = select(g_active_maxfd + 1, &read_fds, &write_fds, NULL, &timeout); + if (ret == 0) + { + return; + } + + for (i = 0; i <= g_active_maxfd; i++) + { + events = 0; + + if (FD_ISSET(i, &read_fds)) + { + usrsock_host_clear_fd(i, &g_active_read_fds); + events |= NUTTX_USRSOCK_EVENT_RECVFROM_AVAIL; + } + + if (FD_ISSET(i, &write_fds)) + { + usrsock_host_clear_fd(i, &g_active_write_fds); + events |= NUTTX_USRSOCK_EVENT_SENDTO_READY; + } + + if (events) + { + usrsock_event_callback(i, events); + + if (--ret == 0) + { + break; + } + } + } +} diff --git a/arch/sim/src/sim/up_usrsock_host.h b/arch/sim/src/sim/up_usrsock_host.h new file mode 100644 index 0000000000..1374d2cdd2 --- /dev/null +++ b/arch/sim/src/sim/up_usrsock_host.h @@ -0,0 +1,317 @@ +/**************************************************************************** + * arch/sim/src/sim/up_usrsock_host.h + * + * 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 __ARCH_SIM_SRC_SIM_UP_USRSOCK_HOST_H +#define __ARCH_SIM_SRC_SIM_UP_USRSOCK_HOST_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#ifndef __SIM__ +# include +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef __SIM__ + +#define NUTTX_IPPROTO_IP 0 +#define NUTTX_IPPROTO_HOPOPTS 0 +#define NUTTX_IPPROTO_ICMP 1 +#define NUTTX_IPPROTO_IGMP 2 +#define NUTTX_IPPROTO_IPIP 4 +#define NUTTX_IPPROTO_TCP 6 +#define NUTTX_IPPROTO_EGP 8 +#define NUTTX_IPPROTO_PUP 12 +#define NUTTX_IPPROTO_UDP 17 +#define NUTTX_IPPROTO_IDP 22 +#define NUTTX_IPPROTO_TP 29 +#define NUTTX_IPPROTO_DCCP 33 +#define NUTTX_IPPROTO_IPV6 41 +#define NUTTX_IPPROTO_ROUTING 43 +#define NUTTX_IPPROTO_FRAGMENT 44 +#define NUTTX_IPPROTO_RSVP 46 +#define NUTTX_IPPROTO_GRE 47 +#define NUTTX_IPPROTO_ESP 50 +#define NUTTX_IPPROTO_AH 51 +#define NUTTX_IPPROTO_ICMP6 58 +#define NUTTX_IPPROTO_NONE 59 +#define NUTTX_IPPROTO_DSTOPTS 60 +#define NUTTX_IPPROTO_MTP 92 +#define NUTTX_IPPROTO_ENCAP 98 +#define NUTTX_IPPROTO_BEETPH 94 +#define NUTTX_IPPROTO_PIM 103 +#define NUTTX_IPPROTO_COMP 108 +#define NUTTX_IPPROTO_SCTP 132 +#define NUTTX_IPPROTO_UDPLITE 136 +#define NUTTX_IPPROTO_MPLS 137 +#define NUTTX_IPPROTO_RAW 255 + +#define NUTTX_PF_UNSPEC 0 +#define NUTTX_PF_UNIX 1 +#define NUTTX_PF_LOCAL 1 +#define NUTTX_PF_INET 2 +#define NUTTX_PF_INET6 10 +#define NUTTX_PF_NETLINK 16 +#define NUTTX_PF_ROUTE NUTTX_PF_NETLINK +#define NUTTX_PF_PACKET 17 +#define NUTTX_PF_CAN 29 +#define NUTTX_PF_BLUETOOTH 31 +#define NUTTX_PF_IEEE802154 36 +#define NUTTX_PF_PKTRADIO 64 +#define NUTTX_PF_RPMSG 65 + +#define NUTTX_AF_UNSPEC NUTTX_PF_UNSPEC +#define NUTTX_AF_UNIX NUTTX_PF_UNIX +#define NUTTX_AF_LOCAL NUTTX_PF_LOCAL +#define NUTTX_AF_INET NUTTX_PF_INET +#define NUTTX_AF_INET6 NUTTX_PF_INET6 +#define NUTTX_AF_NETLINK NUTTX_PF_NETLINK +#define NUTTX_AF_ROUTE NUTTX_PF_ROUTE +#define NUTTX_AF_PACKET NUTTX_PF_PACKET +#define NUTTX_AF_CAN NUTTX_PF_CAN +#define NUTTX_AF_BLUETOOTH NUTTX_PF_BLUETOOTH +#define NUTTX_AF_IEEE802154 NUTTX_PF_IEEE802154 +#define NUTTX_AF_PKTRADIO NUTTX_PF_PKTRADIO +#define NUTTX_AF_RPMSG NUTTX_PF_RPMSG + +#define NUTTX_SOCK_UNSPEC 0 +#define NUTTX_SOCK_STREAM 1 +#define NUTTX_SOCK_DGRAM 2 +#define NUTTX_SOCK_RAW 3 +#define NUTTX_SOCK_RDM 4 +#define NUTTX_SOCK_SEQPACKET 5 +#define NUTTX_SOCK_PACKET 10 +#define NUTTX_SOCK_CLOEXEC 02000000 +#define NUTTX_SOCK_NONBLOCK 00004000 + +#define NUTTX_SOCK_MAX (NUTTX_SOCK_PACKET + 1) +#define NUTTX_SOCK_TYPE_MASK 0xf + +#define NUTTX_MSG_OOB 0x0001 +#define NUTTX_MSG_PEEK 0x0002 +#define NUTTX_MSG_DONTROUTE 0x0004 +#define NUTTX_MSG_CTRUNC 0x0008 +#define NUTTX_MSG_PROXY 0x0010 +#define NUTTX_MSG_TRUNC 0x0020 +#define NUTTX_MSG_DONTWAIT 0x0040 +#define NUTTX_MSG_EOR 0x0080 +#define NUTTX_MSG_WAITALL 0x0100 +#define NUTTX_MSG_FIN 0x0200 +#define NUTTX_MSG_SYN 0x0400 +#define NUTTX_MSG_CONFIRM 0x0800 +#define NUTTX_MSG_RST 0x1000 +#define NUTTX_MSG_ERRQUEUE 0x2000 +#define NUTTX_MSG_NOSIGNAL 0x4000 +#define NUTTX_MSG_MORE 0x8000 + +#define NUTTX_SOL_SOCKET 1 +#define NUTTX_SO_ACCEPTCONN 0 +#define NUTTX_SO_BROADCAST 1 +#define NUTTX_SO_DEBUG 2 +#define NUTTX_SO_DONTROUTE 3 +#define NUTTX_SO_ERROR 4 +#define NUTTX_SO_KEEPALIVE 5 +#define NUTTX_SO_LINGER 6 +#define NUTTX_SO_OOBINLINE 7 +#define NUTTX_SO_RCVBUF 8 +#define NUTTX_SO_RCVLOWAT 9 +#define NUTTX_SO_RCVTIMEO 10 +#define NUTTX_SO_REUSEADDR 11 +#define NUTTX_SO_SNDBUF 12 +#define NUTTX_SO_SNDLOWAT 13 +#define NUTTX_SO_SNDTIMEO 14 +#define NUTTX_SO_TYPE 15 +#define NUTTX_SO_TIMESTAMP 16 + +#define NUTTX_SO_SNDBUFFORCE 32 +#define NUTTX_SO_RCVBUFFORCE 33 +#define NUTTX_SO_RXQ_OVFL 40 + +#define NUTTX_SOL_IP NUTTX_IPPROTO_IP +#define NUTTX_SOL_IPV6 NUTTX_IPPROTO_IPV6 +#define NUTTX_SOL_TCP NUTTX_IPPROTO_TCP +#define NUTTX_SOL_UDP NUTTX_IPPROTO_UDP + +#define NUTTX_SOL_HCI 0 +#define NUTTX_SOL_L2CAP 6 +#define NUTTX_SOL_SCO 17 +#define NUTTX_SOL_RFCOMM 18 + +#define NUTTX___SO_PROTOCOL 16 + +#define NUTTX_SHUT_RD 1 +#define NUTTX_SHUT_WR 2 +#define NUTTX_SHUT_RDWR 3 + +#define NUTTX_SCM_RIGHTS 0x01 +#define NUTTX_SCM_CREDENTIALS 0x02 +#define NUTTX_SCM_SECURITY 0x03 + +#define NUTTX_IP_MULTICAST_IF (NUTTX__SO_PROTOCOL + 1) +#define NUTTX_IP_MULTICAST_TTL (NUTTX__SO_PROTOCOL + 2) +#define NUTTX_IP_MULTICAST_LOOP (NUTTX__SO_PROTOCOL + 3) +#define NUTTX_IP_ADD_MEMBERSHIP (NUTTX__SO_PROTOCOL + 4) +#define NUTTX_IP_DROP_MEMBERSHIP (NUTTX__SO_PROTOCOL + 5) +#define NUTTX_IP_UNBLOCK_SOURCE (NUTTX__SO_PROTOCOL + 6) +#define NUTTX_IP_BLOCK_SOURCE (NUTTX__SO_PROTOCOL + 7) +#define NUTTX_IP_ADD_SOURCE_MEMBERSHIP (NUTTX__SO_PROTOCOL + 8) +#define NUTTX_IP_DROP_SOURCE_MEMBERSHIP (NUTTX__SO_PROTOCOL + 9) +#define NUTTX_IP_MSFILTER (NUTTX__SO_PROTOCOL + 10) +#define NUTTX_IP_MULTICAST_ALL (NUTTX__SO_PROTOCOL + 11) +#define NUTTX_IP_PKTINFO (NUTTX__SO_PROTOCOL + 12) +#define NUTTX_IP_TOS (NUTTX__SO_PROTOCOL + 13) +#define NUTTX_IP_TTL (NUTTX__SO_PROTOCOL + 14) + +/* Event message flags */ + +#define NUTTX_USRSOCK_EVENT_ABORT (1 << 1) +#define NUTTX_USRSOCK_EVENT_SENDTO_READY (1 << 2) +#define NUTTX_USRSOCK_EVENT_RECVFROM_AVAIL (1 << 3) +#define NUTTX_USRSOCK_EVENT_REMOTE_CLOSED (1 << 4) + +/**************************************************************************** + * Type Definitions + ****************************************************************************/ + +typedef unsigned int nuttx_socklen_t; + +#ifdef CONFIG_NET_IPv6 +struct nuttx_sockaddr_storage +{ + sa_family_t ss_family; /* Address family */ + char ss_data[26]; /* 26-bytes of address data */ +}; +#else +struct nuttx_sockaddr_storage +{ + sa_family_t ss_family; /* Address family */ + char ss_data[14]; /* 14-bytes of address data */ +}; +#endif + +struct nuttx_sockaddr +{ + sa_family_t sa_family; /* Address family: See AF_* definitions */ + char sa_data[14]; /* 14-bytes data (actually variable length) */ +}; + +struct nuttx_linger +{ + int l_onoff; /* Indicates whether linger option is enabled. */ + int l_linger; /* Linger time, in seconds. */ +}; + +struct nuttx_iovec +{ + void *iov_base; /* Base address of I/O memory region */ + size_t iov_len; /* Size of the memory pointed to by iov_base */ +}; + +struct nuttx_msghdr +{ + void *msg_name; /* Socket name */ + socklen_t msg_namelen; /* Length of name */ + struct nuttx_iovec *msg_iov; /* Data blocks */ + unsigned long msg_iovlen; /* Number of blocks */ + void *msg_control; /* Per protocol magic + * (eg BSD file descriptor passing) + */ + unsigned long msg_controllen; /* Length of cmsg list */ + unsigned int msg_flags; +}; + +struct nuttx_cmsghdr +{ + unsigned long cmsg_len; /* Data byte count, including hdr */ + int cmsg_level; /* Originating protocol */ + int cmsg_type; /* Protocol-specific type */ +}; + +#endif /* __SIM__ */ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __SIM__ +int usrsock_event_callback(int16_t usockid, uint16_t events); + +int usrsock_host_socket(int domain, int type, int protocol); +int usrsock_host_close(int sockfd); +int usrsock_host_connect(int sockfd, const struct nuttx_sockaddr *addr, + nuttx_socklen_t addrlen); +ssize_t usrsock_host_sendto(int sockfd, const void *buf, size_t len, + int flags, + const struct nuttx_sockaddr *dest_addr, + nuttx_socklen_t addrlen); +ssize_t usrsock_host_recvfrom(int sockfd, void *buf, size_t len, int flags, + struct nuttx_sockaddr *src_addr, + nuttx_socklen_t *addrlen); +int usrsock_host_setsockopt(int sockfd, int level, int optname, + const void *optval, nuttx_socklen_t optlen); +int usrsock_host_getsockopt(int sockfd, int level, int optname, + void *optval, nuttx_socklen_t *optlen); +int usrsock_host_getsockname(int sockfd, + struct nuttx_sockaddr *addr, + nuttx_socklen_t *addrlen); +int usrsock_host_getpeername(int sockfd, + struct nuttx_sockaddr *addr, + nuttx_socklen_t *addrlen); +int usrsock_host_bind(int sockfd, const struct nuttx_sockaddr *addr, + nuttx_socklen_t addrlen); +int usrsock_host_listen(int sockfd, int backlog); +int usrsock_host_accept(int sockfd, struct nuttx_sockaddr *addr, + nuttx_socklen_t *addrlen); +int usrsock_host_ioctl(int fd, unsigned long request, ...); +#else +int usrsock_host_socket(int domain, int type, int protocol); +int usrsock_host_close(int sockfd); +int usrsock_host_connect(int sockfd, const struct sockaddr *addr, + socklen_t addrlen); +ssize_t usrsock_host_sendto(int sockfd, const void *buf, size_t len, + int flags, + const struct sockaddr *dest_addr, + socklen_t addrlen); +ssize_t usrsock_host_recvfrom(int sockfd, void *buf, size_t len, int flags, + struct sockaddr *src_addr, + socklen_t *addrlen); +int usrsock_host_setsockopt(int sockfd, int level, int optname, + const void *optval, socklen_t optlen); +int usrsock_host_getsockopt(int sockfd, int level, int optname, + void *optval, socklen_t *optlen); +int usrsock_host_getsockname(int sockfd, struct sockaddr *addr, + socklen_t *addrlen); +int usrsock_host_getpeername(int sockfd, struct sockaddr *addr, + socklen_t *addrlen); +int usrsock_host_bind(int sockfd, const struct sockaddr *addr, + socklen_t addrlen); +int usrsock_host_listen(int sockfd, int backlog); +int usrsock_host_accept(int sockfd, struct sockaddr *addr, + socklen_t *addrlen); +int usrsock_host_ioctl(int fd, unsigned long request, ...); + +void usrsock_host_loop(void); +#endif /* __SIM__ */ + +#endif /* __ARCH_SIM_SRC_SIM_UP_USRSOCK_HOST_H */