mirror of
https://github.com/esphome/esphome.git
synced 2026-09-11 15:27:33 +00:00
Refresh the watchdog on every authenticated removal
This commit is contained in:
@@ -458,6 +458,22 @@ def _validate_esp8266_action_strings(config: ConfigType) -> ConfigType:
|
||||
return config
|
||||
|
||||
|
||||
def _validate_outgoing_socket_implementation(config: ConfigType) -> ConfigType:
|
||||
"""A raw lwip_tcp socket can be selected explicitly on any platform."""
|
||||
if CONF_OUTGOING_CONNECTION not in config:
|
||||
return config
|
||||
from esphome.components import socket
|
||||
|
||||
socket_conf = fv.full_config.get().get("socket") or {}
|
||||
if socket_conf.get(socket.CONF_IMPLEMENTATION) == socket.IMPLEMENTATION_LWIP_TCP:
|
||||
raise cv.Invalid(
|
||||
"outgoing_connection is not supported with the lwip_tcp socket "
|
||||
"implementation because it cannot make outgoing connections",
|
||||
path=[CONF_OUTGOING_CONNECTION],
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
def _validate_outgoing_host_ipv6(config: ConfigType) -> ConfigType:
|
||||
"""An IPv6 host silently dials 255.255.255.255 on a build without IPv6."""
|
||||
if (
|
||||
@@ -477,7 +493,9 @@ def _validate_outgoing_host_ipv6(config: ConfigType) -> ConfigType:
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = cv.All(
|
||||
_validate_esp8266_action_strings, _validate_outgoing_host_ipv6
|
||||
_validate_esp8266_action_strings,
|
||||
_validate_outgoing_socket_implementation,
|
||||
_validate_outgoing_host_ipv6,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -174,7 +174,9 @@ void OutgoingConnectionManager::poll_connect_(APIServer *server, uint32_t now) {
|
||||
void OutgoingConnectionManager::handoff_(APIServer *server, uint32_t now) {
|
||||
this->dialed_conn_ = server->add_outgoing_client_(std::move(this->dial_socket_));
|
||||
if (this->dialed_conn_ == nullptr) {
|
||||
this->schedule_retry_(now);
|
||||
// Only preconditions (slot limit, key cleared) refuse the handoff; the
|
||||
// peer is reachable, so do not escalate the backoff
|
||||
this->schedule_wait_(now, PRECONDITION_RETRY_MS);
|
||||
return;
|
||||
}
|
||||
// Connected; dialed_conn_ gates further dialing until the session settles
|
||||
|
||||
@@ -239,14 +239,15 @@ void APIServer::remove_client_(uint8_t client_index) {
|
||||
|
||||
// Last client disconnected - set warning and start tracking for reboot timeout
|
||||
// (suppressed while provisioning is pending - see loop()).
|
||||
// Refresh on every authenticated removal, not just the last one, so an
|
||||
// unauthenticated straggler removed later (e.g. a port scan, or a dial to
|
||||
// a host that accepts TCP but never speaks the API) cannot discard a
|
||||
// healthy session's timestamp and trigger a spurious reboot
|
||||
if (was_authenticated) {
|
||||
this->last_connected_ = App.get_loop_component_start_time();
|
||||
}
|
||||
if (this->api_connection_count_ == 0 && this->reboot_timeout_ != 0 && !this->provisioning_pending_()) {
|
||||
this->status_set_warning(LOG_STR("waiting for client connection"));
|
||||
// A session that never authenticated (e.g. a port scan, or a dial to a
|
||||
// host that accepts TCP but never speaks the API) must not reset the
|
||||
// reboot watchdog
|
||||
if (was_authenticated) {
|
||||
this->last_connected_ = App.get_loop_component_start_time();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
|
||||
|
||||
@@ -5,7 +5,11 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome.components.api import CONFIG_SCHEMA, _validate_outgoing_host_ipv6
|
||||
from esphome.components.api import (
|
||||
CONFIG_SCHEMA,
|
||||
_validate_outgoing_host_ipv6,
|
||||
_validate_outgoing_socket_implementation,
|
||||
)
|
||||
from esphome.components.esp32 import KEY_BOARD, KEY_VARIANT, VARIANT_ESP32
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import PlatformFramework
|
||||
@@ -68,6 +72,20 @@ def test_outgoing_connection_rejected_on_raw_lwip_platforms(
|
||||
CONFIG_SCHEMA(_api_config({"host": "192.168.1.2"}))
|
||||
|
||||
|
||||
def test_outgoing_connection_rejects_lwip_tcp_socket(
|
||||
set_core_config: SetCoreConfigCallable,
|
||||
) -> None:
|
||||
"""An explicit lwip_tcp socket selection is rejected at final validate."""
|
||||
set_core_config(
|
||||
PlatformFramework.ESP32_IDF,
|
||||
platform_data=ESP32_PLATFORM_DATA,
|
||||
full_config={"socket": {"implementation": "lwip_tcp"}},
|
||||
)
|
||||
config = CONFIG_SCHEMA(_api_config({"host": "192.168.1.2"}))
|
||||
with pytest.raises(cv.Invalid, match="lwip_tcp"):
|
||||
_validate_outgoing_socket_implementation(config)
|
||||
|
||||
|
||||
def test_outgoing_connection_rejects_hostnames(
|
||||
set_core_config: SetCoreConfigCallable,
|
||||
) -> None:
|
||||
|
||||
Reference in New Issue
Block a user