From 077d164b142828214d6f1cc2485d251ccc66e928 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 1 Jul 2019 14:07:12 -0600 Subject: [PATCH] /net/inet: Simplify design of change in last commit. --- net/inet/Make.defs | 6 +- net/inet/inet.h | 5 +- net/inet/inet_close.c | 151 ++++++++++++++++++++++++++++++++-------- net/inet/inet_txdrain.c | 7 +- 4 files changed, 128 insertions(+), 41 deletions(-) diff --git a/net/inet/Make.defs b/net/inet/Make.defs index 20f2683bf3bb..07895886f82a 100644 --- a/net/inet/Make.defs +++ b/net/inet/Make.defs @@ -35,6 +35,8 @@ # PF_INET/PF_INET6 socket address families +SOCK_CSRCS += inet_txdrain.c + ifeq ($(CONFIG_NET_IPv4),y) SOCK_CSRCS += inet_sockif.c inet_recvfrom.c inet_close.c SOCK_CSRCS += inet_globals.c @@ -52,10 +54,6 @@ ifeq ($(CONFIG_NET_IPv6),y) SOCK_CSRCS += ipv6_setsockopt.c ipv6_getsockname.c ipv6_getpeername.c endif -ifeq ($(CONFIG_NET_SOLINGER),y) -SOCK_CSRCS += inet_txdrain.c -endif - # Include inet build support DEPPATH += --dep-path inet diff --git a/net/inet/inet.h b/net/inet/inet.h index 2c0f4c7e98ef..154f149c2c1a 100644 --- a/net/inet/inet.h +++ b/net/inet/inet.h @@ -309,8 +309,7 @@ int inet_close(FAR struct socket *psock); * Name: inet_txdrain * * Description: - * Wait for any buffered Tx data to be sent from the socket. This is part - * of the implementation of SO_LINGER + * Wait for any buffered Tx data to be sent from the socket. * * Parameters: * psock - Pointer to the socket structure instance @@ -322,11 +321,9 @@ int inet_close(FAR struct socket *psock); * ****************************************************************************/ -#ifdef CONFIG_NET_SOLINGER struct timespec; int inet_txdrain(FAR struct socket *psock, FAR const struct timespec *abstime); -#endif #undef EXTERN #if defined(__cplusplus) diff --git a/net/inet/inet_close.c b/net/inet/inet_close.c index 092312dabe73..6ebf3d451499 100644 --- a/net/inet/inet_close.c +++ b/net/inet/inet_close.c @@ -38,7 +38,6 @@ ****************************************************************************/ #include -#ifdef CONFIG_NET #include #include @@ -290,24 +289,26 @@ static inline int tcp_close_disconnect(FAR struct socket *psock) { /* Get the current time */ - DEBUGVERIFY(clock_gettime(CLOCK_REALTIME, &abstime)); - - /* NOTE: s_linger's unit is deciseconds so we don't need to update - * abstime.tv_nsec here. - */ + ret = clock_gettime(CLOCK_REALTIME, &abstime); + if (ret >= 0) + { + /* NOTE: s_linger's unit is deciseconds so we don't need to update + * abstime.tv_nsec here. + */ - abstime.tv_sec += psock->s_linger / DSEC_PER_SEC; + abstime.tv_sec += psock->s_linger / DSEC_PER_SEC; - /* Wait until abstime for the buffered TX data to be sent. */ + /* Wait until abstime for the buffered TX data to be sent. */ - ret = inet_txdrain(psock, &abstime); - if (ret < 0) - { - /* inet_txdrain may fail, but that won't stop us from closing the - * socket. - */ + ret = tcp_txdrain(psock, &abstime); + if (ret < 0) + { + /* tcp_txdrain may fail, but that won't stop us from closing + * the socket. + */ - nerr("ERROR: inet_txdrain() failed: %d\n", ret); + nerr("ERROR: tcp_txdrain() failed: %d\n", ret); + } } } #endif @@ -395,6 +396,101 @@ static inline int tcp_close_disconnect(FAR struct socket *psock) } #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; +#ifdef CONFIG_NET_SOLINGER + struct timespec abstime; + bool linger; +#endif + 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. + */ + + linger = _SO_GETOPT(psock->s_options, SO_LINGER); + if (linger) + { + /* Get the current time */ + + ret = clock_gettime(CLOCK_REALTIME, &abstime); + if (ret >= 0) + { + /* NOTE: s_linger's unit is deciseconds so we don't need to update + * abstime.tv_nsec here. + */ + + abstime.tv_sec += psock->s_linger / DSEC_PER_SEC; + + /* Wait until abstime for the buffered TX data to be sent. */ + + ret = udp_txdrain(psock, &abstime); + 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); + } + } + } +#endif + +#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 ****************************************************************************/ @@ -441,7 +537,7 @@ int inet_close(FAR struct socket *psock) tcp_unlisten(conn); /* No longer accepting connections */ conn->crefs = 0; /* Discard our reference to the connection */ - /* Break any current connections */ + /* Break any current connections and close the socket */ ret = tcp_close_disconnect(psock); if (ret < 0) @@ -481,6 +577,7 @@ int inet_close(FAR struct socket *psock) { #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). @@ -488,21 +585,18 @@ int inet_close(FAR struct socket *psock) if (conn->crefs <= 1) { - /* Yes... */ + /* Yes... Clost the socket */ -#ifdef CONFIG_NET_UDP_WRITE_BUFFERS - /* Free any semi-permanent write buffer callback in place. */ - - if (psock->s_sndcb != NULL) + ret = udp_close(psock); + if (ret < 0) { - udp_callback_free(conn->dev, conn, psock->s_sndcb); - psock->s_sndcb = NULL; - } -#endif - /* And free the connection structure */ + /* This would normally occur only if there is a timeout + * from a lingering close. + */ - conn->crefs = 0; - udp_free(psock->s_conn); + nerr("ERROR: udp_close failed: %d\n", ret); + return ret; + } } else { @@ -524,4 +618,3 @@ int inet_close(FAR struct socket *psock) return OK; } -#endif /* CONFIG_NET */ diff --git a/net/inet/inet_txdrain.c b/net/inet/inet_txdrain.c index bdec90b43015..ca3fc37d9b92 100644 --- a/net/inet/inet_txdrain.c +++ b/net/inet/inet_txdrain.c @@ -60,8 +60,7 @@ * Name: inet_txdrain * * Description: - * Wait for any buffered Tx data to be sent from the socket. This is part - * of the implementation of SO_LINGER + * Wait for any buffered Tx data to be sent from the socket. * * Parameters: * psock - Pointer to the socket structure instance @@ -84,7 +83,7 @@ int inet_txdrain(FAR struct socket *psock, switch (psock->s_type) { -#if defined(NET_TCP_HAVE_STACK) && defined(CONFIG_NET_TCP_WRITE_BUFFERS) +#if defined(NET_TCP_HAVE_STACK) case SOCK_STREAM: { ret = tcp_txdrain(psock, abstime); @@ -92,7 +91,7 @@ int inet_txdrain(FAR struct socket *psock, break; #endif -#if defined(NET_UDP_HAVE_STACK) && defined(CONFIG_NET_UDP_WRITE_BUFFERS) +#if defined(NET_UDP_HAVE_STACK) case SOCK_DGRAM: { ret = udp_txdrain(psock, abstime);