[ota,socket] Add SO_SNDTIMEO and use delay(0) in readall_

- Add SO_SNDTIMEO to OTA socket to prevent blocking writes from
  stalling the WDT when the TCP send buffer is full
- Add SO_SNDTIMEO as no-op in raw TCP (writes never block)
- Use delay(0) instead of delay(1) in readall_() since SO_RCVTIMEO
  already handles the wait
- Keep delay(1) in writeall_() since raw TCP writes are non-blocking
  and would spin on EWOULDBLOCK without it
This commit is contained in:
J. Nick Koston
2026-03-09 21:49:06 -10:00
parent c43015a467
commit 5aa9c18dfc
3 changed files with 11 additions and 1 deletions
@@ -258,6 +258,9 @@ void ESPHomeOTAComponent::handle_data_() {
tv.tv_sec = 2;
tv.tv_usec = 0;
this->client_->setsockopt(SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
// Also set send timeout to prevent blocking writes from stalling the WDT
// when the TCP send buffer is full (e.g., network congestion).
this->client_->setsockopt(SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
this->client_->setblocking(true);
// Acknowledge auth OK - 1 byte
@@ -413,7 +416,9 @@ bool ESPHomeOTAComponent::readall_(uint8_t *buf, size_t len) {
} else {
at += read;
}
this->yield_and_feed_watchdog_();
// read() already waited via SO_RCVTIMEO, just yield without 1ms stall
App.feed_wdt();
delay(0);
}
return true;
+1
View File
@@ -52,6 +52,7 @@
#define SO_KEEPALIVE 0x0008 /* keep connections alive */
#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
#define SO_RCVTIMEO 0x1006 /* receive timeout */
#define SO_SNDTIMEO 0x1005 /* send timeout */
#define SOL_SOCKET 0xfff /* options for socket level */
@@ -355,6 +355,10 @@ int LWIPRawCommon::setsockopt(int level, int optname, const void *optval, sockle
this->recv_timeout_cs_ = cs > 255 ? 255 : static_cast<uint8_t>(cs);
return 0;
}
if (level == SOL_SOCKET && optname == SO_SNDTIMEO) {
// Raw TCP writes are non-blocking (tcp_write), so send timeout is a no-op.
return 0;
}
if (level == IPPROTO_TCP && optname == TCP_NODELAY) {
if (optlen != 4) {
errno = EINVAL;