esp-idf: httpd: httpd_accept_conn: error in accept (23) (IDFGH-9118)

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

General issue report

IDF version : v4.3.4-dirty

When open the first web page in the browser,it works fine.Then open a new page in other browser,some source can’t load. I have set lwip max socket num =16. And I also used socket in other places,such as tcp server,tcp client,mqtt… I have read the #9395 and add the code bellow in web server config.

void close_fd_cb(httpd_handle_t hd, int sockfd)
{
	struct linger so_linger;
	so_linger.l_onoff = true;
	so_linger.l_linger = 0;
	setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger));
	close(sockfd);
	ESP_LOGI(TAG, "close() fd (%d) success.", sockfd);
}

    httpd_config_t config = HTTPD_DEFAULT_CONFIG();

    config.uri_match_fn = httpd_uri_match_wildcard;
    config.max_uri_handlers = 64;
    config.max_open_sockets = 12;
    config.lru_purge_enable = true;
    config.close_fn = close_fd_cb;

It seems difficult to trigger。Rarely seen “close() fd (%d) success.”

the error lwip log is bellow:

lwip_accept(48)...
W (34520) httpd: httpd_accept_conn: error in accept (23)
W (34521) httpd: httpd_server: error accepting new connection
lwip_select(64, 0x3ffcbb90, 0x0, 0x0, tvsec=-1 tvusec=-1)
lwip_selscan: fd=48 ready for reading
lwip_selscan: fd=61 ready for reading
lwip_selscan: fd=62 ready for reading
lwip_select: nready=3
lwip_recvfrom(61, 0x3ffc8fb8, 128, 0x0, ..)
lwip_recv_tcp: top while sock->lastdata=0x0
lwip_recv_tcp: netconn_recv err=0, pbuf=0x3ffcd05c
lwip_recv_tcp: buflen=381 recv_left=128 off=0
lwip_recv_tcp: lastdata now pbuf=0x3ffcd05c
lwip_recvfrom(61):  addr=192.168.3.110 port=3991 len=128
lwip_recvfrom(61, 0x3ffc9018, 128, 0x0, ..)
lwip_recv_tcp: top while sock->lastdata=0x3ffcd05c
lwip_recv_tcp: buflen=253 recv_left=128 off=0
lwip_recv_tcp: lastdata now pbuf=0x3ffcd05c
lwip_recvfrom(61):  addr=192.168.3.110 port=3991 len=128
lwip_recvfrom(61, 0x3ffc9098, 128, 0x0, ..)
lwip_recv_tcp: top while sock->lastdata=0x3ffcd05c
lwip_recv_tcp: buflen=125 recv_left=128 off=0
lwip_recv_tcp: deleting pbuf=0x3ffcd05c
lwip_recv_tcp: top while sock->lastdata=0x0
lwip_recv_tcp: netconn_recv err=-7, pbuf=0x0
lwip_recvfrom(61):  addr=192.168.3.110 port=3991 len=125
lwip_send(61, data=0x3ffc8fb8, size=78, flags=0x0)
lwip_send(61) err=0 written=78
lwip_send(61, data=0x3f4c4454, size=2, flags=0x0)
lwip_send(61) err=0 written=2
lwip_send(61, data=0x3f466525, size=37051, flags=0x0)
lwip_send(61) err=0 written=37051
lwip_recvfrom(62, 0x3ffc8fb8, 128, 0x0, ..)
lwip_recv_tcp: top while sock->lastdata=0x0
lwip_recv_tcp: netconn_recv err=0, pbuf=0x3ffcd120
lwip_recv_tcp: buflen=376 recv_left=128 off=0
lwip_recv_tcp: lastdata now pbuf=0x3ffcd120
lwip_recvfrom(62):  addr=192.168.3.110 port=3992 len=128
lwip_recvfrom(62, 0x3ffc901d, 128, 0x0, ..)
lwip_recv_tcp: top while sock->lastdata=0x3ffcd120
lwip_recv_tcp: buflen=248 recv_left=128 off=0
lwip_recv_tcp: lastdata now pbuf=0x3ffcd120
lwip_select: timeout expired
lwip_recvfrom(62):  addr=192.168.3.110 port=3992 len=128
lwip_select(61, 0x3ffd1468, 0x0, 0x3ffd1470, tvsec=0 tvusec=0)
lwip_select: no timeout, returning 0
lwip_recvfrom(62, 0x3ffc909d, 128, 0x0, ..)
lwip_select(61, 0x3ffd1518, 0x0, 0x3ffd1520, tvsec=1 tvusec=0)
lwip_recv_tcp: top while sock->lastdata=0x3ffcd120
lwip_recv_tcp: buflen=120 recv_left=128 off=0
lwip_recv_tcp: deleting pbuf=0x3ffcd120
lwip_recv_tcp: top while sock->lastdata=0x0
lwip_recv_tcp: netconn_recv err=-7, pbuf=0x0
lwip_recvfrom(62):  addr=192.168.3.110 port=3992 len=120
lwip_send(62, data=0x3ffc8fb8, size=78, flags=0x0)
lwip_send(62) err=0 written=78
lwip_send(62, data=0x3f4c4454, size=2, flags=0x0)
lwip_send(62) err=0 written=2
lwip_send(62, data=0x3f4a72b5, size=31567, flags=0x0)
lwip_send(62) err=0 written=31567
lwip_accept(48)...
W (34818) httpd: httpd_accept_conn: error in accept (23)
W (34819) httpd: httpd_server: error accepting new connection
lwip_select(64, 0x3ffcbb90, 0x0, 0x0, tvsec=-1 tvusec=-1)
lwip_select: timeout expired
lwip_select(61, 0x3ffd1468, 0x0, 0x3ffd1470, tvsec=0 tvusec=0)
lwip_select: no timeout, returning 0
lwip_select(61, 0x3ffd1518, 0x0, 0x3ffd1520, tvsec=1 tvusec=0)
lwip_select: timeout expired
lwip_select(61, 0x3ffd1468, 0x0, 0x3ffd1470, tvsec=0 tvusec=0)
lwip_select: no timeout, returning 0
lwip_select(61, 0x3ffd1518, 0x0, 0x3ffd1520, tvsec=1 tvusec=0)
lwip_selscan: fd=59 ready for reading
lwip_select: nready=1
lwip_recvfrom(59, 0x3ffcba80, 1, 0x0, ..)
lwip_recv_tcp: top while sock->lastdata=0x0
lwip_recv_tcp: netconn_recv err=0, pbuf=0x3ffcd120
lwip_recv_tcp: buflen=29 recv_left=1 off=0
lwip_recv_tcp: lastdata now pbuf=0x3ffcd120
lwip_recvfrom(59):  addr=192.168.3.110 port=3977 len=1
lwip_recvfrom(59, 0x3ffcba60, 1, 0x0, ..)
lwip_recv_tcp: top while sock->lastdata=0x3ffcd120
lwip_recv_tcp: buflen=28 recv_left=1 off=0
lwip_recv_tcp: lastdata now pbuf=0x3ffcd120
lwip_recvfrom(59):  addr=192.168.3.110 port=3977 len=1
lwip_recvfrom(59, 0x3ffcba61, 4, 0x0, ..)
lwip_recv_tcp: top while sock->lastdata=0x3ffcd120
lwip_recv_tcp: buflen=27 recv_left=4 off=0
lwip_recv_tcp: lastdata now pbuf=0x3ffcd120
lwip_recvfrom(59):  addr=192.168.3.110 port=3977 len=4
lwip_recvfrom(59, 0x3ffcba90, 23, 0x0, ..)
lwip_recv_tcp: top while sock->lastdata=0x3ffcd120
lwip_recv_tcp: buflen=23 recv_left=23 off=0
lwip_recv_tcp: deleting pbuf=0x3ffcd120
lwip_recvfrom(59):  addr=192.168.3.110 port=3977 len=23
lwip_send(59, data=0x3ffcba10, size=4, flags=0x0)
lwip_send(59) err=0 written=4
lwip_send(59, data=0x3ffcc538, size=627, flags=0x0)
lwip_send(59) err=0 written=627
lwip_select(64, 0x3ffcbb90, 0x0, 0x0, tvsec=-1 tvusec=-1)
lwip_select: timeout expired
lwip_select(61, 0x3ffd1468, 0x0, 0x3ffd1470, tvsec=0 tvusec=0)
lwip_select: no timeout, returning 0
lwip_select(61, 0x3ffd1518, 0x0, 0x3ffd1520, tvsec=1 tvusec=0)

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 15 (2 by maintainers)

Most upvoted comments

@ArvinHou I think you can follow this patch to add keep-alive function.

diff --git a/components/esp_http_server/include/esp_http_server.h b/components/esp_http_server/include/esp_http_server.h
index 1c8b785..26ad32c 100644
--- a/components/esp_http_server/include/esp_http_server.h
+++ b/components/esp_http_server/include/esp_http_server.h
@@ -36,6 +36,7 @@ initializer that should be kept in sync
         .lru_purge_enable   = false,                    \
         .recv_wait_timeout  = 5,                        \
         .send_wait_timeout  = 5,                        \
+        .keep_alive_enable = true,                      \
         .global_user_ctx = NULL,                        \
         .global_user_ctx_free_fn = NULL,                \
         .global_transport_ctx = NULL,                   \
@@ -154,6 +155,10 @@ typedef struct httpd_config {
     bool        lru_purge_enable;   /*!< Purge "Least Recently Used" connection */
     uint16_t    recv_wait_timeout;  /*!< Timeout for recv function (in seconds)*/
     uint16_t    send_wait_timeout;  /*!< Timeout for send function (in seconds)*/
+    bool keep_alive_enable; /*!< Enable keep-alive timeout */
+    int keep_alive_idle;    /*!< Keep-alive idle time. Default is 5 (second) */
+    int keep_alive_interval;/*!< Keep-alive interval time. Default is 5 (second) */
+    int keep_alive_count;   /*!< Keep-alive packet retry send count. Default is 3 counts */
 
     /**
      * Global user context.
diff --git a/components/esp_http_server/src/httpd_main.c b/components/esp_http_server/src/httpd_main.c
index c7dfff1..e19cd47 100644
--- a/components/esp_http_server/src/httpd_main.c
+++ b/components/esp_http_server/src/httpd_main.c
@@ -59,13 +59,39 @@ static esp_err_t httpd_accept_conn(struct httpd_data *hd, int listen_fd)
     tv.tv_usec = 0;
     setsockopt(new_fd, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tv, sizeof(tv));
 
+    if (hd->config.keep_alive_enable) {
+        int keep_alive_enable = 1;
+        int keep_alive_idle = hd->config.keep_alive_idle ? hd->config.keep_alive_idle : 5;
+        int keep_alive_interval = hd->config.keep_alive_interval ? hd->config.keep_alive_interval : 5;
+        int keep_alive_count = hd->config.keep_alive_count ? hd->config.keep_alive_count : 3;
+        ESP_LOGD(TAG, "Enable TCP keep alive. idle: %d, interval: %d, count: %d", keep_alive_idle, keep_alive_interval, keep_alive_count);
+
+        if (setsockopt(new_fd, SOL_SOCKET, SO_KEEPALIVE, &keep_alive_enable, sizeof(keep_alive_enable)) < 0) {
+            ESP_LOGW(TAG, LOG_FMT("error enabling SO_KEEPALIVE (%d)"), errno);
+            goto exit;
+        }
+        if (setsockopt(new_fd, IPPROTO_TCP, TCP_KEEPIDLE, &keep_alive_idle, sizeof(keep_alive_idle)) < 0) {
+            ESP_LOGW(TAG, LOG_FMT("error set TCP_KEEPIDLE (%d)"), errno);
+            goto exit;
+        }
+        if (setsockopt(new_fd, IPPROTO_TCP, TCP_KEEPINTVL, &keep_alive_interval, sizeof(keep_alive_interval)) < 0) {
+            ESP_LOGW(TAG, LOG_FMT("error set TCP_KEEPINTVL (%d)"), errno);
+            goto exit;
+        }
+        if (setsockopt(new_fd, IPPROTO_TCP, TCP_KEEPCNT, &keep_alive_count, sizeof(keep_alive_count)) < 0) {
+            ESP_LOGW(TAG, LOG_FMT("error set TCP_KEEPCNT (%d)"), errno);
+            goto exit;
+        }
+    }
     if (ESP_OK != httpd_sess_new(hd, new_fd)) {
         ESP_LOGW(TAG, LOG_FMT("session creation failed"));
-        close(new_fd);
-        return ESP_FAIL;
+        goto exit;
     }
     ESP_LOGD(TAG, LOG_FMT("complete"));
     return ESP_OK;
+exit:
+    close(new_fd);
+    return ESP_FAIL;
 }
 
 struct httpd_ctrl_data {

And when you close web page, the browser may not close socket, so when you close browser, it will release the previous sockets.