Diff between coreHTTP example

Created Diff never expires
52 removals
416 lines
52 additions
414 lines
/*
/*
* AWS IoT Device SDK for Embedded C 202103.00
* AWS IoT Device SDK for Embedded C 202103.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
* subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in all
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
*/


/* Standard includes. */
/* Standard includes. */
#include <assert.h>
#include <assert.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>


/* POSIX includes. */
/* POSIX includes. */
#include <unistd.h>
#include <unistd.h>


/* Include Demo Config as the first non-system header. */
/* Include Demo Config as the first non-system header. */
#include "demo_config.h"
#include "demo_config.h"


/* Common HTTP demo utilities. */
/* Common HTTP demo utilities. */
#include "http_demo_utils.h"
#include "http_demo_utils.h"


/* HTTP API header. */
/* HTTP API header. */
#include "core_http_client.h"
#include "core_http_client.h"


/* OpenSSL transport header. */
/* OpenSSL transport header. */
#include "openssl_posix.h"
#include "tls_freertos.h"

#include "demo_header.h"


/* Check that AWS IoT Core endpoint is defined. */
/* Check that AWS IoT Core endpoint is defined. */
#ifndef AWS_IOT_ENDPOINT
#define AWS_IOT_ENDPOINT CONFIG_AWS_IOT_ENDPOINT
#error "AWS_IOT_ENDPOINT must be defined to your AWS IoT Core endpoint."
#ifndef ROOT_CA_PEM
#endif
#if CONFIG_BROKER_CERTIFICATE_OVERRIDDEN == 1

static const uint8_t root_cert_auth_pem_start[] = "-----BEGIN CERTIFICATE-----\n" CONFIG_BROKER_CERTIFICATE_OVERRIDE "\n-----END CERTIFICATE-----";
/* Check that TLS port used for AWS IoT Core is defined. */
#else
#ifndef AWS_HTTPS_PORT
extern const uint8_t root_cert_auth_pem_start[] asm("_binary_root_cert_auth_pem_start");
#error "Please define a AWS_HTTPS_PORT."
#endif
extern const uint8_t root_cert_auth_pem_end[] asm("_binary_root_cert_auth_pem_end");
#endif
#endif


/* Check that a path for HTTP Method POST is defined. */
/* Check that a path for HTTP Method POST is defined. */
#ifndef POST_PATH
#ifndef POST_PATH
#error "Please define a POST_PATH."
#error "Please define a POST_PATH."
#endif
#endif


/* Check that a path for Root CA certificate is defined. */
/* Check that a path for Root CA certificate is defined. */
#ifndef ROOT_CA_CERT_PATH

#error "Please define a ROOT_CA_CERT_PATH."
#endif


/* Check that a path for the client certificate is defined. */
/* Check that a path for the client certificate is defined. */
#ifndef CLIENT_CERT_PATH
#ifndef CLIENT_CERTIFICATE_PEM
#error "Please define a CLIENT_CERT_PATH."
extern const uint8_t client_cert_pem_start[] asm("_binary_client_crt_start");
extern const uint8_t client_cert_pem_end[] asm("_binary_client_crt_end");
#endif
#endif

#ifndef CLIENT_PRIVATE_KEY_PEM
/* Check that a path for the client's private key is defined. */
extern const uint8_t client_key_pem_start[] asm("_binary_client_key_start");
#ifndef CLIENT_PRIVATE_KEY_PATH
extern const uint8_t client_key_pem_end[] asm("_binary_client_key_end");
#error "Please define a CLIENT_PRIVATE_KEY_PATH."
#endif
#endif


/**
/**
* @brief ALPN protocol name to be sent as part of the ClientHello message.
* @brief ALPN protocol name to be sent as part of the ClientHello message.
*
*
* @note When using ALPN, port 443 must be used to connect to AWS IoT Core.
* @note When using ALPN, port 443 must be used to connect to AWS IoT Core.
*/
*/
#define IOT_CORE_ALPN_PROTOCOL_NAME "\x0ex-amzn-http-ca"
#define IOT_CORE_ALPN_PROTOCOL_NAME "x-amzn-http-ca"


/* Check that transport timeout for transport send and receive is defined. */
/* Check that transport timeout for transport send and receive is defined. */
#ifndef TRANSPORT_SEND_RECV_TIMEOUT_MS
#ifndef TRANSPORT_SEND_RECV_TIMEOUT_MS
#define TRANSPORT_SEND_RECV_TIMEOUT_MS ( 1000 )
#define TRANSPORT_SEND_RECV_TIMEOUT_MS ( 1500 )
#endif
#endif


/* Check that size of the user buffer is defined. */
/* Check that size of the user buffer is defined. */
#ifndef USER_BUFFER_LENGTH
#ifndef USER_BUFFER_LENGTH
#define USER_BUFFER_LENGTH ( 2048 )
#define USER_BUFFER_LENGTH ( 2048 )
#endif
#endif


/* Check that a request body to send for the POST request is defined. */
/* Check that a request body to send for the POST request is defined. */
#ifndef REQUEST_BODY
#ifndef REQUEST_BODY
#error "Please define a REQUEST_BODY."
#error "Please define a REQUEST_BODY."
#endif
#endif


/**
/**
* @brief The length of the AWS IoT Endpoint.
* @brief The length of the AWS IoT Endpoint.
*/
*/
#define AWS_IOT_ENDPOINT_LENGTH ( sizeof( AWS_IOT_ENDPOINT ) - 1 )
#define AWS_IOT_ENDPOINT_LENGTH ( sizeof( AWS_IOT_ENDPOINT ) - 1 )


/**
/**
* @brief The length of the HTTP POST method.
* @brief The length of the HTTP POST method.
*/
*/
#define HTTP_METHOD_POST_LENGTH ( sizeof( HTTP_METHOD_POST ) - 1 )
#define HTTP_METHOD_POST_LENGTH ( sizeof( HTTP_METHOD_POST ) - 1 )


/**
/**
* @brief The length of the HTTP POST path.
* @brief The length of the HTTP POST path.
*/
*/
#define POST_PATH_LENGTH ( sizeof( POST_PATH ) - 1 )
#define POST_PATH_LENGTH ( sizeof( POST_PATH ) - 1 )


/**
/**
* @brief Length of the request body.
* @brief Length of the request body.
*/
*/
#define REQUEST_BODY_LENGTH ( sizeof( REQUEST_BODY ) - 1 )
#define REQUEST_BODY_LENGTH ( sizeof( REQUEST_BODY ) - 1 )


/**
/**
* @brief A buffer used in the demo for storing HTTP request headers and
* @brief A buffer used in the demo for storing HTTP request headers and
* HTTP response headers and body.
* HTTP response headers and body.
*
*
* @note This demo shows how the same buffer can be re-used for storing the HTTP
* @note This demo shows how the same buffer can be re-used for storing the HTTP
* response after the HTTP request is sent out. However, the user can also
* response after the HTTP request is sent out. However, the user can also
* decide to use separate buffers for storing the HTTP request and response.
* decide to use separate buffers for storing the HTTP request and response.
*/
*/
static uint8_t userBuffer[ USER_BUFFER_LENGTH ];
static uint8_t userBuffer[ USER_BUFFER_LENGTH ];


/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/


/* Each compilation unit must define the NetworkContext struct. */
struct NetworkContext
{
OpensslParams_t * pParams;
};

/*-----------------------------------------------------------*/

/**
/**
* @brief Connect to HTTP server with reconnection retries.
* @brief Connect to HTTP server with reconnection retries.
*
*
* @param[out] pNetworkContext The output parameter to return the created network context.
* @param[out] pNetworkContext The output parameter to return the created network context.
*
*
* @return EXIT_FAILURE on failure; EXIT_SUCCESS on successful connection.
* @return EXIT_FAILURE on failure; EXIT_SUCCESS on successful connection.
*/
*/
static int32_t connectToServer( NetworkContext_t * pNetworkContext );
static int32_t connectToServer( NetworkContext_t * pNetworkContext );


/**
/**
* @brief Send an HTTP request based on a specified method and path, then
* @brief Send an HTTP request based on a specified method and path, then
* print the response received from the server.
* print the response received from the server.
*
*
* @param[in] pTransportInterface The transport interface for making network calls.
* @param[in] pTransportInterface The transport interface for making network calls.
* @param[in] pMethod The HTTP request method.
* @param[in] pMethod The HTTP request method.
* @param[in] methodLen The length of the HTTP request method.
* @param[in] methodLen The length of the HTTP request method.
* @param[in] pPath The Request-URI to the objects of interest.
* @param[in] pPath The Request-URI to the objects of interest.
* @param[in] pathLen The length of the Request-URI.
* @param[in] pathLen The length of the Request-URI.
*
*
* @return EXIT_FAILURE on failure; EXIT_SUCCESS on success.
* @return EXIT_FAILURE on failure; EXIT_SUCCESS on success.
*/
*/
static int32_t sendHttpRequest( const TransportInterface_t * pTransportInterface,
static int32_t sendHttpRequest( const TransportInterface_t * pTransportInterface,
const char * pMethod,
const char * pMethod,
size_t methodLen,
size_t methodLen,
const char * pPath,
const char * pPath,
size_t pathLen );
size_t pathLen );


/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/


static int32_t connectToServer( NetworkContext_t * pNetworkContext )
static int32_t connectToServer( NetworkContext_t * pNetworkContext )
{
{
int32_t returnStatus = EXIT_FAILURE;
int32_t returnStatus = EXIT_FAILURE;
/* Status returned by OpenSSL transport implementation. */
/* Status returned by OpenSSL transport implementation. */
OpensslStatus_t opensslStatus;
TlsTransportStatus_t opensslStatus;
/* Credentials to establish the TLS connection. */
/* Credentials to establish the TLS connection. */
OpensslCredentials_t opensslCredentials;
NetworkCredentials_t *opensslCredentials = (NetworkCredentials_t*) malloc (sizeof (NetworkCredentials_t));
/* Information about the server to send the HTTP requests. */
/* Information about the server to send the HTTP requests. */
ServerInfo_t serverInfo;
ServerInfo_t serverInfo;


/* Initialize TLS credentials. */
/* Initialize TLS credentials. */
( void ) memset( &opensslCredentials, 0, sizeof( opensslCredentials ) );
opensslCredentials->pClientCert = ( const unsigned char * ) client_cert_pem_start;
opensslCredentials.pClientCertPath = CLIENT_CERT_PATH;
opensslCredentials->clientCertSize = client_cert_pem_end - client_cert_pem_start;
opensslCredentials.pPrivateKeyPath = CLIENT_PRIVATE_KEY_PATH;
opensslCredentials->pPrivateKey = ( const unsigned char * ) client_key_pem_start;
opensslCredentials.pRootCaPath = ROOT_CA_CERT_PATH;
opensslCredentials->privateKeySize = client_key_pem_end - client_key_pem_start;
opensslCredentials.sniHostName = AWS_IOT_ENDPOINT;
opensslCredentials->pRootCa = ( const unsigned char * ) root_cert_auth_pem_start;
opensslCredentials->rootCaSize = root_cert_auth_pem_end - root_cert_auth_pem_start;
opensslCredentials->disableSni = 0;


/* ALPN is required when communicating to AWS IoT Core over port 443 through HTTP. */
/* ALPN is required when communicating to AWS IoT Core over port 443 through HTTP. */
if( AWS_HTTPS_PORT == 443 )
if( AWS_HTTPS_PORT == 443 )
{
{
opensslCredentials.pAlpnProtos = IOT_CORE_ALPN_PROTOCOL_NAME;
static const char * pcAlpnProtocols[] = { NULL, NULL };
opensslCredentials.alpnProtosLen = strlen( IOT_CORE_ALPN_PROTOCOL_NAME );
pcAlpnProtocols[0] = IOT_CORE_ALPN_PROTOCOL_NAME;
opensslCredentials->pAlpnProtos = pcAlpnProtocols;

} else {
opensslCredentials->pAlpnProtos = NULL;
}
}


/* Initialize server information. */
/* Initialize server information. */
serverInfo.pHostName = AWS_IOT_ENDPOINT;
serverInfo.pHostName = AWS_IOT_ENDPOINT;
serverInfo.hostNameLength = AWS_IOT_ENDPOINT_LENGTH;
serverInfo.hostNameLength = AWS_IOT_ENDPOINT_LENGTH;
serverInfo.port = AWS_HTTPS_PORT;
serverInfo.port = AWS_HTTPS_PORT;


/* Establish a TLS session with the HTTP server. This example connects
/* Establish a TLS session with the HTTP server. This example connects
* to the HTTP server as specified in AWS_IOT_ENDPOINT and AWS_HTTPS_PORT
* to the HTTP server as specified in AWS_IOT_ENDPOINT and AWS_HTTPS_PORT
* in demo_config.h. */
* in demo_config.h. */
LogInfo( ( "Establishing a TLS session to %.*s:%d.",
LogInfo( ( "Establishing a TLS session to %.*s:%d.",
( int32_t ) AWS_IOT_ENDPOINT_LENGTH,
( int32_t ) AWS_IOT_ENDPOINT_LENGTH,
AWS_IOT_ENDPOINT,
AWS_IOT_ENDPOINT,
AWS_HTTPS_PORT ) );
AWS_HTTPS_PORT ) );
opensslStatus = Openssl_Connect( pNetworkContext,
opensslStatus = TLS_FreeRTOS_Connect ( pNetworkContext,
&serverInfo,
serverInfo.pHostName,
&opensslCredentials,
serverInfo.port,
TRANSPORT_SEND_RECV_TIMEOUT_MS,
opensslCredentials,
TRANSPORT_SEND_RECV_TIMEOUT_MS );
TRANSPORT_SEND_RECV_TIMEOUT_MS,
TRANSPORT_SEND_RECV_TIMEOUT_MS );


if( opensslStatus == OPENSSL_SUCCESS )
if( opensslStatus == TLS_TRANSPORT_SUCCESS )
{
{
returnStatus = EXIT_SUCCESS;
returnStatus = EXIT_SUCCESS;
}
}
else
else
{
{
returnStatus = EXIT_FAILURE;
returnStatus = EXIT_FAILURE;
}
}


return returnStatus;
return returnStatus;
}
}


/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/


static int32_t sendHttpRequest( const TransportInterface_t * pTransportInterface,
static int32_t sendHttpRequest( const TransportInterface_t * pTransportInterface,
const char * pMethod,
const char * pMethod,
size_t methodLen,
size_t methodLen,
const char * pPath,
const char * pPath,
size_t pathLen )
size_t pathLen )
{
{
/* Return value of this method. */
/* Return value of this method. */
int32_t returnStatus = EXIT_SUCCESS;
int32_t returnStatus = EXIT_SUCCESS;


/* Configurations of the initial request headers that are passed to
/* Configurations of the initial request headers that are passed to
* #HTTPClient_InitializeRequestHeaders. */
* #HTTPClient_InitializeRequestHeaders. */
HTTPRequestInfo_t requestInfo;
HTTPRequestInfo_t requestInfo;
/* Represents a response returned from an HTTP server. */
/* Represents a response returned from an HTTP server. */
HTTPResponse_t response;
HTTPResponse_t response;
/* Represents header data that will be sent in an HTTP request. */
/* Represents header data that will be sent in an HTTP request. */
HTTPRequestHeaders_t requestHeaders;
HTTPRequestHeaders_t requestHeaders;


/* Return value of all methods from the HTTP Client library API. */
/* Return value of all methods from the HTTP Client library API. */
HTTPStatus_t httpStatus = HTTPSuccess;
HTTPStatus_t httpStatus = HTTPSuccess;


assert( pMethod != NULL );
assert( pMethod != NULL );
assert( pPath != NULL );
assert( pPath != NULL );


/* Initialize all HTTP Client library API structs to 0. */
/* Initialize all HTTP Client library API structs to 0. */
( void ) memset( &requestInfo, 0, sizeof( requestInfo ) );
( void ) memset( &requestInfo, 0, sizeof( requestInfo ) );
( void ) memset( &response, 0, sizeof( response ) );
( void ) memset( &response, 0, sizeof( response ) );
( void ) memset( &requestHeaders, 0, sizeof( requestHeaders ) );
( void ) memset( &requestHeaders, 0, sizeof( requestHeaders ) );


/* Initialize the request object. */
/* Initialize the request object. */
requestInfo.pHost = AWS_IOT_ENDPOINT;
requestInfo.pHost = AWS_IOT_ENDPOINT;
requestInfo.hostLen = AWS_IOT_ENDPOINT_LENGTH;
requestInfo.hostLen = AWS_IOT_ENDPOINT_LENGTH;
requestInfo.pMethod = pMethod;
requestInfo.pMethod = pMethod;
requestInfo.methodLen = methodLen;
requestInfo.methodLen = methodLen;
requestInfo.pPath = pPath;
requestInfo.pPath = pPath;
requestInfo.pathLen = pathLen;
requestInfo.pathLen = pathLen;


/* Set "Connection" HTTP header to "keep-alive" so that multiple requests
/* Set "Connection" HTTP header to "keep-alive" so that multiple requests
* can be sent over the same established TCP connection. */
* can be sent over the same established TCP connection. */
requestInfo.reqFlags = HTTP_REQUEST_KEEP_ALIVE_FLAG;
requestInfo.reqFlags = HTTP_REQUEST_KEEP_ALIVE_FLAG;


/* Set the buffer used for storing request headers. */
/* Set the buffer used for storing request headers. */
requestHeaders.pBuffer = userBuffer;
requestHeaders.pBuffer = userBuffer;
requestHeaders.bufferLen = USER_BUFFER_LENGTH;
requestHeaders.bufferLen = USER_BUFFER_LENGTH;


httpStatus = HTTPClient_InitializeRequestHeaders( &requestHeaders,
httpStatus = HTTPClient_InitializeRequestHeaders( &requestHeaders,
&requestInfo );
&requestInfo );


if( httpStatus == HTTPSuccess )
if( httpStatus == HTTPSuccess )
{
{
/* Initialize the response object. The same buffer used for storing
/* Initialize the response object. The same buffer used for storing
* request headers is reused here. */
* request headers is reused here. */
response.pBuffer = userBuffer;
response.pBuffer = userBuffer;
response.bufferLen = USER_BUFFER_LENGTH;
response.bufferLen = USER_BUFFER_LENGTH;


LogInfo( ( "Sending HTTP %.*s request to %.*s%.*s...",
LogInfo( ( "Sending HTTP %.*s request to %.*s%.*s...",
( int32_t ) requestInfo.methodLen, requestInfo.pMethod,
( int32_t ) requestInfo.methodLen, requestInfo.pMethod,
( int32_t ) AWS_IOT_ENDPOINT_LENGTH, AWS_IOT_ENDPOINT,
( int32_t ) AWS_IOT_ENDPOINT_LENGTH, AWS_IOT_ENDPOINT,
( int32_t ) requestInfo.pathLen, requestInfo.pPath ) );
( int32_t ) requestInfo.pathLen, requestInfo.pPath ) );
LogDebug( ( "Request Headers:\n%.*s\n"
LogDebug( ( "Request Headers:\n%.*s\n"
"Request Body:\n%.*s\n",
"Request Body:\n%.*s\n",
( int32_t ) requestHeaders.headersLen,
( int32_t ) requestHeaders.headersLen,
( char * ) requestHeaders.pBuffer,
( char * ) requestHeaders.pBuffer,
( int32_t ) REQUEST_BODY_LENGTH, REQUEST_BODY ) );
( int32_t ) REQUEST_BODY_LENGTH, REQUEST_BODY ) );


/* Send the request and receive the response. */
/* Send the request and receive the response. */
httpStatus = HTTPClient_Send( pTransportInterface,
httpStatus = HTTPClient_Send( pTransportInterface,
&requestHeaders,
&requestHeaders,
( uint8_t * ) REQUEST_BODY,
( uint8_t * ) REQUEST_BODY,
REQUEST_BODY_LENGTH,
REQUEST_BODY_LENGTH,
&response,
&response,
0 );
0 );
}
}
else
else
{
{
LogError( ( "Failed to initialize HTTP request headers: Error=%s.",
LogError( ( "Failed to initialize HTTP request headers: Error=%s.",
HTTPClient_strerror( httpStatus ) ) );
HTTPClient_strerror( httpStatus ) ) );
}
}


if( httpStatus == HTTPSuccess )
if( httpStatus == HTTPSuccess )
{
{
LogInfo( ( "Received HTTP response from %.*s%.*s...\n"
LogInfo( ( "Received HTTP response from %.*s%.*s...\n"
"Response Headers:\n%.*s\n"
"Response Headers:\n%.*s\n"
"Response Status:\n%u\n"
"Response Status:\n%u\n"
"Response Body:\n%.*s\n",
"Response Body:\n%.*s\n",
( int32_t ) AWS_IOT_ENDPOINT_LENGTH, AWS_IOT_ENDPOINT,
( int32_t ) AWS_IOT_ENDPOINT_LENGTH, AWS_IOT_ENDPOINT,
( int32_t ) requestInfo.pathLen, requestInfo.pPath,
( int32_t ) requestInfo.pathLen, requestInfo.pPath,
( int32_t ) response.headersLen, response.pHeaders,
( int32_t ) response.headersLen, response.pHeaders,
response.statusCode,
response.statusCode,
( int32_t ) response.bodyLen, response.pBody ) );
( int32_t ) response.bodyLen, response.pBody ) );
}
}
else
else
{
{
LogError( ( "Failed to send HTTP %.*s request to %.*s%.*s: Error=%s.",
LogError( ( "Failed to send HTTP %.*s request to %.*s%.*s: Error=%s.",
( int32_t ) requestInfo.methodLen, requestInfo.pMethod,
( int32_t ) requestInfo.methodLen, requestInfo.pMethod,
( int32_t ) AWS_IOT_ENDPOINT_LENGTH, AWS_IOT_ENDPOINT,
( int32_t ) AWS_IOT_ENDPOINT_LENGTH, AWS_IOT_ENDPOINT,
( int32_t ) requestInfo.pathLen, requestInfo.pPath,
( int32_t ) requestInfo.pathLen, requestInfo.pPath,
HTTPClient_strerror( httpStatus ) ) );
HTTPClient_strerror( httpStatus ) ) );
}
}


if( httpStatus != HTTPSuccess )
if( httpStatus != HTTPSuccess )
{
{
returnStatus = EXIT_FAILURE;
returnStatus = EXIT_FAILURE;
}
}


return returnStatus;
return returnStatus;
}
}


/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/


/**
/**
* @brief Entry point of demo.
* @brief Entry point of demo.
*
*
* This example resolves the AWS IoT Core endpoint, establishes a TCP connection,
* This example resolves the AWS IoT Core endpoint, establishes a TCP connection,
* performs a mutually authenticated TLS handshake occurs such that all further
* performs a mutually authenticated TLS handshake occurs such that all further
* communication is encrypted. After which, HTTP Client Library API is used to
* communication is encrypted. After which, HTTP Client Library API is used to
* make a POST request to AWS IoT Core in order to publish a message to a topic
* make a POST request to AWS IoT Core in order to publish a message to a topic
* named topic with QoS=1 so that all clients subscribed to the topic receive
* named topic with QoS=1 so that all clients subscribed to the topic receive
* the message at least once. Any possible errors are also logged.
* the message at least once. Any possible errors are also logged.
*
*
* @note This example is single-threaded and uses statically allocated memory.
* @note This example is single-threaded and uses statically allocated memory.
*
*
*/
*/
int main( int argc,
int aws_iot_demo_main( int argc,
char ** argv )
char ** argv )
{
{
/* Return value of main. */
/* Return value of main. */
int32_t returnStatus = EXIT_SUCCESS;
int32_t returnStatus = EXIT_SUCCESS;
/* The transport layer interface used by the HTTP Client library. */
/* The transport layer interface used by the HTTP Client library. */
TransportInterface_t transportInterface;
TransportInterface_t transportInterface;
/* The network context for the transport layer interface. */
/* The network context for the transport layer interface. */
NetworkContext_t networkContext;
NetworkContext_t networkContext;
OpensslParams_t opensslParams;


( void ) argc;
( void ) argc;
( void ) argv;
( void ) argv;


/* Set the pParams member of the network context with desired transport. */
/* Set the pParams member of the network context with desired transport. */
networkContext.pParams = &opensslParams;


/**************************** Connect. ******************************/
/**************************** Connect. ******************************/


/* Establish TLS connection on top of TCP connection using OpenSSL. */
/* Establish TLS connection on top of TCP connection using OpenSSL. */
if( returnStatus == EXIT_SUCCESS )
if( returnStatus == EXIT_SUCCESS )
{
{
LogInfo( ( "Performing TLS handshake on top of the TCP connection." ) );
LogInfo( ( "Performing TLS handshake on top of the TCP connection." ) );


/* Attempt to connect to the HTTP server. If connection fails, retry after
/* Attempt to connect to the HTTP server. If connection fails, retry after
* a timeout. Timeout value will be exponentially increased till the maximum
* a timeout. Timeout value will be exponentially increased till the maximum
* attempts are reached or maximum timeout value is reached. The function
* attempts are reached or maximum timeout value is reached. The function
* returns EXIT_FAILURE if the TCP connection cannot be established to
* returns EXIT_FAILURE if the TCP connection cannot be established to
* broker after configured number of attempts. */
* broker after configured number of attempts. */
returnStatus = connectToServerWithBackoffRetries( connectToServer,
returnStatus = connectToServerWithBackoffRetries( connectToServer,
&networkContext );
&networkContext );


if( returnStatus == EXIT_FAILURE )
if( returnStatus == EXIT_FAILURE )
{
{
/* Log error to indicate connection failure after all
/* Log error to indicate connection failure after all
* reconnect attempts are over. */
* reconnect attempts are over. */
LogError( ( "Failed to connect to HTTP server %.*s.",
LogError( ( "Failed to connect to HTTP server %.*s.",
( int32_t ) AWS_IOT_ENDPOINT_LENGTH,
( int32_t ) AWS_IOT_ENDPOINT_LENGTH,
AWS_IOT_ENDPOINT ) );
AWS_IOT_ENDPOINT ) );
}
}
}
}


/* Define the transport interface. */
/* Define the transport interface. */
if( returnStatus == EXIT_SUCCESS )
if( returnStatus == EXIT_SUCCESS )
{
{
( void ) memset( &transportInterface, 0, sizeof( transportInterface ) );
( void ) memset( &transportInterface, 0, sizeof( transportInterface ) );
transportInterface.recv = Openssl_Recv;
transportInterface.recv = TLS_FreeRTOS_recv;
transportInterface.send = Openssl_Send;
transportInterface.send = TLS_FreeRTOS_send;
transportInterface.pNetworkContext = &networkContext;
transportInterface.pNetworkContext = &networkContext;
}
}


/*********************** Send HTTPS request. ************************/
/*********************** Send HTTPS request. ************************/


if( returnStatus == EXIT_SUCCESS )
if( returnStatus == EXIT_SUCCESS )
{
{
returnStatus = sendHttpRequest( &transportInterface,
returnStatus = sendHttpRequest( &transportInterface,
HTTP_METHOD_POST,
HTTP_METHOD_POST,
HTTP_METHOD_POST_LENGTH,
HTTP_METHOD_POST_LENGTH,
POST_PATH,
POST_PATH,
POST_PATH_LENGTH );
POST_PATH_LENGTH );
}
}


if( returnStatus == EXIT_SUCCESS )
if( returnStatus == EXIT_SUCCESS )
{
{
/* Log message indicating an iteration completed successfully. */
/* Log message indicating an iteration completed successfully. */
LogInfo( ( "Demo completed successfully." ) );
LogInfo( ( "Demo completed successfully." ) );
}
}


/************************** Disconnect. *****************************/
/************************** Disconnect. *****************************/


/* End TLS session, then close TCP connection. */
/* End TLS session, then close TCP connection. */
( void ) Openssl_Disconnect( &networkContext );
( void ) TLS_FreeRTOS_Disconnect( &networkContext );


return returnStatus;
return returnStatus;
}
}