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
+19 -7
View File
@@ -1,7 +1,7 @@
/****************************************************************************
* include/netinet/tcp.h
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2017-2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -46,15 +46,27 @@
* Pre-processor Definitions
****************************************************************************/
/* "The netinet/tcp.h header shall define the following macro for use as a
* socket option at the IPPROTO_TCP level:" -- OpenGroup.org
/* Per OpenGroup.org:
*
* "The netinet/tcp.h header shall define the following macro for use as a
* socket option at the IPPROTO_TCP level:" -- OpenGroup.org
*/
#define TCP_NODELAY __SO_PROTOCOL /* Avoid coalescing of small segments. */
#define TCP_NODELAY (__SO_PROTOCOL + 0) /* Avoid coalescing of small segments. */
/* "The macro shall be defined in the header. The implementation need not
* allow the value of the option to be set via setsockopt() or retrieved via
* getsockopt()." -- OpenGroup.org
/* "The macro shall be defined in the header. The implementation need not
* allow the value of the option to be set via setsockopt() or retrieved via
* getsockopt()."
*/
/* Additional TCP protocol socket operations not specified at OpenGroup.org */
/* TCP protocol socket operations needed to support TCP Keep-Alive: */
#define TCP_KEEPIDLE (__SO_PROTOCOL + 1) /* Start keeplives after this IDLE period
* Argument: struct timeval */
#define TCP_KEEPINTVL (__SO_PROTOCOL + 2) /* Interval between keepalives
* Argument: struct timeval */
#define TCP_KEEPCNT (__SO_PROTOCOL + 3) /* Number of keepalives before death
* Argument: max retry count */
#endif /* __INCLUDE_NETINET_TCP_H */
+21 -3
View File
@@ -1,7 +1,7 @@
/****************************************************************************
* include/nuttx/clock.h
*
* Copyright (C) 2007-2009, 2011-2012, 2014, 2016-2017 Gregory Nutt.
* Copyright (C) 2007-2009, 2011-2012, 2014, 2016-2018 Gregory Nutt.
All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
@@ -120,6 +120,21 @@
#define NSEC_PER_USEC 1000L /* Microseconds */
#define SEC_PER_MIN 60L
#define NSEC_PER_MIN (NSEC_PER_SEC * SEC_PER_MIN)
#define USEC_PER_MIN (USEC_PER_SEC * SEC_PER_MIN)
#define MSEC_PER_MIN (MSEC_PER_SEC * SEC_PER_MIN)
#define DSEC_PER_MIN (HSEC_PER_SEC * SEC_PER_MIN)
#define HSEC_PER_MIN (HSEC_PER_SEC * SEC_PER_MIN)
#define MIN_PER_HOUR 60L
#define NSEC_PER_HOUR (NSEC_PER_MIN * MIN_PER_HOUR)
#define USEC_PER_HOUR (USEC_PER_MIN * MIN_PER_HOUR)
#define MSEC_PER_HOUR (MSEC_PER_MIN * MIN_PER_HOUR)
#define DSEC_PER_HOUR (HSEC_PER_SEC * MIN_PER_HOUR)
#define HSEC_PER_HOUR (DSEC_PER_MIN * MIN_PER_HOUR)
#define SEC_PER_HOUR (SEC_PER_MIN * MIN_PER_HOUR)
/* If CONFIG_SCHED_TICKLESS is not defined, then the interrupt interval of
* the system timer is given by USEC_PER_TICK. This is the expected number
* of microseconds between calls from the processor-specific logic to
@@ -145,10 +160,13 @@
* preferred for that reason (at the risk of overflow)
*/
#define TICK_PER_DSEC (USEC_PER_DSEC / USEC_PER_TICK) /* Truncates! */
#define TICK_PER_HSEC (USEC_PER_HSEC / USEC_PER_TICK) /* Truncates! */
#define TICK_PER_HOUR (USEC_PER_HOUR / USEC_PER_TICK) /* Truncates! */
#define TICK_PER_MIN (USEC_PER_MIN / USEC_PER_TICK) /* Truncates! */
#define TICK_PER_SEC (USEC_PER_SEC / USEC_PER_TICK) /* Truncates! */
#define TICK_PER_MSEC (USEC_PER_MSEC / USEC_PER_TICK) /* Truncates! */
#define TICK_PER_DSEC (USEC_PER_DSEC / USEC_PER_TICK) /* Truncates! */
#define TICK_PER_HSEC (USEC_PER_HSEC / USEC_PER_TICK) /* Truncates! */
#define MSEC_PER_TICK (USEC_PER_TICK / USEC_PER_MSEC) /* Truncates! */
#define NSEC_PER_TICK (USEC_PER_TICK * NSEC_PER_USEC) /* Exact */
+13 -5
View File
@@ -1,7 +1,8 @@
/****************************************************************************
* include/sys/socket.h
*
* Copyright (C) 2007, 2009, 2011, 2015-2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2007, 2009, 2011, 2015-2016, 2018 Gregory Nutt. All
* rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -128,7 +129,7 @@
* an integer value */
#define SO_KEEPALIVE 5 /* Keeps connections active by enabling the periodic transmission
* of messages (get/set).
* arg: pointer to integer containing a boolean value */
* arg: pointer to integer containing a boolean int value */
#define SO_LINGER 6 /* Lingers on a close() if data is present (get/set)
* arg: struct linger */
#define SO_OOBINLINE 7 /* Leaves received out-of-band data (data marked urgent) inline
@@ -149,15 +150,22 @@
* being sent(get/set). arg: struct timeval */
#define SO_TYPE 15 /* Reports the socket type (get only). return: int */
/* Protocol-level socket operations */
#define SOL_IP 1 /* See options in include/netinet/ip.h */
#define SOL_IPV6 2 /* See options in include/netinet/ip6.h */
#define SOL_TCP 3 /* See options in include/netinet/tcp.h */
#define SOL_UDP 4 /* See options in include/netinit/udp.h */
/* Protocol-level socket options may begin with this value */
#define __SO_PROTOCOL 16
/* Values for the 'how' argument of shutdown() */
#define SHUT_RD 1 /* Bit 0: Disables further receive operations */
#define SHUT_WR 2 /* Bit 1: Disables further send operations */
#define SHUT_RDWR 3 /* Bits 0+1: Disables further send and receive operations */
#define SHUT_RD 1 /* Bit 0: Disables further receive operations */
#define SHUT_WR 2 /* Bit 1: Disables further send operations */
#define SHUT_RDWR 3 /* Bits 0+1: Disables further send and receive operations */
/****************************************************************************
* Type Definitions
+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.
*
****************************************************************************/
+8
View File
@@ -20,6 +20,14 @@ config NET_TCP_NO_STACK
if NET_TCP && !NET_TCP_NO_STACK
config NET_TCP_KEEPALIVE
bool "TCP/IP Keep-alive support"
default n
select NET_TCPPROTO_OPTIONS
depends on EXPERIMENTAL
---help---
Enable support for the SO_KEEPALIVE socket option
config NET_TCPURGDATA
bool "Urgent data"
default n
+5 -1
View File
@@ -1,7 +1,7 @@
############################################################################
# net/tcp/Make.defs
#
# Copyright (C) 2014, 2017 Gregory Nutt. All rights reserved.
# Copyright (C) 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
@@ -58,6 +58,10 @@ NET_CSRCS += tcp_netpoll.c
endif
endif
ifeq ($(CONFIG_NET_TCPPROTO_OPTIONS),y)
SOCK_CSRCS += tcp_setsockopt.c tcp_getsockopt.c
endif
# Transport layer
NET_CSRCS += tcp_conn.c tcp_seqno.c tcp_devpoll.c tcp_finddev.c tcp_timer.c
+84
View File
@@ -45,6 +45,7 @@
#include <sys/types.h>
#include <queue.h>
#include <nuttx/clock.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/ip.h>
@@ -199,6 +200,21 @@ struct tcp_conn_s
FAR struct tcp_backlog_s *backlog;
#endif
#ifdef CONFIG_NET_TCP_KEEPALIVE
/* There fields manage TCP/IP keep-alive. All times are in units of the
* system clock tick.
*/
systime_t keeptime; /* Last time that the TCP socket was known to be
* alive (ACK or data received) OR time that the
* last probe was sent. */
uint16_t keepidle; /* Elapsed idle time before first probe sent (dsec) */
uint16_t keepintvl; /* Interval between probes (dsec) */
bool keepalive; /* True: KeepAlive enabled; false: disabled */
uint8_t keepcnt; /* Number of retries before the socket is closed */
uint8_t keepretries; /* Number of retries attempted */
#endif
/* Application callbacks:
*
* Data transfer events are retained in 'list'. Event handlers in 'list'
@@ -1271,6 +1287,74 @@ struct socket;
ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf,
size_t len);
/****************************************************************************
* Name: tcp_setsockopt
*
* Description:
* tcp_setsockopt() sets the TCP-protocol option specified by the
* 'option' argument to the value pointed to by the 'value' argument for
* the socket specified by the 'psock' argument.
*
* See <netinet/tcp.h> for the a complete list of values of TCP protocol
* options.
*
* Input Parameters:
* psock Socket structure of socket to operate on
* 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. See psock_setcockopt() for
* the list of possible error values.
*
****************************************************************************/
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
int tcp_setsockopt(FAR struct socket *psock, int option,
FAR const void *value, socklen_t value_len);
#endif
/****************************************************************************
* Name: tcp_getsockopt
*
* Description:
* tcp_getsockopt() retrieves 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. See psock_getsockopt() for
* the complete list of appropriate return error codes.
*
****************************************************************************/
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
int tcp_getsockopt(FAR struct socket *psock, int option,
FAR void *value, FAR socklen_t *value_len);
#endif
/****************************************************************************
* Name: psock_tcp_cansend
*
+9 -1
View File
@@ -1,7 +1,8 @@
/****************************************************************************
* net/tcp/tcp_conn.c
*
* Copyright (C) 2007-2011, 2013-2015 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2011, 2013-2015, 2018 Gregory Nutt. All rights
* reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Large parts of this file were leveraged from uIP logic:
@@ -53,6 +54,7 @@
#include <arch/irq.h>
#include <nuttx/clock.h>
#include <nuttx/net/netconfig.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
@@ -714,6 +716,12 @@ FAR struct tcp_conn_s *tcp_alloc(uint8_t domain)
conn->tcpstateflags = TCP_ALLOCATED;
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
conn->domain = domain;
#endif
#ifdef CONFIG_NET_TCP_KEEPALIVE
conn->keeptime = clock_systimer();
conn->keepidle = 2 * DSEC_PER_HOUR;
conn->keepintvl = 2 * DSEC_PER_SEC;
conn->keepcnt = 3;
#endif
}
+254
View File
@@ -0,0 +1,254 @@
/****************************************************************************
* net/tcp/tcp_setsockopt.c
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 <nuttx/config.h>
#include <sys/time.h>
#include <stdint.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <netinet/tcp.h>
#include <nuttx/net/net.h>
#include <nuttx/net/tcp.h>
#include "socket/socket.h"
#include "utils/utils.h"
#include "tcp/tcp.h"
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: tcp_getsockopt
*
* Description:
* tcp_getsockopt() retrieves 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. See psock_getsockopt() for
* the complete list of appropriate return error codes.
*
****************************************************************************/
int tcp_getsockopt(FAR struct socket *psock, int option,
FAR void *value, FAR socklen_t *value_len)
{
#ifdef CONFIG_NET_TCP_KEEPALIVE
/* Keep alive options are the only TCP protocol socket option currently
* supported.
*/
FAR struct tcp_conn_s *conn;
int ret;
DEBUGASSERT(psock != NULL && value != NULL && value_len != NULL &&
psock->s_conn != NULL);
conn = (FAR struct tcp_conn_s *)psock->s_conn;
/* All of the TCP protocol options apply only TCP sockets. The sockets
* do not have to be connected.. that might occur later with the KeepAlive
* already configured.
*/
if (psock->s_type != SOCK_STREAM)
{
nerr("ERROR: Not a TCP socket\n");
return -ENOTCONN;
}
/* Handle the Keep-Alive option */
switch (option)
{
/* Handle the SO_KEEPALIVE socket-level option.
*
* 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 */
if (*value_len < sizeof(int))
{
/* REVISIT: POSIX says that we should truncate the value if it
* is larger than value_len. That just doesn't make sense
* to me in this case.
*/
ret = -EINVAL;
}
else
{
FAR int *keepalive = (FAR int *)value;
*keepalive = (int)conn->keepalive;
*value_len = sizeof(int);
ret = OK;
}
break;
case TCP_NODELAY: /* Avoid coalescing of small segments. */
nerr("ERROR: TCP_NODELAY not supported\n");
ret = -ENOSYS;
break;
case TCP_KEEPIDLE: /* Start keepalives after this IDLE period */
if (*value_len < sizeof(struct timeval))
{
/* REVISIT: POSIX says that we should truncate the value if it
* is larger than value_len. That just doesn't make sense
* to me in this case.
*/
ret = -EINVAL;
}
else
{
FAR struct timeval *tv = (FAR struct timeval *)value;
if (tv == NULL)
{
ret = -EINVAL;
}
else
{
/* Convert the KeepIdle time from deciseconds to struct
* timeval.
*/
net_dsec2timeval(conn->keepidle, tv);
*value_len = sizeof(struct timeval);
ret = OK;
}
}
break;
case TCP_KEEPINTVL: /* Interval between keepalives */
if (*value_len < sizeof(struct timeval))
{
/* REVISIT: POSIX says that we should truncate the value if it
* is larger than value_len. That just doesn't make sense
* to me in this case.
*/
ret = -EINVAL;
}
else
{
FAR struct timeval *tv = (FAR struct timeval *)value;
if (tv == NULL)
{
ret = -EINVAL;
}
else
{
/* Convert the KeepIdle time from deciseconds to struct
* timeval.
*/
net_dsec2timeval(conn->keepintvl, tv);
*value_len = sizeof(struct timeval);
ret = OK;
}
}
break;
case TCP_KEEPCNT: /* Number of keepalives before death */
if (*value_len < sizeof(int))
{
/* REVISIT: POSIX says that we should truncate the value if it
* is larger than value_len. That just doesn't make sense
* to me in this case.
*/
ret = -EINVAL;
}
else
{
FAR int *keepcnt = (FAR int *)value;
*keepcnt = (int)conn->keepcnt;
*value_len = sizeof(int);
ret = OK;
}
break;
default:
nerr("ERROR: Unrecognized TCP option: %d\n", option);
ret = -ENOPROTOOPT;
break;
}
return ret;
#else
return -ENOPROTOOPT;
#endif /* CONFIG_NET_TCP_KEEPALIVE */
}
#endif /* CONFIG_NET_TCPPROTO_OPTIONS */
+27 -7
View File
@@ -2,7 +2,7 @@
* net/tcp/tcp_input.c
* Handling incoming TCP input
*
* Copyright (C) 2007-2014, 2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2014, 2017-2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Adapted for NuttX from logic in uIP which also has a BSD-like license:
@@ -51,6 +51,7 @@
#include <assert.h>
#include <debug.h>
#include <nuttx/clock.h>
#include <nuttx/net/netconfig.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/netstats.h>
@@ -385,7 +386,7 @@ found:
dev->d_len -= (len + iplen);
/* First, check if the sequence number of the incoming packet is
* what we're expecting next. If not, we send out an ACK with the
* what we're expecting next. If not, we send out an ACK with the
* correct numbers in, unless we are in the SYN_RCVD state and
* receive a SYN, in which case we should retransmit our SYNACK
* (which is done further down).
@@ -685,14 +686,14 @@ found:
case TCP_ESTABLISHED:
/* In the ESTABLISHED state, we call upon the application to feed
* data into the d_buf. If the TCP_ACKDATA flag is set, the
* data into the d_buf. If the TCP_ACKDATA flag is set, the
* application should put new data into the buffer, otherwise we are
* retransmitting an old segment, and the application should put that
* data into the buffer.
*
* If the incoming packet is a FIN, we should close the connection on
* this side as well, and we send out a FIN and enter the LAST_ACK
* state. We require that there is no outstanding data; otherwise the
* state. We require that there is no outstanding data; otherwise the
* sequence numbers will be screwed up.
*/
@@ -763,6 +764,25 @@ found:
#endif /* CONFIG_NET_TCPURGDATA */
}
#ifdef NET_TCP_KEEPALIVE
/* If the established socket receives an ACK or any kind of data
* from the remote peer (whether we accept it or not), then reset
* the keep alive timer.
*/
if (conn->keepalive && (dev->d_len > 0 || (tcp->flags & TCP_ACK) != 0))
{
/* Reset the last known "alive" time.
*
* REVISIT: At this level, we don't actually know if keep-
* alive is enabled for this connection.
*/
conn->keeptime = clock_systimer();
conn->keepretries = 0;
}
#endif
/* If d_len > 0 we have TCP data in the packet, and we flag this
* by setting the TCP_NEWDATA flag. If the application has stopped
* the data flow using TCP_STOPPED, we must not accept any data
@@ -776,19 +796,19 @@ found:
/* If this packet constitutes an ACK for outstanding data (flagged
* by the TCP_ACKDATA flag), we should call the application since it
* might want to send more data. If the incoming packet had data
* might want to send more data. If the incoming packet had data
* from the peer (as flagged by the TCP_NEWDATA flag), the
* application must also be notified.
*
* When the application is called, the d_len field
* contains the length of the incoming data. The application can
* contains the length of the incoming data. The application can
* access the incoming data through the global pointer
* d_appdata, which usually points hdrlen bytes into the d_buf
* array.
*
* If the application wishes to send any data, this data should be
* put into the d_appdata and the length of the data should be
* put into d_len. If the application don't have any data to
* put into d_len. If the application don't have any data to
* send, d_len must be set to 0.
*/
+2 -2
View File
@@ -1,7 +1,7 @@
/****************************************************************************
* net/tcp/tcp_monitor.c
*
* Copyright (C) 2007-2013, 2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2013, 2017-2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -206,7 +206,7 @@ static uint16_t tcp_disconnect_event(FAR struct net_driver_s *dev,
*
****************************************************************************/
void tcp_shutdown_monitor(FAR struct tcp_conn_s *conn, uint16_t flags)
static void tcp_shutdown_monitor(FAR struct tcp_conn_s *conn, uint16_t flags)
{
DEBUGASSERT(conn);
+267
View File
@@ -0,0 +1,267 @@
/****************************************************************************
* net/tcp/tcp_setsockopt.c
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 <nuttx/config.h>
#include <sys/time.h>
#include <stdint.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <netinet/tcp.h>
#include <nuttx/clock.h>
#include <nuttx/net/net.h>
#include <nuttx/net/tcp.h>
#include "socket/socket.h"
#include "utils/utils.h"
#include "tcp/tcp.h"
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: tcp_setsockopt
*
* Description:
* tcp_setsockopt() sets the TCP-protocol option specified by the
* 'option' argument to the value pointed to by the 'value' argument for
* the socket specified by the 'psock' argument.
*
* See <netinet/tcp.h> for the a complete list of values of TCP protocol
* options.
*
* Input Parameters:
* psock Socket structure of socket to operate on
* 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. See psock_setcockopt() for
* the list of possible error values.
*
****************************************************************************/
int tcp_setsockopt(FAR struct socket *psock, int option,
FAR const void *value, socklen_t value_len)
{
#ifdef CONFIG_NET_TCP_KEEPALIVE
/* Keep alive options are the only TCP protocol socket option currently
* supported.
*/
FAR struct tcp_conn_s *conn;
int ret;
DEBUGASSERT(psock != NULL && value != NULL && psock->s_conn != NULL);
conn = (FAR struct tcp_conn_s *)psock->s_conn;
/* All of the TCP protocol options apply only TCP sockets. The sockets
* do not have to be connected.. that might occur later with the KeepAlive
* already configured.
*/
if (psock->s_type != SOCK_STREAM)
{
nerr("ERROR: Not a TCP socket\n");
return -ENOTCONN;
}
/* Handle the Keep-Alive option */
switch (option)
{
/* Handle the SO_KEEPALIVE socket-level option.
*
* 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 */
if (value_len != sizeof(int))
{
ret = -EDOM;
}
else
{
int keepalive = *(FAR int *)value;
if (keepalive != 0 && keepalive != 1)
{
nerr("ERROR: SO_KEEPALIVE value out of range: %d\n",
keepalive);
return -EDOM;
}
else
{
conn->keepalive = (bool)keepalive;
conn->keeptime = clock_systimer(); /* Reset start time */
ret = OK;
}
}
break;
case TCP_NODELAY: /* Avoid coalescing of small segments. */
nerr("ERROR: TCP_NODELAY not supported\n");
ret = -ENOSYS;
break;
case TCP_KEEPIDLE: /* Start keepalives after this IDLE period */
if (value_len != sizeof(struct timeval))
{
ret = -EDOM;
}
else
{
FAR struct timeval *tv = (FAR struct timeval *)value;
if (tv == NULL)
{
ret = -EINVAL;
}
else
{
unsigned int dsecs;
/* Get the IDLE time value. Any microsecond remainder will
* be forced to the next larger, whole decisecond value.
*/
dsecs = (socktimeo_t)net_timeval2dsec(tv, TV2DS_CEIL);
if (dsecs > UINT16_MAX)
{
nwarn("WARNING: TCP_KEEPIDLE value out of range: %u\n",
dsecs);
ret = -EDOM;
}
else
{
conn->keepidle = (uint16_t)dsecs;
conn->keeptime = clock_systimer(); /* Reset start time */
ret = OK;
}
}
}
break;
case TCP_KEEPINTVL: /* Interval between keepalives */
if (value_len != sizeof(struct timeval))
{
ret = -EDOM;
}
else
{
FAR struct timeval *tv = (FAR struct timeval *)value;
if (tv == NULL)
{
ret = -EINVAL;
}
else
{
unsigned int dsecs;
/* Get the IDLE time value. Any microsecond remainder will
* be forced to the next larger, whole decisecond value.
*/
dsecs = (socktimeo_t)net_timeval2dsec(tv, TV2DS_CEIL);
if (dsecs > UINT16_MAX)
{
nwarn("WARNING: TCP_KEEPINTVL value out of range: %u\n",
dsecs);
ret = -EDOM;
}
else
{
conn->keepintvl = (uint16_t)dsecs;
conn->keeptime = clock_systimer(); /* Reset start time */
ret = OK;
}
}
}
break;
case TCP_KEEPCNT: /* Number of keepalives before death */
if (value_len != sizeof(int))
{
ret = -EDOM;
}
else
{
int keepcnt = *(FAR int *)value;
if (keepcnt < 0 || keepcnt > UINT8_MAX)
{
nerr("ERROR: TCP_KEEPCNT value out of range: %d\n", keepcnt);
return -EDOM;
}
else
{
conn->keepcnt = (uint8_t)keepcnt;
conn->keeptime = clock_systimer(); /* Reset start time */
ret = OK;
}
}
break;
default:
nerr("ERROR: Unrecognized TCP option: %d\n", option);
ret = -ENOPROTOOPT;
break;
}
return ret;
#else
return -ENOPROTOOPT;
#endif /* CONFIG_NET_TCP_KEEPALIVE */
}
#endif /* CONFIG_NET_TCPPROTO_OPTIONS */
+87 -5
View File
@@ -2,7 +2,8 @@
* net/tcp/tcp_timer.c
* Poll for the availability of TCP TX data
*
* Copyright (C) 2007-2010, 2015-2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2010, 2015-2016, 2018 Gregory Nutt. All rights
* reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Adapted for NuttX from logic in uIP which also has a BSD-like license:
@@ -50,11 +51,13 @@
#include <debug.h>
#include <nuttx/net/netconfig.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/netstats.h>
#include <nuttx/net/tcp.h>
#include "devif/devif.h"
#include "socket/socket.h"
#include "tcp/tcp.h"
/****************************************************************************
@@ -347,10 +350,6 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
else if ((conn->tcpstateflags & TCP_STATE_MASK) == TCP_ESTABLISHED)
{
/* If there was no need for a retransmission, we poll the
* application for new data.
*/
/* The TCP connection is established and, hence, should be bound
* to a device. Make sure that the polling device is the one that
* we are bound to.
@@ -359,6 +358,89 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
DEBUGASSERT(conn->dev != NULL);
if (dev == conn->dev)
{
#ifdef CONFIG_NET_TCP_KEEPALIVE
/* Is this an established connected with KeepAlive enabled? */
if (conn->keepalive)
{
socktimeo_t timeo;
/* If this is the first probe, then the keepstart time is
* the time that the last ACK or data was received from the
* remote.
*
* On subsequent retries, keepstart is the time that the
* last probe was sent.
*/
if (conn->keepretries > 0)
{
timeo = (socktimeo_t)conn->keepintvl;
}
else
{
timeo = (socktimeo_t)conn->keepidle;
}
/* Yes... has the idle period elapsed with no data or ACK
* received from the remote peer?
*/
if (net_timeo(conn->keeptime, timeo))
{
/* Yes.. Has the retry count expired? */
if (conn->keepretries >= conn->keepcnt)
{
/* Yes... stop the network monitor, closing the connection and all sockets
* associated with the connection.
*/
tcp_stop_monitor(conn, TCP_ABORT);
}
else
{
unsigned int tcpiplen;
/* No.. we need to send another probe.
*
* Get the size of the IP header and the TCP header.
*/
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
if (conn->domain == PF_INET)
#endif
{
tcpiplen = IPv4_HDRLEN + TCP_HDRLEN;
}
#endif
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
else
#endif
{
tcpiplen = IPv6_HDRLEN + TCP_HDRLEN;
}
#endif
/* And send the probe */
tcp_send(dev, conn, TCP_ACK, tcpiplen);
/* Update for the next probe */
conn->keeptime = clock_systimer();
conn->keepretries++;
}
goto done;
}
}
#endif
/* There was no need for a retransmission and there was no
* need to probe the remote peer. We poll the application for
* new outgoing data.
*/
result = tcp_callback(dev, conn, TCP_POLL);
tcp_appsend(dev, conn, result);
goto done;