The lwIP httpd has no way to stop: its listening PCB and callbacks outlive the caller. With the shared lwIP runtime the server would keep accepting connections while any other client polls the network.
Add httpd_deinit(), which aborts the open connections and closes the listening PCB. Open connections are only tracked with LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED. With SO_REUSE, set SOF_REUSEADDR on the listening PCB: connections closed by the server stay in TIME-WAIT and would make the next bind fail. Signed-off-by: Vitaliy Sochnev <[email protected]> --- lib/lwip/lwip/src/apps/http/httpd.c | 51 ++++++++++++++++++++- lib/lwip/lwip/src/include/lwip/apps/httpd.h | 1 + 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/lib/lwip/lwip/src/apps/http/httpd.c b/lib/lwip/lwip/src/apps/http/httpd.c index 9477e855e..745477272 100644 --- a/lib/lwip/lwip/src/apps/http/httpd.c +++ b/lib/lwip/lwip/src/apps/http/httpd.c @@ -98,6 +98,7 @@ #include "lwip/altcp.h" #include "lwip/altcp_tcp.h" +#include "lwip/tcp.h" #if HTTPD_ENABLE_HTTPS #include "lwip/altcp_tls.h" #endif @@ -345,6 +346,9 @@ static char *http_cgi_params[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Params extracted static char *http_cgi_param_vals[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Values for each extracted param */ #endif /* LWIP_HTTPD_CGI */ +/** listening PCB set up by httpd_init(), closed by httpd_deinit() */ +static struct altcp_pcb *httpd_listen_pcb; + #if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED /** global list of active HTTP connections, use to kill the oldest when running out of memory */ @@ -2658,7 +2662,7 @@ http_accept(void *arg, struct altcp_pcb *pcb, err_t err) return ERR_OK; } -static void +static struct altcp_pcb * httpd_init_pcb(struct altcp_pcb *pcb, u16_t port) { err_t err; @@ -2673,6 +2677,7 @@ httpd_init_pcb(struct altcp_pcb *pcb, u16_t port) LWIP_ASSERT("httpd_init: tcp_listen failed", pcb != NULL); altcp_accept(pcb, http_accept); } + return pcb; } /** @@ -2694,9 +2699,51 @@ httpd_init(void) /* LWIP_ASSERT_CORE_LOCKED(); is checked by tcp_new() */ +#if SO_REUSE + { + /* rebind while connections of a previous run are in TIME-WAIT */ + struct tcp_pcb *tpcb = tcp_new_ip_type(IPADDR_TYPE_ANY); + if (tpcb != NULL) { + ip_set_option(tpcb, SOF_REUSEADDR); +#if LWIP_ALTCP + pcb = altcp_tcp_wrap(tpcb); + if (pcb == NULL) { + tcp_close(tpcb); + } +#else /* LWIP_ALTCP */ + pcb = tpcb; +#endif /* LWIP_ALTCP */ + } else { + pcb = NULL; + } + } +#else /* SO_REUSE */ pcb = altcp_tcp_new_ip_type(IPADDR_TYPE_ANY); +#endif /* SO_REUSE */ LWIP_ASSERT("httpd_init: tcp_new failed", pcb != NULL); - httpd_init_pcb(pcb, HTTPD_SERVER_PORT); + httpd_listen_pcb = httpd_init_pcb(pcb, HTTPD_SERVER_PORT); +} + +/** + * @ingroup httpd + * Stop the httpd: close the listening PCB set up by httpd_init() and abort + * all open connections, so that no httpd callback runs afterwards. + * Open connections are only known with LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED. + */ +void +httpd_deinit(void) +{ +#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED + /* this also unlinks the http_state from the list */ + while (http_connections != NULL) { + http_close_or_abort_conn(http_connections->pcb, http_connections, 1); + } +#endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */ + if (httpd_listen_pcb != NULL) { + altcp_accept(httpd_listen_pcb, NULL); + altcp_close(httpd_listen_pcb); + httpd_listen_pcb = NULL; + } } #if HTTPD_ENABLE_HTTPS diff --git a/lib/lwip/lwip/src/include/lwip/apps/httpd.h b/lib/lwip/lwip/src/include/lwip/apps/httpd.h index 1ecdd743c..e6ddd023d 100644 --- a/lib/lwip/lwip/src/include/lwip/apps/httpd.h +++ b/lib/lwip/lwip/src/include/lwip/apps/httpd.h @@ -243,6 +243,7 @@ void httpd_post_data_recved(void *connection, u16_t recved_len); #endif /* LWIP_HTTPD_SUPPORT_POST */ void httpd_init(void); +void httpd_deinit(void); #if HTTPD_ENABLE_HTTPS struct altcp_tls_config; -- 2.55.0
