completet https ota

This commit is contained in:
Hendrik Schutter 2021-01-18 17:38:08 +01:00
parent c542dc05ab
commit a0546aa3ef
4 changed files with 72 additions and 125 deletions

View File

@ -22,47 +22,10 @@ https_client_ret_t https_clientInitialize()
i32RetHTTPClient = https_clientInitEmbedTLS(); i32RetHTTPClient = https_clientInitEmbedTLS();
if(i32RetHTTPClient == HTTPS_CLIENT_OK) if (i32RetHTTPClient == HTTPS_CLIENT_ERROR_INIT_EMBEDTLS)
{ {
i32RetHTTPClient = https_clientConnectToServer();
}
if(i32RetHTTPClient == HTTPS_CLIENT_OK)
{
i32RetHTTPClient = https_clientValidateServer();
}
if(i32RetHTTPClient == HTTPS_CLIENT_OK)
{
i32RetHTTPClient = https_clientSendRequest();
}
switch (i32RetHTTPClient)
{
case HTTPS_CLIENT_ERROR_INIT_EMBEDTLS:
ESP_LOGE(TAG, "Unable to initialize EmbedTLS"); ESP_LOGE(TAG, "Unable to initialize EmbedTLS");
i32RetHTTPClient = HTTPS_CLIENT_ERROR; i32RetHTTPClient = HTTPS_CLIENT_ERROR;
break;
case HTTPS_CLIENT_ERROR_INIT_CONNECT_TWO_SERVER:
ESP_LOGE(TAG, "Unable to connect to server");
i32RetHTTPClient = HTTPS_CLIENT_ERROR;
break;
case HTTPS_CLIENT_ERROR_INIT_VALIDATE_SERVER:
ESP_LOGE(TAG, "Unable to validate the server");
i32RetHTTPClient = HTTPS_CLIENT_ERROR;
break;
case HTTPS_CLIENT_ERROR_INIT_SEND_REQUEST:
ESP_LOGE(TAG, "Unable to send request to server");
i32RetHTTPClient = HTTPS_CLIENT_ERROR;
break;
case HTTPS_CLIENT_OK:
ESP_LOGI(TAG, "HTTPS Client successfully initialized");
i32RetHTTPClient = HTTPS_CLIENT_OK;
break;
default:
i32RetHTTPClient = HTTPS_CLIENT_ERROR;
ESP_LOGE(TAG, "Unknown error while init https client");
break;
} }
return i32RetHTTPClient; return i32RetHTTPClient;
} }
@ -78,6 +41,7 @@ https_client_ret_t https_clientRetrieveData(char* pu8Data, uint32_t* pu32DataLen
while (bRetriveData) while (bRetriveData)
{ {
mbedtls_ssl_conf_read_timeout(&sHTTPS_ClientConfig.conf, HTTPS_READ_TIMEOUT); //set timeout
//Reading HTTP response //Reading HTTP response
i32RetRetrieveData = mbedtls_ssl_read(&sHTTPS_ClientConfig.ssl, (unsigned char *)(pu8Data+(*pu32BytesRead)), ((*pu32DataLenght)-(*pu32BytesRead))); i32RetRetrieveData = mbedtls_ssl_read(&sHTTPS_ClientConfig.ssl, (unsigned char *)(pu8Data+(*pu32BytesRead)), ((*pu32DataLenght)-(*pu32BytesRead)));
@ -105,13 +69,18 @@ https_client_ret_t https_clientRetrieveData(char* pu8Data, uint32_t* pu32DataLen
pu32BytesRead = 0; pu32BytesRead = 0;
} }
if(i32RetRetrieveData == MBEDTLS_ERR_SSL_TIMEOUT )
{
//timeout --> stop reading
bRetriveData = false;
}
if(i32RetRetrieveData == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) if(i32RetRetrieveData == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
{ {
//connection is going to be closed //connection is going to be closed
i32RetHTTPClient = HTTPS_CLIENT_ERROR; i32RetHTTPClient = HTTPS_CLIENT_ERROR;
bRetriveData = false; bRetriveData = false;
} }
} }
return i32RetHTTPClient; return i32RetHTTPClient;
} }
@ -120,15 +89,6 @@ https_client_ret_t https_clientReset()
{ {
https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK;
i32RetHTTPClient = https_clientSendRequest();
return i32RetHTTPClient;
}
https_client_ret_t https_clientDeinitialize()
{
https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK;
i32RetHTTPClient = mbedtls_ssl_close_notify(&sHTTPS_ClientConfig.ssl); //close session i32RetHTTPClient = mbedtls_ssl_close_notify(&sHTTPS_ClientConfig.ssl); //close session
if(i32RetHTTPClient != ESP_OK) if(i32RetHTTPClient != ESP_OK)
@ -250,7 +210,7 @@ https_client_ret_t https_clientConnectToServer()
if(i32RetServerConnect == ESP_OK) if(i32RetServerConnect == ESP_OK)
{ {
mbedtls_ssl_set_bio(&sHTTPS_ClientConfig.ssl, &sHTTPS_ClientConfig.server_fd, mbedtls_net_send, mbedtls_net_recv, NULL); mbedtls_ssl_set_bio(&sHTTPS_ClientConfig.ssl, &sHTTPS_ClientConfig.server_fd, mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout);
//Performing the SSL/TLS handshake //Performing the SSL/TLS handshake
while ((i32RetServerConnect = mbedtls_ssl_handshake(&sHTTPS_ClientConfig.ssl)) != 0) while ((i32RetServerConnect = mbedtls_ssl_handshake(&sHTTPS_ClientConfig.ssl)) != 0)

View File

@ -8,6 +8,8 @@ xQueueHandle queueMessageOTA; //mesh ota controll messages like "OTA_Version_Res
SemaphoreHandle_t bsStartStopServerWorker; //binary semaphore SemaphoreHandle_t bsStartStopServerWorker; //binary semaphore
const esp_partition_t* pOTAPartition; //pointer to ota partition
esp_err_t errMeshOTAInitialize() esp_err_t errMeshOTAInitialize()
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
@ -46,6 +48,17 @@ esp_err_t errMeshOTAInitialize()
ERROR_CHECK(errMeshNetworkSetOTAMessageHandleHandle(vAddOTAControllMessageToQueue)); ERROR_CHECK(errMeshNetworkSetOTAMessageHandleHandle(vAddOTAControllMessageToQueue));
ERROR_CHECK(errMeshNetworkSetChangeStateOfServerWorkerHandle(vChangeStateOfServerWorker)); ERROR_CHECK(errMeshNetworkSetChangeStateOfServerWorkerHandle(vChangeStateOfServerWorker));
if(err == ESP_OK)
{
pOTAPartition = esp_ota_get_next_update_partition(NULL); //get ota partition
if(pOTAPartition == NULL)
{
err = ESP_FAIL;
ESP_LOGE(LOG_TAG, "unable to get next ota partition");
}
}
if(err == ESP_OK) if(err == ESP_OK)
{ {
xReturned = xTaskCreate(vTaskServerWorker, "vTaskServerWorker", 8192, NULL, 5, NULL); xReturned = xTaskCreate(vTaskServerWorker, "vTaskServerWorker", 8192, NULL, 5, NULL);
@ -130,7 +143,7 @@ void vTaskServerWorker(void *arg)
{ {
esp_err_t err; esp_err_t err;
bool bNewOTAImage = false; // true if a new ota image was downloaded and validated bool bNewOTAImage = false; // true if a new ota image was downloaded and validated
// bool bFirstRun = true; bool bFirstRun = true;
while(true) while(true)
{ {
@ -140,16 +153,18 @@ void vTaskServerWorker(void *arg)
if (esp_mesh_is_root()) //check again that this node is the root node if (esp_mesh_is_root()) //check again that this node is the root node
{ {
// if(bFirstRun == true) if(bFirstRun == true)
// { {
ERROR_CHECK(https_clientInitialize()); ERROR_CHECK(https_clientInitialize());
// bFirstRun = false; bFirstRun = false;
//} }
ERROR_CHECK(https_clientConnectToServer());
ERROR_CHECK(https_clientValidateServer());
ERROR_CHECK(https_clientSendRequest());
ERROR_CHECK(errOTAHTTPS(&bNewOTAImage)); ERROR_CHECK(errOTAHTTPS(&bNewOTAImage));
https_clientDeinitialize(); https_clientReset();
// https_clientReset();
if(bNewOTAImage == true) if(bNewOTAImage == true)
{ {
@ -167,85 +182,58 @@ void vTaskServerWorker(void *arg)
esp_err_t errOTAHTTPS(bool* pbNewOTAImage) esp_err_t errOTAHTTPS(bool* pbNewOTAImage)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
char buffer[1024U]; char u8OTABuffer[OTA_HTTPS_SEGMENT_SIZE]; //store image segment from server before ota write
uint32_t u32BufferLenght = 1024U; uint32_t u32BufferLenght = OTA_HTTPS_SEGMENT_SIZE; //size of buffer
uint32_t u32BytesRead = 0; uint32_t u32BytesRead = 0; //number of bytes that are read from server, <= u32BufferLenght
char pcRemoteVersionNumber[12]; char pcRemoteVersionNumber[12]; //string for version number in server image
const esp_partition_t * currentPartition; const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset)
const esp_partition_t * otaPartition; static esp_ota_handle_t otaHandle; //OTA process handle
static esp_ota_handle_t otaHandle; uint32_t u32StartOffset = 0U; //start offset for image (exclude the http response data)
uint32_t u32StartOffset; esp_app_desc_t bootPartitionDesc; //Metadate from boot partition
//esp_app_desc_t otaPartitionDesc;
esp_app_desc_t curPartitionDesc;
pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition
ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition
currentPartition = esp_ota_get_boot_partition(); ERROR_CHECK(https_clientRetrieveData(u8OTABuffer, &u32BufferLenght, &u32BytesRead)); //read first bytes if image, including the version
ESP_LOGI(LOG_TAG, "Type: %d", (*currentPartition).subtype);
ESP_LOGI(LOG_TAG, "Start address: %d", (*currentPartition).address);
ESP_LOGI(LOG_TAG, "Size: %d", (*currentPartition).size);
ESP_LOGI(LOG_TAG, "Encrypted: %d", (*currentPartition).encrypted);
ERROR_CHECK(errExtractVersionNumber(u8OTABuffer, &u32BytesRead, pcRemoteVersionNumber)); //extract version numbers
ERROR_CHECK(esp_ota_get_partition_description(currentPartition, &curPartitionDesc)); if(err == ESP_OK) //check if version number is found
//ESP_LOGI(LOG_TAG, "currentPartition project_name: %s", (curPartitionDesc).project_name);
//ESP_LOGI(LOG_TAG, "currentPartition version: %s", (curPartitionDesc).version);
//ESP_LOGI(LOG_TAG, "currentPartition Timestamp: %s %s", (curPartitionDesc).date, (curPartitionDesc).time);
ERROR_CHECK(https_clientRetrieveData(buffer, &u32BufferLenght, &u32BytesRead)); //read first bytes if image, including the version
//ESP_LOGI(LOG_TAG, "Data received: %i", u32BytesRead);
ERROR_CHECK(errExtractVersionNumber(buffer, &u32BytesRead, pcRemoteVersionNumber));
if(err == ESP_OK)
{ {
if(bNewerVersion((curPartitionDesc).version, pcRemoteVersionNumber)) //compare local and remote version if(bNewerVersion((bootPartitionDesc).version, pcRemoteVersionNumber)) //compare local and remote version
{ {
// server image is newer --> OTA update required // server image is newer --> OTA update required
ESP_LOGI(LOG_TAG, "server image is newer --> OTA update required"); ESP_LOGI(LOG_TAG, "server image is newer --> OTA update required");
otaPartition = esp_ota_get_next_update_partition(currentPartition); ERROR_CHECK(errFindImageStart(u8OTABuffer, &u32BufferLenght, &u32StartOffset)); //get image start offset
if(otaPartition == NULL)
{
err = ESP_FAIL;
ESP_LOGE(LOG_TAG, "unable to get next ota partition");
}
ERROR_CHECK(errFindImageStart(buffer, &u32BufferLenght, &u32StartOffset)); //get image start offset
//ESP_LOGI(LOG_TAG, "first byte offset: %i", u32StartOffset);
//ESP_LOGI(LOG_TAG, "first byte: %x", buffer[u32StartOffset]);
//TODO lock ota mutex //TODO lock ota mutex
ERROR_CHECK(esp_ota_begin(otaPartition, OTA_SIZE_UNKNOWN, &otaHandle)); ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process
if(err == ESP_OK) if(err == ESP_OK)
{ {
//image download and ota partition write //image download and ota partition write
ESP_LOGI(LOG_TAG, "start ota https download");
do do
{ {
ESP_LOGI(LOG_TAG, "OTA-Data written: %i", u32BytesRead); //TODO progress log
ERROR_CHECK(esp_ota_write(otaHandle, (const void*) buffer+u32StartOffset, (u32BytesRead-u32StartOffset))); ERROR_CHECK(esp_ota_write(otaHandle, (const void*) u8OTABuffer+u32StartOffset, (u32BytesRead-u32StartOffset)));
if(err == ESP_OK) if(err == ESP_OK)
{ {
//write was succsesfull //write was succsesfull
u32StartOffset = 0U; //reset the offset for next download u32StartOffset = 0U; //reset the offset for next download
https_clientRetrieveData(buffer, &u32BufferLenght, &u32BytesRead); //download next data segment ERROR_CHECK(https_clientRetrieveData(u8OTABuffer, &u32BufferLenght, &u32BytesRead)); //download next data segment
} }
} }
while ((u32BytesRead > 0) && (err == ESP_OK)); while ((u32BytesRead > 0) && (err == ESP_OK)); //loop until error or complete image downloaded
} }
if(err == ESP_OK) if(err == ESP_OK)
{ {
//no error occurred --> finish ota update process //no error occurred --> finish ota update process
ERROR_CHECK(esp_ota_end(otaHandle)); //finish process ERROR_CHECK(esp_ota_end(otaHandle)); //finish process
ERROR_CHECK(esp_ota_set_boot_partition(otaPartition)); //set new image as boot ERROR_CHECK(esp_ota_set_boot_partition(pOTAPartition)); //set new image as boot
if(err == ESP_OK) if(err == ESP_OK)
{ {
*pbNewOTAImage = true; //image validated *pbNewOTAImage = true; //image validated
@ -253,23 +241,17 @@ esp_err_t errOTAHTTPS(bool* pbNewOTAImage)
} }
else else
{ {
// error occurred --> abort ota update process //error occurred --> abort ota update process
ESP_LOGE(LOG_TAG, "abort ota process"); ESP_LOGE(LOG_TAG, "abort ota process due to error 0x%x -> %s", err, esp_err_to_name(err));
ERROR_CHECK(esp_ota_abort(otaHandle)); ERROR_CHECK(esp_ota_abort(otaHandle));
*pbNewOTAImage = false; //ota update failed *pbNewOTAImage = false; //ota update failed
} }
//TODO unlock ota mutex //TODO unlock ota mutex
} //end newer version on server } //end newer version on server
} //end version number extracted } //end version number extracted
return err; return err;
} }
/* /*
* Return true if remote version is newer (higher) than local version * Return true if remote version is newer (higher) than local version
*/ */
@ -403,9 +385,9 @@ esp_err_t esp_mesh_ota_send(mesh_addr_t* dest)
static uint32_t u32index; static uint32_t u32index;
const esp_partition_t * currentPartition = esp_ota_get_boot_partition(); const esp_partition_t * pBootPartition = esp_ota_get_boot_partition();
if((*currentPartition).subtype == 0) if((*pBootPartition).subtype == 0)
{ {
int data_read = 0; int data_read = 0;
@ -422,7 +404,7 @@ esp_err_t esp_mesh_ota_send(mesh_addr_t* dest)
else else
{ {
ESP_LOGI(MESH_TAG, "OTA-Data read: %i", u32index); ESP_LOGI(MESH_TAG, "OTA-Data read: %i", u32index);
err = esp_partition_read(currentPartition, (1024*u32index), packet.au8Payload, 1024 ); err = esp_partition_read(pBootPartition, (1024*u32index), packet.au8Payload, 1024 );
ESP_ERROR_CHECK(err); ESP_ERROR_CHECK(err);
data_read = 1024; data_read = 1024;
u32index++; u32index++;
@ -438,7 +420,7 @@ esp_err_t esp_mesh_ota_send(mesh_addr_t* dest)
} }
else else
{ {
ESP_LOGI(MESH_TAG, "Subtype: %d", (*currentPartition).subtype); ESP_LOGI(MESH_TAG, "Subtype: %d", (*pBootPartition).subtype);
} }
return err; return err;
} }
@ -449,14 +431,14 @@ esp_err_t esp_mesh_ota_receive(mesh_addr_t* dest, struct ota_mesh_packet* packet
static esp_ota_handle_t otaHandle; static esp_ota_handle_t otaHandle;
static uint32_t u32index; static uint32_t u32index;
const esp_partition_t * currentPartition = esp_ota_get_boot_partition(); const esp_partition_t * pBootPartition = esp_ota_get_boot_partition();
const esp_partition_t * otaPartition = esp_ota_get_next_update_partition(currentPartition); const esp_partition_t * pOTAPartition = esp_ota_get_next_update_partition(pBootPartition);
if(u32index == 0) if(u32index == 0)
{ {
//first run //first run
err = esp_ota_begin(otaPartition, OTA_SIZE_UNKNOWN, &otaHandle); err = esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle);
ESP_ERROR_CHECK(err); ESP_ERROR_CHECK(err);
} }
@ -480,11 +462,11 @@ esp_err_t esp_mesh_ota_receive(mesh_addr_t* dest, struct ota_mesh_packet* packet
err = esp_ota_end(otaHandle); err = esp_ota_end(otaHandle);
ESP_ERROR_CHECK(err); ESP_ERROR_CHECK(err);
esp_app_desc_t otaPartitionDesc; esp_app_desc_t otaPartitionDesc;
err = esp_ota_get_partition_description(otaPartition, &otaPartitionDesc); err = esp_ota_get_partition_description(pOTAPartition, &otaPartitionDesc);
ESP_ERROR_CHECK(err); ESP_ERROR_CHECK(err);
ESP_LOGI(MESH_TAG, "otaPartition project_name: %s", (otaPartitionDesc).project_name); ESP_LOGI(MESH_TAG, "pOTAPartition project_name: %s", (otaPartitionDesc).project_name);
err = esp_ota_set_boot_partition(otaPartition); err = esp_ota_set_boot_partition(pOTAPartition);
ESP_ERROR_CHECK(err); ESP_ERROR_CHECK(err);
struct ota_mesh_packet retPacket; struct ota_mesh_packet retPacket;

View File

@ -51,6 +51,8 @@
#define HTTPS_CLIENT_ERROR_INIT_VALIDATE_SERVER -4 #define HTTPS_CLIENT_ERROR_INIT_VALIDATE_SERVER -4
#define HTTPS_CLIENT_ERROR_INIT_SEND_REQUEST -5 #define HTTPS_CLIENT_ERROR_INIT_SEND_REQUEST -5
#define HTTPS_READ_TIMEOUT 1000 //ms
struct HTTPS_Client struct HTTPS_Client
{ {
mbedtls_entropy_context entropy; mbedtls_entropy_context entropy;
@ -65,9 +67,11 @@ typedef int32_t https_client_ret_t;
typedef struct HTTPS_Client HTTPS_Client_t; typedef struct HTTPS_Client HTTPS_Client_t;
https_client_ret_t https_clientInitialize(); https_client_ret_t https_clientInitialize();
https_client_ret_t https_clientConnectToServer();
https_client_ret_t https_clientValidateServer();
https_client_ret_t https_clientSendRequest();
https_client_ret_t https_clientRetrieveData(char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32BytesRead); https_client_ret_t https_clientRetrieveData(char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32BytesRead);
https_client_ret_t https_clientReset(); https_client_ret_t https_clientReset();
https_client_ret_t https_clientDeinitialize();
#endif /* H_HTTPS_CLIENT */ #endif /* H_HTTPS_CLIENT */

View File

@ -20,6 +20,7 @@
#define QUEUE_NODES_SIZE 10 #define QUEUE_NODES_SIZE 10
#define QUEUE_MESSAGE_OTA_SIZE 10 #define QUEUE_MESSAGE_OTA_SIZE 10
#define SERVER_CHECK_INTERVAL 30 //in seconds #define SERVER_CHECK_INTERVAL 30 //in seconds
#define OTA_HTTPS_SEGMENT_SIZE 2048U
#define ERROR_CHECK(x) if (err == ESP_OK) \ #define ERROR_CHECK(x) if (err == ESP_OK) \
{ \ { \