2#if defined(USE_API) && defined(USE_API_OUTGOING_CONNECTION)
20#ifndef API_OUTGOING_CONNECTION_HOST
21static constexpr uint32_t OUTGOING_TARGET_PREF_HASH = 629847102UL;
24#ifndef API_OUTGOING_CONNECTION_HOST
36 if (family == AF_INET6) {
37 const auto *addr6 =
reinterpret_cast<const struct
sockaddr_in6 *
>(&peer);
38 const auto *bytes =
reinterpret_cast<const uint8_t *
>(&addr6->sin6_addr);
40 memcpy(prefix, bytes,
sizeof(prefix));
42 if (prefix[0] == 0 && prefix[1] == 0 && prefix[2] == htonl(0xFFFFUL)) {
44 memcpy(target.
addr, bytes +
sizeof(prefix),
sizeof(
struct in_addr));
51 if (addr6->sin6_scope_id > UINT8_MAX) {
55 memcpy(target.
addr, bytes,
sizeof(target.
addr));
56 target.
scope_id =
static_cast<uint8_t
>(addr6->sin6_scope_id);
60 if (family != AF_INET) {
63 const auto *addr4 =
reinterpret_cast<const struct
sockaddr_in *
>(&peer);
65 memcpy(target.
addr, &addr4->sin_addr,
sizeof(addr4->sin_addr));
71#ifdef API_OUTGOING_CONNECTION_HOST
75 API_OUTGOING_CONNECTION_PORT);
79 auto *addr6 =
reinterpret_cast<struct
sockaddr_in6 *
>(addr);
80 memset(addr6, 0,
sizeof(*addr6));
81 addr6->sin6_family = AF_INET6;
82 addr6->sin6_port = htons(API_OUTGOING_CONNECTION_PORT);
83 memcpy(&addr6->sin6_addr, this->saved_.addr,
sizeof(this->saved_.addr));
85 return sizeof(*addr6);
91 auto *addr4 =
reinterpret_cast<struct
sockaddr_in *
>(addr);
92 memset(addr4, 0,
sizeof(*addr4));
93 addr4->sin_family = AF_INET;
94 addr4->sin_port = htons(API_OUTGOING_CONNECTION_PORT);
95 memcpy(&addr4->sin_addr, this->saved_.addr,
sizeof(addr4->sin_addr));
96 return sizeof(*addr4);
100#ifndef API_OUTGOING_CONNECTION_HOST
114#ifndef API_OUTGOING_CONNECTION_HOST
118 if (this->
target_pref_.
load(&this->saved_) && this->target_sockaddr_(&addr) != 0) {
166 ESP_LOGV(TAG,
"Not dialing: %s",
167 addr_len == 0 ? LOG_STR_LITERAL(
"no target")
168 : (at_limit ? LOG_STR_LITERAL(
"max connections") : LOG_STR_LITERAL(
"no key")));
175 ESP_LOGW(TAG,
"Socket %s failed: errno %d",
176 this->
dial_socket_ ? LOG_STR_LITERAL(
"setblocking") : LOG_STR_LITERAL(
"create"), errno);
180#ifdef API_OUTGOING_CONNECTION_HOST
181 ESP_LOGD(TAG,
"Dialing " API_OUTGOING_CONNECTION_HOST
":%u", API_OUTGOING_CONNECTION_PORT);
183 char host[socket::SOCKADDR_STR_LEN];
185 ESP_LOGD(TAG,
"Dialing %s:%u", host, API_OUTGOING_CONNECTION_PORT);
193 if (errno != EINPROGRESS) {
194 ESP_LOGW(TAG,
"Connect failed: %d", errno);
205 ESP_LOGW(TAG,
"Connect timeout");
221 ESP_LOGW(TAG,
"Connect failed: %d", err);
258 if (was_authenticated) {
277#ifndef API_OUTGOING_CONNECTION_HOST
279 if (!peer_to_target(conn, target)) {
280 ESP_LOGW(TAG,
"Not remembering this target; its address cannot be dialed");
290 ESP_LOGW(TAG,
"Failed to save target");
293 char host[socket::SOCKADDR_STR_LEN];
295 ESP_LOGD(TAG,
"Remembered %s as the dial target", host);
303 " Outgoing connection port: %u\n"
304 " Outgoing connection boot delay: %" PRIu32
"ms",
308#ifdef API_OUTGOING_CONNECTION_HOST
309 ESP_LOGCONFIG(TAG,
" Outgoing connection host: " API_OUTGOING_CONNECTION_HOST);
311 char buf[socket::SOCKADDR_STR_LEN];
313 ESP_LOGCONFIG(TAG,
" Outgoing connection host: %s", buf[0] ==
'\0' ? LOG_STR_LITERAL(
"none remembered yet") : buf);
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
int getpeername(struct sockaddr *addr, socklen_t *addrlen) const
Get the peer address itself, for remembering a dial-back target.
bool at_client_limit_() const
bool has_outgoing_target_client_() const
APIConnection * add_outgoing_client_(std::unique_ptr< socket::Socket > sock)
noise::NoiseContext noise_ctx_
ESPPreferenceObject target_pref_
void poll_connect_(APIServer *server, uint32_t now)
static constexpr uint32_t CONNECT_TIMEOUT_MS
void handoff_(APIServer *server, uint32_t now)
static constexpr uint32_t PRECONDITION_RETRY_MS
socklen_t target_sockaddr_(struct sockaddr_storage *addr) const
Fill addr with the target and return its length, or 0 when there is none.
void format_target_(std::span< char, socket::SOCKADDR_STR_LEN > buf) const
Format the remembered target for a log line; empty when there is none.
void on_client_removed(APIConnection *conn, bool was_authenticated)
Clears the dialed-connection gate; dying unauthenticated escalates the backoff.
void loop(APIServer *server)
void schedule_wait_(uint32_t now, uint32_t wait)
static constexpr uint32_t BOOT_WAIT_MS
void schedule_retry_(uint32_t now)
static constexpr uint32_t CONNECT_POLL_INTERVAL_MS
SavedOutgoingTarget saved_
static constexpr uint32_t BACKOFF_MAX_MS
static constexpr uint32_t BACKOFF_MIN_MS
static constexpr uint32_t IDLE_WAIT_MS
static constexpr uint32_t NETWORK_RETRY_MS
void on_target_client(APIConnection *conn)
A key-verified client declared itself a dial-back target; last one wins.
std::unique_ptr< socket::Socket > dial_socket_
void try_dial_(APIServer *server, uint32_t now)
APIConnection * dialed_conn_
ESPHOME_LOG_TAG(TAG, "api.connection")
ESPHOME_ALWAYS_INLINE bool is_connected()
Return whether the node is connected to the network (through wifi, eth, ...)
ConnectPollResult poll_connect(Socket &sock, int &err_out)
Poll a connect() that returned EINPROGRESS.
socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const char *ip_address, uint16_t port)
Set a sockaddr to the specified address and port for the IP version used by socket_ip().
size_t format_sockaddr_to(const struct sockaddr *addr_ptr, socklen_t len, std::span< char, SOCKADDR_STR_LEN > buf)
Format sockaddr into caller-provided buffer, returns length written (excluding null)
@ CONNECT_POLL_RESULT_CONNECTED
@ CONNECT_POLL_RESULT_ERROR
@ CONNECT_POLL_RESULT_PENDING
std::unique_ptr< Socket > socket_loop_monitored(int domain, int type, int protocol)
Create a socket and monitor it for data in the main loop.
ESPPreferences * global_preferences
uint32_t random_uint32()
Return a random 32-bit unsigned integer.
Application App
Global storage of Application pointer - only one Application can exist.
ESPPreferenceObject make_preference(size_t, uint32_t, bool)
uint8_t addr[TARGET_ADDR_LEN]