mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2025-12-25 00:37:21 +00:00
sockets: change closing: netconn is freed when socket is closed, not before
This is necessary to implement fullduplex sockets that are closed asynchronously: the netconn in the socket must not be freed before all threads have given up using it. We now call the first part of 'netconn_delete()' (moved to 'netconn_prepare_delete()') from lwip_close() and only actually end up calling 'netconn_free()' from 'free_socket()', which might be called later if LWIP_NETCONN_FULLDUPLEX is enabled. Signed-off-by: goldsimon <goldsimon@gmx.de>
This commit is contained in:
@@ -91,6 +91,14 @@
|
||||
#define API_MSG_VAR_FREE_ACCEPT(msg)
|
||||
#endif /* TCP_LISTEN_BACKLOG */
|
||||
|
||||
#if LWIP_NETCONN_FULLDUPLEX
|
||||
#define NETCONN_RECVMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->recvmbox) && (((conn)->flags & NETCONN_FLAG_MBOXINVALID) == 0))
|
||||
#define NETCONN_ACCEPTMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->acceptmbox) && (((conn)->flags & (NETCONN_FLAG_MBOXCLOSED|NETCONN_FLAG_MBOXINVALID)) == 0))
|
||||
#else
|
||||
#define NETCONN_RECVMBOX_WAITABLE(conn) sys_mbox_valid(&(conn)->recvmbox)
|
||||
#define NETCONN_ACCEPTMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->acceptmbox) && (((conn)->flags & NETCONN_FLAG_MBOXCLOSED) == 0))
|
||||
#endif
|
||||
|
||||
static err_t netconn_close_shutdown(struct netconn *conn, u8_t how);
|
||||
|
||||
/**
|
||||
@@ -169,7 +177,7 @@ netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_cal
|
||||
|
||||
/**
|
||||
* @ingroup netconn_common
|
||||
* Close a netconn 'connection' and free its resources.
|
||||
* Close a netconn 'connection' and free all its resources but not the netconn itself.
|
||||
* UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
|
||||
* after this returns.
|
||||
*
|
||||
@@ -177,7 +185,7 @@ netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_cal
|
||||
* @return ERR_OK if the connection was deleted
|
||||
*/
|
||||
err_t
|
||||
netconn_delete(struct netconn *conn)
|
||||
netconn_prepare_delete(struct netconn *conn)
|
||||
{
|
||||
err_t err;
|
||||
API_MSG_VAR_DECLARE(msg);
|
||||
@@ -205,12 +213,43 @@ netconn_delete(struct netconn *conn)
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
netconn_free(conn);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netconn_common
|
||||
* Close a netconn 'connection' and free its resources.
|
||||
* UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
|
||||
* after this returns.
|
||||
*
|
||||
* @param conn the netconn to delete
|
||||
* @return ERR_OK if the connection was deleted
|
||||
*/
|
||||
err_t
|
||||
netconn_delete(struct netconn *conn)
|
||||
{
|
||||
err_t err;
|
||||
|
||||
/* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
|
||||
if (conn == NULL) {
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#if LWIP_NETCONN_FULLDUPLEX
|
||||
if (conn->flags & NETCONN_FLAG_MBOXINVALID) {
|
||||
/* Already called netconn_prepare_delete() before */
|
||||
err = ERR_OK;
|
||||
} else
|
||||
#endif /* LWIP_NETCONN_FULLDUPLEX */
|
||||
{
|
||||
err = netconn_prepare_delete(conn);
|
||||
}
|
||||
if (err == ERR_OK) {
|
||||
netconn_free(conn);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the local or remote IP address and port of a netconn.
|
||||
* For RAW netconns, this returns the protocol instead of a port!
|
||||
@@ -447,14 +486,11 @@ netconn_accept(struct netconn *conn, struct netconn **new_conn)
|
||||
/* return pending error */
|
||||
return err;
|
||||
}
|
||||
if (conn->flags & NETCONN_FLAG_MBOXCLOSED) {
|
||||
if (!NETCONN_ACCEPTMBOX_WAITABLE(conn)) {
|
||||
/* don't accept if closed: this might block the application task
|
||||
waiting on acceptmbox forever! */
|
||||
return ERR_CLSD;
|
||||
}
|
||||
if (!sys_mbox_valid(&conn->acceptmbox)) {
|
||||
return ERR_CLSD;
|
||||
}
|
||||
|
||||
API_MSG_VAR_ALLOC_ACCEPT(msg);
|
||||
|
||||
@@ -531,7 +567,7 @@ netconn_recv_data(struct netconn *conn, void **new_buf, u8_t apiflags)
|
||||
*new_buf = NULL;
|
||||
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
|
||||
if (!sys_mbox_valid(&conn->recvmbox)) {
|
||||
if (!NETCONN_RECVMBOX_WAITABLE(conn)) {
|
||||
err_t err = netconn_err(conn);
|
||||
if (err != ERR_OK) {
|
||||
/* return pending error */
|
||||
@@ -641,7 +677,7 @@ netconn_recv_data_tcp(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags
|
||||
msg = NULL;
|
||||
#endif
|
||||
|
||||
if (!sys_mbox_valid(&conn->recvmbox)) {
|
||||
if (!NETCONN_RECVMBOX_WAITABLE(conn)) {
|
||||
/* This only happens when calling this function more than once *after* receiving FIN */
|
||||
return ERR_CONN;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user