net: Implement shutdown() for usrsock

Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
Zhe Weng 2023-01-29 12:32:19 +08:00 committed by Xiang Xiao
parent 8819eeaf15
commit d3dd349649
11 changed files with 318 additions and 8 deletions

View File

@ -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;

View File

@ -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__ */

View File

@ -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,
};
/****************************************************************************

View File

@ -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_)

View File

@ -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
*

View File

@ -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

View File

@ -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
*
****************************************************************************/

View File

@ -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

View File

@ -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
}

View File

@ -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 <nuttx/config.h>
#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK)
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <arch/irq.h>
#include <sys/socket.h>
#include <nuttx/net/net.h>
#include <nuttx/net/usrsock.h>
#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 */

View File

@ -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 */