From d3dd3496495d54de1bb9e8daf39828816e2c4f78 Mon Sep 17 00:00:00 2001 From: Zhe Weng Date: Sun, 29 Jan 2023 12:32:19 +0800 Subject: [PATCH] net: Implement shutdown() for usrsock Signed-off-by: Zhe Weng --- arch/sim/src/sim/posix/sim_hostusrsock.c | 20 +++ arch/sim/src/sim/sim_hostusrsock.h | 2 + arch/sim/src/sim/sim_usrsock.c | 10 ++ drivers/usrsock/usrsock_rpmsg_server.c | 21 +++ include/nuttx/net/net.h | 34 ++++ include/nuttx/net/usrsock.h | 9 ++ net/socket/shutdown.c | 15 +- net/usrsock/Make.defs | 2 +- net/usrsock/usrsock.h | 23 +++ net/usrsock/usrsock_shutdown.c | 188 +++++++++++++++++++++++ net/usrsock/usrsock_sockif.c | 2 +- 11 files changed, 318 insertions(+), 8 deletions(-) create mode 100644 net/usrsock/usrsock_shutdown.c diff --git a/arch/sim/src/sim/posix/sim_hostusrsock.c b/arch/sim/src/sim/posix/sim_hostusrsock.c index c4f452c508..3899990442 100644 --- a/arch/sim/src/sim/posix/sim_hostusrsock.c +++ b/arch/sim/src/sim/posix/sim_hostusrsock.c @@ -469,6 +469,26 @@ int host_usrsock_ioctl(int fd, unsigned long request, ...) return 0; } +int host_usrsock_shutdown(int sockfd, int how) +{ + switch (how) + { + case NUTTX_SHUT_RD: + how = SHUT_RD; + break; + case NUTTX_SHUT_WR: + how = SHUT_WR; + break; + case NUTTX_SHUT_RDWR: + how = SHUT_RDWR; + break; + default: + return -EINVAL; + } + + return shutdown(sockfd, how) < 0 ? -errno : 0; +} + void host_usrsock_loop(void) { struct timeval timeout; diff --git a/arch/sim/src/sim/sim_hostusrsock.h b/arch/sim/src/sim/sim_hostusrsock.h index fa1a58491d..bf51744020 100644 --- a/arch/sim/src/sim/sim_hostusrsock.h +++ b/arch/sim/src/sim/sim_hostusrsock.h @@ -285,6 +285,7 @@ int host_usrsock_listen(int sockfd, int backlog); int host_usrsock_accept(int sockfd, struct nuttx_sockaddr *addr, nuttx_socklen_t *addrlen); int host_usrsock_ioctl(int fd, unsigned long request, ...); +int host_usrsock_shutdown(int sockfd, int how); #else int host_usrsock_socket(int domain, int type, int protocol); int host_usrsock_close(int sockfd); @@ -311,6 +312,7 @@ int host_usrsock_listen(int sockfd, int backlog); int host_usrsock_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); int host_usrsock_ioctl(int fd, unsigned long request, ...); +int host_usrsock_shutdown(int sockfd, int how); void host_usrsock_loop(void); #endif /* __SIM__ */ diff --git a/arch/sim/src/sim/sim_usrsock.c b/arch/sim/src/sim/sim_usrsock.c index f297ae3aa7..3d5789674b 100644 --- a/arch/sim/src/sim/sim_usrsock.c +++ b/arch/sim/src/sim/sim_usrsock.c @@ -361,6 +361,15 @@ static int usrsock_ioctl_handler(struct usrsock_s *usrsock, req->arglen, req->arglen); } +static int usrsock_shutdown_handler(struct usrsock_s *usrsock, + const void *data, size_t len) +{ + const struct usrsock_request_shutdown_s *req = data; + int ret = host_usrsock_shutdown(req->usockid, req->how); + + return usrsock_send_ack(usrsock, req->head.xid, ret); +} + static const usrsock_handler_t g_usrsock_handler[] = { [USRSOCK_REQUEST_SOCKET] = usrsock_socket_handler, @@ -376,6 +385,7 @@ static const usrsock_handler_t g_usrsock_handler[] = [USRSOCK_REQUEST_LISTEN] = usrsock_listen_handler, [USRSOCK_REQUEST_ACCEPT] = usrsock_accept_handler, [USRSOCK_REQUEST_IOCTL] = usrsock_ioctl_handler, + [USRSOCK_REQUEST_SHUTDOWN] = usrsock_shutdown_handler, }; /**************************************************************************** diff --git a/drivers/usrsock/usrsock_rpmsg_server.c b/drivers/usrsock/usrsock_rpmsg_server.c index 7a56382349..d8e6270a9e 100644 --- a/drivers/usrsock/usrsock_rpmsg_server.c +++ b/drivers/usrsock/usrsock_rpmsg_server.c @@ -110,6 +110,9 @@ static int usrsock_rpmsg_accept_handler(FAR struct rpmsg_endpoint *ept, static int usrsock_rpmsg_ioctl_handler(FAR struct rpmsg_endpoint *ept, FAR void *data, size_t len, uint32_t src, FAR void *priv_); +static int usrsock_rpmsg_shutdown_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv_); static int usrsock_rpmsg_dns_handler(FAR struct rpmsg_endpoint *ept, FAR void *data, size_t len, uint32_t src, FAR void *priv_); @@ -148,6 +151,7 @@ static const rpmsg_ept_cb g_usrsock_rpmsg_handler[] = usrsock_rpmsg_listen_handler, usrsock_rpmsg_accept_handler, usrsock_rpmsg_ioctl_handler, + usrsock_rpmsg_shutdown_handler, usrsock_rpmsg_dns_handler, }; @@ -880,6 +884,23 @@ static int usrsock_rpmsg_ioctl_handler(FAR struct rpmsg_endpoint *ept, ack, 0, req->head.xid, ret, req->arglen, req->arglen, ret); } +static int usrsock_rpmsg_shutdown_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv_) +{ + FAR struct usrsock_request_shutdown_s *req = data; + FAR struct usrsock_rpmsg_s *priv = priv_; + int ret = -EBADF; + + if (req->usockid >= 0 && + req->usockid < CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS) + { + ret = psock_shutdown(&priv->socks[req->usockid], req->how); + } + + return usrsock_rpmsg_send_ack(ept, 0, req->head.xid, ret); +} + static int usrsock_rpmsg_dns_handler(FAR struct rpmsg_endpoint *ept, FAR void *data, size_t len, uint32_t src, FAR void *priv_) diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h index 84d19840e8..e4b915ef44 100644 --- a/include/nuttx/net/net.h +++ b/include/nuttx/net/net.h @@ -1269,6 +1269,40 @@ int psock_getpeername(FAR struct socket *psock, FAR struct sockaddr *addr, int psock_vioctl(FAR struct socket *psock, int cmd, va_list ap); int psock_ioctl(FAR struct socket *psock, int cmd, ...); +/**************************************************************************** + * Name: psock_shutdown + * + * Description: + * The shutdown() function will cause all or part of a full-duplex + * connection on the socket associated with the file descriptor socket to + * be shut down. + * + * The shutdown() function disables subsequent send and/or receive + * operations on a socket, depending on the value of the how argument. + * + * Input Parameters: + * sockfd - Specifies the file descriptor of the socket. + * how - Specifies the type of shutdown. The values are as follows: + * + * SHUT_RD - Disables further receive operations. + * SHUT_WR - Disables further send operations. + * SHUT_RDWR - Disables further send and receive operations. + * + * Returned Value: + * On success, returns the number of characters sent. On any failure, a + * negated errno value is returned. One of: + * + * EINVAL - The how argument is invalid. + * ENOTCONN - The socket is not connected. + * ENOTSOCK - The socket argument does not refer to a socket. + * ENOBUFS - Insufficient resources were available in the system to + * perform the operation. + * EOPNOTSUPP - The operation is not supported for this socket's protocol + * + ****************************************************************************/ + +int psock_shutdown(FAR struct socket *psock, int how); + /**************************************************************************** * Name: psock_poll * diff --git a/include/nuttx/net/usrsock.h b/include/nuttx/net/usrsock.h index 6942c7f86f..70e38e92ae 100644 --- a/include/nuttx/net/usrsock.h +++ b/include/nuttx/net/usrsock.h @@ -85,6 +85,7 @@ enum usrsock_request_types_e USRSOCK_REQUEST_LISTEN, USRSOCK_REQUEST_ACCEPT, USRSOCK_REQUEST_IOCTL, + USRSOCK_REQUEST_SHUTDOWN, USRSOCK_REQUEST__MAX }; @@ -219,6 +220,14 @@ begin_packed_struct struct usrsock_request_ioctl_s uint16_t arglen; } end_packed_struct; +begin_packed_struct struct usrsock_request_shutdown_s +{ + struct usrsock_request_common_s head; + + int16_t usockid; + int16_t how; +} end_packed_struct; + /* Response/event message structures (kernel <= /dev/usrsock <= daemon) */ begin_packed_struct struct usrsock_message_common_s diff --git a/net/socket/shutdown.c b/net/socket/shutdown.c index 74e536c42a..b0a75e7803 100644 --- a/net/socket/shutdown.c +++ b/net/socket/shutdown.c @@ -55,12 +55,15 @@ * SHUT_RDWR - Disables further send and receive operations. * * Returned Value: - * EINVAL - The how argument is invalid. - * ENOTCONN - The socket is not connected. - * ENOTSOCK - The socket argument does not refer to a socket. - * ENOBUFS - Insufficient resources were available in the system to - * perform the operation. - * EOPNOTSUPP - The operation is not supported for this socket's protocol. + * On success, returns the number of characters sent. On any failure, a + * negated errno value is returned. One of: + * + * EINVAL - The how argument is invalid. + * ENOTCONN - The socket is not connected. + * ENOTSOCK - The socket argument does not refer to a socket. + * ENOBUFS - Insufficient resources were available in the system to + * perform the operation. + * EOPNOTSUPP - The operation is not supported for this socket's protocol * ****************************************************************************/ diff --git a/net/usrsock/Make.defs b/net/usrsock/Make.defs index 8b0f5cda74..01402c83d2 100644 --- a/net/usrsock/Make.defs +++ b/net/usrsock/Make.defs @@ -23,7 +23,7 @@ ifeq ($(CONFIG_NET_USRSOCK),y) NET_CSRCS += usrsock_close.c usrsock_conn.c usrsock_bind.c usrsock_connect.c -NET_CSRCS += usrsock_getpeername.c usrsock_devif.c +NET_CSRCS += usrsock_getpeername.c usrsock_devif.c usrsock_shutdown.c NET_CSRCS += usrsock_event.c usrsock_getsockname.c usrsock_getsockopt.c NET_CSRCS += usrsock_poll.c usrsock_recvmsg.c usrsock_sendmsg.c NET_CSRCS += usrsock_setsockopt.c usrsock_socket.c usrsock_sockif.c diff --git a/net/usrsock/usrsock.h b/net/usrsock/usrsock.h index 313db6dfe9..8e9fdae651 100644 --- a/net/usrsock/usrsock.h +++ b/net/usrsock/usrsock.h @@ -642,6 +642,29 @@ int usrsock_getpeername(FAR struct socket *psock, int usrsock_ioctl(FAR struct socket *psock, int cmd, unsigned long arg); +/**************************************************************************** + * Name: usrsock_shutdown + * + * Description: + * The shutdown() function will cause all or part of a full-duplex + * connection on the socket associated with the file descriptor socket to + * be shut down. + * + * The shutdown() function disables subsequent send and/or receive + * operations on a socket, depending on the value of the how argument. + * + * Input Parameters: + * psock A reference to the socket structure of the socket + * how Specifies the type of shutdown. The values are as follows: + * + * SHUT_RD - Disables further receive operations. + * SHUT_WR - Disables further send operations. + * SHUT_RDWR - Disables further send and receive operations. + * + ****************************************************************************/ + +int usrsock_shutdown(FAR struct socket *psock, int how); + #undef EXTERN #ifdef __cplusplus } diff --git a/net/usrsock/usrsock_shutdown.c b/net/usrsock/usrsock_shutdown.c new file mode 100644 index 0000000000..94feb3b3e0 --- /dev/null +++ b/net/usrsock/usrsock_shutdown.c @@ -0,0 +1,188 @@ +/**************************************************************************** + * net/usrsock/usrsock_shutdown.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 +#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK) + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "usrsock/usrsock.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint16_t shutdown_event(FAR struct net_driver_s *dev, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct usrsock_reqstate_s *pstate = pvpriv; + FAR struct usrsock_conn_s *conn = pstate->conn; + + if (flags & USRSOCK_EVENT_ABORT) + { + ninfo("socket aborted.\n"); + + pstate->result = -ECONNABORTED; + + /* Stop further callbacks */ + + pstate->cb->flags = 0; + pstate->cb->priv = NULL; + pstate->cb->event = NULL; + + /* Wake up the waiting thread */ + + nxsem_post(&pstate->recvsem); + } + else if (flags & USRSOCK_EVENT_REQ_COMPLETE) + { + ninfo("request completed.\n"); + + pstate->result = conn->resp.result; + + /* Stop further callbacks */ + + pstate->cb->flags = 0; + pstate->cb->priv = NULL; + pstate->cb->event = NULL; + + /* Wake up the waiting thread */ + + nxsem_post(&pstate->recvsem); + } + + return flags; +} + +/**************************************************************************** + * Name: do_shutdown_request + ****************************************************************************/ + +static int do_shutdown_request(FAR struct usrsock_conn_s *conn, int how) +{ + struct usrsock_request_shutdown_s req = + { + }; + + struct iovec bufs[1]; + + /* Prepare request for daemon to read. */ + + req.head.reqid = USRSOCK_REQUEST_SHUTDOWN; + req.usockid = conn->usockid; + req.how = how; + + bufs[0].iov_base = (FAR void *)&req; + bufs[0].iov_len = sizeof(req); + + return usrsock_do_request(conn, bufs, ARRAY_SIZE(bufs)); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: usrsock_shutdown + * + * Description: + * The shutdown() function will cause all or part of a full-duplex + * connection on the socket associated with the file descriptor socket to + * be shut down. + * + * The shutdown() function disables subsequent send and/or receive + * operations on a socket, depending on the value of the how argument. + * + * Input Parameters: + * psock A reference to the socket structure of the socket + * how Specifies the type of shutdown. The values are as follows: + * + * SHUT_RD - Disables further receive operations. + * SHUT_WR - Disables further send operations. + * SHUT_RDWR - Disables further send and receive operations. + * + ****************************************************************************/ + +int usrsock_shutdown(FAR struct socket *psock, int how) +{ + FAR struct usrsock_conn_s *conn = psock->s_conn; + struct usrsock_reqstate_s state = + { + }; + + int ret; + + net_lock(); + + if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED || + conn->state == USRSOCK_CONN_STATE_ABORTED) + { + /* Already closed? */ + + ninfo("usockid=%d; already closed.\n", conn->usockid); + + ret = OK; + goto errout; + } + + /* Set up event callback for usrsock. */ + + ret = usrsock_setup_request_callback(conn, &state, shutdown_event, + USRSOCK_EVENT_ABORT | + USRSOCK_EVENT_REQ_COMPLETE); + if (ret < 0) + { + nwarn("usrsock_setup_request_callback failed: %d\n", ret); + goto errout; + } + + /* Request user-space daemon to shutdown socket. */ + + ret = do_shutdown_request(conn, how); + if (ret >= 0) + { + /* Wait for completion of request. */ + + net_sem_wait_uninterruptible(&state.recvsem); + ret = state.result; + } + + usrsock_teardown_request_callback(&state); + +errout: + net_unlock(); + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */ diff --git a/net/usrsock/usrsock_sockif.c b/net/usrsock/usrsock_sockif.c index 7eb32f01a1..1ec7467fd3 100644 --- a/net/usrsock/usrsock_sockif.c +++ b/net/usrsock/usrsock_sockif.c @@ -68,7 +68,7 @@ const struct sock_intf_s g_usrsock_sockif = usrsock_sockif_close, /* si_close */ usrsock_ioctl, /* si_ioctl */ NULL, /* si_socketpair */ - NULL /* si_shutdown */ + usrsock_shutdown /* si_shutdown */ #ifdef CONFIG_NET_SOCKOPTS , usrsock_getsockopt /* si_getsockopt */ , usrsock_setsockopt /* si_setsockopt */