feat(esp-tls): add opt-in TCP_NODELAY (CONFIG_ESP_TLS_ENABLE_TCP_NODELAY)

Latency-sensitive small-message protocols (notably MQTT: PUBLISH/PUBACK/
PINGREQ) suffer when Nagle's algorithm interacts with the peer's
delayed-ACK: a small write is withheld until the prior segment is ACKed
while the peer holds that ACK up to ~40-200 ms, stalling each small write
until the delayed-ACK timer fires.

Add CONFIG_ESP_TLS_ENABLE_TCP_NODELAY (default n). When enabled,
esp_tls_set_socket_options() sets TCP_NODELAY on the connection socket
alongside the existing SO_*TIMEO / keepalive options, so small records go
out immediately. Non-fatal (a latency hint), so a failure only warns.
Off by default: no behavior change for existing users.

Signed-off-by: Eric Wang <eric@rwx.one>
This commit is contained in:
Eric Wang
2026-07-20 01:00:28 -07:00
parent 055ba9d3f9
commit 850d652f00
2 changed files with 19 additions and 0 deletions

View File

@@ -22,6 +22,15 @@ menu "ESP-TLS"
esp_tls_stack_ops_t interface.
endchoice
config ESP_TLS_ENABLE_TCP_NODELAY
bool "Enable TCP_NODELAY (disable Nagle's algorithm) on ESP-TLS sockets"
default n
help
Set TCP_NODELAY on every ESP-TLS client connection socket, disabling Nagle's algorithm.
Recommended for latency-sensitive small-message traffic (e.g. MQTT), where Nagle
interacting with the peer's delayed-ACK can stall a small write by ~40-200 ms until
the delayed-ACK timer fires. Off by default (no behavior change).
config ESP_TLS_USE_DS_PERIPHERAL
bool "Use Digital Signature (DS) Peripheral with ESP-TLS"
depends on ESP_TLS_USING_MBEDTLS && SOC_DIG_SIGN_SUPPORTED

View File

@@ -317,6 +317,16 @@ static esp_err_t esp_tls_set_socket_options(int fd, const esp_tls_cfg_t *cfg)
return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
}
#if CONFIG_ESP_TLS_ENABLE_TCP_NODELAY
/* Disable Nagle's algorithm. Small control-plane writes (e.g. MQTT PUBLISH/PUBACK/PINGREQ)
* otherwise interact with the peer's delayed-ACK and stall ~40-200 ms until its timer fires.
* Non-fatal: a latency hint, not required for a correct connection (unlike the timeouts). */
int nodelay = 1;
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay)) != 0) {
ESP_LOGW(TAG, "Fail to setsockopt TCP_NODELAY (non-fatal)");
}
#endif
if (cfg->keep_alive_cfg && cfg->keep_alive_cfg->keep_alive_enable) {
int keep_alive_enable = 1;
int keep_alive_idle = cfg->keep_alive_cfg->keep_alive_idle;