29static const char *
const TAG = 
"esphome.ota";
 
   30static constexpr uint16_t OTA_BLOCK_SIZE = 8192;
 
   31static constexpr size_t OTA_BUFFER_SIZE = 1024;                  
 
   32static constexpr uint32_t OTA_SOCKET_TIMEOUT_HANDSHAKE = 20000;  
 
   33static constexpr uint32_t OTA_SOCKET_TIMEOUT_DATA = 90000;       
 
   35#ifdef USE_OTA_PASSWORD 
   37static constexpr size_t MD5_HEX_SIZE = 32;  
 
   40static constexpr size_t SHA256_HEX_SIZE = 64;  
 
   45#ifdef USE_OTA_STATE_CALLBACK 
   56  int err = this->
server_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, 
sizeof(
int));
 
   61  err = this->
server_->setblocking(
false);
 
 
   94                "Over-The-Air updates:\n" 
   98#ifdef USE_OTA_PASSWORD 
  100    ESP_LOGCONFIG(TAG, 
"  Password configured");
 
 
  115static const uint8_t FEATURE_SUPPORTS_COMPRESSION = 0x01;
 
  117static const uint8_t FEATURE_SUPPORTS_SHA256_AUTH = 0x02;
 
  124#define ALLOW_OTA_DOWNGRADE_MD5 
  133  if (this->
client_ == 
nullptr) {
 
  142    int err = this->
client_->setsockopt(IPPROTO_TCP, TCP_NODELAY, &enable, 
sizeof(
int));
 
  148    err = this->
client_->setblocking(
false);
 
  163    ESP_LOGW(TAG, 
"Handshake timeout");
 
  171      if (!this->
try_read_(5, LOG_STR(
"read magic"))) {
 
  176      static const uint8_t MAGIC_BYTES[5] = {0x6C, 0x26, 0xF7, 0x5C, 0x45};
 
  178        ESP_LOGW(TAG, 
"Magic bytes mismatch! 0x%02X-0x%02X-0x%02X-0x%02X-0x%02X", this->
handshake_buf_[0],
 
  193      if (!this->
try_write_(2, LOG_STR(
"ack magic"))) {
 
  204      if (!this->
try_read_(1, LOG_STR(
"read feature"))) {
 
  211          ((this->
ota_features_ & FEATURE_SUPPORTS_COMPRESSION) != 0 && this->
backend_->supports_compression())
 
  219      if (!this->
try_write_(1, LOG_STR(
"ack feature"))) {
 
  222#ifdef USE_OTA_PASSWORD 
  235#ifdef USE_OTA_PASSWORD 
 
  273  bool update_started = 
false;
 
  275  uint32_t last_progress = 0;
 
  276  uint8_t buf[OTA_BUFFER_SIZE];
 
  277  char *sbuf = 
reinterpret_cast<char *
>(buf);
 
  279#if USE_OTA_VERSION == 2 
  280  size_t size_acknowledged = 0;
 
  293  for (uint8_t i = 0; i < 4; i++) {
 
  297  ESP_LOGV(TAG, 
"Size is %u bytes", ota_size);
 
  305#ifdef USE_OTA_STATE_CALLBACK 
  310  error_code = this->
backend_->begin(ota_size);
 
  313  update_started = 
true;
 
  325  ESP_LOGV(TAG, 
"Update: Binary MD5 is %s", sbuf);
 
  326  this->
backend_->set_update_md5(sbuf);
 
  332  while (total < ota_size) {
 
  334    size_t remaining = ota_size - total;
 
  335    size_t requested = remaining < OTA_BUFFER_SIZE ? remaining : OTA_BUFFER_SIZE;
 
  342      ESP_LOGW(TAG, 
"Read err %d", errno);
 
  344    } 
else if (read == 0) {
 
  345      ESP_LOGW(TAG, 
"Remote closed");
 
  349    error_code = this->
backend_->write(buf, read);
 
  351      ESP_LOGW(TAG, 
"Flash write err %d", error_code);
 
  355#if USE_OTA_VERSION == 2 
  356    while (size_acknowledged + OTA_BLOCK_SIZE <= total || (total == ota_size && size_acknowledged < ota_size)) {
 
  359      size_acknowledged += OTA_BLOCK_SIZE;
 
  364    if (now - last_progress > 1000) {
 
  366      float percentage = (total * 100.0f) / ota_size;
 
  367      ESP_LOGD(TAG, 
"Progress: %0.1f%%", percentage);
 
  368#ifdef USE_OTA_STATE_CALLBACK 
  382    ESP_LOGW(TAG, 
"End update err %d", error_code);
 
  398  ESP_LOGI(TAG, 
"Update complete");
 
  400#ifdef USE_OTA_STATE_CALLBACK 
  407  buf[0] = 
static_cast<uint8_t
>(error_code);
 
  411  if (this->
backend_ != 
nullptr && update_started) {
 
  416#ifdef USE_OTA_STATE_CALLBACK 
 
  422  uint32_t start = 
millis();
 
  424  while (
len - at > 0) {
 
  426    if (now - start > OTA_SOCKET_TIMEOUT_DATA) {
 
  427      ESP_LOGW(TAG, 
"Timeout reading %d bytes", 
len);
 
  434        ESP_LOGW(TAG, 
"Read err %d bytes, errno %d", 
len, errno);
 
  437    } 
else if (read == 0) {
 
  438      ESP_LOGW(TAG, 
"Remote closed");
 
 
  449  uint32_t start = 
millis();
 
  451  while (
len - at > 0) {
 
  453    if (now - start > OTA_SOCKET_TIMEOUT_DATA) {
 
  454      ESP_LOGW(TAG, 
"Timeout writing %d bytes", 
len);
 
  461        ESP_LOGW(TAG, 
"Write err %d bytes, errno %d", 
len, errno);
 
 
  477  ESP_LOGW(TAG, 
"Socket %s: errno %d", LOG_STR_ARG(msg), errno);
 
 
  483  ESP_LOGD(TAG, 
"Starting %s from %s", LOG_STR_ARG(phase), this->
client_->getpeername().c_str());
 
 
  487  ESP_LOGW(TAG, 
"Remote closed at %s", LOG_STR_ARG(during));
 
 
  524  this->handshake_buf_pos_ += read;
 
  526  return this->handshake_buf_pos_ >= to_read;
 
 
  538  this->handshake_buf_pos_ += written;
 
  540  return this->handshake_buf_pos_ >= to_write;
 
 
  551#ifdef USE_OTA_PASSWORD 
 
  561#ifdef USE_OTA_PASSWORD 
  566  bool client_supports_sha256 = (this->
ota_features_ & FEATURE_SUPPORTS_SHA256_AUTH) != 0;
 
  568#ifdef ALLOW_OTA_DOWNGRADE_MD5 
  570  if (client_supports_sha256) {
 
  586  if (!client_supports_sha256) {
 
 
  644      hasher = &sha_hasher;
 
  649      hasher = &md5_hasher;
 
  653    const size_t hex_size = hasher->
get_size() * 2;
 
  654    const size_t nonce_len = hasher->
get_size() / 4;
 
  655    const size_t auth_buf_size = 1 + 3 * hex_size;
 
  656    this->
auth_buf_ = std::make_unique<uint8_t[]>(auth_buf_size);
 
  659    char *buf = 
reinterpret_cast<char *
>(this->
auth_buf_.get() + 1);
 
  660    if (!
random_bytes(
reinterpret_cast<uint8_t *
>(buf), nonce_len)) {
 
  667    hasher->
add(buf, nonce_len);
 
  672#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE 
  674    memcpy(log_buf, buf, hex_size);
 
  675    log_buf[hex_size] = 
'\0';
 
  676    ESP_LOGV(TAG, 
"Auth: Nonce is %s", log_buf);
 
  682  const size_t to_write = 1 + hex_size;
 
  690  this->auth_buf_pos_ += written;
 
  693  if (this->auth_buf_pos_ < to_write) {
 
  698  this->auth_buf_pos_ = 0;
 
 
  704  const size_t to_read = hex_size * 2;  
 
  708  size_t cnonce_offset = 1 + hex_size;  
 
  716  this->auth_buf_pos_ += read;
 
  719  if (this->auth_buf_pos_ < to_read) {
 
  724  const char *nonce = 
reinterpret_cast<char *
>(this->
auth_buf_.get() + 1);
 
  725  const char *cnonce = nonce + hex_size;
 
  726  const char *response = cnonce + hex_size;
 
  743    hasher = &sha_hasher;
 
  748    hasher = &md5_hasher;
 
  753  hasher->
add(this->
password_.c_str(), this->password_.length());
 
  754  hasher->
add(nonce, hex_size * 2);  
 
  757#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE 
  760  memcpy(log_buf, cnonce, hex_size);
 
  761  log_buf[hex_size] = 
'\0';
 
  762  ESP_LOGV(TAG, 
"Auth: CNonce is %s", log_buf);
 
  766  log_buf[hex_size] = 
'\0';
 
  767  ESP_LOGV(TAG, 
"Auth: Result is %s", log_buf);
 
  770  memcpy(log_buf, response, hex_size);
 
  771  log_buf[hex_size] = 
'\0';
 
  772  ESP_LOGV(TAG, 
"Auth: Response is %s", log_buf);
 
 
  793    return SHA256_HEX_SIZE;
 
  799#ifndef USE_OTA_SHA256 
  800#error "Either USE_OTA_MD5 or USE_OTA_SHA256 must be defined when USE_OTA_PASSWORD is enabled" 
 
void feed_wdt(uint32_t time=0)
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.
virtual void mark_failed()
Mark this component as failed.
void status_set_warning(const char *message=nullptr)
void status_momentary_error(const std::string &name, uint32_t length=5000)
void status_clear_warning()
bool would_block_(int error_code) const
std::unique_ptr< ota::OTABackend > backend_
uint8_t handshake_buf_pos_
uint16_t get_port() const
void yield_and_feed_watchdog_()
bool writeall_(const uint8_t *buf, size_t len)
bool try_read_(size_t to_read, const LogString *desc)
bool try_write_(size_t to_write, const LogString *desc)
void dump_config() override
std::unique_ptr< uint8_t[]> auth_buf_
bool handle_write_error_(ssize_t written, const LogString *desc)
uint8_t handshake_buf_[5]
void log_auth_warning_(const LogString *msg)
uint32_t client_connect_time_
float get_setup_priority() const override
void send_error_and_cleanup_(ota::OTAResponseTypes error)
bool handle_read_error_(ssize_t read, const LogString *desc)
void log_read_error_(const LogString *what)
bool readall_(uint8_t *buf, size_t len)
void set_port(uint16_t port)
Manually set the port OTA should listen on.
size_t get_auth_hex_size_() const
std::unique_ptr< socket::Socket > server_
void transition_ota_state_(OTAState next_state)
void cleanup_connection_()
void log_remote_closed_(const LogString *during)
std::unique_ptr< socket::Socket > client_
void log_start_(const LogString *phase)
void log_socket_error_(const LogString *msg)
Base class for hash algorithms.
void get_hex(char *output)
Retrieve the hash as hex characters.
bool equals_hex(const char *expected)
Compare the hash against a provided hex-encoded hash.
virtual void calculate()=0
Compute the hash based on provided data.
virtual void init()=0
Initialize a new hash computation.
virtual size_t get_size() const =0
Get the size of the hash in bytes (16 for MD5, 32 for SHA256)
virtual void add(const uint8_t *data, size_t len)=0
Add bytes of data for the hash.
StateCallbackManager state_callback_
std::string get_use_address()
Get the active network hostname.
void register_ota_platform(OTAComponent *ota_caller)
std::unique_ptr< ota::OTABackend > make_ota_backend()
@ OTA_RESPONSE_UPDATE_PREPARE_OK
@ OTA_RESPONSE_SUPPORTS_COMPRESSION
@ OTA_RESPONSE_BIN_MD5_OK
@ OTA_RESPONSE_UPDATE_END_OK
@ OTA_RESPONSE_RECEIVE_OK
@ OTA_RESPONSE_ERROR_AUTH_INVALID
@ OTA_RESPONSE_ERROR_UNKNOWN
@ OTA_RESPONSE_REQUEST_SHA256_AUTH
@ OTA_RESPONSE_ERROR_MAGIC
@ OTA_RESPONSE_REQUEST_AUTH
const float AFTER_WIFI
For components that should be initialized after WiFi is connected.
std::unique_ptr< Socket > socket_ip_loop_monitored(int type, int protocol)
socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port)
Set a sockaddr to the any address and specified port for the IP version used by socket_ip().
Providing packet encoding functions for exchanging data with a remote host.
bool random_bytes(uint8_t *data, size_t len)
Generate len number of random bytes.
void IRAM_ATTR HOT delay(uint32_t ms)
uint32_t IRAM_ATTR HOT millis()
Application App
Global storage of Application pointer - only one Application can exist.