From 5128effaf839159a5d0897c0d6a3cc4790b55514 Mon Sep 17 00:00:00 2001 From: patacongo Date: Sun, 20 Jan 2013 00:41:33 +0000 Subject: Yet another repair for the previouis botched recvfrom() fix; Fix telnet driver: It needs to break out of the read loop if 0 (meaning not conneced) of a value < 0 (an error) is encountered. git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5541 42af7a65-404d-4744-a932-0658087f49c3 --- apps/ChangeLog.txt | 2 ++ apps/netutils/telnetd/telnetd_driver.c | 18 ++++++++++++-- nuttx/ChangeLog | 3 +++ nuttx/net/recvfrom.c | 43 ++++++++++++++++++++-------------- 4 files changed, 46 insertions(+), 20 deletions(-) diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt index a445c2024..bcc0ac172 100644 --- a/apps/ChangeLog.txt +++ b/apps/ChangeLog.txt @@ -490,3 +490,5 @@ * apps/builtin/: Extensions from Mike Smith. * apps/examples/ftpd/Makefile: Name ftpd_start is not the name of the entrypoint. Should be ftpd_main (from Yan T.) + * apps/netutils/telnetd/telnetd_driver: Was stuck in a loop if + recv[from]() ever returned a value <= 0. diff --git a/apps/netutils/telnetd/telnetd_driver.c b/apps/netutils/telnetd/telnetd_driver.c index 1183a2f70..274fde370 100644 --- a/apps/netutils/telnetd/telnetd_driver.c +++ b/apps/netutils/telnetd/telnetd_driver.c @@ -558,6 +558,8 @@ static ssize_t telnetd_read(FAR struct file *filep, FAR char *buffer, size_t len { if (priv->td_pending > 0) { + /* Process the buffered telnet data */ + FAR const char *src = &priv->td_rxbuffer[priv->td_offset]; ret = telnetd_receive(priv, src, priv->td_pending, buffer, len); } @@ -568,13 +570,25 @@ static ssize_t telnetd_read(FAR struct file *filep, FAR char *buffer, size_t len { ret = psock_recv(&priv->td_psock, priv->td_rxbuffer, CONFIG_TELNETD_RXBUFFER_SIZE, 0); + + /* Did we receive anything? */ + if (ret > 0) { - /* Process the received telnet data */ + /* Yes.. Process the newly received telnet data */ telnetd_dumpbuffer("Received buffer", priv->td_rxbuffer, ret); ret = telnetd_receive(priv, priv->td_rxbuffer, ret, buffer, len); } + + /* Otherwise the peer closed the connection (ret == 0) or an error + * occurred (ret < 0). + */ + + else + { + break; + } } } while (ret == 0); @@ -746,7 +760,7 @@ FAR char *telnetd_driver(int sd, FAR struct telnetd_s *daemon) * instance resided in the daemon's socket array). */ - psock = sockfd_socket(sd); + psock = sockfd_socket(sd); if (!psock) { nlldbg("Failed to convert sd=%d to a socket structure\n", sd); diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 80944db66..77441dd21 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -3993,3 +3993,6 @@ (gracefully). recv[from]() returned success and the closure was never detected. Hmmm.. I don't know why the network monitor did not catch this event. This is an important bug fix. + * net/recvfrom(): Fix a introduced with the last bugfix. If + the peer does an orderly closure of the socket, report 0 not + -ENOTCONN diff --git a/nuttx/net/recvfrom.c b/nuttx/net/recvfrom.c index ac8065f81..a1a6742c5 100644 --- a/nuttx/net/recvfrom.c +++ b/nuttx/net/recvfrom.c @@ -571,40 +571,47 @@ static uint16_t recvfrom_tcpinterrupt(struct uip_driver_s *dev, void *conn, * gracefully disconnected * _SF_CONNECTED==0 && _SF_CLOSED==0 - the socket was * rudely disconnected - * - * These flag settings are probably not necessary if - * CONFIG_NET_TCP_RECVDELAY == 0; in that case we know that - * pstate->rf_recvlen == 0 and we will always return -ENOTCONN. */ 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. + */ + + pstate->rf_result = 0; } 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. - */ + /* 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. + */ #if CONFIG_NET_TCP_RECVDELAY > 0 - if (pstate->rf_recvlen > 0) - { - pstate->rf_result = 0; - } - else - { - pstate->rf_result = -ENOTCONN; - } + if (pstate->rf_recvlen > 0) + { + pstate->rf_result = 0; + } + else + { + pstate->rf_result = -ENOTCONN; + } #else - pstate->rf_result = -ENOTCONN; + pstate->rf_result = -ENOTCONN; #endif + } /* Wake up the waiting thread */ -- cgit v1.2.3