2022-01-07 08:10:08 -05:00
/*
* SPDX - FileCopyrightText : 2017 - 2022 Espressif Systems ( Shanghai ) CO LTD
*
* SPDX - License - Identifier : Apache - 2.0
*/
2018-07-12 08:15:44 -04:00
# 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
2022-01-28 05:59:29 -05:00
# define IMAGE_HEADER_SIZE (1024)
/* This is kept sufficiently large enough to cover image format headers
* and also this defines default minimum OTA buffer chunk size */
# define DEFAULT_OTA_BUF_SIZE (IMAGE_HEADER_SIZE)
_Static_assert ( DEFAULT_OTA_BUF_SIZE > ( sizeof ( esp_image_header_t ) + sizeof ( esp_image_segment_header_t ) + sizeof ( esp_app_desc_t ) + 1 ) , " OTA data buffer too small " ) ;
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 ;
2022-01-28 06:10:06 -05:00
# if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
decrypt_cb_t decrypt_cb ;
2022-03-10 07:02:42 -05:00
void * decrypt_user_ctx ;
2022-01-28 06:10:06 -05:00
# endif
2019-04-03 10:25:27 -04:00
} ;
typedef struct esp_https_ota_handle esp_https_ota_t ;
2022-03-17 04:20:30 -04:00
static bool redirection_required ( int status_code )
{
switch ( status_code ) {
case HttpStatus_MovedPermanently :
case HttpStatus_Found :
case HttpStatus_SeeOther :
case HttpStatus_TemporaryRedirect :
case HttpStatus_PermanentRedirect :
return true ;
default :
return false ;
}
return false ;
}
2019-04-03 10:25:27 -04:00
static bool process_again ( int status_code )
{
switch ( status_code ) {
case HttpStatus_MovedPermanently :
case HttpStatus_Found :
2022-03-17 04:20:30 -04:00
case HttpStatus_SeeOther :
2019-11-28 22:17:51 -05:00
case HttpStatus_TemporaryRedirect :
2022-03-17 04:20:30 -04:00
case HttpStatus_PermanentRedirect :
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 ;
2022-03-17 04:20:30 -04:00
if ( redirection_required ( status_code ) ) {
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
2022-01-28 05:59:29 -05:00
char upgrade_data_buf [ 256 ] ;
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
*/
2022-01-28 05:59:29 -05:00
int data_read = esp_http_client_read ( http_client , upgrade_data_buf , sizeof ( upgrade_data_buf ) ) ;
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 ) ;
}
2022-01-28 06:10:06 -05:00
# if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
static esp_err_t esp_https_ota_decrypt_cb ( esp_https_ota_t * handle , decrypt_cb_arg_t * args )
{
2022-03-10 07:02:42 -05:00
esp_err_t ret = handle - > decrypt_cb ( args , handle - > decrypt_user_ctx ) ;
2022-01-28 06:10:06 -05:00
if ( ret ! = ESP_OK ) {
ESP_LOGE ( TAG , " Decrypt callback failed %d " , ret ) ;
return ret ;
}
if ( args - > data_out_len > 0 ) {
return ESP_OK ;
} else {
return ESP_HTTPS_OTA_IN_PROGRESS ;
}
}
static void esp_https_ota_decrypt_cb_free_buf ( void * buffer )
{
free ( buffer ) ;
}
# endif // CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
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 ;
}
2022-01-28 06:10:06 -05:00
# if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
esp_https_ota_decrypt_cb_free_buf ( ( void * ) buffer ) ;
# endif
2019-04-03 10:25:27 -04:00
return err ;
}
2022-03-01 23:31:42 -05:00
static bool is_server_verification_enabled ( const esp_https_ota_config_t * ota_config ) {
2021-04-08 06:06:24 -04:00
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
}
2022-03-01 23:31:42 -05:00
esp_err_t esp_https_ota_begin ( const esp_https_ota_config_t * ota_config , esp_https_ota_handle_t * handle )
2019-04-03 10:25:27 -04:00
{
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 ) ) {
2022-01-28 06:11:22 -05:00
# if CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP
ESP_LOGW ( TAG , " Continuing with insecure option because CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP is set. " ) ;
2021-04-19 09:56:10 -04:00
# 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 ) ;
2022-01-07 08:10:08 -05:00
if ( err = = ESP_OK ) {
int status = esp_http_client_get_status_code ( https_ota_handle - > http_client ) ;
if ( status ! = HttpStatus_Ok ) {
ESP_LOGE ( TAG , " Received incorrect http status %d " , status ) ;
err = ESP_FAIL ;
goto http_cleanup ;
}
} else {
ESP_LOGE ( TAG , " ESP HTTP client perform failed: %d " , err ) ;
2021-02-02 02:55:40 -05:00
goto http_cleanup ;
}
2022-01-07 08:10:08 -05:00
2021-02-02 02:55:40 -05:00
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 ) ;
2022-01-07 08:10:08 -05:00
goto http_cleanup ;
2020-08-21 03:10:56 -04:00
}
}
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
}
2022-01-28 06:10:06 -05:00
# if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
if ( ota_config - > decrypt_cb = = NULL ) {
err = ESP_ERR_INVALID_ARG ;
goto http_cleanup ;
}
https_ota_handle - > decrypt_cb = ota_config - > decrypt_cb ;
2022-03-10 07:02:42 -05:00
https_ota_handle - > decrypt_user_ctx = ota_config - > decrypt_user_ctx ;
2022-01-28 06:10:06 -05:00
# endif
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 ;
}
2022-01-10 08:02:37 -05:00
static esp_err_t read_header ( esp_https_ota_t * handle )
2019-04-03 10:25:27 -04:00
{
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 ) ;
2022-03-07 00:35:43 -05:00
if ( data_read < 0 ) {
if ( data_read = = - ESP_ERR_HTTP_EAGAIN ) {
ESP_LOGD ( TAG , " ESP_ERR_HTTP_EAGAIN invoked: Call timed out before data was ready " ) ;
continue ;
}
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 ;
2022-01-10 08:02:37 -05:00
return ESP_OK ;
}
esp_err_t esp_https_ota_get_img_desc ( esp_https_ota_handle_t https_ota_handle , esp_app_desc_t * new_app_info )
{
2022-03-09 02:03:39 -05:00
# if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
// This API is not supported in case firmware image is encrypted in nature.
// It is recommended to retrieve image description through decryption callback in application layer.
return ESP_ERR_NOT_SUPPORTED ;
# endif
2022-01-10 08:02:37 -05:00
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 " ) ;
2022-01-28 06:01:47 -05:00
return ESP_ERR_INVALID_STATE ;
2022-01-10 08:02:37 -05:00
}
if ( read_header ( handle ) ! = ESP_OK ) {
return ESP_FAIL ;
}
2022-01-28 06:01:47 -05:00
const int app_desc_offset = sizeof ( esp_image_header_t ) + sizeof ( esp_image_segment_header_t ) ;
esp_app_desc_t * app_info = ( esp_app_desc_t * ) & handle - > ota_upgrade_buf [ app_desc_offset ] ;
if ( app_info - > magic_word ! = ESP_APP_DESC_MAGIC_WORD ) {
ESP_LOGE ( TAG , " Incorrect app descriptor magic " ) ;
return ESP_FAIL ;
}
memcpy ( new_app_info , app_info , 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
2022-01-28 06:01:47 -05:00
static esp_err_t esp_ota_verify_chip_id ( const void * arg )
2022-01-10 08:02:37 -05:00
{
2022-01-28 06:01:47 -05:00
esp_image_header_t * data = ( esp_image_header_t * ) ( arg ) ;
2022-01-10 08:02:37 -05:00
if ( data - > chip_id ! = CONFIG_IDF_FIRMWARE_CHIP_ID ) {
ESP_LOGE ( TAG , " Mismatch chip id, expected %d, found %d " , CONFIG_IDF_FIRMWARE_CHIP_ID , data - > chip_id ) ;
return ESP_ERR_INVALID_VERSION ;
}
return ESP_OK ;
}
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
*/
2022-01-10 08:02:37 -05:00
int binary_file_len = 0 ;
2019-04-03 10:25:27 -04:00
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
*/
2022-01-10 08:02:37 -05:00
binary_file_len = handle - > binary_file_len ;
2021-02-02 02:55:40 -05:00
handle - > binary_file_len = 0 ;
2022-01-10 08:02:37 -05:00
} else {
if ( read_header ( handle ) ! = ESP_OK ) {
return ESP_FAIL ;
}
binary_file_len = IMAGE_HEADER_SIZE ;
}
2022-01-28 06:10:06 -05:00
const void * data_buf = ( const void * ) handle - > ota_upgrade_buf ;
# if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
decrypt_cb_arg_t args = { } ;
args . data_in = handle - > ota_upgrade_buf ;
args . data_in_len = binary_file_len ;
err = esp_https_ota_decrypt_cb ( handle , & args ) ;
if ( err = = ESP_OK ) {
data_buf = args . data_out ;
binary_file_len = args . data_out_len ;
} else {
ESP_LOGE ( TAG , " Decryption of image header failed " ) ;
return ESP_FAIL ;
}
# endif // CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
err = esp_ota_verify_chip_id ( data_buf ) ;
2022-01-10 08:02:37 -05:00
if ( err ! = ESP_OK ) {
return err ;
2019-04-03 10:25:27 -04:00
}
2022-01-28 06:10:06 -05:00
return _ota_write ( handle , data_buf , binary_file_len ) ;
2019-04-03 10:25:27 -04:00
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 .
*/
2022-03-07 00:35:43 -05:00
if ( ! esp_http_client_is_complete_data_received ( handle - > http_client ) ) {
ESP_LOGE ( TAG , " Connection closed before complete data was received! " ) ;
2019-12-09 09:23:05 -05:00
return ESP_FAIL ;
}
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 ) {
2022-01-28 06:10:06 -05:00
const void * data_buf = ( const void * ) handle - > ota_upgrade_buf ;
int data_len = data_read ;
# if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
decrypt_cb_arg_t args = { } ;
args . data_in = handle - > ota_upgrade_buf ;
args . data_in_len = data_read ;
err = esp_https_ota_decrypt_cb ( handle , & args ) ;
if ( err = = ESP_OK ) {
data_buf = args . data_out ;
data_len = args . data_out_len ;
} else {
return err ;
}
# endif // CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
return _ota_write ( handle , data_buf , data_len ) ;
2020-03-30 02:22:38 -04:00
} else {
2022-03-07 00:35:43 -05:00
if ( data_read = = - ESP_ERR_HTTP_EAGAIN ) {
ESP_LOGD ( TAG , " ESP_ERR_HTTP_EAGAIN invoked: Call timed out before data was ready " ) ;
return ESP_ERR_HTTPS_OTA_IN_PROGRESS ;
}
2021-08-02 07:34:14 -04:00
ESP_LOGE ( TAG , " data read %d, errno %d " , data_read , errno ) ;
2020-03-30 02:22:38 -04:00
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 ;
}
2022-03-01 23:31:42 -05:00
esp_err_t esp_https_ota ( const esp_https_ota_config_t * ota_config )
2019-04-03 10:25:27 -04:00
{
2022-03-01 23:31:42 -05:00
if ( ota_config = = NULL | | ota_config - > http_config = = NULL ) {
ESP_LOGE ( TAG , " esp_https_ota: Invalid argument " ) ;
2019-04-03 10:25:27 -04:00
return ESP_ERR_INVALID_ARG ;
2020-11-10 02:40:01 -05:00
}
2019-04-03 10:25:27 -04:00
esp_https_ota_handle_t https_ota_handle = NULL ;
2022-03-01 23:31:42 -05:00
esp_err_t err = esp_https_ota_begin ( ota_config , & https_ota_handle ) ;
2019-04-03 10:25:27 -04:00
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
}