From 9ba6eb716d65cf391a20ea2894193604bced670b Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 18 Jun 2018 16:59:15 +0100 Subject: [PATCH] mg_lwip: Fix race during clean conenction teardown Set CLOSE_IMMEDIATELY flag when destroying conn. This avoid some races in LWIP adapter. CL: mg_lwip: Fix race during clean conenction teardown PUBLISHED_FROM=5c67982390dfaf83527e85d1291f64c6050aa932 --- mongoose.c | 14 ++++++++++---- src/common/platforms/lwip/mg_lwip_ev_mgr.c | 7 ++++--- src/common/platforms/lwip/mg_lwip_net_if.c | 2 +- src/mg_net.c | 5 +++++ 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/mongoose.c b/mongoose.c index 82aebae8..f19033d8 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2466,6 +2466,11 @@ void mg_close_conn(struct mg_connection *conn) { mg_ssl_if_conn_close_notify(conn); } #endif + /* + * Clearly mark the connection as going away (if not already). + * Some net_if impls (LwIP) need this for cleanly handling half-dead conns. + */ + conn->flags |= MG_F_CLOSE_IMMEDIATELY; mg_remove_conn(conn); conn->iface->vtable->destroy_conn(conn); mg_call(conn, NULL, conn->user_data, MG_EV_CLOSE, NULL); @@ -14901,7 +14906,7 @@ static err_t mg_lwip_tcp_conn_cb(void *arg, struct tcp_pcb *tpcb, err_t err) { static void mg_lwip_tcp_error_cb(void *arg, err_t err) { struct mg_connection *nc = (struct mg_connection *) arg; DBG(("%p conn error %d", nc, err)); - if (nc == NULL) return; + if (nc == NULL || (nc->flags & MG_F_CLOSE_IMMEDIATELY)) return; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; cs->pcb.tcp = NULL; /* Has already been deallocated */ if (nc->flags & MG_F_CONNECTING) { @@ -15538,10 +15543,11 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) { (struct mg_ev_mgr_lwip_data *) mgr->ifaces[MG_MAIN_IFACE]->data; while (md->sig_queue_len > 0) { mgos_lock(); - int sig = md->sig_queue[md->start_index].sig; - struct mg_connection *nc = md->sig_queue[md->start_index].nc; + int i = md->start_index; + int sig = md->sig_queue[i].sig; + struct mg_connection *nc = md->sig_queue[i].nc; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - md->start_index = (md->start_index + 1) % MG_SIG_QUEUE_LEN; + md->start_index = (i + 1) % MG_SIG_QUEUE_LEN; md->sig_queue_len--; mgos_unlock(); if (nc->iface == NULL || nc->mgr == NULL) continue; diff --git a/src/common/platforms/lwip/mg_lwip_ev_mgr.c b/src/common/platforms/lwip/mg_lwip_ev_mgr.c index 1e844a82..39937fc9 100644 --- a/src/common/platforms/lwip/mg_lwip_ev_mgr.c +++ b/src/common/platforms/lwip/mg_lwip_ev_mgr.c @@ -53,10 +53,11 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) { (struct mg_ev_mgr_lwip_data *) mgr->ifaces[MG_MAIN_IFACE]->data; while (md->sig_queue_len > 0) { mgos_lock(); - int sig = md->sig_queue[md->start_index].sig; - struct mg_connection *nc = md->sig_queue[md->start_index].nc; + int i = md->start_index; + int sig = md->sig_queue[i].sig; + struct mg_connection *nc = md->sig_queue[i].nc; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - md->start_index = (md->start_index + 1) % MG_SIG_QUEUE_LEN; + md->start_index = (i + 1) % MG_SIG_QUEUE_LEN; md->sig_queue_len--; mgos_unlock(); if (nc->iface == NULL || nc->mgr == NULL) continue; diff --git a/src/common/platforms/lwip/mg_lwip_net_if.c b/src/common/platforms/lwip/mg_lwip_net_if.c index f73f607a..2090fca3 100644 --- a/src/common/platforms/lwip/mg_lwip_net_if.c +++ b/src/common/platforms/lwip/mg_lwip_net_if.c @@ -126,7 +126,7 @@ static err_t mg_lwip_tcp_conn_cb(void *arg, struct tcp_pcb *tpcb, err_t err) { static void mg_lwip_tcp_error_cb(void *arg, err_t err) { struct mg_connection *nc = (struct mg_connection *) arg; DBG(("%p conn error %d", nc, err)); - if (nc == NULL) return; + if (nc == NULL || (nc->flags & MG_F_CLOSE_IMMEDIATELY)) return; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; cs->pcb.tcp = NULL; /* Has already been deallocated */ if (nc->flags & MG_F_CONNECTING) { diff --git a/src/mg_net.c b/src/mg_net.c index 050ac791..ad9a8fb0 100644 --- a/src/mg_net.c +++ b/src/mg_net.c @@ -176,6 +176,11 @@ void mg_close_conn(struct mg_connection *conn) { mg_ssl_if_conn_close_notify(conn); } #endif + /* + * Clearly mark the connection as going away (if not already). + * Some net_if impls (LwIP) need this for cleanly handling half-dead conns. + */ + conn->flags |= MG_F_CLOSE_IMMEDIATELY; mg_remove_conn(conn); conn->iface->vtable->destroy_conn(conn); mg_call(conn, NULL, conn->user_data, MG_EV_CLOSE, NULL);