Centralize TCP loss-of-connection bit twiddling

git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5542 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2013-01-20 17:21:42 +00:00
parent 28a0cf4aa0
commit 70cab4d797
5 changed files with 120 additions and 92 deletions

View File

@ -1,7 +1,7 @@
/****************************************************************************
* apps/netutils/telnetd_driver.c
*
* Copyright (C) 2007, 2009, 2011-2012 Gregory Nutt. All rights reserved.
* Copyright (C) 2007, 2009, 2011-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* This is a leverage of similar logic from uIP which has a compatible BSD
@ -593,6 +593,13 @@ static ssize_t telnetd_read(FAR struct file *filep, FAR char *buffer, size_t len
}
while (ret == 0);
/* Return:
*
* ret > 0: The number of characters copied into the user buffer by
* telnetd_receive().
* ret <= 0: Loss of connection or error events reported by recv().
*/
return ret;
}

View File

@ -1,7 +1,7 @@
/****************************************************************************
* net/net_internal.h
*
* Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2009, 2011-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -139,94 +139,96 @@
* Public Variables
****************************************************************************/
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/* List of registered ethernet device drivers */
#if CONFIG_NSOCKET_DESCRIPTORS > 0
extern struct uip_driver_s *g_netdevices;
EXTERN struct uip_driver_s *g_netdevices;
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C" {
#else
#define EXTERN extern
#endif
/* net_sockets.c *************************************************************/
EXTERN int sockfd_allocate(int minsd);
EXTERN void sock_release(FAR struct socket *psock);
EXTERN void sockfd_release(int sockfd);
EXTERN FAR struct socket *sockfd_socket(int sockfd);
int sockfd_allocate(int minsd);
void sock_release(FAR struct socket *psock);
void sockfd_release(int sockfd);
FAR struct socket *sockfd_socket(int sockfd);
/* net_connect.c *************************************************************/
#ifdef CONFIG_NET_TCP
EXTERN int net_startmonitor(FAR struct socket *psock);
EXTERN void net_stopmonitor(FAR struct uip_conn *conn);
int net_startmonitor(FAR struct socket *psock);
void net_stopmonitor(FAR struct uip_conn *conn);
void net_lostconnection(FAR struct socket *psock, uint16_t flags);
#endif
/* net_close.c ***************************************************************/
EXTERN int psock_close(FAR struct socket *psock);
int psock_close(FAR struct socket *psock);
/* sockopt support ***********************************************************/
#if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK)
EXTERN int net_timeo(uint32_t start_time, socktimeo_t timeo);
EXTERN socktimeo_t net_timeval2dsec(struct timeval *tv);
EXTERN void net_dsec2timeval(uint16_t dsec, struct timeval *tv);
int net_timeo(uint32_t start_time, socktimeo_t timeo);
socktimeo_t net_timeval2dsec(FAR struct timeval *tv);
void net_dsec2timeval(uint16_t dsec, FAR struct timeval *tv);
#endif
/* net_register.c ************************************************************/
#if CONFIG_NSOCKET_DESCRIPTORS > 0
EXTERN void netdev_seminit(void);
EXTERN void netdev_semtake(void);
EXTERN void netdev_semgive(void);
void netdev_seminit(void);
void netdev_semtake(void);
void netdev_semgive(void);
#endif
/* net_findbyname.c **********************************************************/
#if CONFIG_NSOCKET_DESCRIPTORS > 0
EXTERN FAR struct uip_driver_s *netdev_findbyname(const char *ifname);
FAR struct uip_driver_s *netdev_findbyname(FAR const char *ifname);
#endif
/* net_findbyaddr.c **********************************************************/
#if CONFIG_NSOCKET_DESCRIPTORS > 0
EXTERN FAR struct uip_driver_s *netdev_findbyaddr(const uip_ipaddr_t *raddr);
FAR struct uip_driver_s *netdev_findbyaddr(FAR const uip_ipaddr_t *raddr);
#endif
/* net_txnotify.c ************************************************************/
#if CONFIG_NSOCKET_DESCRIPTORS > 0
EXTERN void netdev_txnotify(const uip_ipaddr_t *raddr);
void netdev_txnotify(const uip_ipaddr_t *raddr);
#endif
/* net_count.c ***************************************************************/
#if CONFIG_NSOCKET_DESCRIPTORS > 0
EXTERN int netdev_count(void);
int netdev_count(void);
#endif
/* net_arptimer.c ************************************************************/
#ifdef CONFIG_NET_ARP
EXTERN void arptimer_init(void);
void arptimer_init(void);
#else
# define arptimer_init()
#endif
/* send.c ********************************************************************/
EXTERN ssize_t psock_send(FAR struct socket *psock, const void *buf,
size_t len, int flags);
ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len,
int flags);
#undef EXTERN
#if defined(__cplusplus)

View File

@ -1,7 +1,7 @@
/****************************************************************************
* net/net_monitor.c
*
* Copyright (C) 2007-2012 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -67,7 +67,6 @@ static void connection_event(struct uip_conn *conn, uint16_t flags);
* Some connection related event has occurred
*
* Parameters:
* dev The sructure of the network driver that caused the interrupt
* conn The connection structure associated with the socket
* flags Set of events describing why the callback was invoked
*
@ -79,7 +78,7 @@ static void connection_event(struct uip_conn *conn, uint16_t flags);
*
****************************************************************************/
static void connection_event(struct uip_conn *conn, uint16_t flags)
static void connection_event(FAR struct uip_conn *conn, uint16_t flags)
{
FAR struct socket *psock = (FAR struct socket *)conn->connection_private;
@ -87,37 +86,11 @@ static void connection_event(struct uip_conn *conn, uint16_t flags)
{
nllvdbg("flags: %04x s_flags: %02x\n", flags, psock->s_flags);
/* These loss-of-connection events may be reported:
*
* UIP_CLOSE: The remote host has closed the connection
* UIP_ABORT: The remote host has aborted the connection
* UIP_TIMEDOUT: Connection aborted due to too many retransmissions.
*
* And we need to set these two socket status bits appropriately:
*
* _SF_CONNECTED==1 && _SF_CLOSED==0 - the socket is connected
* _SF_CONNECTED==0 && _SF_CLOSED==1 - the socket was gracefully disconnected
* _SF_CONNECTED==0 && _SF_CLOSED==0 - the socket was rudely disconnected
*/
/* UIP_CLOSE, UIP_ABORT, or UIP_TIMEDOUT: Loss-of-connection events */
if ((flags & UIP_CLOSE) != 0)
if ((flags & (UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT)) != 0)
{
/* The peer gracefully closed the connection. Marking the
* connection as disconnected will suppress some subsequent
* ENOTCONN errors from receive. A graceful disconnection is
* not handle as an error but as an "end-of-file"
*/
psock->s_flags &= ~_SF_CONNECTED;
psock->s_flags |= _SF_CLOSED;
}
else if ((flags & (UIP_ABORT|UIP_TIMEDOUT)) != 0)
{
/* The loss of connection was less than graceful. This will (eventually)
* be reported as an ENOTCONN error.
*/
psock->s_flags &= ~(_SF_CONNECTED |_SF_CLOSED);
net_lostconnection(psock, flags);
}
/* UIP_CONNECTED: The socket is successfully connected */
@ -184,4 +157,60 @@ void net_stopmonitor(FAR struct uip_conn *conn)
conn->connection_event = NULL;
}
/****************************************************************************
* Name: net_lostconnection
*
* Description:
* Called when a loss-of-connection event has occurred.
*
* Parameters:
* psock The TCP socket structure associated.
* flags Set of connection events events
*
* Returned Value:
* None
*
* Assumptions:
* Running at the interrupt level
*
****************************************************************************/
void net_lostconnection(FAR struct socket *psock, uint16_t flags)
{
DEBUGASSERT(psock)
/* These loss-of-connection events may be reported:
*
* UIP_CLOSE: The remote host has closed the connection
* UIP_ABORT: The remote host has aborted the connection
* UIP_TIMEDOUT: Connection aborted due to too many retransmissions.
*
* And we need to set these two socket status bits appropriately:
*
* _SF_CONNECTED==1 && _SF_CLOSED==0 - the socket is connected
* _SF_CONNECTED==0 && _SF_CLOSED==1 - the socket was gracefully disconnected
* _SF_CONNECTED==0 && _SF_CLOSED==0 - the socket was rudely disconnected
*/
if ((flags & UIP_CLOSE) != 0)
{
/* The peer gracefully closed the connection. Marking the
* connection as disconnected will suppress some subsequent
* ENOTCONN errors from receive. A graceful disconnection is
* not handle as an error but as an "end-of-file"
*/
psock->s_flags &= ~_SF_CONNECTED;
psock->s_flags |= _SF_CLOSED;
}
else if ((flags & (UIP_ABORT|UIP_TIMEDOUT)) != 0)
{
/* The loss of connection was less than graceful. This will (eventually)
* be reported as an ENOTCONN error.
*/
psock->s_flags &= ~(_SF_CONNECTED |_SF_CLOSED);
}
}
#endif /* CONFIG_NET && CONFIG_NET_TCP */

View File

@ -1,7 +1,7 @@
/****************************************************************************
* net/recvfrom.c
*
* Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2009, 2011-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -464,10 +464,11 @@ static inline void recvfrom_tcpsender(struct uip_driver_s *dev, struct recvfrom_
****************************************************************************/
#ifdef CONFIG_NET_TCP
static uint16_t recvfrom_tcpinterrupt(struct uip_driver_s *dev, void *conn,
void *pvpriv, uint16_t flags)
static uint16_t recvfrom_tcpinterrupt(FAR struct uip_driver_s *dev,
FAR void *conn, FAR void *pvpriv,
uint16_t flags)
{
struct recvfrom_s *pstate = (struct recvfrom_s *)pvpriv;
FAR struct recvfrom_s *pstate = (struct recvfrom_s *)pvpriv;
nllvdbg("flags: %04x\n", flags);
@ -553,9 +554,7 @@ static uint16_t recvfrom_tcpinterrupt(struct uip_driver_s *dev, void *conn,
else if ((flags & (UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT)) != 0)
{
FAR struct socket *psock = 0;
nllvdbg("error\n");
nllvdbg("Lost connection\n");
/* Stop further callbacks */
@ -563,24 +562,14 @@ static uint16_t recvfrom_tcpinterrupt(struct uip_driver_s *dev, void *conn,
pstate->rf_cb->priv = NULL;
pstate->rf_cb->event = NULL;
/* Check if the peer gracefully closed the connection. We need
* these flags in case we return zero (below) to remember the
* state of the connection.
*
* _SF_CONNECTED==0 && _SF_CLOSED==1 - the socket was
* gracefully disconnected
* _SF_CONNECTED==0 && _SF_CLOSED==0 - the socket was
* rudely disconnected
*/
/* Handle loss-of-connection event */
net_lostconnection(pstate->rf_sock, flags);
/* Check if the peer gracefully closed the connection. */
psock = pstate->rf_sock;
if ((flags & UIP_CLOSE) != 0)
{
/* Report that the connection was gracefully closed */
psock->s_flags &= ~_SF_CONNECTED;
psock->s_flags |= _SF_CLOSED;
/* This case should always return success (zero)! The value of
* rf_recvlen, if zero, will indicate that the connection was
* gracefully closed.
@ -590,10 +579,6 @@ static uint16_t recvfrom_tcpinterrupt(struct uip_driver_s *dev, void *conn,
}
else
{
/* Report that the connection was rudely lost */
psock->s_flags &= ~(_SF_CONNECTED |_SF_CLOSED);
/* If no data has been received, then return ENOTCONN.
* Otherwise, let this return success. The failure will
* be reported the next time that recv[from]() is called.

View File

@ -227,6 +227,8 @@ static uint16_t send_interrupt(struct uip_driver_s *dev, void *pvconn,
/* Report not connected */
nllvdbg("Lost connection\n");
net_lostconnection(pstate->snd_sock, flags);
pstate->snd_sent = -ENOTCONN;
goto end_wait;
}
@ -275,10 +277,13 @@ static uint16_t send_interrupt(struct uip_driver_s *dev, void *pvconn,
* 3. Not enough data for two packets.
*
* Then we will split the remaining, single packet into two partial
* packets. This will stimulate the RFC 1122 not into ACKing sooner.
* packets. This will stimulate the RFC 1122 peer to ACK sooner.
*
* Check if there is more data to be sent (more than or equal to
* CONFIG_NET_TCP_SPLIT_SIZE):
* Don't try to split very small packets (less than CONFIG_NET_TCP_SPLIT_SIZE).
* Only the first even packet and the last odd packets could have
* sndlen less than CONFIG_NET_TCP_SPLIT_SIZE. The value of sndlen on
* the last even packet is guaranteed to be at least MSS/2 by the
* logic below.
*/
if (sndlen >= CONFIG_NET_TCP_SPLIT_SIZE)