Squashed commit of the following:

net/tcp:  Add logic to send probes when SO_KEEPALIVE is enabled.
    net/tcp:  TCP socket should not have to be connected to configure KeepAlive.
    net/: Add a separate configuration to enable/disable KEEPALIVE socket options.
    net/tcp: Arguments to TCP keep-alive timing functions probably should be struct timeval as are the times for other time-related socket options.
    net/tcp:  Fix a backward conditional
    net/tcp:  Add some more checks and debug output to TCP-protocol socket options.
    net/tcp:  Cosmetic changes to some alignment.
    net/:  Adds socket options needed to manage TCP-keepalive and TCP state machine logic to detect if that the remote peer is alive.  Still missing the timer poll logic to send the keep-alive probes and the state machine logic to respond to probes.
This commit is contained in:
Gregory Nutt
2018-03-12 10:59:46 -06:00
parent 0885ad7b14
commit 251924a734
15 changed files with 1110 additions and 142 deletions
+6
View File
@@ -24,6 +24,12 @@ config NET_SOCKOPTS
---help---
Enable or disable support for socket options
config NET_TCPPROTO_OPTIONS
bool
default n
---help---
Enable or disable support for TCP protocol level socket options.
if NET_SOCKOPTS
config NET_SOLINGER
+148 -44
View File
@@ -1,7 +1,8 @@
/****************************************************************************
* net/socket/getsockopt.c
*
* Copyright (C) 2007-2009, 2012, 2014, 2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2009, 2012, 2014, 2017-2018 Gregory Nutt. All rights
* reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -48,19 +49,20 @@
#include <errno.h>
#include "socket/socket.h"
#include "tcp/tcp.h"
#include "usrsock/usrsock.h"
#include "utils/utils.h"
/****************************************************************************
* Public Functions
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: psock_getsockopt
* Name: psock_socketlevel_option
*
* Description:
* getsockopt() retrieve thse value for the option specified by the
* 'option' argument for the socket specified by the 'psock' argument. If
* getsockopt() retrieve the value for the option specified by the
* 'option' argument for the socket specified by the 'psock' argument. If
* the size of the option value is greater than 'value_len', the value
* stored in the object pointed to by the 'value' argument will be silently
* truncated. Otherwise, the length pointed to by the 'value_len' argument
@@ -68,9 +70,12 @@
*
* The 'level' argument specifies the protocol level of the option. To
* retrieve options at the socket level, specify the level argument as
* SOL_SOCKET.
* SOL_SOCKET; to retrieve options at the TCP-protocol level, the level
* argument is SOL_CP.
*
* See <sys/socket.h> a complete list of values for the 'option' argument.
* See <sys/socket.h> a complete list of values for the socket-level
* 'option' argument. Protocol-specific options are are protocol specific
* header files (such as netinet/tcp.h for the case of the TCP protocol).
*
* Parameters:
* psock Socket structure of the socket to query
@@ -80,24 +85,14 @@
* value_len The length of the argument value
*
* Returned Value:
* Returns zero (OK) on success. On failure, it returns a negated errno
* value to indicate the nature of the error.
*
* EINVAL
* The specified option is invalid at the specified socket 'level' or the
* socket has been shutdown.
* ENOPROTOOPT
* The 'option' is not supported by the protocol.
* ENOTSOCK
* The 'psock' argument does not refer to a socket.
* ENOBUFS
* Insufficient resources are available in the system to complete the
* call.
* Returns zero (OK) on success. On failure, it returns a negated errno
* value to indicate the nature of the error. See psock_getsockopt() for
* the complete list of appropriate return error codes.
*
****************************************************************************/
int psock_getsockopt(FAR struct socket *psock, int level, int option,
FAR void *value, FAR socklen_t *value_len)
static int psock_socketlevel_option(FAR struct socket *psock, int option,
FAR void *value, FAR socklen_t *value_len)
{
/* Verify that the socket option if valid (but might not be supported ) */
@@ -126,7 +121,7 @@ int psock_getsockopt(FAR struct socket *psock, int level, int option,
default: /* Other options are passed to usrsock daemon. */
{
return usrsock_getsockopt(conn, level, option, value, value_len);
return usrsock_getsockopt(conn, SOL_SOCKET, option, value, value_len);
}
}
}
@@ -144,8 +139,10 @@ int psock_getsockopt(FAR struct socket *psock, int level, int option,
case SO_DEBUG: /* Enables recording of debugging information */
case SO_BROADCAST: /* Permits sending of broadcast messages */
case SO_REUSEADDR: /* Allow reuse of local addresses */
case SO_KEEPALIVE: /* Keeps connections active by enabling the
* periodic transmission */
#ifndef CONFIG_NET_TCPPROTO_OPTIONS
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
* periodic transmission of probes */
#endif
case SO_OOBINLINE: /* Leaves received out-of-band data inline */
case SO_DONTROUTE: /* Requests outgoing messages bypass standard routing */
{
@@ -172,6 +169,23 @@ int psock_getsockopt(FAR struct socket *psock, int level, int option,
}
break;
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
/* Any connection-oriented protocol could potentially support
* SO_KEEPALIVE. However, this option is currently only available for
* TCP/IP.
*
* NOTE: SO_KEEPALIVE is not really a socket-level option; it is a
* protocol-level option. A given TCP connection may service multiple
* sockets (via dup'ing of the socket). There is, however, still only
* one connection to be monitored and that is a global attribute across
* all of the clones that may use the underlying connection.
*/
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
* periodic transmission of probes */
return tcp_getsockopt(psock, option, value, value_len);
#endif
case SO_TYPE: /* Reports the socket type */
{
/* Verify that option is the size of an 'int'. Should also check
@@ -257,24 +271,114 @@ int psock_getsockopt(FAR struct socket *psock, int level, int option,
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: psock_getsockopt
*
* Description:
* getsockopt() retrieve the value for the option specified by the
* 'option' argument for the socket specified by the 'psock' argument. If
* the size of the option value is greater than 'value_len', the value
* stored in the object pointed to by the 'value' argument will be silently
* truncated. Otherwise, the length pointed to by the 'value_len' argument
* will be modified to indicate the actual length of the 'value'.
*
* The 'level' argument specifies the protocol level of the option. To
* retrieve options at the socket level, specify the level argument as
* SOL_SOCKET; to retrieve options at the TCP-protocol level, the level
* argument is SOL_CP.
*
* See <sys/socket.h> a complete list of values for the socket-level
* 'option' argument. Protocol-specific options are are protocol specific
* header files (such as netinet/tcp.h for the case of the TCP protocol).
*
* Parameters:
* psock Socket structure of the socket to query
* level Protocol level to set the option
* option identifies the option to get
* value Points to the argument value
* value_len The length of the argument value
*
* Returned Value:
* Returns zero (OK) on success. On failure, it returns a negated errno
* value to indicate the nature of the error.
*
* EINVAL
* The specified option is invalid at the specified socket 'level' or the
* socket has been shutdown.
* ENOPROTOOPT
* The 'option' is not supported by the protocol.
* ENOTSOCK
* The 'psock' argument does not refer to a socket.
* ENOBUFS
* Insufficient resources are available in the system to complete the
* call.
*
****************************************************************************/
int psock_getsockopt(FAR struct socket *psock, int level, int option,
FAR void *value, FAR socklen_t *value_len)
{
int ret;
/* Handle retrieval of the socket option according to the level at which
* option should be applied.
*/
switch (level)
{
case SOL_SOCKET: /* Socket-level options (see include/sys/socket.h) */
ret = psock_socketlevel_option(psock, option, value, value_len);
break;
case SOL_TCP: /* TCP protocol socket options (see include/netinet/tcp.h) */
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
ret = tcp_getsockopt(psock, option, value, value_len);
break;
#endif
/* These levels are defined in sys/socket.h, but are not yet
* implemented.
*/
case SOL_IP: /* TCP protocol socket options (see include/netinet/ip.h) */
case SOL_IPV6: /* TCP protocol socket options (see include/netinet/ip6.h) */
case SOL_UDP: /* TCP protocol socket options (see include/netinit/udp.h) */
ret = -ENOSYS;
break;
default: /* The provided level is invalid */
ret = -EINVAL;
break;
}
return ret;
}
/****************************************************************************
* Name: getsockopt
*
* Description:
* getsockopt() retrieve thse value for the option specified by the
* getsockopt() retrieve the value for the option specified by the
* 'option' argument for the socket specified by the 'sockfd' argument. If
* the size of the option value is greater than 'value_len', the value
* stored in the object pointed to by the 'value' argument will be silently
* truncated. Otherwise, the length pointed to by the 'value_len' argument
* will be modified to indicate the actual length of the'value'.
* will be modified to indicate the actual length of the 'value'.
*
* The 'level' argument specifies the protocol level of the option. To
* retrieve options at the socket level, specify the level argument as
* SOL_SOCKET.
* SOL_SOCKET; to retrieve options at the TCP-protocol level, the level
* argument is SOL_CP.
*
* See <sys/socket.h> a complete list of values for the 'option' argument.
* See <sys/socket.h> a complete list of values for the socket-level
* 'option' argument. Protocol-specific options are are protocol specific
* header files (such as netinet/tcp.h for the case of the TCP protocol).
*
* Parameters:
* Input Parameters:
* sockfd Socket descriptor of socket
* level Protocol level to set the option
* option identifies the option to get
@@ -282,21 +386,21 @@ int psock_getsockopt(FAR struct socket *psock, int level, int option,
* value_len The length of the argument value
*
* Returned Value:
* Returns zero (OK) on success. On failure, -1 (ERROR) is returned and th
* errno variable is set appropriately:
* Returns zero (OK) on success. On failure, -1 (ERROR) is returned and th
* errno variable is set appropriately:
*
* EBADF
* The 'sockfd' argument is not a valid socket descriptor.
* EINVAL
* The specified option is invalid at the specified socket 'level' or the
* socket has been shutdown.
* ENOPROTOOPT
* The 'option' is not supported by the protocol.
* ENOTSOCK
* The 'sockfd' argument does not refer to a socket.
* ENOBUFS
* Insufficient resources are available in the system to complete the
* call.
* EBADF
* The 'sockfd' argument is not a valid socket descriptor.
* EINVAL
* The specified option is invalid at the specified socket 'level' or the
* socket has been shutdown.
* ENOPROTOOPT
* The 'option' is not supported by the protocol.
* ENOTSOCK
* The 'sockfd' argument does not refer to a socket.
* ENOBUFS
* Insufficient resources are available in the system to complete the
* call.
*
****************************************************************************/
+160 -67
View File
@@ -1,8 +1,8 @@
/****************************************************************************
* net/socket/setsockopt.c
*
* Copyright (C) 2007, 2008, 2011-2012, 2014-2015, 2017 Gregory Nutt. All
* rights reserved.
* Copyright (C) 2007, 2008, 2011-2012, 2014-2015, 2017-2018 Gregory Nutt.
* All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -52,6 +52,7 @@
#include <nuttx/net/net.h>
#include "socket/socket.h"
#include "tcp/tcp.h"
#include "usrsock/usrsock.h"
#include "utils/utils.h"
@@ -60,54 +61,31 @@
****************************************************************************/
/****************************************************************************
* Name: psock_setsockopt
* Name: psock_socketlevel_option
*
* Description:
* psock_setsockopt() sets the option specified by the 'option' argument,
* at the protocol level specified by the 'level' argument, to the value
* pointed to by the 'value' argument for the socket on the 'psock' argument.
* psock_socketlevel_option() sets the socket-level option specified by the
* 'option' argument to the value pointed to by the 'value' argument for
* the socket specified by the 'psock' argument.
*
* The 'level' argument specifies the protocol level of the option. To set
* options at the socket level, specify the level argument as SOL_SOCKET.
* See <sys/socket.h> a complete list of values for the socket level
* 'option' argument.
*
* See <sys/socket.h> a complete list of values for the 'option' argument.
*
* Parameters:
* Input Parameters:
* psock Socket structure of socket to operate on
* level Protocol level to set the option
* option identifies the option to set
* value Points to the argument value
* value_len The length of the argument value
*
* Returned Value:
* Returns zero (OK) on success. On failure, it returns a negated errno
* value to indicate the nature of the error:
*
* EDOM
* The send and receive timeout values are too big to fit into the
* timeout fields in the socket structure.
* EINVAL
* The specified option is invalid at the specified socket 'level' or the
* socket has been shut down.
* EISCONN
* The socket is already connected, and a specified option cannot be set
* while the socket is connected.
* ENOPROTOOPT
* The 'option' is not supported by the protocol.
* ENOTSOCK
* The 'sockfd' argument does not refer to a socket.
* ENOMEM
* There was insufficient memory available for the operation to complete.
* ENOBUFS
* Insufficient resources are available in the system to complete the
* call.
*
* Assumptions:
* Returns zero (OK) on success. On failure, it returns a negated errno
* value to indicate the nature of the error. See psock_setcockopt() for
* the list of possible error values.
*
****************************************************************************/
int psock_setsockopt(FAR struct socket *psock, int level, int option,
FAR const void *value, socklen_t value_len)
static int psock_socketlevel_option(FAR struct socket *psock, int option,
FAR const void *value, socklen_t value_len)
{
/* Verify that the socket option if valid (but might not be supported ) */
@@ -135,7 +113,8 @@ int psock_setsockopt(FAR struct socket *psock, int level, int option,
default: /* Other options are passed to usrsock daemon. */
{
return usrsock_setsockopt(conn, level, option, value, value_len);
return usrsock_setsockopt(conn, SOL_SOCKET, option, value,
value_len);
}
}
}
@@ -153,8 +132,10 @@ int psock_setsockopt(FAR struct socket *psock, int level, int option,
case SO_DEBUG: /* Enables recording of debugging information */
case SO_BROADCAST: /* Permits sending of broadcast messages */
case SO_REUSEADDR: /* Allow reuse of local addresses */
case SO_KEEPALIVE: /* Keeps connections active by enabling the
* periodic transmission */
#ifndef CONFIG_NET_TCPPROTO_OPTIONS
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
* periodic transmission of probes */
#endif
case SO_OOBINLINE: /* Leaves received out-of-band data inline */
case SO_DONTROUTE: /* Requests outgoing messages bypass standard routing */
{
@@ -194,6 +175,23 @@ int psock_setsockopt(FAR struct socket *psock, int level, int option,
}
break;
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
/* Any connection-oriented protocol could potentially support
* SO_KEEPALIVE. However, this option is currently only available for
* TCP/IP.
*
* NOTE: SO_KEEPALIVE is not really a socket-level option; it is a
* protocol-level option. A given TCP connection may service multiple
* sockets (via dup'ing of the socket). There is, however, still only
* one connection to be monitored and that is a global attribute across
* all of the clones that may use the underlying connection.
*/
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
* periodic transmission of probes */
return tcp_setsockopt(psock, option, value, value_len);
#endif
case SO_RCVTIMEO:
case SO_SNDTIMEO:
{
@@ -208,7 +206,7 @@ int psock_setsockopt(FAR struct socket *psock, int level, int option,
}
/* Get the timeout value. Any microsecond remainder will be
* force to the next larger, whole decisecond value.
* forced to the next larger, whole decisecond value.
*/
timeo = (socktimeo_t)net_timeval2dsec(tv, TV2DS_CEIL);
@@ -296,6 +294,99 @@ int psock_setsockopt(FAR struct socket *psock, int level, int option,
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: psock_setsockopt
*
* Description:
* psock_setsockopt() sets the option specified by the 'option' argument,
* at the protocol level specified by the 'level' argument, to the value
* pointed to by the 'value' argument for the socket specified by the
* 'psock' argument.
*
* The 'level' argument specifies the protocol level of the option. To set
* options at the socket level, specify the level argument as SOL_SOCKET.
*
* See <sys/socket.h> a complete list of values for the socket level
* 'option' argument.
*
* Protocol level options, such as SOL_TCP, are defined in protocol-specific
* header files, for example include/netinet/tcp.h
*
* Input Parameters:
* psock Socket structure of socket to operate on
* level Protocol level to set the option
* option identifies the option to set
* value Points to the argument value
* value_len The length of the argument value
*
* Returned Value:
* Returns zero (OK) on success. On failure, it returns a negated errno
* value to indicate the nature of the error:
*
* EDOM
* The send and receive timeout values are too big to fit into the
* timeout fields in the socket structure.
* EINVAL
* The specified option is invalid at the specified socket 'level' or the
* socket has been shut down.
* EISCONN
* The socket is already connected, and a specified option cannot be set
* while the socket is connected.
* ENOPROTOOPT
* The 'option' is not supported by the protocol.
* ENOTSOCK
* The 'sockfd' argument does not refer to a socket.
* ENOMEM
* There was insufficient memory available for the operation to complete.
* ENOBUFS
* Insufficient resources are available in the system to complete the
* call.
*
****************************************************************************/
int psock_setsockopt(FAR struct socket *psock, int level, int option,
FAR const void *value, socklen_t value_len)
{
int ret;
/* Handle setting of the socket option according to the level at which
* option should be applied.
*/
switch (level)
{
case SOL_SOCKET: /* Socket-level options (see include/sys/socket.h) */
ret = psock_socketlevel_option(psock, option, value, value_len);
break;
case SOL_TCP: /* TCP protocol socket options (see include/netinet/tcp.h) */
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
ret = tcp_setsockopt(psock, option, value, value_len);
break;
#endif
/* These levels are defined in sys/socket.h, but are not yet
* implemented.
*/
case SOL_IP: /* TCP protocol socket options (see include/netinet/ip.h) */
case SOL_IPV6: /* TCP protocol socket options (see include/netinet/ip6.h) */
case SOL_UDP: /* TCP protocol socket options (see include/netinit/udp.h) */
ret = -ENOSYS;
break;
default: /* The provided level is invalid */
ret = -EINVAL;
break;
}
return ret;
}
/****************************************************************************
* Name: setsockopt
*
@@ -305,12 +396,16 @@ int psock_setsockopt(FAR struct socket *psock, int level, int option,
* pointed to by the 'value' argument for the socket associated with the
* file descriptor specified by the 'sockfd' argument.
*
* The 'level' argument specifies the protocol level of the option. To set
* The 'level' argument specifies the protocol level of the option. To set
* options at the socket level, specify the level argument as SOL_SOCKET.
*
* See <sys/socket.h> a complete list of values for the 'option' argument.
* See <sys/socket.h> a complete list of values for the socket level
* 'option' argument.
*
* Parameters:
* Protocol level options, such as SOL_TCP, are defined in protocol-specific
* header files, for example include/netinet/tcp.h
*
* Input Parameters:
* sockfd Socket descriptor of socket
* level Protocol level to set the option
* option identifies the option to set
@@ -318,30 +413,28 @@ int psock_setsockopt(FAR struct socket *psock, int level, int option,
* value_len The length of the argument value
*
* Returned Value:
* 0 on success; -1 on failure
* 0 on success; -1 on failure
*
* EBADF
* The 'sockfd' argument is not a valid socket descriptor.
* EDOM
* The send and receive timeout values are too big to fit into the
* timeout fields in the socket structure.
* EINVAL
* The specified option is invalid at the specified socket 'level' or the
* socket has been shut down.
* EISCONN
* The socket is already connected, and a specified option cannot be set
* while the socket is connected.
* ENOPROTOOPT
* The 'option' is not supported by the protocol.
* ENOTSOCK
* The 'sockfd' argument does not refer to a socket.
* ENOMEM
* There was insufficient memory available for the operation to complete.
* ENOBUFS
* Insufficient resources are available in the system to complete the
* call.
*
* Assumptions:
* EBADF
* The 'sockfd' argument is not a valid socket descriptor.
* EDOM
* The send and receive timeout values are too big to fit into the
* timeout fields in the socket structure.
* EINVAL
* The specified option is invalid at the specified socket 'level' or the
* socket has been shut down.
* EISCONN
* The socket is already connected, and a specified option cannot be set
* while the socket is connected.
* ENOPROTOOPT
* The 'option' is not supported by the protocol.
* ENOTSOCK
* The 'sockfd' argument does not refer to a socket.
* ENOMEM
* There was insufficient memory available for the operation to complete.
* ENOBUFS
* Insufficient resources are available in the system to complete the
* call.
*
****************************************************************************/