diff --git a/net/socket/Kconfig b/net/socket/Kconfig index fe6b028929..7b6f32d3c8 100644 --- a/net/socket/Kconfig +++ b/net/socket/Kconfig @@ -15,8 +15,8 @@ config NET_NACTIVESOCKETS int "Max socket operations" default 16 ---help--- - Maximum number of concurrent socket operations (recv, send, etc.). - Default: 16 + Maximum number of concurrent socket operations (recv, send, + connection monitoring, etc.). Default: 16 config NET_SOCKOPTS bool "Socket options" diff --git a/net/socket/net_monitor.c b/net/socket/net_monitor.c index 34a675eb36..8198f73d84 100644 --- a/net/socket/net_monitor.c +++ b/net/socket/net_monitor.c @@ -58,7 +58,9 @@ * Private Function Prototypes ****************************************************************************/ -static void connection_event(FAR struct tcp_conn_s *conn, uint16_t flags); +static uint16_t connection_event(FAR struct net_driver_s *dev, + FAR void *pvconn, FAR void *pvpriv, + uint16_t flags); /**************************************************************************** * Private Functions @@ -70,6 +72,7 @@ static void connection_event(FAR struct tcp_conn_s *conn, uint16_t flags); * Some connection related event has occurred * * Parameters: + * dev The device which as active when the event was detected. * conn The connection structure associated with the socket * flags Set of events describing why the callback was invoked * @@ -77,13 +80,15 @@ static void connection_event(FAR struct tcp_conn_s *conn, uint16_t flags); * None * * Assumptions: - * Running at the interrupt level + * The network is locked. * ****************************************************************************/ -static void connection_event(FAR struct tcp_conn_s *conn, uint16_t flags) +static uint16_t connection_event(FAR struct net_driver_s *dev, + FAR void *pvconn, FAR void *pvpriv, + uint16_t flags) { - FAR struct socket *psock = (FAR struct socket *)conn->connection_private; + FAR struct socket *psock = (FAR struct socket *)pvpriv; if (psock) { @@ -108,6 +113,8 @@ static void connection_event(FAR struct tcp_conn_s *conn, uint16_t flags) psock->s_flags &= ~_SF_CLOSED; } } + + return flags; } /**************************************************************************** @@ -129,13 +136,16 @@ static void connection_event(FAR struct tcp_conn_s *conn, uint16_t flags) * case, -ENOTCONN is returned. * * Assumptions: - * The caller holds the network lock. + * The caller holds the network lock (if not, it will be locked momentarily + * by this function). * ****************************************************************************/ int net_startmonitor(FAR struct socket *psock) { FAR struct tcp_conn_s *conn = psock->s_conn; + FAR struct devif_callback_s *cb; + net_lock_t save; DEBUGASSERT(psock && conn); @@ -144,30 +154,51 @@ int net_startmonitor(FAR struct socket *psock) * registered the monitoring callback.) */ + save = net_lock(); if (!(conn->tcpstateflags == TCP_ESTABLISHED || conn->tcpstateflags == TCP_SYN_RCVD)) { /* Invoke the TCP_CLOSE connection event now */ - connection_event(conn, TCP_CLOSE); + (void)connection_event(NULL, conn, psock, TCP_CLOSE); /* Make sure that the monitor is stopped */ conn->connection_private = NULL; + conn->connection_devcb = NULL; conn->connection_event = NULL; /* And return -ENOTCONN to indicate the the monitor was not started * because the socket was already disconnected. */ + net_unlock(save); return -ENOTCONN; } + DEBUGASSERT(conn->connection_event == NULL && + conn->connection_devcb == NULL); + + /* Allocate a callback structure that we will use to get callbacks if + * the network goes down. + */ + + cb = tcp_monitor_callback_alloc(conn); + if (cb != NULL) + { + cb->event = connection_event; + cb->priv = (void*)psock; + cb->flags = NETDEV_DOWN; + } + + conn->connection_devcb = cb; + /* Set up to receive callbacks on connection-related events */ conn->connection_private = (void*)psock; conn->connection_event = connection_event; + net_unlock(save); return OK; } @@ -183,14 +214,32 @@ int net_startmonitor(FAR struct socket *psock) * Returned Value: * None * + * Assumptions: + * The caller holds the network lock (if not, it will be locked momentarily + * by this function). + * ****************************************************************************/ void net_stopmonitor(FAR struct tcp_conn_s *conn) { + net_lock_t save; + DEBUGASSERT(conn); + /* Free any allocated device event callback structure */ + + save = net_lock(); + if (conn->connection_devcb) + { + tcp_monitor_callback_free(conn, conn->connection_devcb); + } + + /* Nullify all connection event data */ + conn->connection_private = NULL; + conn->connection_devcb = NULL; conn->connection_event = NULL; + net_unlock(save); } /**************************************************************************** @@ -207,7 +256,7 @@ void net_stopmonitor(FAR struct tcp_conn_s *conn) * None * * Assumptions: - * Running at the interrupt level + * The caller holds the network lock. * ****************************************************************************/ diff --git a/net/socket/socket.h b/net/socket/socket.h index 8c0cae0d3a..7137b143ef 100644 --- a/net/socket/socket.h +++ b/net/socket/socket.h @@ -237,7 +237,8 @@ FAR struct socket *sockfd_socket(int sockfd); * case, -ENOTCONN is returned. * * Assumptions: - * The caller holds the network lock. + * The caller holds the network lock (if not, it will be locked momentarily + * by this function). * ****************************************************************************/ @@ -257,6 +258,10 @@ int net_startmonitor(FAR struct socket *psock); * Returned Value: * None * + * Assumptions: + * The caller holds the network lock (if not, it will be locked momentarily + * by this function). + * ****************************************************************************/ #ifdef CONFIG_NET_TCP @@ -277,7 +282,7 @@ void net_stopmonitor(FAR struct tcp_conn_s *conn); * None * * Assumptions: - * Running at the interrupt level + * The caller holds the network lock. * ****************************************************************************/ diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index f48499e7f4..85f56dd785 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -63,15 +63,42 @@ /* Allocate a new TCP data callback */ #ifdef CONFIG_NETDEV_MULTINIC +/* These macros allocate and free callback structures used for receiving + * notifications of TCP data-related events. + */ + # define tcp_callback_alloc(conn) \ devif_callback_alloc(conn->dev, &conn->list) # define tcp_callback_free(conn,cb) \ devif_callback_free(conn->dev, cb, &conn->list) + +/* These macros allocate and free callback structures used for receiving + * notifications of device-related events. + */ + +# define tcp_monitor_callback_alloc(conn) \ + devif_callback_alloc(conn->dev, NULL) +# define tcp_monitor_callback_free(conn,cb) \ + devif_callback_free(conn->dev, cb, NULL) + #else +/* These macros allocate and free callback structures used for receiving + * notifications of TCP data-related events. + */ + # define tcp_callback_alloc(conn) \ devif_callback_alloc(g_netdevices, &conn->list) # define tcp_callback_free(conn,cb) \ devif_callback_free(g_netdevices, cb, &conn->list) + +/* These macros allocate and free callback structures used for receiving + * notifications of device-related events. + */ + +# define tcp_monitor_callback_alloc(conn) \ + devif_callback_alloc(g_netdevices, NULL) +# define tcp_monitor_callback_free(conn,cb) \ + devif_callback_free(g_netdevices, cb, NULL) #endif /* Get the current maximum segment size that can be sent on the current @@ -227,17 +254,34 @@ struct tcp_conn_s FAR struct devif_callback_s *list; - /* accept() is called when the TCP logic has created a connection */ + /* accept() is called when the TCP logic has created a connection + * + * accept_private: This is private data that will be available to the + * accept() handler when it is invoked with a point to this structure + * as an argument. + * accept: This is the the pointer to the accept handler. + */ FAR void *accept_private; int (*accept)(FAR struct tcp_conn_s *listener, FAR struct tcp_conn_s *conn); /* connection_event() is called on any of the subset of connection-related * events. + * + * connection_private: This is private data that will be available to + * the connection_event() handler when it is invoked with a point to + * this structure as an argument. + * connection_devcb: this is the allocated callback structure that is + * used to + * connection_event: This is the the pointer to the connection event + * handler. */ FAR void *connection_private; - void (*connection_event)(FAR struct tcp_conn_s *conn, uint16_t flags); + FAR struct devif_callback_s *connection_devcb; + uint16_t (*connection_event)(FAR struct net_driver_s *dev, + FAR void *pvconn, FAR void *pvpriv, + uint16_t flags); }; /* This structure supports TCP write buffering */ diff --git a/net/tcp/tcp_callback.c b/net/tcp/tcp_callback.c index 8a438e3050..68f4277232 100644 --- a/net/tcp/tcp_callback.c +++ b/net/tcp/tcp_callback.c @@ -201,7 +201,8 @@ uint16_t tcp_callback(FAR struct net_driver_s *dev, { /* Perform the callback */ - conn->connection_event(conn, flags); + flags = conn->connection_event(dev, conn, conn->connection_private, + flags); } return flags;