diff --git a/mongoose.c b/mongoose.c index 25c3393042df56fa63ce83170ebd4f503bd3750a..1ce98d01a385cbcb9c8f37fbee61220c80a01d55 100644 --- a/mongoose.c +++ b/mongoose.c @@ -14051,15 +14051,31 @@ void mg_lwip_mgr_schedule_poll(struct mg_mgr *mgr); /* Amalgamated: #include "common/mg_mem.h" */ +#include <lwip/init.h> #include <lwip/pbuf.h> #include <lwip/tcp.h> -#if CS_PLATFORM != CS_P_STM32 +#include <lwip/tcpip.h> +#if LWIP_VERSION >= 0x01050000 +#include <lwip/priv/tcpip_priv.h> /* For tcp_seg */ +#else #include <lwip/tcp_impl.h> #endif #include <lwip/udp.h> /* Amalgamated: #include "common/cs_dbg.h" */ +/* + * Newest versions of LWIP have ip_2_ip4, older have ipX_2_ip, + * even older have nothing. + */ +#ifndef ip_2_ip4 +#ifdef ipX_2_ip +#define ip_2_ip4(addr) ipX_2_ip(addr) +#else +#define ip_2_ip4(addr) (addr) +#endif +#endif + /* * Depending on whether Mongoose is compiled with ipv6 support, use right * lwip functions @@ -14077,16 +14093,12 @@ void mg_lwip_mgr_schedule_poll(struct mg_mgr *mgr); #define TCP_BIND tcp_bind #define UDP_BIND udp_bind #define IPADDR_NTOA ipaddr_ntoa -#define SET_ADDR(dst, src) (dst)->sin.sin_addr.s_addr = GET_IPV4(src) +#define SET_ADDR(dst, src) (dst)->sin.sin_addr.s_addr = ip_2_ip4(src)->addr #endif -/* - * If lwip is compiled with ipv6 support, then API changes even for ipv4 - */ -#if !defined(LWIP_IPV6) || !LWIP_IPV6 -#define GET_IPV4(ipX_addr) ((ipX_addr)->addr) -#else -#define GET_IPV4(ipX_addr) ((ipX_addr)->ip4.addr) +#if NO_SYS +#define tcpip_callback(fn, arg) (fn)(arg) +typedef void (*tcpip_callback_fn)(void *arg); #endif void mg_lwip_ssl_do_hs(struct mg_connection *nc); @@ -14256,8 +14268,17 @@ static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, return ERR_OK; } -void mg_lwip_if_connect_tcp(struct mg_connection *nc, - const union socket_address *sa) { +struct mg_lwip_if_connect_tcp_ctx { + struct mg_connection *nc; + const union socket_address *sa; +}; + +static void mg_lwip_if_connect_tcp_tcpip(void *arg) { + struct mg_lwip_if_connect_tcp_ctx *ctx = + (struct mg_lwip_if_connect_tcp_ctx *) arg; + struct mg_connection *nc = ctx->nc; + const union socket_address *sa = ctx->sa; + struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct tcp_pcb *tpcb = TCP_NEW(); cs->pcb.tcp = tpcb; @@ -14281,12 +14302,17 @@ void mg_lwip_if_connect_tcp(struct mg_connection *nc, } } +void mg_lwip_if_connect_tcp(struct mg_connection *nc, + const union socket_address *sa) { + struct mg_lwip_if_connect_tcp_ctx ctx = {.nc = nc, .sa = sa}; + tcpip_callback(mg_lwip_if_connect_tcp_tcpip, &ctx); +} + /* * Lwip included in the SDKs for nRF5x chips has different type for the * callback of `udp_recv()` */ -#if CS_PLATFORM == CS_P_NRF51 || CS_PLATFORM == CS_P_NRF52 || \ - CS_PLATFORM == CS_P_STM32 +#if LWIP_VERSION >= 0x01050000 static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) #else @@ -14304,7 +14330,11 @@ static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p, return; } union socket_address *sa = (union socket_address *) sap->payload; +#if LWIP_VERSION >= 0x01050000 + sa->sin.sin_addr.s_addr = ip_2_ip4(addr)->addr; +#else sa->sin.sin_addr.s_addr = addr->addr; +#endif sa->sin.sin_port = htons(port); /* Logic in the recv handler requires that there be exactly one data pbuf. */ p = pbuf_coalesce(p, PBUF_RAW); @@ -14353,7 +14383,8 @@ static void mg_lwip_handle_recv_udp(struct mg_connection *nc) { } } -void mg_lwip_if_connect_udp(struct mg_connection *nc) { +static void mg_lwip_if_connect_udp_tcpip(void *arg) { + struct mg_connection *nc = (struct mg_connection *) arg; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct udp_pcb *upcb = udp_new(); cs->err = UDP_BIND(upcb, IP_ADDR_ANY, 0 /* any port */); @@ -14367,6 +14398,10 @@ void mg_lwip_if_connect_udp(struct mg_connection *nc) { mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc); } +void mg_lwip_if_connect_udp(struct mg_connection *nc) { + tcpip_callback(mg_lwip_if_connect_udp_tcpip, nc); +} + void mg_lwip_accept_conn(struct mg_connection *nc, struct tcp_pcb *tpcb) { union socket_address sa; SET_ADDR(&sa, &tpcb->remote_ip); @@ -14374,13 +14409,17 @@ void mg_lwip_accept_conn(struct mg_connection *nc, struct tcp_pcb *tpcb) { mg_if_accept_tcp_cb(nc, &sa, sizeof(sa.sin)); } +static void tcp_close_tcpip(void *arg) { + tcp_close((struct tcp_pcb *) arg); +} + void mg_lwip_handle_accept(struct mg_connection *nc) { struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; #if MG_ENABLE_SSL if (cs->lc->flags & MG_F_SSL) { if (mg_ssl_if_conn_accept(nc, cs->lc) != MG_SSL_OK) { LOG(LL_ERROR, ("SSL error")); - tcp_close(cs->pcb.tcp); + tcpip_callback(tcp_close_tcpip, cs->pcb.tcp); } } else #endif @@ -14415,7 +14454,16 @@ static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err) { return ERR_OK; } -int mg_lwip_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) { +struct mg_lwip_if_listen_ctx { + struct mg_connection *nc; + union socket_address *sa; + int ret; +}; + +static void mg_lwip_if_listen_tcp_tcpip(void *arg) { + struct mg_lwip_if_listen_ctx *ctx = (struct mg_lwip_if_listen_ctx *) arg; + struct mg_connection *nc = ctx->nc; + union socket_address *sa = ctx->sa; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct tcp_pcb *tpcb = TCP_NEW(); ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr; @@ -14424,16 +14472,26 @@ int mg_lwip_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) { DBG(("%p tcp_bind(%s:%u) = %d", nc, IPADDR_NTOA(ip), port, cs->err)); if (cs->err != ERR_OK) { tcp_close(tpcb); - return -1; + ctx->ret = -1; + return; } tcp_arg(tpcb, nc); tpcb = tcp_listen(tpcb); cs->pcb.tcp = tpcb; tcp_accept(tpcb, mg_lwip_accept_cb); - return 0; + ctx->ret = 0; } -int mg_lwip_if_listen_udp(struct mg_connection *nc, union socket_address *sa) { +int mg_lwip_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) { + struct mg_lwip_if_listen_ctx ctx = {.nc = nc, .sa = sa}; + tcpip_callback(mg_lwip_if_listen_tcp_tcpip, &ctx); + return ctx.ret; +} + +static void mg_lwip_if_listen_udp_tcpip(void *arg) { + struct mg_lwip_if_listen_ctx *ctx = (struct mg_lwip_if_listen_ctx *) arg; + struct mg_connection *nc = ctx->nc; + union socket_address *sa = ctx->sa; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct udp_pcb *upcb = udp_new(); ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr; @@ -14442,24 +14500,43 @@ int mg_lwip_if_listen_udp(struct mg_connection *nc, union socket_address *sa) { DBG(("%p udb_bind(%s:%u) = %d", nc, IPADDR_NTOA(ip), port, cs->err)); if (cs->err != ERR_OK) { udp_remove(upcb); - return -1; + ctx->ret = -1; + } else { + udp_recv(upcb, mg_lwip_udp_recv_cb, nc); + cs->pcb.udp = upcb; + ctx->ret = 0; } - udp_recv(upcb, mg_lwip_udp_recv_cb, nc); - cs->pcb.udp = upcb; - return 0; } -int mg_lwip_tcp_write(struct mg_connection *nc, const void *data, - uint16_t len) { +int mg_lwip_if_listen_udp(struct mg_connection *nc, union socket_address *sa) { + struct mg_lwip_if_listen_ctx ctx = {.nc = nc, .sa = sa}; + tcpip_callback(mg_lwip_if_listen_udp_tcpip, &ctx); + return ctx.ret; +} + +struct mg_lwip_tcp_write_ctx { + struct mg_connection *nc; + const void *data; + uint16_t len; + int ret; +}; + +static void tcp_output_tcpip(void *arg) { + tcp_output((struct tcp_pcb *) arg); +} + +static void mg_lwip_tcp_write_tcpip(void *arg) { + struct mg_lwip_tcp_write_ctx *ctx = (struct mg_lwip_tcp_write_ctx *) arg; + struct mg_connection *nc = ctx->nc; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct tcp_pcb *tpcb = cs->pcb.tcp; - if (tpcb == NULL) return -1; - len = MIN(tpcb->mss, MIN(len, tpcb->snd_buf)); + uint16_t len = MIN(tpcb->mss, MIN(ctx->len, tpcb->snd_buf)); if (len == 0) { DBG(("%p no buf avail %u %u %u %p %p", tpcb, tpcb->acked, tpcb->snd_buf, tpcb->snd_queuelen, tpcb->unsent, tpcb->unacked)); - tcp_output(tpcb); - return 0; + tcpip_callback(tcp_output_tcpip, tpcb); + ctx->ret = 0; + return; } /* * On ESP8266 we only allow one TCP segment in flight at any given time. @@ -14469,22 +14546,49 @@ int mg_lwip_tcp_write(struct mg_connection *nc, const void *data, */ #if CS_PLATFORM == CS_P_ESP8266 if (tpcb->unacked != NULL) { - return 0; + ctx->ret = 0; + return; } if (tpcb->unsent != NULL) { len = MIN(len, (TCP_MSS - tpcb->unsent->len)); } #endif - cs->err = tcp_write(tpcb, data, len, TCP_WRITE_FLAG_COPY); + cs->err = tcp_write(tpcb, ctx->data, len, TCP_WRITE_FLAG_COPY); DBG(("%p tcp_write %u = %d", tpcb, len, cs->err)); if (cs->err != ERR_OK) { /* * We ignore ERR_MEM because memory will be freed up when the data is sent * and we'll retry. */ - return (cs->err == ERR_MEM ? 0 : -1); + ctx->ret = (cs->err == ERR_MEM ? 0 : -1); + return; } - return len; + ctx->ret = len; +} + +static int mg_lwip_tcp_write(struct mg_connection *nc, const void *data, + uint16_t len) { + struct mg_lwip_tcp_write_ctx ctx = {.nc = nc, .data = data, .len = len}; + struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; + struct tcp_pcb *tpcb = cs->pcb.tcp; + if (tpcb == NULL) { + return -1; + } + tcpip_callback(mg_lwip_tcp_write_tcpip, &ctx); + return ctx.ret; +} + +struct udp_sendto_ctx { + struct udp_pcb *upcb; + struct pbuf *p; + ip_addr_t *ip; + uint16_t port; + int ret; +}; + +static void udp_sendto_tcpip(void *arg) { + struct udp_sendto_ctx *ctx = (struct udp_sendto_ctx *) arg; + ctx->ret = udp_sendto(ctx->upcb, ctx->p, ctx->ip, ctx->port); } static int mg_lwip_udp_send(struct mg_connection *nc, const void *data, @@ -14508,7 +14612,9 @@ static int mg_lwip_udp_send(struct mg_connection *nc, const void *data, return 0; } memcpy(p->payload, data, len); - cs->err = udp_sendto(upcb, p, (ip_addr_t *) ip, port); + struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = ip, .port = port}; + tcpip_callback(udp_sendto_tcpip, &ctx); + cs->err = ctx.ret; DBG(("%p udp_sendto = %d", nc, cs->err)); pbuf_free(p); return (cs->err == ERR_OK ? len : -1); @@ -14544,6 +14650,16 @@ void mg_lwip_if_udp_send(struct mg_connection *nc, const void *buf, mg_lwip_mgr_schedule_poll(nc->mgr); } +struct tcp_recved_ctx { + struct tcp_pcb *tpcb; + size_t len; +}; + +void tcp_recved_tcpip(void *arg) { + struct tcp_recved_ctx *ctx = (struct tcp_recved_ctx *) arg; + tcp_recved(ctx->tpcb, ctx->len); +} + void mg_lwip_if_recved(struct mg_connection *nc, size_t len) { if (nc->flags & MG_F_UDP) return; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; @@ -14552,14 +14668,16 @@ void mg_lwip_if_recved(struct mg_connection *nc, size_t len) { return; } DBG(("%p %p %u", nc, cs->pcb.tcp, len)); -/* Currently SSL acknowledges data immediately. - * TODO(rojer): Find a way to propagate mg_lwip_if_recved. */ + struct tcp_recved_ctx ctx = {.tpcb = cs->pcb.tcp, .len = len}; #if MG_ENABLE_SSL if (!(nc->flags & MG_F_SSL)) { - tcp_recved(cs->pcb.tcp, len); + tcpip_callback(tcp_recved_tcpip, &ctx); + } else { + /* Currently SSL acknowledges data immediately. + * TODO(rojer): Find a way to propagate mg_lwip_if_recved. */ } #else - tcp_recved(cs->pcb.tcp, len); + tcpip_callback(tcp_recved_tcpip, &ctx); #endif mbuf_trim(&nc->recv_mbuf); } @@ -14573,6 +14691,10 @@ int mg_lwip_if_create_conn(struct mg_connection *nc) { return 1; } +static void udp_remove_tcpip(void *arg) { + udp_remove((struct udp_pcb *) arg); +} + void mg_lwip_if_destroy_conn(struct mg_connection *nc) { if (nc->sock == INVALID_SOCKET) return; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; @@ -14582,7 +14704,7 @@ void mg_lwip_if_destroy_conn(struct mg_connection *nc) { tcp_arg(tpcb, NULL); DBG(("%p tcp_close %p", nc, tpcb)); tcp_arg(tpcb, NULL); - tcp_close(tpcb); + tcpip_callback(tcp_close_tcpip, tpcb); } while (cs->rx_chain != NULL) { struct pbuf *seg = cs->rx_chain; @@ -14596,7 +14718,7 @@ void mg_lwip_if_destroy_conn(struct mg_connection *nc) { struct udp_pcb *upcb = cs->pcb.udp; if (upcb != NULL) { DBG(("%p udp_remove %p", nc, upcb)); - udp_remove(upcb); + tcpip_callback(udp_remove_tcpip, upcb); } memset(cs, 0, sizeof(*cs)); MG_FREE(cs); @@ -14830,7 +14952,7 @@ time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) { if (nc->sock != INVALID_SOCKET && !(nc->flags & (MG_F_UDP | MG_F_LISTENING)) && cs->pcb.tcp != NULL && cs->pcb.tcp->unsent != NULL) { - tcp_output(cs->pcb.tcp); + tcpip_callback(tcp_output_tcpip, cs->pcb.tcp); } if (nc->ev_timer_time > 0) { if (num_timers == 0 || nc->ev_timer_time < min_timer) {