From b2e2ad9a459522611620f33899a337d8d2fbf3a5 Mon Sep 17 00:00:00 2001
From: Deomid Ryabkov <rojer@cesanta.com>
Date: Wed, 12 Apr 2017 16:43:11 +0100
Subject: [PATCH] Fix hexdump on ESP8266, deliver MG_EV_SEND [...]

[...] after handing data off to LWIP, do not wait for ACK.
We don't do it in net_if_socket, don't do it here either.
Also prevents multiple send attempt on the same send_mbuf data.

PUBLISHED_FROM=4e5a677ebda84af1514f34299e53ce856a537883
---
 mongoose.c | 120 +++++++++++++++++++++++------------------------------
 1 file changed, 52 insertions(+), 68 deletions(-)

diff --git a/mongoose.c b/mongoose.c
index 8c8a63493..1521e7476 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -2020,12 +2020,10 @@ MG_INTERNAL void mg_call(struct mg_connection *nc,
   }
 
 #if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
-  /* LCOV_EXCL_START */
   if (nc->mgr->hexdump_file != NULL && ev != MG_EV_POLL && ev != MG_EV_RECV &&
       ev != MG_EV_SEND /* handled separately */) {
     mg_hexdump_connection(nc, nc->mgr->hexdump_file, NULL, 0, ev);
   }
-/* LCOV_EXCL_STOP */
 #endif
   if (ev_handler != NULL) {
     unsigned long flags_before = nc->flags;
@@ -9591,8 +9589,7 @@ void mg_hexdumpf(FILE *fp, const void *buf, int len) {
 void mg_hexdump_connection(struct mg_connection *nc, const char *path,
                            const void *buf, int num_bytes, int ev) {
   FILE *fp = NULL;
-  char *hexbuf, src[60], dst[60];
-  int buf_size = num_bytes * 5 + 100;
+  char src[60], dst[60];
   const char *tag = NULL;
   switch (ev) {
     case MG_EV_RECV:
@@ -9630,13 +9627,11 @@ void mg_hexdump_connection(struct mg_connection *nc, const char *path,
                                                 MG_SOCK_STRINGIFY_PORT |
                                                 MG_SOCK_STRINGIFY_REMOTE);
   fprintf(fp, "%lu %p %s %s %s %d\n", (unsigned long) mg_time(), (void *) nc,
-          src, tag, dst, num_bytes);
-  if (num_bytes > 0 && (hexbuf = (char *) MG_MALLOC(buf_size)) != NULL) {
-    mg_hexdump(buf, num_bytes, hexbuf, buf_size);
-    fprintf(fp, "%s", hexbuf);
-    MG_FREE(hexbuf);
+          src, tag, dst, (int) num_bytes);
+  if (num_bytes > 0) {
+    mg_hexdumpf(fp, buf, num_bytes);
   }
-  if (fp != stdin && fp != stdout) fclose(fp);
+  if (fp != stdout && fp != stderr) fclose(fp);
 }
 #endif
 
@@ -13983,10 +13978,9 @@ struct mg_lwip_conn_state {
 enum mg_sig_type {
   MG_SIG_CONNECT_RESULT = 1,
   MG_SIG_RECV = 2,
-  MG_SIG_SENT_CB = 3,
-  MG_SIG_CLOSE_CONN = 4,
-  MG_SIG_TOMBSTONE = 5,
-  MG_SIG_ACCEPT = 6,
+  MG_SIG_CLOSE_CONN = 3,
+  MG_SIG_TOMBSTONE = 4,
+  MG_SIG_ACCEPT = 5,
 };
 
 void mg_lwip_post_signal(enum mg_sig_type sig, struct mg_connection *nc);
@@ -14206,14 +14200,10 @@ static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb,
                                  u16_t num_sent) {
   struct mg_connection *nc = (struct mg_connection *) arg;
   DBG(("%p %p %u", nc, tpcb, num_sent));
-  if (nc == NULL) {
-    tcp_abort(tpcb);
-    return ERR_ABRT;
+  if ((nc->flags & MG_F_SEND_AND_CLOSE) && !(nc->flags & MG_F_WANT_WRITE) &&
+      nc->send_mbuf.len == 0 && tpcb->unacked == 0) {
+    mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
   }
-  struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
-  cs->num_sent += num_sent;
-
-  mg_lwip_post_signal(MG_SIG_SENT_CB, nc);
   return ERR_OK;
 }
 
@@ -14436,49 +14426,29 @@ int mg_lwip_tcp_write(struct mg_connection *nc, const void *data,
     len = MIN(len, (TCP_MSS - tpcb->unsent->len));
   }
 #endif
-  err_t err = tcp_write(tpcb, data, len, TCP_WRITE_FLAG_COPY);
-  DBG(("%p tcp_write %u = %d", tpcb, len, err));
-  if (err != ERR_OK) {
+  cs->err = tcp_write(tpcb, 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 (err == ERR_MEM ? 0 : -1);
+    return (cs->err == ERR_MEM ? 0 : -1);
   }
   return len;
 }
 
-static void mg_lwip_send_more(struct mg_connection *nc) {
+static int mg_lwip_udp_send(struct mg_connection *nc, const void *data,
+                            uint16_t len) {
   struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
-  if (nc->sock == INVALID_SOCKET || cs->pcb.tcp == NULL) {
-    DBG(("%p invalid socket", nc));
-    return;
-  }
-  int num_written = mg_lwip_tcp_write(nc, nc->send_mbuf.buf, nc->send_mbuf.len);
-  DBG(("%p mg_lwip_tcp_write %u = %d", nc, nc->send_mbuf.len, num_written));
-  if (num_written == 0) return;
-  if (num_written < 0) {
-    mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
-  }
-}
-
-void mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf,
-                         size_t len) {
-  mbuf_append(&nc->send_mbuf, buf, len);
-  mg_lwip_mgr_schedule_poll(nc->mgr);
-}
-
-void mg_lwip_if_udp_send(struct mg_connection *nc, const void *buf,
-                         size_t len) {
-  struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
-  if (nc->sock == INVALID_SOCKET || cs->pcb.udp == NULL) {
+  if (cs->pcb.udp == NULL) {
     /*
      * In case of UDP, this usually means, what
      * async DNS resolve is still in progress and connection
      * is not ready yet
      */
     DBG(("%p socket is not connected", nc));
-    return;
+    return -1;
   }
   struct udp_pcb *upcb = cs->pcb.udp;
   struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
@@ -14486,20 +14456,45 @@ void mg_lwip_if_udp_send(struct mg_connection *nc, const void *buf,
   u16_t port = ntohs(nc->sa.sin.sin_port);
   if (p == NULL) {
     DBG(("OOM"));
-    return;
+    return 0;
   }
-  memcpy(p->payload, buf, len);
+  memcpy(p->payload, data, len);
   cs->err = udp_sendto(upcb, p, (ip_addr_t *) ip, port);
   DBG(("%p udp_sendto = %d", nc, cs->err));
   pbuf_free(p);
-  if (cs->err != ERR_OK) {
-    mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
+  return (cs->err == ERR_OK ? len : -1);
+}
+
+static void mg_lwip_send_more(struct mg_connection *nc) {
+  int num_sent = 0;
+  if (nc->sock == INVALID_SOCKET) return;
+  if (nc->flags & MG_F_UDP) {
+    num_sent = mg_lwip_udp_send(nc, nc->send_mbuf.buf, nc->send_mbuf.len);
+    DBG(("%p mg_lwip_udp_send %u = %d", nc, nc->send_mbuf.len, num_sent));
+  } else {
+    num_sent = mg_lwip_tcp_write(nc, nc->send_mbuf.buf, nc->send_mbuf.len);
+    DBG(("%p mg_lwip_tcp_write %u = %d", nc, nc->send_mbuf.len, num_sent));
+  }
+  if (num_sent == 0) return;
+  if (num_sent > 0) {
+    mg_if_sent_cb(nc, num_sent);
   } else {
-    cs->num_sent += len;
-    mg_lwip_post_signal(MG_SIG_SENT_CB, nc);
+    mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
   }
 }
 
+void mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf,
+                         size_t len) {
+  mbuf_append(&nc->send_mbuf, buf, len);
+  mg_lwip_mgr_schedule_poll(nc->mgr);
+}
+
+void mg_lwip_if_udp_send(struct mg_connection *nc, const void *buf,
+                         size_t len) {
+  mbuf_append(&nc->send_mbuf, buf, len);
+  mg_lwip_mgr_schedule_poll(nc->mgr);
+}
+
 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;
@@ -14697,17 +14692,6 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) {
         }
         break;
       }
-      case MG_SIG_SENT_CB: {
-        mg_if_sent_cb(nc, cs->num_sent);
-        cs->num_sent = 0;
-
-        if (nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE) &&
-            !(nc->flags & MG_F_WANT_WRITE)) {
-          mg_close_conn(nc);
-        }
-
-        break;
-      }
       case MG_SIG_TOMBSTONE: {
         break;
       }
@@ -14791,8 +14775,8 @@ time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) {
     } else
 #endif /* MG_ENABLE_SSL */
     {
-      if (!(nc->flags & (MG_F_CONNECTING | MG_F_UDP))) {
-        if (nc->send_mbuf.len > 0) mg_lwip_send_more(nc);
+      if (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING)) {
+        mg_lwip_send_more(nc);
       }
     }
     if (nc->sock != INVALID_SOCKET &&
-- 
GitLab