net/tcp: add nonblock connect(2) support
Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
parent
1a55d933ef
commit
9701a678bd
@ -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++;
|
||||
|
@ -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)
|
||||
netdev_txnotify_dev(((FAR struct tcp_conn_s *)psock->s_conn)->dev);
|
||||
|
||||
/* Non-blocking connection ? set the socket error
|
||||
* and start the monitor
|
||||
*/
|
||||
|
||||
if (_SS_ISNONBLOCK(psock->s_flags))
|
||||
{
|
||||
/* Notify the device driver that new connection is available. */
|
||||
|
||||
netdev_txnotify_dev(((FAR struct tcp_conn_s *)psock->s_conn)->dev);
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
ret = net_lockedwait(&state.tc_sem);
|
||||
|
||||
/* Uninitialize the state structure */
|
||||
|
||||
nxsem_destroy(&state.tc_sem);
|
||||
|
||||
/* If net_lockedwait failed, negated errno was returned. */
|
||||
ret = -EINPROGRESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set up the callbacks in the connection */
|
||||
|
||||
ret = psock_setup_callbacks(psock, &state);
|
||||
if (ret >= 0)
|
||||
{
|
||||
/* If the wait succeeded, then get the new error value from
|
||||
* the state structure
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
ret = state.tc_result;
|
||||
ret = net_lockedwait(&state.tc_sem);
|
||||
|
||||
/* Uninitialize the state structure */
|
||||
|
||||
nxsem_destroy(&state.tc_sem);
|
||||
|
||||
/* If net_lockedwait failed, negated errno was returned. */
|
||||
|
||||
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 */
|
||||
|
||||
psock_teardown_callbacks(&state, ret);
|
||||
}
|
||||
|
||||
/* Make sure that no further events are processed */
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user