summaryrefslogtreecommitdiff
path: root/nuttx/net/recvfrom.c
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-06-05 16:13:50 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-06-05 16:13:50 +0000
commitd6e0fecec1f8b8bfa14784fa2a33f5f4da66148e (patch)
tree7f58b3685481214d1ccecd7080f0872fb5deec3b /nuttx/net/recvfrom.c
parentab784567291b1925d616ea9b9d2577f42d2699a5 (diff)
downloadpx4-nuttx-d6e0fecec1f8b8bfa14784fa2a33f5f4da66148e.tar.gz
px4-nuttx-d6e0fecec1f8b8bfa14784fa2a33f5f4da66148e.tar.bz2
px4-nuttx-d6e0fecec1f8b8bfa14784fa2a33f5f4da66148e.zip
Fix a bug in recvfrom()
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3670 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/net/recvfrom.c')
-rw-r--r--nuttx/net/recvfrom.c69
1 files changed, 51 insertions, 18 deletions
diff --git a/nuttx/net/recvfrom.c b/nuttx/net/recvfrom.c
index 335e2b322..d974b85cf 100644
--- a/nuttx/net/recvfrom.c
+++ b/nuttx/net/recvfrom.c
@@ -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
+ recvfrom_readahead(&state);
+#endif
- /* Handle any any TCP data already buffered in a read-ahead buffer. */
+ /* Verify that the SOCK_STREAM has been or still is connected */
- recvfrom_readahead(&state);
+ 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 */