diff --git a/net/inet/Make.defs b/net/inet/Make.defs index 980db1bf49..c27b728aed 100644 --- a/net/inet/Make.defs +++ b/net/inet/Make.defs @@ -38,10 +38,10 @@ SOCK_CSRCS += inet_txdrain.c ifeq ($(CONFIG_NET_IPv4),y) -SOCK_CSRCS += inet_sockif.c inet_recvfrom.c inet_close.c +SOCK_CSRCS += inet_sockif.c inet_recvfrom.c SOCK_CSRCS += inet_globals.c else ifeq ($(CONFIG_NET_IPv6),y) -SOCK_CSRCS += inet_sockif.c inet_recvfrom.c inet_close.c +SOCK_CSRCS += inet_sockif.c inet_recvfrom.c SOCK_CSRCS += inet_globals.c endif diff --git a/net/inet/inet_sockif.c b/net/inet/inet_sockif.c index 5a05fda804..5ce865f3b2 100644 --- a/net/inet/inet_sockif.c +++ b/net/inet/inet_sockif.c @@ -1280,6 +1280,123 @@ static ssize_t inet_sendfile(FAR struct socket *psock, * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: inet_close + * + * Description: + * Performs the close operation on an AF_INET or AF_INET6 socket instance + * + * Input Parameters: + * psock Socket instance + * + * Returned Value: + * 0 on success; -1 on error with errno set appropriately. + * + * Assumptions: + * + ****************************************************************************/ + +int inet_close(FAR struct socket *psock) +{ + /* Perform some pre-close operations for the AF_INET/AF_INET6 address + * types. + */ + + switch (psock->s_type) + { +#ifdef CONFIG_NET_TCP + case SOCK_STREAM: + { +#ifdef NET_TCP_HAVE_STACK + FAR struct tcp_conn_s *conn = psock->s_conn; + int ret; + + /* Is this the last reference to the connection structure (there + * could be more if the socket was dup'ed). + */ + + if (conn->crefs <= 1) + { + /* Yes... Clost the socket */ + + ret = tcp_close(psock); + if (ret < 0) + { + /* This would normally occur only if there is a timeout + * from a lingering close. + */ + + nerr("ERROR: tcp_close failed: %d\n", ret); + return ret; + } + } + else + { + /* No.. Just decrement the reference count */ + + conn->crefs--; + + /* Stop monitor for this socket only */ + + tcp_close_monitor(psock); + } +#else + nwarn("WARNING: SOCK_STREAM support is not available in this " + "configuration\n"); + return -EAFNOSUPPORT; +#endif /* NET_TCP_HAVE_STACK */ + } + break; +#endif /* CONFIG_NET_TCP */ + +#ifdef CONFIG_NET_UDP + case SOCK_DGRAM: + { +#ifdef NET_UDP_HAVE_STACK + FAR struct udp_conn_s *conn = psock->s_conn; + int ret; + + /* Is this the last reference to the connection structure (there + * could be more if the socket was dup'ed). + */ + + if (conn->crefs <= 1) + { + /* Yes... Clost the socket */ + + ret = udp_close(psock); + if (ret < 0) + { + /* This would normally occur only if there is a timeout + * from a lingering close. + */ + + nerr("ERROR: udp_close failed: %d\n", ret); + return ret; + } + } + else + { + /* No.. Just decrement the reference count */ + + conn->crefs--; + } +#else + nwarn("WARNING: SOCK_DGRAM support is not available in this " + "configuration\n"); + return -EAFNOSUPPORT; +#endif /* NET_UDP_HAVE_STACK */ + } + break; +#endif /* CONFIG_NET_UDP */ + + default: + return -EBADF; + } + + return OK; +} + /**************************************************************************** * Name: inet_sockif * diff --git a/net/tcp/Make.defs b/net/tcp/Make.defs index 4cc27dbb95..8b165daf56 100644 --- a/net/tcp/Make.defs +++ b/net/tcp/Make.defs @@ -66,7 +66,7 @@ endif # Transport layer 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 +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_recvwindow.c tcp_netpoll.c diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index af62daba4e..93e3cf6b71 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -667,6 +667,22 @@ void tcp_close_monitor(FAR struct socket *psock); void tcp_lost_connection(FAR struct socket *psock, FAR struct devif_callback_s *cb, uint16_t flags); +/**************************************************************************** + * Name: tcp_close + * + * Description: + * Break any current TCP connection + * + * Input Parameters: + * psock - An instance of the internal socket structure. + * + * Assumptions: + * Called from normal user-level logic + * + ****************************************************************************/ + +int tcp_close(FAR struct socket *psock); + /**************************************************************************** * Name: tcp_ipv4_select * diff --git a/net/inet/inet_close.c b/net/tcp/tcp_close.c similarity index 67% rename from net/inet/inet_close.c rename to net/tcp/tcp_close.c index dd5dd83e97..d326c3ee9f 100644 --- a/net/inet/inet_close.c +++ b/net/tcp/tcp_close.c @@ -1,7 +1,7 @@ /**************************************************************************** - * net/inet/inet_close.c + * net/tcp/tcp_close.c * - * Copyright (C) 2007-2017, 2019 Gregory Nutt. All rights reserved. + * Copyright (C) 2020 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -38,38 +38,25 @@ ****************************************************************************/ #include +#ifdef CONFIG_NET_TCP -#include -#include -#include -#include #include #include #include -#include - -#include #include #include #include -#include #include "netdev/netdev.h" #include "devif/devif.h" #include "tcp/tcp.h" -#include "udp/udp.h" -#include "pkt/pkt.h" -#include "local/local.h" #include "socket/socket.h" -#include "usrsock/usrsock.h" -#include "inet/inet.h" /**************************************************************************** * Private Types ****************************************************************************/ -#ifdef NET_TCP_HAVE_STACK struct tcp_close_s { FAR struct devif_callback_s *cl_cb; /* Reference to TCP callback instance */ @@ -77,7 +64,6 @@ struct tcp_close_s sem_t cl_sem; /* Signals disconnect completion */ int cl_result; /* The result of the close */ }; -#endif /**************************************************************************** * Private Functions @@ -85,22 +71,8 @@ struct tcp_close_s /**************************************************************************** * Name: tcp_close_eventhandler - * - * Description: - * Handle network callback events. - * - * Input Parameters: - * conn - TCP connection structure - * - * Returned Value: - * None - * - * Assumptions: - * Called from normal user-level logic - * ****************************************************************************/ -#ifdef NET_TCP_HAVE_STACK static uint16_t tcp_close_eventhandler(FAR struct net_driver_s *dev, FAR void *pvconn, FAR void *pvpriv, uint16_t flags) @@ -197,7 +169,6 @@ end_wait: ninfo("Resuming\n"); return flags; } -#endif /* NET_TCP_HAVE_STACK */ /**************************************************************************** * Name: tcp_close_txnotify @@ -215,7 +186,6 @@ end_wait: * ****************************************************************************/ -#ifdef NET_TCP_HAVE_STACK static inline void tcp_close_txnotify(FAR struct socket *psock, FAR struct tcp_conn_s *conn) { @@ -246,7 +216,6 @@ static inline void tcp_close_txnotify(FAR struct socket *psock, } #endif /* CONFIG_NET_IPv6 */ } -#endif /* NET_TCP_HAVE_STACK */ /**************************************************************************** * Name: tcp_close_disconnect @@ -265,7 +234,6 @@ static inline void tcp_close_txnotify(FAR struct socket *psock, * ****************************************************************************/ -#ifdef NET_TCP_HAVE_STACK static inline int tcp_close_disconnect(FAR struct socket *psock) { struct tcp_close_s state; @@ -389,215 +357,52 @@ static inline int tcp_close_disconnect(FAR struct socket *psock) net_unlock(); return ret; } -#endif /* NET_TCP_HAVE_STACK */ - -/**************************************************************************** - * Name: udp_close - * - * Description: - * Break any current UDP connection - * - * Input Parameters: - * conn - UDP connection structure - * - * Returned Value: - * None - * - * Assumptions: - * Called from normal user-level logic - * - ****************************************************************************/ - -#ifdef NET_UDP_HAVE_STACK -static inline int udp_close(FAR struct socket *psock) -{ - FAR struct udp_conn_s *conn; - unsigned int timeout = UINT_MAX; - int ret; - - /* Interrupts are disabled here to avoid race conditions */ - - net_lock(); - - conn = (FAR struct udp_conn_s *)psock->s_conn; - DEBUGASSERT(conn != NULL); - -#ifdef CONFIG_NET_SOLINGER - /* SO_LINGER - * Lingers on a close() if data is present. This option controls the - * action taken when unsent messages queue on a socket and close() is - * performed. If SO_LINGER is set, the system shall block the calling - * thread during close() until it can transmit the data or until the - * time expires. If SO_LINGER is not specified, and close() is issued, - * the system handles the call in a way that allows the calling thread - * to continue as quickly as possible. This option takes a linger - * structure, as defined in the header, to specify the - * state of the option and linger interval. - */ - - if (_SO_GETOPT(psock->s_options, SO_LINGER)) - { - timeout = _SO_TIMEOUT(psock->s_linger); - } -#endif - - /* Wait until for the buffered TX data to be sent. */ - - ret = udp_txdrain(psock, timeout); - if (ret < 0) - { - /* udp_txdrain may fail, but that won't stop us from closing - * the socket. - */ - - nerr("ERROR: udp_txdrain() failed: %d\n", ret); - } - -#ifdef CONFIG_NET_UDP_WRITE_BUFFERS - /* Free any semi-permanent write buffer callback in place. */ - - if (psock->s_sndcb != NULL) - { - udp_callback_free(conn->dev, conn, psock->s_sndcb); - psock->s_sndcb = NULL; - } -#endif - - /* And free the connection structure */ - - conn->crefs = 0; - udp_free(psock->s_conn); - net_unlock(); - return OK; -} -#endif /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** - * Name: inet_close + * Name: tcp_close * * Description: - * Performs the close operation on an AF_INET or AF_INET6 socket instance + * Break any current TCP connection * * Input Parameters: - * psock Socket instance - * - * Returned Value: - * 0 on success; -1 on error with errno set appropriately. + * psock - An instance of the internal socket structure. * * Assumptions: + * Called from normal user-level logic * ****************************************************************************/ -int inet_close(FAR struct socket *psock) +int tcp_close(FAR struct socket *psock) { - /* Perform some pre-close operations for the AF_INET/AF_INET6 address - * types. - */ + FAR struct tcp_conn_s *conn = psock->s_conn; + int ret; - switch (psock->s_type) + /* Perform the disconnection now */ + + tcp_unlisten(conn); /* No longer accepting connections */ + conn->crefs = 0; /* Discard our reference to the connection */ + + /* Break any current connections and close the socket */ + + ret = tcp_close_disconnect(psock); + if (ret < 0) { -#ifdef CONFIG_NET_TCP - case SOCK_STREAM: - { -#ifdef NET_TCP_HAVE_STACK - FAR struct tcp_conn_s *conn = psock->s_conn; - int ret; + /* This would normally occur only if there is a timeout + * from a lingering close. + */ - /* Is this the last reference to the connection structure (there - * could be more if the socket was dup'ed). - */ - - if (conn->crefs <= 1) - { - /* Yes... then perform the disconnection now */ - - tcp_unlisten(conn); /* No longer accepting connections */ - conn->crefs = 0; /* Discard our reference to the connection */ - - /* Break any current connections and close the socket */ - - ret = tcp_close_disconnect(psock); - if (ret < 0) - { - /* This would normally occur only if there is a timeout - * from a lingering close. - */ - - nerr("ERROR: tcp_close_disconnect failed: %d\n", ret); - return ret; - } - - /* Stop the network monitor for all sockets */ - - tcp_stop_monitor(conn, TCP_CLOSE); - } - else - { - /* No.. Just decrement the reference count */ - - conn->crefs--; - - /* Stop monitor for this socket only */ - - tcp_close_monitor(psock); - } -#else - nwarn("WARNING: SOCK_STREAM support is not available in this " - "configuration\n"); - return -EAFNOSUPPORT; -#endif /* NET_TCP_HAVE_STACK */ - } - break; -#endif /* CONFIG_NET_TCP */ - -#ifdef CONFIG_NET_UDP - case SOCK_DGRAM: - { -#ifdef NET_UDP_HAVE_STACK - FAR struct udp_conn_s *conn = psock->s_conn; - int ret; - - /* Is this the last reference to the connection structure (there - * could be more if the socket was dup'ed). - */ - - if (conn->crefs <= 1) - { - /* Yes... Clost the socket */ - - ret = udp_close(psock); - if (ret < 0) - { - /* This would normally occur only if there is a timeout - * from a lingering close. - */ - - nerr("ERROR: udp_close failed: %d\n", ret); - return ret; - } - } - else - { - /* No.. Just decrement the reference count */ - - conn->crefs--; - } -#else - nwarn("WARNING: SOCK_DGRAM support is not available in this " - "configuration\n"); - return -EAFNOSUPPORT; -#endif /* NET_UDP_HAVE_STACK */ - } - break; -#endif /* CONFIG_NET_UDP */ - - default: - return -EBADF; + nerr("ERROR: tcp_close_disconnect failed: %d\n", ret); + return ret; } + /* Stop the network monitor for all sockets */ + + tcp_stop_monitor(conn, TCP_CLOSE); return OK; } + +#endif /* CONFIG_NET_TCP */ diff --git a/net/udp/Make.defs b/net/udp/Make.defs index 0501ae4508..1c9487a558 100644 --- a/net/udp/Make.defs +++ b/net/udp/Make.defs @@ -60,7 +60,7 @@ endif # Transport layer NET_CSRCS += udp_conn.c udp_devpoll.c udp_send.c udp_input.c udp_finddev.c -NET_CSRCS += udp_callback.c udp_ipselect.c udp_netpoll.c +NET_CSRCS += udp_close.c udp_callback.c udp_ipselect.c udp_netpoll.c # UDP write buffering diff --git a/net/udp/udp.h b/net/udp/udp.h index aa1caef7aa..40d3a97a99 100644 --- a/net/udp/udp.h +++ b/net/udp/udp.h @@ -300,6 +300,22 @@ int udp_bind(FAR struct udp_conn_s *conn, FAR const struct sockaddr *addr); int udp_connect(FAR struct udp_conn_s *conn, FAR const struct sockaddr *addr); +/**************************************************************************** + * Name: udp_close + * + * Description: + * Break any current UDP connection + * + * Input Parameters: + * psock - An instance of the internal socket structure. + * + * Assumptions: + * Called from normal user-level logic + * + ****************************************************************************/ + +int udp_close(FAR struct socket *psock); + /**************************************************************************** * Name: udp_ipv4_select * diff --git a/net/udp/udp_close.c b/net/udp/udp_close.c new file mode 100644 index 0000000000..ec735c47ce --- /dev/null +++ b/net/udp/udp_close.c @@ -0,0 +1,138 @@ +/**************************************************************************** + * net/udp/udp_close.c + * + * Copyright (C) 2020 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_UDP) + +#include +#include +#include + +#include +#include + +#include "devif/devif.h" +#include "udp/udp.h" +#include "socket/socket.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: udp_close + * + * Description: + * Break any current UDP connection + * + * Input Parameters: + * conn - UDP connection structure + * + * Returned Value: + * None + * + * Assumptions: + * Called from normal user-level logic + * + ****************************************************************************/ + +int udp_close(FAR struct socket *psock) +{ + FAR struct udp_conn_s *conn; + unsigned int timeout = UINT_MAX; + int ret; + + /* Interrupts are disabled here to avoid race conditions */ + + net_lock(); + + conn = (FAR struct udp_conn_s *)psock->s_conn; + DEBUGASSERT(conn != NULL); + +#ifdef CONFIG_NET_SOLINGER + /* SO_LINGER + * Lingers on a close() if data is present. This option controls the + * action taken when unsent messages queue on a socket and close() is + * performed. If SO_LINGER is set, the system shall block the calling + * thread during close() until it can transmit the data or until the + * time expires. If SO_LINGER is not specified, and close() is issued, + * the system handles the call in a way that allows the calling thread + * to continue as quickly as possible. This option takes a linger + * structure, as defined in the header, to specify the + * state of the option and linger interval. + */ + + if (_SO_GETOPT(psock->s_options, SO_LINGER)) + { + timeout = _SO_TIMEOUT(psock->s_linger); + } +#endif + + /* Wait until for the buffered TX data to be sent. */ + + UNUSED(timeout); + ret = udp_txdrain(psock, timeout); + if (ret < 0) + { + /* udp_txdrain may fail, but that won't stop us from closing + * the socket. + */ + + nerr("ERROR: udp_txdrain() failed: %d\n", ret); + } + +#ifdef CONFIG_NET_UDP_WRITE_BUFFERS + /* Free any semi-permanent write buffer callback in place. */ + + if (psock->s_sndcb != NULL) + { + udp_callback_free(conn->dev, conn, psock->s_sndcb); + psock->s_sndcb = NULL; + } +#endif + + /* And free the connection structure */ + + conn->crefs = 0; + udp_free(psock->s_conn); + net_unlock(); + return OK; +} + +#endif /* CONFIG_NET && CONFIG_NET_UDP */