time_t mg_mgr_poll(struct mg_mgr *mgr, int timeout_ms) { int n = 0; time_t now = time(NULL); struct mg_connection *nc, *tmp; (void) timeout_ms; DBG(("begin poll, now=%u, hf=%u, sf lwm=%u", (unsigned int) now, system_get_free_heap_size(), 0U)); for (nc = mgr->active_connections; nc != NULL; nc = tmp) { struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; (void) cs; tmp = nc->next; n++; if (nc->flags & MG_F_CLOSE_IMMEDIATELY) { mg_close_conn(nc); continue; } mg_if_poll(nc, now); mg_if_timer(nc, now); if (nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE) && !(nc->flags & MG_F_WANT_WRITE)) { mg_close_conn(nc); continue; } #ifdef SSL_KRYPTON if (nc->ssl != NULL && cs != NULL && cs->pcb.tcp != NULL && cs->pcb.tcp->state == ESTABLISHED) { if (((nc->flags & MG_F_WANT_WRITE) || nc->send_mbuf.len > 0) && cs->pcb.tcp->snd_buf > 0) { /* Can write more. */ if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { if (!(nc->flags & MG_F_CONNECTING)) mg_lwip_ssl_send(nc); } else { mg_lwip_ssl_do_hs(nc); } } if (cs->rx_chain != NULL) { if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { if (!(nc->flags & MG_F_CONNECTING)) mg_lwip_ssl_recv(nc); } else { mg_lwip_ssl_do_hs(nc); } } } else #endif /* SSL_KRYPTON */ { if (!(nc->flags & (MG_F_CONNECTING | MG_F_UDP))) { if (nc->send_mbuf.len > 0) mg_lwip_send_more(nc); } } } DBG(("end poll, %d conns", n)); return now; }
static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { struct mg_connection *nc = (struct mg_connection *) arg; DBG(("%p %p %u %d", nc, tpcb, (p != NULL ? p->tot_len : 0), err)); if (p == NULL) { if (nc != NULL) { system_os_post(MG_TASK_PRIORITY, MG_SIG_CLOSE_CONN, (uint32_t) nc); } else { /* Tombstoned connection, do nothing. */ } return ERR_OK; } else if (nc == NULL) { tcp_abort(tpcb); return ERR_ARG; } struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; /* * If we get a chain of more than one segment at once, we need to bump * refcount on the subsequent bufs to make them independent. */ if (p->next != NULL) { struct pbuf *q = p->next; for (; q != NULL; q = q->next) pbuf_ref(q); } if (cs->rx_chain == NULL) { cs->rx_chain = p; cs->rx_offset = 0; } else { pbuf_chain(cs->rx_chain, p); } #ifdef SSL_KRYPTON if (nc->ssl != NULL) { if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { mg_lwip_ssl_recv(nc); } else { mg_lwip_ssl_do_hs(nc); } return ERR_OK; } #endif while (cs->rx_chain != NULL) { struct pbuf *seg = cs->rx_chain; size_t len = (seg->len - cs->rx_offset); char *data = (char *) malloc(len); if (data == NULL) { DBG(("OOM")); return ERR_MEM; } pbuf_copy_partial(seg, data, len, cs->rx_offset); mg_if_recv_tcp_cb(nc, data, len); /* callee takes over data */ cs->rx_offset += len; if (cs->rx_offset == cs->rx_chain->len) { cs->rx_chain = pbuf_dechain(cs->rx_chain); pbuf_free(seg); cs->rx_offset = 0; } } if (nc->send_mbuf.len > 0) { mg_lwip_mgr_schedule_poll(nc->mgr); } return ERR_OK; }
time_t mg_mgr_poll(struct mg_mgr *mgr, int timeout_ms) { int n = 0; double now = mg_time(); struct mg_connection *nc, *tmp; double min_timer = 0; int num_timers = 0; DBG(("begin poll @%u, hf=%u", (unsigned int) (now * 1000), system_get_free_heap_size())); for (nc = mgr->active_connections; nc != NULL; nc = tmp) { struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; (void) cs; tmp = nc->next; n++; if (nc->flags & MG_F_CLOSE_IMMEDIATELY) { mg_close_conn(nc); continue; } mg_if_poll(nc, now); mg_if_timer(nc, now); if (nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE) && !(nc->flags & MG_F_WANT_WRITE)) { mg_close_conn(nc); continue; } #ifdef SSL_KRYPTON if (nc->ssl != NULL && cs != NULL && cs->pcb.tcp != NULL && cs->pcb.tcp->state == ESTABLISHED) { if (((nc->flags & MG_F_WANT_WRITE) || nc->send_mbuf.len > 0) && cs->pcb.tcp->snd_buf > 0) { /* Can write more. */ if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { if (!(nc->flags & MG_F_CONNECTING)) mg_lwip_ssl_send(nc); } else { mg_lwip_ssl_do_hs(nc); } } if (cs->rx_chain != NULL || (nc->flags & MG_F_WANT_READ)) { if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { if (!(nc->flags & MG_F_CONNECTING)) mg_lwip_ssl_recv(nc); } else { mg_lwip_ssl_do_hs(nc); } } } else #endif /* SSL_KRYPTON */ { if (!(nc->flags & (MG_F_CONNECTING | MG_F_UDP))) { if (nc->send_mbuf.len > 0) mg_lwip_send_more(nc); } } if (nc->ev_timer_time > 0) { if (num_timers == 0 || nc->ev_timer_time < min_timer) { min_timer = nc->ev_timer_time; } num_timers++; } } now = mg_time(); timeout_ms = MG_POLL_INTERVAL_MS; if (num_timers > 0) { double timer_timeout_ms = (min_timer - now) * 1000 + 1 /* rounding */; if (timer_timeout_ms < timeout_ms) { timeout_ms = timer_timeout_ms; } } if (timeout_ms <= 0) timeout_ms = 1; DBG(("end poll @%u, %d conns, %d timers (min %u), next in %d ms", (unsigned int) (now * 1000), n, num_timers, (unsigned int) (min_timer * 1000), timeout_ms)); os_timer_disarm(&s_poll_tmr); os_timer_arm(&s_poll_tmr, timeout_ms, 0 /* no repeat */); return now; }
static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { struct mg_connection *nc = (struct mg_connection *) arg; DBG(("%p %p %u %d", nc, tpcb, (p != NULL ? p->tot_len : 0), err)); if (p == NULL) { if (nc != NULL) { mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); } else { /* Tombstoned connection, do nothing. */ } return ERR_OK; } else if (nc == NULL) { tcp_abort(tpcb); return ERR_ARG; } struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; /* * If we get a chain of more than one segment at once, we need to bump * refcount on the subsequent bufs to make them independent. */ if (p->next != NULL) { struct pbuf *q = p->next; for (; q != NULL; q = q->next) pbuf_ref(q); } if (cs->rx_chain == NULL) { cs->rx_chain = p; cs->rx_offset = 0; } else { if (pbuf_clen(cs->rx_chain) >= 4) { /* ESP SDK has a limited pool of 5 pbufs. We must not hog them all or RX * will be completely blocked. We already have at least 4 in the chain, * this one is, so we have to make a copy and release this one. */ struct pbuf *np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); if (np != NULL) { pbuf_copy(np, p); pbuf_free(p); p = np; } } pbuf_chain(cs->rx_chain, p); } #ifdef SSL_KRYPTON if (nc->ssl != NULL) { if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { mg_lwip_ssl_recv(nc); } else { mg_lwip_ssl_do_hs(nc); } return ERR_OK; } #endif while (cs->rx_chain != NULL) { struct pbuf *seg = cs->rx_chain; size_t len = (seg->len - cs->rx_offset); char *data = (char *) malloc(len); if (data == NULL) { DBG(("OOM")); return ERR_MEM; } pbuf_copy_partial(seg, data, len, cs->rx_offset); mg_if_recv_tcp_cb(nc, data, len); /* callee takes over data */ cs->rx_offset += len; if (cs->rx_offset == cs->rx_chain->len) { cs->rx_chain = pbuf_dechain(cs->rx_chain); pbuf_free(seg); cs->rx_offset = 0; } } if (nc->send_mbuf.len > 0) { mg_lwip_mgr_schedule_poll(nc->mgr); } return ERR_OK; }
time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) { struct mg_mgr *mgr = iface->mgr; int n = 0; double now = mg_time(); struct mg_connection *nc, *tmp; double min_timer = 0; int num_timers = 0; #if 0 DBG(("begin poll @%u", (unsigned int) (now * 1000))); #endif mg_ev_mgr_lwip_process_signals(mgr); for (nc = mgr->active_connections; nc != NULL; nc = tmp) { struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; tmp = nc->next; n++; if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) || ((nc->flags & MG_F_SEND_AND_CLOSE) && (nc->flags & MG_F_UDP) && (nc->send_mbuf.len == 0))) { mg_close_conn(nc); continue; } mg_if_poll(nc, now); mg_if_timer(nc, now); #if MG_ENABLE_SSL if ((nc->flags & MG_F_SSL) && cs != NULL && cs->pcb.tcp != NULL && cs->pcb.tcp->state == ESTABLISHED) { if (((nc->flags & MG_F_WANT_WRITE) || ((nc->send_mbuf.len > 0) && (nc->flags & MG_F_SSL_HANDSHAKE_DONE))) && cs->pcb.tcp->snd_buf > 0) { /* Can write more. */ if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { if (!(nc->flags & MG_F_CONNECTING)) mg_lwip_ssl_send(nc); } else { mg_lwip_ssl_do_hs(nc); } } if (cs->rx_chain != NULL || (nc->flags & MG_F_WANT_READ)) { if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { if (!(nc->flags & MG_F_CONNECTING)) mg_lwip_ssl_recv(nc); } else { mg_lwip_ssl_do_hs(nc); } } } else #endif /* MG_ENABLE_SSL */ { if (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING)) { mg_lwip_send_more(nc); } } if (nc->sock != INVALID_SOCKET && !(nc->flags & (MG_F_UDP | MG_F_LISTENING)) && cs->pcb.tcp != NULL && cs->pcb.tcp->unsent != NULL) { tcpip_callback(tcp_output_tcpip, cs->pcb.tcp); } if (nc->ev_timer_time > 0) { if (num_timers == 0 || nc->ev_timer_time < min_timer) { min_timer = nc->ev_timer_time; } num_timers++; } if (nc->sock != INVALID_SOCKET) { /* Try to consume data from cs->rx_chain */ mg_lwip_consume_rx_chain_tcp(nc); /* * If the connection is about to close, and rx_chain is finally empty, * send the MG_SIG_CLOSE_CONN signal */ if (cs->draining_rx_chain && cs->rx_chain == NULL) { mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); } } } #if 0 DBG(("end poll @%u, %d conns, %d timers (min %u), next in %d ms", (unsigned int) (now * 1000), n, num_timers, (unsigned int) (min_timer * 1000), timeout_ms)); #endif (void) timeout_ms; return now; }