You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/08/20 02:19:13 UTC
[incubator-nuttx] branch master updated: net/tcp: add nonblock
connect(2) support
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 9701a67 net/tcp: add nonblock connect(2) support
9701a67 is described below
commit 9701a678bdf42f6282db5dd50febbbd69925a738
Author: chao.an <an...@xiaomi.com>
AuthorDate: Tue Aug 10 20:42:35 2021 +0800
net/tcp: add nonblock connect(2) support
Signed-off-by: chao.an <an...@xiaomi.com>
---
fs/vfs/fs_select.c | 2 +-
net/tcp/tcp_connect.c | 67 +++++++++++++++++++++++++++++++--------------------
net/tcp/tcp_monitor.c | 42 +++++++++++++++++++++++---------
net/tcp/tcp_netpoll.c | 58 +++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 129 insertions(+), 40 deletions(-)
diff --git a/fs/vfs/fs_select.c b/fs/vfs/fs_select.c
index 1a3734a..908a786 100644
--- a/fs/vfs/fs_select.c
+++ b/fs/vfs/fs_select.c
@@ -242,7 +242,7 @@ int select(int nfds, FAR fd_set *readfds, FAR fd_set *writefds,
if (writefds)
{
- if (pollset[ndx].revents & POLLOUT)
+ if (pollset[ndx].revents & (POLLOUT | POLLHUP))
{
FD_SET(pollset[ndx].fd, writefds);
ret++;
diff --git a/net/tcp/tcp_connect.c b/net/tcp/tcp_connect.c
index d64767f..d72f366 100644
--- a/net/tcp/tcp_connect.c
+++ b/net/tcp/tcp_connect.c
@@ -318,52 +318,66 @@ int psock_tcp_connect(FAR struct socket *psock,
if (ret >= 0)
{
- /* Set up the callbacks in the connection */
+ /* Notify the device driver that new connection is available. */
- ret = psock_setup_callbacks(psock, &state);
- if (ret >= 0)
- {
- /* Notify the device driver that new connection is available. */
+ netdev_txnotify_dev(((FAR struct tcp_conn_s *)psock->s_conn)->dev);
- netdev_txnotify_dev(((FAR struct tcp_conn_s *)psock->s_conn)->dev);
+ /* Non-blocking connection ? set the socket error
+ * and start the monitor
+ */
- /* Wait for either the connect to complete or for an error/timeout
- * to occur. NOTES: net_lockedwait will also terminate if a signal
- * is received.
- */
+ if (_SS_ISNONBLOCK(psock->s_flags))
+ {
+ ret = -EINPROGRESS;
+ }
+ else
+ {
+ /* Set up the callbacks in the connection */
- ret = net_lockedwait(&state.tc_sem);
+ ret = psock_setup_callbacks(psock, &state);
+ if (ret >= 0)
+ {
+ /* Wait for either the connect to complete or for an
+ * error/timeout to occur.
+ * NOTES: net_lockedwait will also terminate if a
+ * signal is received.
+ */
- /* Uninitialize the state structure */
+ ret = net_lockedwait(&state.tc_sem);
- nxsem_destroy(&state.tc_sem);
+ /* Uninitialize the state structure */
- /* If net_lockedwait failed, negated errno was returned. */
+ nxsem_destroy(&state.tc_sem);
- if (ret >= 0)
- {
- /* If the wait succeeded, then get the new error value from
- * the state structure
- */
+ /* If net_lockedwait failed, negated errno was returned. */
- ret = state.tc_result;
- }
+ if (ret >= 0)
+ {
+ /* If the wait succeeded, then get the new error
+ * value from the state structure
+ */
+
+ ret = state.tc_result;
+ }
- /* Make sure that no further events are processed */
+ /* Make sure that no further events are processed */
- psock_teardown_callbacks(&state, ret);
+ psock_teardown_callbacks(&state, ret);
+ }
}
/* Check if the socket was successfully connected. */
- if (ret >= 0)
+ if (ret >= 0 || ret == -EINPROGRESS)
{
+ int ret2;
+
/* Yes... Now that we are connected, we need to set up to monitor
* the state of the connection up the connection event monitor.
*/
- ret = tcp_start_monitor(psock);
- if (ret < 0)
+ ret2 = tcp_start_monitor(psock);
+ if (ret2 < 0)
{
/* tcp_start_monitor() can only fail on certain race
* conditions where the connection was lost just before
@@ -372,6 +386,7 @@ int psock_tcp_connect(FAR struct socket *psock,
*/
tcp_stop_monitor(psock->s_conn, TCP_ABORT);
+ ret = ret2;
}
}
}
diff --git a/net/tcp/tcp_monitor.c b/net/tcp/tcp_monitor.c
index ab55018..3ee5f08 100644
--- a/net/tcp/tcp_monitor.c
+++ b/net/tcp/tcp_monitor.c
@@ -41,9 +41,9 @@
****************************************************************************/
static void tcp_close_connection(FAR struct socket *psock, uint16_t flags);
-static uint16_t tcp_disconnect_event(FAR struct net_driver_s *dev,
- FAR void *pvconn, FAR void *pvpriv,
- uint16_t flags);
+static uint16_t tcp_monitor_event(FAR struct net_driver_s *dev,
+ FAR void *pvconn, FAR void *pvpriv,
+ uint16_t flags);
/****************************************************************************
* Private Functions
@@ -106,7 +106,7 @@ static void tcp_close_connection(FAR struct socket *psock, uint16_t flags)
}
/****************************************************************************
- * Name: tcp_disconnect_event
+ * Name: tcp_monitor_event
*
* Description:
* Some connection related event has occurred
@@ -124,9 +124,9 @@ static void tcp_close_connection(FAR struct socket *psock, uint16_t flags)
*
****************************************************************************/
-static uint16_t tcp_disconnect_event(FAR struct net_driver_s *dev,
- FAR void *pvconn, FAR void *pvpriv,
- uint16_t flags)
+static uint16_t tcp_monitor_event(FAR struct net_driver_s *dev,
+ FAR void *pvconn, FAR void *pvpriv,
+ uint16_t flags)
{
FAR struct socket *psock = (FAR struct socket *)pvpriv;
@@ -164,9 +164,13 @@ static uint16_t tcp_disconnect_event(FAR struct net_driver_s *dev,
* TODO: Implement this.
*/
+ /* Clear the socket error */
+
+ _SO_SETERRNO(psock, OK);
+
/* Indicate that the socket is now connected */
- psock->s_flags |= _SF_CONNECTED;
+ psock->s_flags |= (_SF_BOUND | _SF_CONNECTED);
psock->s_flags &= ~_SF_CLOSED;
}
}
@@ -242,20 +246,27 @@ static void tcp_shutdown_monitor(FAR struct tcp_conn_s *conn, uint16_t flags)
int tcp_start_monitor(FAR struct socket *psock)
{
- FAR struct tcp_conn_s *conn;
FAR struct devif_callback_s *cb;
+ FAR struct tcp_conn_s *conn;
+ bool nonblock_conn;
DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
conn = (FAR struct tcp_conn_s *)psock->s_conn;
+ net_lock();
+
+ /* Non-blocking connection ? */
+
+ nonblock_conn = (conn->tcpstateflags == TCP_SYN_SENT &&
+ _SS_ISNONBLOCK(psock->s_flags));
+
/* Check if the connection has already been closed before any callbacks
* have been registered. (Maybe the connection is lost before accept has
* registered the monitoring callback.)
*/
- net_lock();
if (!(conn->tcpstateflags == TCP_ESTABLISHED ||
- conn->tcpstateflags == TCP_SYN_RCVD))
+ conn->tcpstateflags == TCP_SYN_RCVD || nonblock_conn))
{
/* Invoke the TCP_CLOSE connection event now */
@@ -276,9 +287,16 @@ int tcp_start_monitor(FAR struct socket *psock)
cb = devif_callback_alloc(conn->dev, &conn->connevents);
if (cb != NULL)
{
- cb->event = tcp_disconnect_event;
+ cb->event = tcp_monitor_event;
cb->priv = (FAR void *)psock;
cb->flags = TCP_DISCONN_EVENTS;
+
+ /* Monitor the connected event */
+
+ if (nonblock_conn)
+ {
+ cb->flags |= TCP_CONNECTED;
+ }
}
net_unlock();
diff --git a/net/tcp/tcp_netpoll.c b/net/tcp/tcp_netpoll.c
index 8f28da4..4d64797 100644
--- a/net/tcp/tcp_netpoll.c
+++ b/net/tcp/tcp_netpoll.c
@@ -30,6 +30,7 @@
#include <debug.h>
#include <nuttx/net/net.h>
+#include <nuttx/net/tcp.h>
#include <nuttx/semaphore.h>
#include "devif/devif.h"
@@ -67,6 +68,7 @@ static uint16_t tcp_poll_eventhandler(FAR struct net_driver_s *dev,
FAR void *pvpriv, uint16_t flags)
{
FAR struct tcp_poll_s *info = (FAR struct tcp_poll_s *)pvpriv;
+ int reason;
ninfo("flags: %04x\n", flags);
@@ -85,10 +87,50 @@ static uint16_t tcp_poll_eventhandler(FAR struct net_driver_s *dev,
eventset |= POLLIN & info->fds->events;
}
+ /* Non-blocking connection */
+
+ if ((flags & TCP_CONNECTED) != 0)
+ {
+ eventset |= POLLOUT & info->fds->events;
+ }
+
/* Check for a loss of connection events. */
if ((flags & TCP_DISCONN_EVENTS) != 0)
{
+ /* TCP_TIMEDOUT: Connection aborted due to too many
+ * retransmissions.
+ */
+
+ if ((flags & TCP_TIMEDOUT) != 0)
+ {
+ /* Indicate that the connection timedout?) */
+
+ reason = ETIMEDOUT;
+ }
+
+ else if ((flags & NETDEV_DOWN) != 0)
+ {
+ /* The network device went down. Indicate that the remote host
+ * is unreachable.
+ */
+
+ reason = ENETUNREACH;
+ }
+
+ /* TCP_CLOSE: The remote host has closed the connection
+ * TCP_ABORT: The remote host has aborted the connection
+ */
+
+ else
+ {
+ /* Indicate that remote host refused the connection */
+
+ reason = ECONNREFUSED;
+ }
+
+ _SO_SETERRNO(info->psock, reason);
+
/* Mark that the connection has been lost */
tcp_lost_connection(info->psock, info->cb, flags);
@@ -156,6 +198,7 @@ int tcp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
FAR struct tcp_conn_s *conn = psock->s_conn;
FAR struct tcp_poll_s *info;
FAR struct devif_callback_s *cb;
+ bool nonblock_conn;
int ret = OK;
/* Sanity check */
@@ -171,6 +214,11 @@ int tcp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
net_lock();
+ /* Non-blocking connection ? */
+
+ nonblock_conn = (conn->tcpstateflags == TCP_SYN_SENT &&
+ _SS_ISNONBLOCK(psock->s_flags));
+
/* Find a container to hold the poll information */
info = conn->pollinfo;
@@ -214,6 +262,13 @@ int tcp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
| TCP_ACKDATA
#endif
;
+
+ /* Monitor the connected event */
+
+ if (nonblock_conn)
+ {
+ cb->flags |= TCP_CONNECTED;
+ }
}
if ((fds->events & POLLIN) != 0)
@@ -276,7 +331,8 @@ int tcp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
* Action: Return with POLLHUP|POLLERR events
*/
- if (!_SS_ISCONNECTED(psock->s_flags) && !_SS_ISLISTENING(psock->s_flags))
+ if (!nonblock_conn && !_SS_ISCONNECTED(psock->s_flags) &&
+ !_SS_ISLISTENING(psock->s_flags))
{
/* We were previously connected but lost the connection either due
* to a graceful shutdown by the remote peer or because of some