2018-07-12 08:15:44 -04:00
|
|
|
// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <esp_https_ota.h>
|
|
|
|
#include <esp_log.h>
|
2019-10-14 16:56:21 -04:00
|
|
|
#include <esp_ota_ops.h>
|
2019-12-09 09:23:05 -05:00
|
|
|
#include <errno.h>
|
2020-11-16 23:48:35 -05:00
|
|
|
#include <sys/param.h>
|
2018-07-12 08:15:44 -04:00
|
|
|
|
2019-04-03 10:25:27 -04:00
|
|
|
#define IMAGE_HEADER_SIZE sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t) + 1
|
|
|
|
#define DEFAULT_OTA_BUF_SIZE IMAGE_HEADER_SIZE
|
2021-02-02 02:55:40 -05:00
|
|
|
#define DEFAULT_REQUEST_SIZE (64 * 1024)
|
2018-07-12 08:15:44 -04:00
|
|
|
static const char *TAG = "esp_https_ota";
|
|
|
|
|
2019-04-03 10:25:27 -04:00
|
|
|
typedef enum {
|
|
|
|
ESP_HTTPS_OTA_INIT,
|
|
|
|
ESP_HTTPS_OTA_BEGIN,
|
|
|
|
ESP_HTTPS_OTA_IN_PROGRESS,
|
|
|
|
ESP_HTTPS_OTA_SUCCESS,
|
|
|
|
} esp_https_ota_state;
|
|
|
|
|
|
|
|
struct esp_https_ota_handle {
|
|
|
|
esp_ota_handle_t update_handle;
|
|
|
|
const esp_partition_t *update_partition;
|
|
|
|
esp_http_client_handle_t http_client;
|
|
|
|
char *ota_upgrade_buf;
|
|
|
|
size_t ota_upgrade_buf_size;
|
|
|
|
int binary_file_len;
|
2021-02-02 02:55:40 -05:00
|
|
|
int image_length;
|
|
|
|
int max_http_request_size;
|
2019-04-03 10:25:27 -04:00
|
|
|
esp_https_ota_state state;
|
2020-07-21 08:53:28 -04:00
|
|
|
bool bulk_flash_erase;
|
2021-02-02 02:55:40 -05:00
|
|
|
bool partial_http_download;
|
2019-04-03 10:25:27 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct esp_https_ota_handle esp_https_ota_t;
|
|
|
|
|
|
|
|
static bool process_again(int status_code)
|
|
|
|
{
|
|
|
|
switch (status_code) {
|
|
|
|
case HttpStatus_MovedPermanently:
|
|
|
|
case HttpStatus_Found:
|
2019-11-28 22:17:51 -05:00
|
|
|
case HttpStatus_TemporaryRedirect:
|
2019-04-03 10:25:27 -04:00
|
|
|
case HttpStatus_Unauthorized:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static esp_err_t _http_handle_response_code(esp_http_client_handle_t http_client, int status_code)
|
|
|
|
{
|
|
|
|
esp_err_t err;
|
2019-11-28 22:17:51 -05:00
|
|
|
if (status_code == HttpStatus_MovedPermanently || status_code == HttpStatus_Found || status_code == HttpStatus_TemporaryRedirect) {
|
2019-04-03 10:25:27 -04:00
|
|
|
err = esp_http_client_set_redirection(http_client);
|
|
|
|
if (err != ESP_OK) {
|
|
|
|
ESP_LOGE(TAG, "URL redirection Failed");
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
} else if (status_code == HttpStatus_Unauthorized) {
|
|
|
|
esp_http_client_add_auth(http_client);
|
2020-07-06 02:01:57 -04:00
|
|
|
} else if(status_code == HttpStatus_NotFound || status_code == HttpStatus_Forbidden) {
|
|
|
|
ESP_LOGE(TAG, "File not found(%d)", status_code);
|
|
|
|
return ESP_FAIL;
|
2021-05-24 02:11:50 -04:00
|
|
|
} else if (status_code >= HttpStatus_BadRequest && status_code < HttpStatus_InternalError) {
|
|
|
|
ESP_LOGE(TAG, "Client error (%d)", status_code);
|
|
|
|
return ESP_FAIL;
|
|
|
|
} else if (status_code >= HttpStatus_InternalError) {
|
|
|
|
ESP_LOGE(TAG, "Server error (%d)", status_code);
|
2020-07-06 02:01:57 -04:00
|
|
|
return ESP_FAIL;
|
2019-04-03 10:25:27 -04:00
|
|
|
}
|
2020-11-10 02:40:01 -05:00
|
|
|
|
2019-04-03 10:25:27 -04:00
|
|
|
char upgrade_data_buf[DEFAULT_OTA_BUF_SIZE];
|
2020-02-13 03:13:58 -05:00
|
|
|
// process_again() returns true only in case of redirection.
|
2019-04-03 10:25:27 -04:00
|
|
|
if (process_again(status_code)) {
|
2020-02-13 03:13:58 -05:00
|
|
|
while (1) {
|
2019-12-09 09:23:05 -05:00
|
|
|
/*
|
2020-02-13 03:13:58 -05:00
|
|
|
* In case of redirection, esp_http_client_read() is called
|
|
|
|
* to clear the response buffer of http_client.
|
2019-12-09 09:23:05 -05:00
|
|
|
*/
|
2020-02-13 03:13:58 -05:00
|
|
|
int data_read = esp_http_client_read(http_client, upgrade_data_buf, DEFAULT_OTA_BUF_SIZE);
|
2020-03-30 02:22:38 -04:00
|
|
|
if (data_read <= 0) {
|
2020-02-13 03:13:58 -05:00
|
|
|
return ESP_OK;
|
2019-04-03 10:25:27 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static esp_err_t _http_connect(esp_http_client_handle_t http_client)
|
|
|
|
{
|
|
|
|
esp_err_t err = ESP_FAIL;
|
2019-08-15 09:10:00 -04:00
|
|
|
int status_code, header_ret;
|
2019-04-03 10:25:27 -04:00
|
|
|
do {
|
2021-02-10 00:32:13 -05:00
|
|
|
char *post_data = NULL;
|
|
|
|
/* Send POST request if body is set.
|
|
|
|
* Note: Sending POST request is not supported if partial_http_download
|
|
|
|
* is enabled
|
|
|
|
*/
|
|
|
|
int post_len = esp_http_client_get_post_field(http_client, &post_data);
|
|
|
|
err = esp_http_client_open(http_client, post_len);
|
2019-04-03 10:25:27 -04:00
|
|
|
if (err != ESP_OK) {
|
|
|
|
ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
|
|
|
|
return err;
|
|
|
|
}
|
2021-02-10 00:32:13 -05:00
|
|
|
if (post_len) {
|
|
|
|
int write_len = 0;
|
|
|
|
while (post_len > 0) {
|
|
|
|
write_len = esp_http_client_write(http_client, post_data, post_len);
|
|
|
|
if (write_len < 0) {
|
|
|
|
ESP_LOGE(TAG, "Write failed");
|
|
|
|
return ESP_FAIL;
|
|
|
|
}
|
2021-04-08 08:04:57 -04:00
|
|
|
post_len -= write_len;
|
|
|
|
post_data += write_len;
|
2021-02-10 00:32:13 -05:00
|
|
|
}
|
|
|
|
}
|
2019-08-15 09:10:00 -04:00
|
|
|
header_ret = esp_http_client_fetch_headers(http_client);
|
|
|
|
if (header_ret < 0) {
|
|
|
|
return header_ret;
|
|
|
|
}
|
2019-04-03 10:25:27 -04:00
|
|
|
status_code = esp_http_client_get_status_code(http_client);
|
2019-08-15 09:10:00 -04:00
|
|
|
err = _http_handle_response_code(http_client, status_code);
|
|
|
|
if (err != ESP_OK) {
|
|
|
|
return err;
|
2019-04-03 10:25:27 -04:00
|
|
|
}
|
|
|
|
} while (process_again(status_code));
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _http_cleanup(esp_http_client_handle_t client)
|
2018-07-12 08:15:44 -04:00
|
|
|
{
|
|
|
|
esp_http_client_close(client);
|
|
|
|
esp_http_client_cleanup(client);
|
|
|
|
}
|
|
|
|
|
2019-04-03 10:25:27 -04:00
|
|
|
static esp_err_t _ota_write(esp_https_ota_t *https_ota_handle, const void *buffer, size_t buf_len)
|
2018-07-12 08:15:44 -04:00
|
|
|
{
|
2019-04-03 10:25:27 -04:00
|
|
|
if (buffer == NULL || https_ota_handle == NULL) {
|
|
|
|
return ESP_FAIL;
|
|
|
|
}
|
|
|
|
esp_err_t err = esp_ota_write(https_ota_handle->update_handle, buffer, buf_len);
|
|
|
|
if (err != ESP_OK) {
|
2020-10-12 07:46:15 -04:00
|
|
|
ESP_LOGE(TAG, "Error: esp_ota_write failed! err=0x%x", err);
|
2019-04-03 10:25:27 -04:00
|
|
|
} else {
|
|
|
|
https_ota_handle->binary_file_len += buf_len;
|
|
|
|
ESP_LOGD(TAG, "Written image length %d", https_ota_handle->binary_file_len);
|
|
|
|
err = ESP_ERR_HTTPS_OTA_IN_PROGRESS;
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2021-04-08 06:06:24 -04:00
|
|
|
static bool is_server_verification_enabled(esp_https_ota_config_t *ota_config) {
|
|
|
|
return (ota_config->http_config->cert_pem
|
|
|
|
|| ota_config->http_config->use_global_ca_store
|
2021-04-15 20:33:59 -04:00
|
|
|
|| ota_config->http_config->crt_bundle_attach != NULL);
|
2021-04-08 06:06:24 -04:00
|
|
|
}
|
|
|
|
|
2019-04-03 10:25:27 -04:00
|
|
|
esp_err_t esp_https_ota_begin(esp_https_ota_config_t *ota_config, esp_https_ota_handle_t *handle)
|
|
|
|
{
|
|
|
|
esp_err_t err;
|
2019-05-21 13:42:18 -04:00
|
|
|
|
2019-04-03 10:25:27 -04:00
|
|
|
if (handle == NULL || ota_config == NULL || ota_config->http_config == NULL) {
|
|
|
|
ESP_LOGE(TAG, "esp_https_ota_begin: Invalid argument");
|
2019-05-21 13:42:18 -04:00
|
|
|
if (handle) {
|
|
|
|
*handle = NULL;
|
|
|
|
}
|
2018-07-12 08:15:44 -04:00
|
|
|
return ESP_ERR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
2021-04-08 06:06:24 -04:00
|
|
|
if (!is_server_verification_enabled(ota_config)) {
|
2021-04-19 09:56:10 -04:00
|
|
|
#if CONFIG_OTA_ALLOW_HTTP
|
|
|
|
ESP_LOGW(TAG, "Continuing with insecure option because CONFIG_OTA_ALLOW_HTTP is set.");
|
|
|
|
#else
|
2021-04-08 06:06:24 -04:00
|
|
|
ESP_LOGE(TAG, "No option for server verification is enabled in esp_http_client config.");
|
2019-05-21 13:42:18 -04:00
|
|
|
*handle = NULL;
|
2018-12-31 04:02:35 -05:00
|
|
|
return ESP_ERR_INVALID_ARG;
|
|
|
|
#endif
|
2021-04-19 09:56:10 -04:00
|
|
|
}
|
2018-07-12 08:15:44 -04:00
|
|
|
|
2019-04-03 10:25:27 -04:00
|
|
|
esp_https_ota_t *https_ota_handle = calloc(1, sizeof(esp_https_ota_t));
|
|
|
|
if (!https_ota_handle) {
|
|
|
|
ESP_LOGE(TAG, "Couldn't allocate memory to upgrade data buffer");
|
2019-05-21 13:42:18 -04:00
|
|
|
*handle = NULL;
|
2019-04-03 10:25:27 -04:00
|
|
|
return ESP_ERR_NO_MEM;
|
2018-07-12 08:15:44 -04:00
|
|
|
}
|
2020-11-10 02:40:01 -05:00
|
|
|
|
2021-02-02 02:55:40 -05:00
|
|
|
https_ota_handle->partial_http_download = ota_config->partial_http_download;
|
|
|
|
https_ota_handle->max_http_request_size = (ota_config->max_http_request_size == 0) ? DEFAULT_REQUEST_SIZE : ota_config->max_http_request_size;
|
|
|
|
|
2019-04-03 10:25:27 -04:00
|
|
|
/* Initiate HTTP Connection */
|
|
|
|
https_ota_handle->http_client = esp_http_client_init(ota_config->http_config);
|
|
|
|
if (https_ota_handle->http_client == NULL) {
|
|
|
|
ESP_LOGE(TAG, "Failed to initialise HTTP connection");
|
|
|
|
err = ESP_FAIL;
|
|
|
|
goto failure;
|
2018-07-12 08:15:44 -04:00
|
|
|
}
|
|
|
|
|
2021-02-02 02:55:40 -05:00
|
|
|
if (https_ota_handle->partial_http_download) {
|
|
|
|
esp_http_client_set_method(https_ota_handle->http_client, HTTP_METHOD_HEAD);
|
|
|
|
err = esp_http_client_perform(https_ota_handle->http_client);
|
|
|
|
if (err != ESP_OK || esp_http_client_get_status_code(https_ota_handle->http_client) != HttpStatus_Ok) {
|
|
|
|
ESP_LOGE(TAG, "Failed to get image length");
|
|
|
|
goto http_cleanup;
|
|
|
|
}
|
|
|
|
https_ota_handle->image_length = esp_http_client_get_content_length(https_ota_handle->http_client);
|
|
|
|
esp_http_client_close(https_ota_handle->http_client);
|
|
|
|
|
|
|
|
if (https_ota_handle->image_length > https_ota_handle->max_http_request_size) {
|
|
|
|
char *header_val = NULL;
|
|
|
|
asprintf(&header_val, "bytes=0-%d", https_ota_handle->max_http_request_size - 1);
|
|
|
|
if (header_val == NULL) {
|
|
|
|
ESP_LOGE(TAG, "Failed to allocate memory for HTTP header");
|
|
|
|
err = ESP_ERR_NO_MEM;
|
|
|
|
goto http_cleanup;
|
|
|
|
}
|
|
|
|
esp_http_client_set_header(https_ota_handle->http_client, "Range", header_val);
|
|
|
|
free(header_val);
|
|
|
|
}
|
|
|
|
esp_http_client_set_method(https_ota_handle->http_client, HTTP_METHOD_GET);
|
|
|
|
}
|
|
|
|
|
2020-08-21 03:10:56 -04:00
|
|
|
if (ota_config->http_client_init_cb) {
|
|
|
|
err = ota_config->http_client_init_cb(https_ota_handle->http_client);
|
|
|
|
if (err != ESP_OK) {
|
2020-10-12 07:46:15 -04:00
|
|
|
ESP_LOGE(TAG, "http_client_init_cb returned 0x%x", err);
|
2020-08-21 03:10:56 -04:00
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-03 10:25:27 -04:00
|
|
|
err = _http_connect(https_ota_handle->http_client);
|
2018-07-12 08:15:44 -04:00
|
|
|
if (err != ESP_OK) {
|
2019-04-03 10:25:27 -04:00
|
|
|
ESP_LOGE(TAG, "Failed to establish HTTP connection");
|
|
|
|
goto http_cleanup;
|
2018-07-12 08:15:44 -04:00
|
|
|
}
|
|
|
|
|
2021-04-15 11:24:17 -04:00
|
|
|
if (!https_ota_handle->partial_http_download) {
|
|
|
|
https_ota_handle->image_length = esp_http_client_get_content_length(https_ota_handle->http_client);
|
|
|
|
}
|
|
|
|
|
2019-04-03 10:25:27 -04:00
|
|
|
https_ota_handle->update_partition = NULL;
|
2018-07-12 08:15:44 -04:00
|
|
|
ESP_LOGI(TAG, "Starting OTA...");
|
2019-04-03 10:25:27 -04:00
|
|
|
https_ota_handle->update_partition = esp_ota_get_next_update_partition(NULL);
|
|
|
|
if (https_ota_handle->update_partition == NULL) {
|
2018-07-12 08:15:44 -04:00
|
|
|
ESP_LOGE(TAG, "Passive OTA partition not found");
|
2019-04-03 10:25:27 -04:00
|
|
|
err = ESP_FAIL;
|
|
|
|
goto http_cleanup;
|
2018-07-12 08:15:44 -04:00
|
|
|
}
|
|
|
|
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x",
|
2019-04-03 10:25:27 -04:00
|
|
|
https_ota_handle->update_partition->subtype, https_ota_handle->update_partition->address);
|
2018-07-12 08:15:44 -04:00
|
|
|
|
2020-11-16 23:48:35 -05:00
|
|
|
const int alloc_size = MAX(ota_config->http_config->buffer_size, DEFAULT_OTA_BUF_SIZE);
|
2019-04-03 10:25:27 -04:00
|
|
|
https_ota_handle->ota_upgrade_buf = (char *)malloc(alloc_size);
|
|
|
|
if (!https_ota_handle->ota_upgrade_buf) {
|
|
|
|
ESP_LOGE(TAG, "Couldn't allocate memory to upgrade data buffer");
|
|
|
|
err = ESP_ERR_NO_MEM;
|
|
|
|
goto http_cleanup;
|
2018-07-12 08:15:44 -04:00
|
|
|
}
|
2019-04-03 10:25:27 -04:00
|
|
|
https_ota_handle->ota_upgrade_buf_size = alloc_size;
|
2020-07-21 08:53:28 -04:00
|
|
|
https_ota_handle->bulk_flash_erase = ota_config->bulk_flash_erase;
|
2019-04-03 10:25:27 -04:00
|
|
|
https_ota_handle->binary_file_len = 0;
|
|
|
|
*handle = (esp_https_ota_handle_t)https_ota_handle;
|
|
|
|
https_ota_handle->state = ESP_HTTPS_OTA_BEGIN;
|
|
|
|
return ESP_OK;
|
|
|
|
|
|
|
|
http_cleanup:
|
|
|
|
_http_cleanup(https_ota_handle->http_client);
|
|
|
|
failure:
|
|
|
|
free(https_ota_handle);
|
2019-05-21 13:42:18 -04:00
|
|
|
*handle = NULL;
|
2019-04-03 10:25:27 -04:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
esp_err_t esp_https_ota_get_img_desc(esp_https_ota_handle_t https_ota_handle, esp_app_desc_t *new_app_info)
|
|
|
|
{
|
|
|
|
esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
|
|
|
|
if (handle == NULL || new_app_info == NULL) {
|
|
|
|
ESP_LOGE(TAG, "esp_https_ota_read_img_desc: Invalid argument");
|
|
|
|
return ESP_ERR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
if (handle->state < ESP_HTTPS_OTA_BEGIN) {
|
|
|
|
ESP_LOGE(TAG, "esp_https_ota_read_img_desc: Invalid state");
|
|
|
|
return ESP_FAIL;
|
|
|
|
}
|
2019-12-09 09:23:05 -05:00
|
|
|
/*
|
|
|
|
* `data_read_size` holds number of bytes needed to read complete header.
|
|
|
|
* `bytes_read` holds number of bytes read.
|
|
|
|
*/
|
2019-04-03 10:25:27 -04:00
|
|
|
int data_read_size = IMAGE_HEADER_SIZE;
|
2019-12-09 09:23:05 -05:00
|
|
|
int data_read = 0, bytes_read = 0;
|
|
|
|
/*
|
|
|
|
* while loop is added to download complete image headers, even if the headers
|
|
|
|
* are not sent in a single packet.
|
|
|
|
*/
|
2021-02-02 02:55:40 -05:00
|
|
|
while (data_read_size > 0 && !esp_http_client_is_complete_data_received(handle->http_client)) {
|
2019-12-09 09:23:05 -05:00
|
|
|
data_read = esp_http_client_read(handle->http_client,
|
|
|
|
(handle->ota_upgrade_buf + bytes_read),
|
|
|
|
data_read_size);
|
|
|
|
/*
|
2020-03-30 02:22:38 -04:00
|
|
|
* As esp_http_client_read doesn't return negative error code if select fails, we rely on
|
2019-12-09 09:23:05 -05:00
|
|
|
* `errno` to check for underlying transport connectivity closure if any
|
|
|
|
*/
|
2020-03-30 02:22:38 -04:00
|
|
|
if (errno == ENOTCONN || errno == ECONNRESET || errno == ECONNABORTED || data_read < 0) {
|
2019-12-09 09:23:05 -05:00
|
|
|
ESP_LOGE(TAG, "Connection closed, errno = %d", errno);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
data_read_size -= data_read;
|
|
|
|
bytes_read += data_read;
|
2019-04-03 10:25:27 -04:00
|
|
|
}
|
2019-12-09 09:23:05 -05:00
|
|
|
if (data_read_size > 0) {
|
|
|
|
ESP_LOGE(TAG, "Complete headers were not received");
|
2019-04-03 10:25:27 -04:00
|
|
|
return ESP_FAIL;
|
2018-07-12 08:15:44 -04:00
|
|
|
}
|
2019-12-09 09:23:05 -05:00
|
|
|
handle->binary_file_len = bytes_read;
|
|
|
|
memcpy(new_app_info, &handle->ota_upgrade_buf[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t));
|
2020-11-10 02:40:01 -05:00
|
|
|
return ESP_OK;
|
2019-04-03 10:25:27 -04:00
|
|
|
}
|
2019-01-30 03:54:20 -05:00
|
|
|
|
2019-04-03 10:25:27 -04:00
|
|
|
esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle)
|
|
|
|
{
|
|
|
|
esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
|
|
|
|
if (handle == NULL) {
|
|
|
|
ESP_LOGE(TAG, "esp_https_ota_perform: Invalid argument");
|
|
|
|
return ESP_ERR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
if (handle->state < ESP_HTTPS_OTA_BEGIN) {
|
|
|
|
ESP_LOGE(TAG, "esp_https_ota_perform: Invalid state");
|
|
|
|
return ESP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
esp_err_t err;
|
|
|
|
int data_read;
|
2020-07-21 08:53:28 -04:00
|
|
|
const int erase_size = handle->bulk_flash_erase ? OTA_SIZE_UNKNOWN : OTA_WITH_SEQUENTIAL_WRITES;
|
2019-04-03 10:25:27 -04:00
|
|
|
switch (handle->state) {
|
|
|
|
case ESP_HTTPS_OTA_BEGIN:
|
2020-07-21 08:53:28 -04:00
|
|
|
err = esp_ota_begin(handle->update_partition, erase_size, &handle->update_handle);
|
2019-04-03 10:25:27 -04:00
|
|
|
if (err != ESP_OK) {
|
|
|
|
ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
handle->state = ESP_HTTPS_OTA_IN_PROGRESS;
|
|
|
|
/* In case `esp_https_ota_read_img_desc` was invoked first,
|
|
|
|
then the image data read there should be written to OTA partition
|
|
|
|
*/
|
|
|
|
if (handle->binary_file_len) {
|
2021-02-02 02:55:40 -05:00
|
|
|
/*
|
|
|
|
* Header length gets added to handle->binary_file_len in _ota_write
|
|
|
|
* Clear handle->binary_file_len to avoid additional 289 bytes in binary_file_len
|
|
|
|
*/
|
|
|
|
int binary_file_len = handle->binary_file_len;
|
|
|
|
handle->binary_file_len = 0;
|
|
|
|
return _ota_write(handle, (const void *)handle->ota_upgrade_buf, binary_file_len);
|
2019-04-03 10:25:27 -04:00
|
|
|
}
|
|
|
|
/* falls through */
|
|
|
|
case ESP_HTTPS_OTA_IN_PROGRESS:
|
|
|
|
data_read = esp_http_client_read(handle->http_client,
|
|
|
|
handle->ota_upgrade_buf,
|
|
|
|
handle->ota_upgrade_buf_size);
|
|
|
|
if (data_read == 0) {
|
2020-01-27 07:03:36 -05:00
|
|
|
/*
|
2021-02-02 02:55:40 -05:00
|
|
|
* esp_http_client_is_complete_data_received is added to check whether
|
2020-01-27 07:03:36 -05:00
|
|
|
* complete image is received.
|
|
|
|
*/
|
2021-02-02 02:55:40 -05:00
|
|
|
bool is_recv_complete = esp_http_client_is_complete_data_received(handle->http_client);
|
2019-12-09 09:23:05 -05:00
|
|
|
/*
|
2020-03-30 02:22:38 -04:00
|
|
|
* As esp_http_client_read doesn't return negative error code if select fails, we rely on
|
2020-01-27 07:03:36 -05:00
|
|
|
* `errno` to check for underlying transport connectivity closure if any.
|
|
|
|
* Incase the complete data has not been received but the server has sent
|
|
|
|
* an ENOTCONN or ECONNRESET, failure is returned. We close with success
|
|
|
|
* if complete data has been received.
|
2019-12-09 09:23:05 -05:00
|
|
|
*/
|
2020-02-19 05:53:56 -05:00
|
|
|
if ((errno == ENOTCONN || errno == ECONNRESET || errno == ECONNABORTED) && !is_recv_complete) {
|
2019-12-09 09:23:05 -05:00
|
|
|
ESP_LOGE(TAG, "Connection closed, errno = %d", errno);
|
|
|
|
return ESP_FAIL;
|
2020-01-27 07:03:36 -05:00
|
|
|
} else if (!is_recv_complete) {
|
2019-12-09 09:23:05 -05:00
|
|
|
return ESP_ERR_HTTPS_OTA_IN_PROGRESS;
|
|
|
|
}
|
2021-08-06 00:55:00 -04:00
|
|
|
ESP_LOGD(TAG, "Connection closed");
|
2019-04-03 10:25:27 -04:00
|
|
|
} else if (data_read > 0) {
|
|
|
|
return _ota_write(handle, (const void *)handle->ota_upgrade_buf, data_read);
|
2020-03-30 02:22:38 -04:00
|
|
|
} else {
|
|
|
|
return ESP_FAIL;
|
2019-04-03 10:25:27 -04:00
|
|
|
}
|
2021-02-02 02:55:40 -05:00
|
|
|
if (!handle->partial_http_download || (handle->partial_http_download && handle->image_length == handle->binary_file_len)) {
|
|
|
|
handle->state = ESP_HTTPS_OTA_SUCCESS;
|
|
|
|
}
|
2018-07-12 08:15:44 -04:00
|
|
|
break;
|
2019-04-03 10:25:27 -04:00
|
|
|
default:
|
|
|
|
ESP_LOGE(TAG, "Invalid ESP HTTPS OTA State");
|
|
|
|
return ESP_FAIL;
|
2018-07-12 08:15:44 -04:00
|
|
|
break;
|
2019-04-03 10:25:27 -04:00
|
|
|
}
|
2021-02-02 02:55:40 -05:00
|
|
|
if (handle->partial_http_download) {
|
|
|
|
if (handle->state == ESP_HTTPS_OTA_IN_PROGRESS && handle->image_length > handle->binary_file_len) {
|
|
|
|
esp_http_client_close(handle->http_client);
|
|
|
|
char *header_val = NULL;
|
|
|
|
if ((handle->image_length - handle->binary_file_len) > handle->max_http_request_size) {
|
|
|
|
asprintf(&header_val, "bytes=%d-%d", handle->binary_file_len, (handle->binary_file_len + handle->max_http_request_size - 1));
|
|
|
|
} else {
|
|
|
|
asprintf(&header_val, "bytes=%d-", handle->binary_file_len);
|
|
|
|
}
|
|
|
|
if (header_val == NULL) {
|
|
|
|
ESP_LOGE(TAG, "Failed to allocate memory for HTTP header");
|
|
|
|
return ESP_ERR_NO_MEM;
|
|
|
|
}
|
|
|
|
esp_http_client_set_header(handle->http_client, "Range", header_val);
|
|
|
|
free(header_val);
|
|
|
|
err = _http_connect(handle->http_client);
|
|
|
|
if (err != ESP_OK) {
|
|
|
|
ESP_LOGE(TAG, "Failed to establish HTTP connection");
|
|
|
|
return ESP_FAIL;
|
|
|
|
}
|
2021-08-06 00:55:00 -04:00
|
|
|
ESP_LOGD(TAG, "Connection start");
|
2021-02-02 02:55:40 -05:00
|
|
|
return ESP_ERR_HTTPS_OTA_IN_PROGRESS;
|
|
|
|
}
|
|
|
|
}
|
2019-04-03 10:25:27 -04:00
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
|
2019-08-15 09:10:00 -04:00
|
|
|
bool esp_https_ota_is_complete_data_received(esp_https_ota_handle_t https_ota_handle)
|
|
|
|
{
|
2021-02-02 02:55:40 -05:00
|
|
|
bool ret = false;
|
2019-08-15 09:10:00 -04:00
|
|
|
esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
|
2021-02-02 02:55:40 -05:00
|
|
|
if (handle->partial_http_download) {
|
|
|
|
ret = (handle->image_length == handle->binary_file_len);
|
|
|
|
} else {
|
|
|
|
ret = esp_http_client_is_complete_data_received(handle->http_client);
|
|
|
|
}
|
|
|
|
return ret;
|
2019-08-15 09:10:00 -04:00
|
|
|
}
|
|
|
|
|
2019-04-03 10:25:27 -04:00
|
|
|
esp_err_t esp_https_ota_finish(esp_https_ota_handle_t https_ota_handle)
|
|
|
|
{
|
|
|
|
esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
|
|
|
|
if (handle == NULL) {
|
|
|
|
return ESP_ERR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
if (handle->state < ESP_HTTPS_OTA_BEGIN) {
|
|
|
|
return ESP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
esp_err_t err = ESP_OK;
|
|
|
|
switch (handle->state) {
|
|
|
|
case ESP_HTTPS_OTA_SUCCESS:
|
|
|
|
case ESP_HTTPS_OTA_IN_PROGRESS:
|
|
|
|
err = esp_ota_end(handle->update_handle);
|
|
|
|
/* falls through */
|
|
|
|
case ESP_HTTPS_OTA_BEGIN:
|
2019-05-21 13:42:18 -04:00
|
|
|
if (handle->ota_upgrade_buf) {
|
|
|
|
free(handle->ota_upgrade_buf);
|
|
|
|
}
|
|
|
|
if (handle->http_client) {
|
|
|
|
_http_cleanup(handle->http_client);
|
|
|
|
}
|
2019-04-03 10:25:27 -04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ESP_LOGE(TAG, "Invalid ESP HTTPS OTA State");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((err == ESP_OK) && (handle->state == ESP_HTTPS_OTA_SUCCESS)) {
|
|
|
|
esp_err_t err = esp_ota_set_boot_partition(handle->update_partition);
|
|
|
|
if (err != ESP_OK) {
|
2020-10-12 07:46:15 -04:00
|
|
|
ESP_LOGE(TAG, "esp_ota_set_boot_partition failed! err=0x%x", err);
|
2018-07-12 08:15:44 -04:00
|
|
|
}
|
|
|
|
}
|
2019-05-21 13:42:18 -04:00
|
|
|
free(handle);
|
2019-04-03 10:25:27 -04:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-08-14 06:24:15 -04:00
|
|
|
esp_err_t esp_https_ota_abort(esp_https_ota_handle_t https_ota_handle)
|
|
|
|
{
|
|
|
|
esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
|
|
|
|
if (handle == NULL) {
|
|
|
|
return ESP_ERR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (handle->state < ESP_HTTPS_OTA_BEGIN) {
|
|
|
|
return ESP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
esp_err_t err = ESP_OK;
|
|
|
|
switch (handle->state) {
|
|
|
|
case ESP_HTTPS_OTA_SUCCESS:
|
|
|
|
case ESP_HTTPS_OTA_IN_PROGRESS:
|
|
|
|
err = esp_ota_abort(handle->update_handle);
|
|
|
|
/* falls through */
|
|
|
|
case ESP_HTTPS_OTA_BEGIN:
|
|
|
|
if (handle->ota_upgrade_buf) {
|
|
|
|
free(handle->ota_upgrade_buf);
|
|
|
|
}
|
|
|
|
if (handle->http_client) {
|
|
|
|
_http_cleanup(handle->http_client);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
err = ESP_ERR_INVALID_STATE;
|
|
|
|
ESP_LOGE(TAG, "Invalid ESP HTTPS OTA State");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
free(handle);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2019-04-03 10:25:27 -04:00
|
|
|
int esp_https_ota_get_image_len_read(esp_https_ota_handle_t https_ota_handle)
|
|
|
|
{
|
|
|
|
esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
|
|
|
|
if (handle == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (handle->state < ESP_HTTPS_OTA_IN_PROGRESS) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return handle->binary_file_len;
|
|
|
|
}
|
|
|
|
|
2021-04-15 11:24:17 -04:00
|
|
|
int esp_https_ota_get_image_size(esp_https_ota_handle_t https_ota_handle)
|
|
|
|
{
|
|
|
|
esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
|
|
|
|
if (handle == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (handle->state < ESP_HTTPS_OTA_BEGIN) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return handle->image_length;
|
|
|
|
}
|
|
|
|
|
2019-04-03 10:25:27 -04:00
|
|
|
esp_err_t esp_https_ota(const esp_http_client_config_t *config)
|
|
|
|
{
|
|
|
|
if (!config) {
|
|
|
|
ESP_LOGE(TAG, "esp_http_client config not found");
|
|
|
|
return ESP_ERR_INVALID_ARG;
|
2020-11-10 02:40:01 -05:00
|
|
|
}
|
2019-04-03 10:25:27 -04:00
|
|
|
|
|
|
|
esp_https_ota_config_t ota_config = {
|
|
|
|
.http_config = config,
|
|
|
|
};
|
|
|
|
|
|
|
|
esp_https_ota_handle_t https_ota_handle = NULL;
|
|
|
|
esp_err_t err = esp_https_ota_begin(&ota_config, &https_ota_handle);
|
|
|
|
if (https_ota_handle == NULL) {
|
|
|
|
return ESP_FAIL;
|
2018-07-12 08:15:44 -04:00
|
|
|
}
|
|
|
|
|
2019-04-03 10:25:27 -04:00
|
|
|
while (1) {
|
|
|
|
err = esp_https_ota_perform(https_ota_handle);
|
|
|
|
if (err != ESP_ERR_HTTPS_OTA_IN_PROGRESS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-12 08:15:44 -04:00
|
|
|
if (err != ESP_OK) {
|
2020-08-14 06:24:15 -04:00
|
|
|
esp_https_ota_abort(https_ota_handle);
|
2018-07-12 08:15:44 -04:00
|
|
|
return err;
|
2020-08-14 06:24:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
esp_err_t ota_finish_err = esp_https_ota_finish(https_ota_handle);
|
|
|
|
if (ota_finish_err != ESP_OK) {
|
2019-04-03 10:25:27 -04:00
|
|
|
return ota_finish_err;
|
2018-07-12 08:15:44 -04:00
|
|
|
}
|
|
|
|
return ESP_OK;
|
2019-08-15 09:10:00 -04:00
|
|
|
}
|