2016-09-21 02:44:27 -04:00
/* HTTPS GET Example using plain mbedTLS sockets
*
* Contacts the howsmyssl . com API via TLS v1 .2 and reads a JSON
* response .
*
* Adapted from the ssl_client1 example in mbedtls .
*
* Original Copyright ( C ) 2006 - 2016 , ARM Limited , All Rights Reserved , Apache 2.0 License .
* Additions Copyright ( C ) Copyright 2015 - 2016 Espressif Systems ( Shanghai ) PTE LTD , Apache 2.0 License .
*
*
* 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 <string.h>
2016-11-23 16:08:09 -05:00
# include <stdlib.h>
2021-09-24 03:57:06 -04:00
# include <time.h>
# include <sys/time.h>
2016-09-21 02:44:27 -04:00
# include "freertos/FreeRTOS.h"
# include "freertos/task.h"
2016-09-26 01:48:36 -04:00
# include "freertos/event_groups.h"
2016-09-21 02:44:27 -04:00
# include "esp_wifi.h"
2019-04-11 06:54:26 -04:00
# include "esp_event.h"
2016-09-21 02:44:27 -04:00
# include "esp_log.h"
# include "esp_system.h"
2016-09-26 21:16:40 -04:00
# include "nvs_flash.h"
2021-09-24 03:57:06 -04:00
# include "nvs.h"
2019-04-11 06:54:26 -04:00
# include "protocol_examples_common.h"
2021-09-24 03:57:06 -04:00
# include "esp_sntp.h"
2019-08-31 10:19:21 -04:00
# include "esp_netif.h"
2016-09-21 02:44:27 -04:00
# include "lwip/err.h"
# include "lwip/sockets.h"
# include "lwip/sys.h"
# include "lwip/netdb.h"
# include "lwip/dns.h"
2018-02-14 08:21:26 -05:00
# include "esp_tls.h"
2019-09-29 06:04:34 -04:00
# include "esp_crt_bundle.h"
2021-09-24 03:57:06 -04:00
# include "time_sync.h"
2018-02-12 13:11:31 -05:00
2016-09-21 02:44:27 -04:00
/* Constants that aren't configurable in menuconfig */
# define WEB_SERVER "www.howsmyssl.com"
# define WEB_PORT "443"
# define WEB_URL "https: //www.howsmyssl.com/a/check"
2021-11-12 05:18:53 -05:00
# define SERVER_URL_MAX_SZ 256
2016-09-21 02:44:27 -04:00
static const char * TAG = " example " ;
2021-09-24 03:57:06 -04:00
/* Timer interval once every day (24 Hours) */
# define TIME_PERIOD (86400000000ULL)
2021-11-12 05:18:53 -05:00
static const char HOWSMYSSL_REQUEST [ ] = " GET " WEB_URL " HTTP/1.1 \r \n "
" Host: " WEB_SERVER " \r \n "
" User-Agent: esp-idf/1.0 esp32 \r \n "
" \r \n " ;
# ifdef CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS
static const char LOCAL_SRV_REQUEST [ ] = " GET " CONFIG_EXAMPLE_LOCAL_SERVER_URL " HTTP/1.1 \r \n "
2021-01-08 06:26:28 -05:00
" Host: " WEB_SERVER " \r \n "
" User-Agent: esp-idf/1.0 esp32 \r \n "
" \r \n " ;
2021-11-12 05:18:53 -05:00
# endif
2016-09-21 02:44:27 -04:00
2021-01-08 06:26:28 -05:00
/* Root cert for howsmyssl.com, taken from server_root_cert.pem
The PEM file was extracted from the output of this command :
openssl s_client - showcerts - connect www . howsmyssl . com : 443 < / dev / null
The CA root cert is the last cert given in the chain of certs .
To embed it in the app binary , the PEM file is named
in the component . mk COMPONENT_EMBED_TXTFILES variable .
*/
extern const uint8_t server_root_cert_pem_start [ ] asm ( " _binary_server_root_cert_pem_start " ) ;
extern const uint8_t server_root_cert_pem_end [ ] asm ( " _binary_server_root_cert_pem_end " ) ;
2021-11-12 05:18:53 -05:00
extern const uint8_t local_server_cert_pem_start [ ] asm ( " _binary_local_server_cert_pem_start " ) ;
extern const uint8_t local_server_cert_pem_end [ ] asm ( " _binary_local_server_cert_pem_end " ) ;
# ifdef CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS
2021-09-01 23:36:09 -04:00
esp_tls_client_session_t * tls_client_session = NULL ;
2021-11-12 05:18:53 -05:00
static bool save_client_session = false ;
2021-09-01 23:36:09 -04:00
# endif
2021-11-12 05:18:53 -05:00
static void https_get_request ( esp_tls_cfg_t cfg , const char * WEB_SERVER_URL , const char * REQUEST )
2016-09-21 02:44:27 -04:00
{
char buf [ 512 ] ;
2018-02-12 13:11:31 -05:00
int ret , len ;
2016-09-21 02:44:27 -04:00
2021-11-12 05:18:53 -05:00
struct esp_tls * tls = esp_tls_conn_http_new ( WEB_SERVER_URL , & cfg ) ;
2019-09-29 06:04:34 -04:00
2021-01-08 06:26:28 -05:00
if ( tls ! = NULL ) {
ESP_LOGI ( TAG , " Connection established... " ) ;
} else {
ESP_LOGE ( TAG , " Connection failed... " ) ;
goto exit ;
}
2019-09-29 06:04:34 -04:00
2021-11-12 05:18:53 -05:00
# ifdef CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS
2021-09-01 23:36:09 -04:00
/* The TLS session is successfully established, now saving the session ctx for reuse */
2021-11-12 05:18:53 -05:00
if ( save_client_session ) {
free ( tls_client_session ) ;
2021-09-01 23:36:09 -04:00
tls_client_session = esp_tls_get_client_session ( tls ) ;
}
# endif
2021-01-08 06:26:28 -05:00
size_t written_bytes = 0 ;
do {
ret = esp_tls_conn_write ( tls ,
REQUEST + written_bytes ,
2021-11-12 05:18:53 -05:00
strlen ( REQUEST ) - written_bytes ) ;
2021-01-08 06:26:28 -05:00
if ( ret > = 0 ) {
ESP_LOGI ( TAG , " %d bytes written " , ret ) ;
written_bytes + = ret ;
} else if ( ret ! = ESP_TLS_ERR_SSL_WANT_READ & & ret ! = ESP_TLS_ERR_SSL_WANT_WRITE ) {
ESP_LOGE ( TAG , " esp_tls_conn_write returned: [0x%02X](%s) " , ret , esp_err_to_name ( ret ) ) ;
2018-02-26 05:34:47 -05:00
goto exit ;
2016-09-21 02:44:27 -04:00
}
2021-11-12 05:18:53 -05:00
} while ( written_bytes < strlen ( REQUEST ) ) ;
2019-09-29 06:04:34 -04:00
2021-01-08 06:26:28 -05:00
ESP_LOGI ( TAG , " Reading HTTP response... " ) ;
2017-08-17 03:25:39 -04:00
2021-01-08 06:26:28 -05:00
do {
len = sizeof ( buf ) - 1 ;
bzero ( buf , sizeof ( buf ) ) ;
ret = esp_tls_conn_read ( tls , ( char * ) buf , len ) ;
if ( ret = = ESP_TLS_ERR_SSL_WANT_WRITE | | ret = = ESP_TLS_ERR_SSL_WANT_READ ) {
continue ;
}
2017-08-17 03:25:39 -04:00
2021-01-08 06:26:28 -05:00
if ( ret < 0 ) {
ESP_LOGE ( TAG , " esp_tls_conn_read returned [-0x%02X](%s) " , - ret , esp_err_to_name ( ret ) ) ;
break ;
2016-09-21 02:44:27 -04:00
}
2021-01-08 06:26:28 -05:00
if ( ret = = 0 ) {
ESP_LOGI ( TAG , " connection closed " ) ;
break ;
}
len = ret ;
ESP_LOGD ( TAG , " %d bytes read " , len ) ;
/* Print response directly to stdout as it is read */
for ( int i = 0 ; i < len ; i + + ) {
putchar ( buf [ i ] ) ;
}
putchar ( ' \n ' ) ; // JSON output doesn't have a newline at end
} while ( 1 ) ;
exit :
esp_tls_conn_delete ( tls ) ;
for ( int countdown = 10 ; countdown > = 0 ; countdown - - ) {
ESP_LOGI ( TAG , " %d... " , countdown ) ;
vTaskDelay ( 1000 / portTICK_PERIOD_MS ) ;
2016-09-21 02:44:27 -04:00
}
}
2021-01-08 06:26:28 -05:00
static void https_get_request_using_crt_bundle ( void )
{
ESP_LOGI ( TAG , " https_request using crt bundle " ) ;
esp_tls_cfg_t cfg = {
. crt_bundle_attach = esp_crt_bundle_attach ,
} ;
2021-11-12 05:18:53 -05:00
https_get_request ( cfg , WEB_URL , HOWSMYSSL_REQUEST ) ;
2021-01-08 06:26:28 -05:00
}
2021-09-01 23:36:09 -04:00
2021-01-08 06:26:28 -05:00
static void https_get_request_using_cacert_buf ( void )
{
ESP_LOGI ( TAG , " https_request using cacert_buf " ) ;
esp_tls_cfg_t cfg = {
. cacert_buf = ( const unsigned char * ) server_root_cert_pem_start ,
. cacert_bytes = server_root_cert_pem_end - server_root_cert_pem_start ,
} ;
2021-11-12 05:18:53 -05:00
https_get_request ( cfg , WEB_URL , HOWSMYSSL_REQUEST ) ;
2021-01-08 06:26:28 -05:00
}
static void https_get_request_using_global_ca_store ( void )
{
esp_err_t esp_ret = ESP_FAIL ;
ESP_LOGI ( TAG , " https_request using global ca_store " ) ;
esp_ret = esp_tls_set_global_ca_store ( server_root_cert_pem_start , server_root_cert_pem_end - server_root_cert_pem_start ) ;
if ( esp_ret ! = ESP_OK ) {
ESP_LOGE ( TAG , " Error in setting the global ca store: [%02X] (%s),could not complete the https_request using global_ca_store " , esp_ret , esp_err_to_name ( esp_ret ) ) ;
return ;
}
esp_tls_cfg_t cfg = {
. use_global_ca_store = true ,
} ;
2021-11-12 05:18:53 -05:00
https_get_request ( cfg , WEB_URL , HOWSMYSSL_REQUEST ) ;
2021-01-08 06:26:28 -05:00
esp_tls_free_global_ca_store ( ) ;
}
2021-11-12 05:18:53 -05:00
# ifdef CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS
static void https_get_request_to_local_server ( const char * url )
{
ESP_LOGI ( TAG , " https_request to local server " ) ;
esp_tls_cfg_t cfg = {
. cacert_buf = ( const unsigned char * ) local_server_cert_pem_start ,
. cacert_bytes = local_server_cert_pem_end - local_server_cert_pem_start ,
. skip_common_name = true ,
} ;
save_client_session = true ;
https_get_request ( cfg , url , LOCAL_SRV_REQUEST ) ;
}
static void https_get_request_using_already_saved_session ( const char * url )
2021-09-01 23:36:09 -04:00
{
ESP_LOGI ( TAG , " https_request using saved client session " ) ;
esp_tls_cfg_t cfg = {
. client_session = tls_client_session ,
} ;
2021-11-12 05:18:53 -05:00
https_get_request ( cfg , url , LOCAL_SRV_REQUEST ) ;
2021-09-01 23:36:09 -04:00
free ( tls_client_session ) ;
2021-11-12 05:18:53 -05:00
save_client_session = false ;
2021-09-01 23:36:09 -04:00
tls_client_session = NULL ;
}
# endif
2021-01-08 06:26:28 -05:00
static void https_request_task ( void * pvparameters )
{
ESP_LOGI ( TAG , " Start https_request example " ) ;
2021-11-12 05:18:53 -05:00
# ifdef CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS
char * server_url = NULL ;
# ifdef CONFIG_EXAMPLE_LOCAL_SERVER_URL_FROM_STDIN
char url_buf [ SERVER_URL_MAX_SZ ] ;
if ( strcmp ( CONFIG_EXAMPLE_LOCAL_SERVER_URL , " FROM_STDIN " ) = = 0 ) {
example_configure_stdin_stdout ( ) ;
fgets ( url_buf , SERVER_URL_MAX_SZ , stdin ) ;
int len = strlen ( url_buf ) ;
url_buf [ len - 1 ] = ' \0 ' ;
server_url = url_buf ;
} else {
ESP_LOGE ( TAG , " Configuration mismatch: invalid url for local server " ) ;
abort ( ) ;
}
printf ( " \n Server URL obtained is %s \n " , url_buf ) ;
# else
server_url = CONFIG_EXAMPLE_LOCAL_SERVER_URL ;
# endif /* CONFIG_EXAMPLE_LOCAL_SERVER_URL_FROM_STDIN */
https_get_request_to_local_server ( server_url ) ;
https_get_request_using_already_saved_session ( server_url ) ;
# endif
2021-01-08 06:26:28 -05:00
https_get_request_using_crt_bundle ( ) ;
2021-11-12 05:18:53 -05:00
printf ( " Minimum free heap size: %d bytes \n " , esp_get_minimum_free_heap_size ( ) ) ;
2021-01-08 06:26:28 -05:00
https_get_request_using_cacert_buf ( ) ;
https_get_request_using_global_ca_store ( ) ;
ESP_LOGI ( TAG , " Finish https_request example " ) ;
vTaskDelete ( NULL ) ;
}
2019-07-16 05:33:30 -04:00
void app_main ( void )
2016-09-21 02:44:27 -04:00
{
2017-03-14 09:39:44 -04:00
ESP_ERROR_CHECK ( nvs_flash_init ( ) ) ;
2019-11-29 04:54:02 -05:00
ESP_ERROR_CHECK ( esp_netif_init ( ) ) ;
2019-04-11 06:54:26 -04:00
ESP_ERROR_CHECK ( esp_event_loop_create_default ( ) ) ;
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read " Establishing Wi-Fi or Ethernet Connection " section in
* examples / protocols / README . md for more information about this function .
*/
ESP_ERROR_CHECK ( example_connect ( ) ) ;
2021-09-24 03:57:06 -04:00
if ( esp_reset_reason ( ) = = ESP_RST_POWERON ) {
ESP_LOGI ( TAG , " Updating time from NVS " ) ;
ESP_ERROR_CHECK ( update_time_from_nvs ( ) ) ;
}
const esp_timer_create_args_t nvs_update_timer_args = {
. callback = & fetch_and_store_time_in_nvs ,
} ;
esp_timer_handle_t nvs_update_timer ;
ESP_ERROR_CHECK ( esp_timer_create ( & nvs_update_timer_args , & nvs_update_timer ) ) ;
ESP_ERROR_CHECK ( esp_timer_start_periodic ( nvs_update_timer , TIME_PERIOD ) ) ;
2021-01-08 06:26:28 -05:00
xTaskCreate ( & https_request_task , " https_get_task " , 8192 , NULL , 5 , NULL ) ;
2016-09-21 02:44:27 -04:00
}