Fix a bug in recvfrom()

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3670 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2011-06-05 16:13:50 +00:00
parent 9a988150f0
commit 6fa6c78928
2 changed files with 59 additions and 19 deletions

View File

@ -1796,4 +1796,11 @@
testing of the FTP client shell.
* fd/fs_fdopen.c and net/net_checksd.c: Add support so that fdopen may
be used with socket descriptors.
* net/recvfrom.c: Fix an error found in receiving small files via FTP:
The small file is received a buffered in the readahead buffer, then the
socket is disconnected. When the app calls recvfrom, the socket is
already disconnected and the buffered data is stranded. Now, recvfrom
will continue to return success after the socket is disconnected until
the readahead buffer is drained.

View File

@ -682,6 +682,13 @@ static void recvfrom_init(FAR struct socket *psock, FAR void *buf, size_t len,
pstate->rf_starttime = clock_systimer();
#endif
}
/* The only uninitialization that has to be performed is destroying the
* semaphore.
*/
#define recvfrom_uninit(s) sem_destroy(&(s)->rf_sem)
#endif /* CONFIG_NET_UDP || CONFIG_NET_TCP */
/****************************************************************************
@ -706,10 +713,6 @@ static ssize_t recvfrom_result(int result, struct recvfrom_s *pstate)
{
int save_errno = errno; /* In case something we do changes it */
/* Release semaphore in the state structure */
sem_destroy(&pstate->rf_sem);
/* Check for a error/timeout detected by the interrupt handler. Errors are
* signaled by negative errno values for the rcv length
*/
@ -783,8 +786,7 @@ static ssize_t udp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
ret = uip_udpconnect(conn, NULL);
if (ret < 0)
{
uip_unlock(save);
return ret;
goto errout_with_state;
}
/* Set up the callback in the connection */
@ -814,7 +816,6 @@ static ssize_t udp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
uip_udpdisable(conn);
uip_udpcallbackfree(conn, state.rf_cb);
uip_unlock(save);
ret = recvfrom_result(ret, &state);
}
else
@ -822,6 +823,9 @@ static ssize_t udp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
ret = -EBUSY;
}
errout_with_state:
uip_unlock(save);
recvfrom_uninit(&state);
return ret;
}
#endif /* CONFIG_NET_UDP */
@ -859,15 +863,6 @@ static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
uip_lock_t save;
int ret = OK;
/* Verify that the SOCK_STREAM has been connected */
if (!_SS_ISCONNECTED(psock->s_flags))
{
/* The SOCK_STREAM must be connected in order to receive */
return -ENOTCONN;
}
/* Initialize the state structure. This is done with interrupts
* disabled because we don't want anything to happen until we
* are ready.
@ -876,11 +871,47 @@ static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
save = uip_lock();
recvfrom_init(psock, buf, len, infrom, &state);
/* Handle any any TCP data already buffered in a read-ahead buffer. NOTE
* that there may be read-ahead data to be retrieved even after the
* socket has been disconnected.
*/
#if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0
/* Handle any any TCP data already buffered in a read-ahead buffer. */
recvfrom_readahead(&state);
#endif
/* Verify that the SOCK_STREAM has been or still is connected */
if (!_SS_ISCONNECTED(psock->s_flags))
{
/* Was any data transferred from the readahead buffer after we were
* disconnected?
*/
#if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0
if (state.rf_recvlen <= 0)
{
/* Nothing was received. The SOCK_STREAM must be re-connected in
* order to receive an additional data.
*/
ret = -ENOTCONN;
}
else
{
/* The socket is disconnected, but there is data in the read-ahead
* buffer. The return value is the number of bytes read from the
* read-ahead buffer */
ret = state.rf_recvlen;
}
#else
/* The SOCK_STREAM must be connected inorder to receive data. */
ret = -ENOTCONN;
#endif
}
else
/* In general, this uIP-based implementation will not support non-blocking
* socket operations... except in a few cases: Here for TCP receive with read-ahead
@ -888,6 +919,7 @@ static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
* if no data was obtained from the read-ahead buffers.
*/
#if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0
if (_SS_ISNONBLOCK(psock->s_flags))
{
/* Return OK if something was received; EGAIN if not */
@ -944,6 +976,7 @@ static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
}
uip_unlock(save);
recvfrom_uninit(&state);
return ret;
}
#endif /* CONFIG_NET_TCP */