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)