diff --git a/ChangeLog b/ChangeLog index c498961dbb..58a7d78813 100644 --- a/ChangeLog +++ b/ChangeLog @@ -248,3 +248,5 @@ * Removed unused uIP files * sched/, mm/, net/ subystem debug can not be selectively enabled/disabled + * Correct socket close logic -- needs to disconnect TCP socket on close + * uIP webserver now seems to be fully functional diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html index 3b9d5ad10e..969f78cd6a 100644 --- a/Documentation/NuttX.html +++ b/Documentation/NuttX.html @@ -8,7 +8,7 @@

NuttX RTOS

-

Last Updated: November 23, 2007

+

Last Updated: November 24, 2007

@@ -728,6 +728,8 @@ Other memory: * Removed unused uIP files * sched/, mm/, net/ subystem debug can not be selectively enabled/disabled + * Correct socket close logic -- needs to disconnect TCP socket on close + * uIP webserver now seems to be fully functional diff --git a/TODO b/TODO index 8cc39d820f..a9f96642c1 100644 --- a/TODO +++ b/TODO @@ -33,7 +33,6 @@ o Network but is not implemented. - uIP's netutils/telnetd (and maybe others) are seriously broken. Need to be re-written to use listen() and accept() -- uIP's netutils/webserver hangs (I think NuttX is not properly closing the connection) - uIP's netutils/smtp, dpcpc, resolv, webclient -- untested - Should implement SOCK_RAW - Performance Improvements (uIP is not very fast): diff --git a/net/connect.c b/net/connect.c index c6faa9e73a..2316e1ba33 100644 --- a/net/connect.c +++ b/net/connect.c @@ -47,6 +47,7 @@ #include #include +#include #include "net-internal.h" @@ -257,7 +258,10 @@ static uint8 tcp_connect_interrupt(struct uip_driver_s *dev, else { - return 0; + /* Drop data received in this state */ + + dev->d_len = 0; + return flags & ~UIP_NEWDATA; } nvdbg("Resuming: %d\n", pstate->tc_result); diff --git a/net/net-close.c b/net/net-close.c index 76dd7693f5..24a526ba6d 100644 --- a/net/net-close.c +++ b/net/net-close.c @@ -42,12 +42,144 @@ #include #include + #include +#include + +#include +#include #include "net-internal.h" /**************************************************************************** - * Global Functions + * Private Types + ****************************************************************************/ + +#ifdef CONFIG_NET_TCP +struct tcp_close_s +{ + FAR struct socket *cl_psock; /* Reference to the TCP socket */ + sem_t cl_sem; /* Semaphore signals disconnect completion */ +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: netclose_disconnect + * + * Description: + * Break any current TCP connection + * + * Parameters: + * conn - uIP TCP connection structure + * + * Returned Value: + * None + * + * Assumptions: + * Called from normal user-level logic + * + ****************************************************************************/ + +#ifdef CONFIG_NET_TCP +static uint8 netclose_interrupt(struct uip_driver_s *dev, + struct uip_conn *conn, uint8 flags) +{ + struct tcp_close_s *pstate = (struct tcp_close_s *)conn->data_private; + + nvdbg("flags: %02x\n", flags); + + if (pstate) + { + /* UIP_CLOSE: The remote host has closed the connection + * UIP_ABORT: The remote host has aborted the connection + */ + + if ((flags & (UIP_CLOSE|UIP_ABORT)) != 0) + { + /* The disconnection is complete */ + + conn->data_private = NULL; + conn->data_event = NULL; + sem_post(&pstate->cl_sem); + nvdbg("Resuming\n"); + } + else + { + /* Drop data received in this state and make sure that UIP_CLOSE + * is set in the response + */ + + dev->d_len = 0; + return (flags & ~UIP_NEWDATA) | UIP_CLOSE; + } + } + + return flags; +} +#endif /* CONFIG_NET_TCP */ + +/**************************************************************************** + * Function: netclose_disconnect + * + * Description: + * Break any current TCP connection + * + * Parameters: + * conn - uIP TCP connection structure + * + * Returned Value: + * None + * + * Assumptions: + * Called from normal user-level logic + * + ****************************************************************************/ + +#ifdef CONFIG_NET_TCP +static inline void netclose_disconnect(FAR struct socket *psock) +{ + struct tcp_close_s state; + struct uip_conn *conn; + irqstate_t flags; + + /* Interrupts are disabled here to avoid race conditions */ + + flags = irqsave(); + + /* Is the TCP socket in a connected state? */ + + if (_SS_ISCONNECTED(psock->s_flags)) + { + /* Set up to receive TCP data events */ + + state.cl_psock = psock; + sem_init(&state.cl_sem, 0, 0); + + conn = psock->s_conn; + conn->data_private = (void*)&state; + conn->data_event = netclose_interrupt; + + /* Wait for the disconnect event */ + + (void)sem_wait(&state.cl_sem); + + /* We are now disconnected */ + + sem_destroy(&state.cl_sem); + conn->data_private = NULL; + conn->data_event = NULL; + } + + irqrestore(flags); +} +#endif + +/**************************************************************************** + * Public Functions ****************************************************************************/ /**************************************************************************** @@ -87,20 +219,21 @@ int net_close(int sockfd) case SOCK_STREAM: { struct uip_conn *conn = psock->s_conn; - uip_unlisten(conn); - uip_tcpfree(conn); + uip_unlisten(conn); /* No longer accepting connections */ + netclose_disconnect(psock); /* Break any current connections */ + uip_tcpfree(conn); /* Free uIP resources */ } break; #endif #ifdef CONFIG_NET_UDP case SOCK_DGRAM: - uip_udpfree(psock->s_conn); + uip_udpfree(psock->s_conn); /* Free uIP resources */ break; #endif default: - err = -EBADF; + err = EBADF; goto errout; } diff --git a/net/sendto.c b/net/sendto.c index ba9bac0afd..a0f3cc4a10 100644 --- a/net/sendto.c +++ b/net/sendto.c @@ -196,18 +196,18 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) { FAR struct socket *psock; +#ifdef CONFIG_NET_UDP #ifdef CONFIG_NET_IPv6 FAR const struct sockaddr_in6 *into = (const struct sockaddr_in6 *)to; #else FAR const struct sockaddr_in *into = (const struct sockaddr_in *)to; #endif -#ifdef CONFIG_NET_UDP struct uip_udp_conn *udp_conn; struct sendto_s state; irqstate_t save; + int ret; #endif int err; - int ret; /* If to is NULL or tolen is zero, then this function is same as send (for * connected socket types)