2#if defined(USE_API) && defined(USE_API_OUTGOING_CONNECTION)
18static const char *
const TAG =
"api.outgoing";
20#ifndef API_OUTGOING_CONNECTION_HOST
21static constexpr uint32_t OUTGOING_TARGET_PREF_HASH = 629847102UL;
24#ifndef API_OUTGOING_CONNECTION_HOST
27static bool peer_to_target(APIConnection *conn, SavedOutgoingTarget &target) {
31 if (conn->getpeername((
struct sockaddr *) &peer, &peer_len) != 0) {
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)) {
43 target.family = AF_INET;
44 memcpy(target.addr, bytes +
sizeof(prefix),
sizeof(
struct in_addr));
51 if (addr6->sin6_scope_id > UINT8_MAX) {
54 target.family = AF_INET6;
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);
64 target.family = AF_INET;
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) {
163 ESP_LOGV(TAG,
"Not dialing: %s",
164 addr_len == 0 ? LOG_STR_LITERAL(
"no target")
165 : (at_limit ? LOG_STR_LITERAL(
"max connections") : LOG_STR_LITERAL(
"no key")));
172 ESP_LOGW(TAG,
"Socket %s failed: errno %d",
173 this->
dial_socket_ ? LOG_STR_LITERAL(
"setblocking") : LOG_STR_LITERAL(
"create"), errno);
177#ifdef API_OUTGOING_CONNECTION_HOST
178 ESP_LOGD(TAG,
"Dialing " API_OUTGOING_CONNECTION_HOST
":%u", API_OUTGOING_CONNECTION_PORT);
180 char host[socket::SOCKADDR_STR_LEN];
182 ESP_LOGD(TAG,
"Dialing %s:%u", host, API_OUTGOING_CONNECTION_PORT);
190 if (errno != EINPROGRESS) {
191 ESP_LOGW(TAG,
"Connect failed: %d", errno);
201 ESP_LOGW(TAG,
"Connect timeout");
213 ESP_LOGW(TAG,
"Connect failed: %d", err);
250 if (was_authenticated) {
269#ifndef API_OUTGOING_CONNECTION_HOST
271 if (!peer_to_target(conn, target)) {
272 ESP_LOGW(TAG,
"Not remembering this target; its address cannot be dialed");
282 ESP_LOGW(TAG,
"Failed to save target");
285 char host[socket::SOCKADDR_STR_LEN];
287 ESP_LOGD(TAG,
"Remembered %s as the dial target", host);
295 " Outgoing connection port: %u\n"
296 " Outgoing connection boot delay: %" PRIu32
"ms",
300#ifdef API_OUTGOING_CONNECTION_HOST
301 ESP_LOGCONFIG(TAG,
" Outgoing connection host: " API_OUTGOING_CONNECTION_HOST);
303 char buf[socket::SOCKADDR_STR_LEN];
305 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.
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)
SavedOutgoingTarget saved_
static constexpr uint32_t BACKOFF_MAX_MS
static constexpr uint32_t BACKOFF_MIN_MS
static constexpr uint32_t IDLE_WAIT_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_ALWAYS_INLINE bool is_connected()
Return whether the node is connected to the network (through wifi, eth, ...)
std::vector< uint8_t > bytes
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)