net: Implement shutdown() interface and tcp shutdown

Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
Zhe Weng 2023-01-18 18:28:32 +08:00 committed by Xiang Xiao
parent fcdba7a3ef
commit 8819eeaf15
14 changed files with 413 additions and 82 deletions

View File

@ -167,6 +167,7 @@ struct sock_intf_s
CODE int (*si_ioctl)(FAR struct socket *psock, CODE int (*si_ioctl)(FAR struct socket *psock,
int cmd, unsigned long arg); int cmd, unsigned long arg);
CODE int (*si_socketpair)(FAR struct socket *psocks[2]); CODE int (*si_socketpair)(FAR struct socket *psocks[2]);
CODE int (*si_shutdown)(FAR struct socket *psock, int how);
#ifdef CONFIG_NET_SOCKOPTS #ifdef CONFIG_NET_SOCKOPTS
CODE int (*si_getsockopt)(FAR struct socket *psock, int level, CODE int (*si_getsockopt)(FAR struct socket *psock, int level,
int option, FAR void *value, FAR socklen_t *value_len); int option, FAR void *value, FAR socklen_t *value_len);

View File

@ -366,6 +366,7 @@ SYSCALL_LOOKUP(munmap, 2)
SYSCALL_LOOKUP(sendto, 6) SYSCALL_LOOKUP(sendto, 6)
SYSCALL_LOOKUP(sendmsg, 3) SYSCALL_LOOKUP(sendmsg, 3)
SYSCALL_LOOKUP(setsockopt, 5) SYSCALL_LOOKUP(setsockopt, 5)
SYSCALL_LOOKUP(shutdown, 2)
SYSCALL_LOOKUP(socket, 3) SYSCALL_LOOKUP(socket, 3)
SYSCALL_LOOKUP(socketpair, 4) SYSCALL_LOOKUP(socketpair, 4)
#endif #endif

View File

@ -26,7 +26,7 @@ CSRCS += lib_inetntop.c lib_inetpton.c lib_inetnetwork.c
CSRCS += lib_etherntoa.c lib_etheraton.c CSRCS += lib_etherntoa.c lib_etheraton.c
ifeq ($(CONFIG_NET),y) ifeq ($(CONFIG_NET),y)
CSRCS += lib_accept.c lib_shutdown.c CSRCS += lib_accept.c
endif endif
ifeq ($(CONFIG_NET_LOOPBACK),y) ifeq ($(CONFIG_NET_LOOPBACK),y)

View File

@ -1,74 +0,0 @@
/****************************************************************************
* libs/libc/net/lib_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>
#include <sys/socket.h>
#ifdef CONFIG_NET
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: 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:
* Upon successful completion, shutdown() will return 0; otherwise, -1 will
* be returned and errno set to indicate the error.
*
* EBADF - The socket argument is not a valid file descriptor.
* 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.
*
****************************************************************************/
int shutdown(int sockfd, int how)
{
/* REVISIT: Not implemented. */
return OK;
}
#endif /* CONFIG_NET */

View File

@ -86,7 +86,8 @@ const struct sock_intf_s g_can_sockif =
can_recvmsg, /* si_recvmsg */ can_recvmsg, /* si_recvmsg */
can_close, /* si_close */ can_close, /* si_close */
NULL, /* si_ioctl */ NULL, /* si_ioctl */
NULL /* si_socketpair */ NULL, /* si_socketpair */
NULL /* si_shutdown */
#if defined(CONFIG_NET_SOCKOPTS) && defined(CONFIG_NET_CANPROTO_OPTIONS) #if defined(CONFIG_NET_SOCKOPTS) && defined(CONFIG_NET_CANPROTO_OPTIONS)
, can_getsockopt /* si_getsockopt */ , can_getsockopt /* si_getsockopt */
, can_setsockopt /* si_setsockopt */ , can_setsockopt /* si_setsockopt */

View File

@ -91,6 +91,7 @@ static ssize_t inet_recvmsg(FAR struct socket *psock,
static int inet_ioctl(FAR struct socket *psock, static int inet_ioctl(FAR struct socket *psock,
int cmd, unsigned long arg); int cmd, unsigned long arg);
static int inet_socketpair(FAR struct socket *psocks[2]); static int inet_socketpair(FAR struct socket *psocks[2]);
static int inet_shutdown(FAR struct socket *psock, int how);
#ifdef CONFIG_NET_SOCKOPTS #ifdef CONFIG_NET_SOCKOPTS
static int inet_getsockopt(FAR struct socket *psock, int level, static int inet_getsockopt(FAR struct socket *psock, int level,
int option, FAR void *value, FAR socklen_t *value_len); int option, FAR void *value, FAR socklen_t *value_len);
@ -123,7 +124,8 @@ static const struct sock_intf_s g_inet_sockif =
inet_recvmsg, /* si_recvmsg */ inet_recvmsg, /* si_recvmsg */
inet_close, /* si_close */ inet_close, /* si_close */
inet_ioctl, /* si_ioctl */ inet_ioctl, /* si_ioctl */
inet_socketpair /* si_socketpair */ inet_socketpair, /* si_socketpair */
inet_shutdown /* si_shutdown */
#ifdef CONFIG_NET_SOCKOPTS #ifdef CONFIG_NET_SOCKOPTS
, inet_getsockopt /* si_getsockopt */ , inet_getsockopt /* si_getsockopt */
, inet_setsockopt /* si_setsockopt */ , inet_setsockopt /* si_setsockopt */
@ -1980,6 +1982,41 @@ errout:
#endif /* CONFIG_NET_TCP || CONFIG_NET_UDP */ #endif /* CONFIG_NET_TCP || CONFIG_NET_UDP */
} }
/****************************************************************************
* Name: inet_shutdown
*
* Description:
* Performs the shutdown operation on an AF_INET or AF_INET6 socket
*
* Input Parameters:
* psock Socket instance
* how Specifies the type of shutdown
*
* Returned Value:
* 0: Success; Negated errno on failure
*
****************************************************************************/
static int inet_shutdown(FAR struct socket *psock, int how)
{
switch (psock->s_type)
{
#ifdef CONFIG_NET_TCP
case SOCK_STREAM:
#ifdef NET_TCP_HAVE_STACK
return tcp_shutdown(psock, how);
#else
nwarn("WARNING: SOCK_STREAM support is not available in this "
"configuration\n");
return -EAFNOSUPPORT;
#endif /* NET_TCP_HAVE_STACK */
#endif /* CONFIG_NET_TCP */
default:
return -EOPNOTSUPP;
}
}
/**************************************************************************** /****************************************************************************
* Name: inet_sendfile * Name: inet_sendfile
* *

View File

@ -72,6 +72,7 @@ static int local_close(FAR struct socket *psock);
static int local_ioctl(FAR struct socket *psock, static int local_ioctl(FAR struct socket *psock,
int cmd, unsigned long arg); int cmd, unsigned long arg);
static int local_socketpair(FAR struct socket *psocks[2]); static int local_socketpair(FAR struct socket *psocks[2]);
static int local_shutdown(FAR struct socket *psock, int how);
#ifdef CONFIG_NET_SOCKOPTS #ifdef CONFIG_NET_SOCKOPTS
static int local_getsockopt(FAR struct socket *psock, int level, static int local_getsockopt(FAR struct socket *psock, int level,
int option, FAR void *value, FAR socklen_t *value_len); int option, FAR void *value, FAR socklen_t *value_len);
@ -99,7 +100,8 @@ const struct sock_intf_s g_local_sockif =
local_recvmsg, /* si_recvmsg */ local_recvmsg, /* si_recvmsg */
local_close, /* si_close */ local_close, /* si_close */
local_ioctl, /* si_ioctl */ local_ioctl, /* si_ioctl */
local_socketpair /* si_socketpair */ local_socketpair, /* si_socketpair */
local_shutdown /* si_shutdown */
#ifdef CONFIG_NET_SOCKOPTS #ifdef CONFIG_NET_SOCKOPTS
, local_getsockopt /* si_getsockopt */ , local_getsockopt /* si_getsockopt */
, local_setsockopt /* si_setsockopt */ , local_setsockopt /* si_setsockopt */
@ -958,6 +960,35 @@ errout:
#endif /* CONFIG_NET_LOCAL_STREAM || CONFIG_NET_LOCAL_DGRAM */ #endif /* CONFIG_NET_LOCAL_STREAM || CONFIG_NET_LOCAL_DGRAM */
} }
/****************************************************************************
* Name: local_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.
*
****************************************************************************/
static int local_shutdown(FAR struct socket *psock, int how)
{
/* TODO: implement this. */
nerr("ERROR: local_shutdown is not implemented");
return -ENOTSUP;
}
/**************************************************************************** /****************************************************************************
* Public Functions * Public Functions
****************************************************************************/ ****************************************************************************/

View File

@ -22,7 +22,7 @@
SOCK_CSRCS += accept.c bind.c connect.c getsockname.c getpeername.c SOCK_CSRCS += accept.c bind.c connect.c getsockname.c getpeername.c
SOCK_CSRCS += listen.c recv.c recvfrom.c send.c sendto.c socket.c SOCK_CSRCS += listen.c recv.c recvfrom.c send.c sendto.c socket.c
SOCK_CSRCS += socketpair.c net_close.c recvmsg.c sendmsg.c SOCK_CSRCS += socketpair.c net_close.c recvmsg.c sendmsg.c shutdown.c
SOCK_CSRCS += net_dup2.c net_sockif.c net_poll.c net_fstat.c SOCK_CSRCS += net_dup2.c net_sockif.c net_poll.c net_fstat.c
# Socket options # Socket options

146
net/socket/shutdown.c Normal file
View File

@ -0,0 +1,146 @@
/****************************************************************************
* net/socket/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>
#include <errno.h>
#include <sys/socket.h>
#include <nuttx/net/net.h>
#include "socket/socket.h"
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* 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:
* 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)
{
/* Verify that the psock corresponds to valid, allocated socket */
if (psock == NULL || psock->s_conn == NULL)
{
return -EBADF;
}
/* Let the address family's shutdown() method handle the operation */
if (psock->s_sockif && psock->s_sockif->si_shutdown)
{
return psock->s_sockif->si_shutdown(psock, how);
}
return -EOPNOTSUPP;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: 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:
* Upon successful completion, shutdown() will return 0; otherwise, -1 will
* be returned and errno set to indicate the error.
*
* EBADF - The socket argument is not a valid file descriptor.
* 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 shutdown(int sockfd, int how)
{
FAR struct socket *psock;
int ret;
/* Get the underlying socket structure */
ret = sockfd_socket(sockfd, &psock);
/* Then let psock_shutdown() do all of the work */
if (ret == OK)
{
ret = psock_shutdown(psock, how);
}
if (ret < 0)
{
_SO_SETERRNO(psock, -ret);
ret = ERROR;
}
return ret;
}

View File

@ -53,7 +53,7 @@ endif
NET_CSRCS += tcp_conn.c tcp_seqno.c tcp_devpoll.c tcp_finddev.c tcp_timer.c NET_CSRCS += tcp_conn.c tcp_seqno.c tcp_devpoll.c tcp_finddev.c tcp_timer.c
NET_CSRCS += tcp_send.c tcp_input.c tcp_appsend.c tcp_listen.c tcp_close.c NET_CSRCS += tcp_send.c tcp_input.c tcp_appsend.c tcp_listen.c tcp_close.c
NET_CSRCS += tcp_monitor.c tcp_callback.c tcp_backlog.c tcp_ipselect.c NET_CSRCS += tcp_monitor.c tcp_callback.c tcp_backlog.c tcp_ipselect.c
NET_CSRCS += tcp_recvwindow.c tcp_netpoll.c tcp_ioctl.c NET_CSRCS += tcp_recvwindow.c tcp_netpoll.c tcp_ioctl.c tcp_shutdown.c
# TCP write buffering # TCP write buffering

View File

@ -344,8 +344,9 @@ struct tcp_conn_s
FAR struct devif_callback_s *connevents; FAR struct devif_callback_s *connevents;
FAR struct devif_callback_s *connevents_tail; FAR struct devif_callback_s *connevents_tail;
/* Reference to TCP close callback instance */ /* Reference to TCP shutdown/close callback instance */
FAR struct devif_callback_s *shdcb;
FAR struct devif_callback_s *clscb; FAR struct devif_callback_s *clscb;
struct work_s clswork; struct work_s clswork;
@ -767,6 +768,23 @@ void tcp_lost_connection(FAR struct tcp_conn_s *conn,
int tcp_close(FAR struct socket *psock); int tcp_close(FAR struct socket *psock);
/****************************************************************************
* Name: tcp_shutdown
*
* Description:
* Gracefully shutdown a TCP connection by sending a SYN
*
* Input Parameters:
* psock - An instance of the internal socket structure.
* how - Specifies the type of shutdown.
*
* Assumptions:
* Called from normal user-level logic
*
****************************************************************************/
int tcp_shutdown(FAR struct socket *psock, int how);
/**************************************************************************** /****************************************************************************
* Name: tcp_ipv4_select * Name: tcp_ipv4_select
* *

168
net/tcp/tcp_shutdown.c Normal file
View File

@ -0,0 +1,168 @@
/****************************************************************************
* net/tcp/tcp_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>
#ifdef CONFIG_NET_TCP
#include <errno.h>
#include <debug.h>
#include <assert.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/tcp.h>
#include "netdev/netdev.h"
#include "devif/devif.h"
#include "tcp/tcp.h"
#include "socket/socket.h"
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: tcp_shutdown_eventhandler
****************************************************************************/
static uint16_t tcp_shutdown_eventhandler(FAR struct net_driver_s *dev,
FAR void *pvpriv, uint16_t flags)
{
FAR struct tcp_conn_s *conn = pvpriv;
ninfo("flags: %04x\n", flags);
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
/* We don't need the send callback anymore. */
if (conn->sndcb != NULL)
{
conn->sndcb->flags = 0;
conn->sndcb->event = NULL;
/* The callback will be freed by tcp_free. */
conn->sndcb = NULL;
}
#endif
dev->d_len = 0;
flags = (flags & ~TCP_NEWDATA) | TCP_CLOSE;
if (conn->shdcb != NULL)
{
tcp_callback_free(conn, conn->shdcb);
conn->shdcb = NULL;
}
return flags;
}
/****************************************************************************
* Name: tcp_send_fin
*
* Description:
* Send a FIN for TCP connection
*
* Input Parameters:
* conn - TCP connection structure
*
* Returned Value:
* None
*
* Assumptions:
* Called from normal user-level logic
*
****************************************************************************/
static inline int tcp_send_fin(FAR struct socket *psock)
{
FAR struct tcp_conn_s *conn;
int ret = OK;
/* Interrupts are disabled here to avoid race conditions */
net_lock();
conn = (FAR struct tcp_conn_s *)psock->s_conn;
DEBUGASSERT(conn != NULL);
if ((conn->tcpstateflags == TCP_ESTABLISHED ||
conn->tcpstateflags == TCP_SYN_SENT ||
conn->tcpstateflags == TCP_SYN_RCVD))
{
if ((conn->shdcb = tcp_callback_alloc(conn)) == NULL)
{
ret = -EBUSY;
goto out;
}
/* Set up to receive TCP data event callbacks */
conn->shdcb->flags = TCP_POLL;
conn->shdcb->event = tcp_shutdown_eventhandler;
conn->shdcb->priv = conn; /* reference for event handler to free cb */
/* Notify the device driver of the availability of TX data */
tcp_send_txnotify(psock, conn);
}
out:
net_unlock();
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: tcp_shutdown
*
* Description:
* Gracefully shutdown a TCP connection by sending a FIN
*
* Input Parameters:
* psock - An instance of the internal socket structure.
* how - Specifies the type of shutdown.
*
* Assumptions:
* Called from normal user-level logic
*
****************************************************************************/
int tcp_shutdown(FAR struct socket *psock, int how)
{
if (!(how & SHUT_WR))
{
return -EOPNOTSUPP;
}
tcp_unlisten(psock->s_conn); /* No longer accepting connections */
return tcp_send_fin(psock);
}
#endif /* CONFIG_NET_TCP */

View File

@ -67,7 +67,8 @@ const struct sock_intf_s g_usrsock_sockif =
usrsock_recvmsg, /* si_recvmsg */ usrsock_recvmsg, /* si_recvmsg */
usrsock_sockif_close, /* si_close */ usrsock_sockif_close, /* si_close */
usrsock_ioctl, /* si_ioctl */ usrsock_ioctl, /* si_ioctl */
NULL /* si_socketpair */ NULL, /* si_socketpair */
NULL /* si_shutdown */
#ifdef CONFIG_NET_SOCKOPTS #ifdef CONFIG_NET_SOCKOPTS
, usrsock_getsockopt /* si_getsockopt */ , usrsock_getsockopt /* si_getsockopt */
, usrsock_setsockopt /* si_setsockopt */ , usrsock_setsockopt /* si_setsockopt */

View File

@ -152,6 +152,7 @@
"shmctl","sys/shm.h","defined(CONFIG_MM_SHM)","int","int","int","FAR struct shmid_ds *" "shmctl","sys/shm.h","defined(CONFIG_MM_SHM)","int","int","int","FAR struct shmid_ds *"
"shmdt","sys/shm.h","defined(CONFIG_MM_SHM)","int","FAR const void *" "shmdt","sys/shm.h","defined(CONFIG_MM_SHM)","int","FAR const void *"
"shmget","sys/shm.h","defined(CONFIG_MM_SHM)","int","key_t","size_t","int" "shmget","sys/shm.h","defined(CONFIG_MM_SHM)","int","key_t","size_t","int"
"shutdown","sys/socket.h","defined(CONFIG_NET)","int","int","int"
"sigaction","signal.h","","int","int","FAR const struct sigaction *","FAR struct sigaction *" "sigaction","signal.h","","int","int","FAR const struct sigaction *","FAR struct sigaction *"
"sigpending","signal.h","","int","FAR sigset_t *" "sigpending","signal.h","","int","FAR sigset_t *"
"sigprocmask","signal.h","","int","int","FAR const sigset_t *","FAR sigset_t *" "sigprocmask","signal.h","","int","int","FAR const sigset_t *","FAR sigset_t *"

Can't render this file because it has a wrong number of fields in line 2.