diff --git a/.gitmodules b/.gitmodules index b12b4b5cbf..9ac800c5a6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -31,3 +31,6 @@ [submodule "FreeRTOS-Plus/Source/AWS/device-defender"] path = FreeRTOS-Plus/Source/AWS/device-defender url = https://github.com/aws/device-defender-for-aws-iot-embedded-sdk.git +[submodule "FreeRTOS-Plus/Source/Application-Protocols/coreHTTP"] + path = FreeRTOS-Plus/Source/Application-Protocols/coreHTTP + url = https://github.com/FreeRTOS/coreHTTP diff --git a/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Common/main.c b/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Common/main.c new file mode 100644 index 0000000000..17b5c3900b --- /dev/null +++ b/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Common/main.c @@ -0,0 +1,376 @@ +/* + * FreeRTOS Kernel V10.3.0 + * 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 + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * 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, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * 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 + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + */ + +/*** + * See https://www.FreeRTOS.org for configuration and usage instructions. + ***/ + +/* Standard includes. */ +#include +#include + +/* Visual studio intrinsics used so the __debugbreak() function is available + * should an assert get hit. */ +#include + +/* FreeRTOS includes. */ +#include +#include "task.h" + +/* TCP/IP stack includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* Demo logging includes. */ +#include "logging.h" + +/* Demo Specific configs. */ +#include "demo_config.h" + + +/* + * Prototypes for the demos that can be started from this project. Note that the + * HTTP demo is not actually started until the network is ready, which is + * indicated by vApplicationIPNetworkEventHook() executing - hence + * vStartSimpleHTTPDemo() is called from inside vApplicationIPNetworkEventHook(). + */ +extern void vStartSimpleHTTPDemo( void ); + +/* + * Just seeds the simple pseudo random number generator. + * + * !!! NOTE !!! + * This is not a secure method of generating random numbers and production + * devices should use a true random number generator (TRNG). + */ +static void prvSRand( UBaseType_t ulSeed ); + +/* + * Miscellaneous initialization including preparing the logging and seeding the + * random number generator. + */ +static void prvMiscInitialisation( void ); + +/* The default IP and MAC address used by the demo. The address configuration + * defined here will be used if ipconfigUSE_DHCP is 0, or if ipconfigUSE_DHCP is + * 1 but a DHCP server could not be contacted. See the online documentation for + * more information. */ +static const uint8_t ucIPAddress[ 4 ] = { configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 }; +static const uint8_t ucNetMask[ 4 ] = { configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3 }; +static const uint8_t ucGatewayAddress[ 4 ] = { configGATEWAY_ADDR0, configGATEWAY_ADDR1, configGATEWAY_ADDR2, configGATEWAY_ADDR3 }; +static const uint8_t ucDNSServerAddress[ 4 ] = { configDNS_SERVER_ADDR0, configDNS_SERVER_ADDR1, configDNS_SERVER_ADDR2, configDNS_SERVER_ADDR3 }; + +/* Set the following constant to pdTRUE to log using the method indicated by the + * name of the constant, or pdFALSE to not log using the method indicated by the + * name of the constant. Options include to standard out (xLogToStdout), to a disk + * file (xLogToFile), and to a UDP port (xLogToUDP). If xLogToUDP is set to pdTRUE + * then UDP messages are sent to the IP address configured as the UDP logging server + * address (see the configUDP_LOGGING_ADDR0 definitions in FreeRTOSConfig.h) and + * the port number set by configPRINT_PORT in FreeRTOSConfig.h. */ +const BaseType_t xLogToStdout = pdTRUE, xLogToFile = pdFALSE, xLogToUDP = pdFALSE; + +/* Default MAC address configuration. The demo creates a virtual network + * connection that uses this MAC address by accessing the raw Ethernet data + * to and from a real network connection on the host PC. See the + * configNETWORK_INTERFACE_TO_USE definition for information on how to configure + * the real network connection to use. */ +const uint8_t ucMACAddress[ 6 ] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 }; + +/* Used by the pseudo random number generator. */ +static UBaseType_t ulNextRand; +/*-----------------------------------------------------------*/ + +int main( void ) +{ + /* Miscellaneous initialization including preparing the logging and seeding + * the random number generator. */ + prvMiscInitialisation(); + + /* Initialize the network interface. + * + ***NOTE*** Tasks that use the network are created in the network event hook + * when the network is connected and ready for use (see the implementation of + * vApplicationIPNetworkEventHook() below). The address values passed in here + * are used if ipconfigUSE_DHCP is set to 0, or if ipconfigUSE_DHCP is set to 1 + * but a DHCP server cannot be contacted. */ + FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress ); + + /* Start the RTOS scheduler. */ + vTaskStartScheduler(); + + /* If all is well, the scheduler will now be running, and the following + * line will never be reached. If the following line does execute, then + * there was insufficient FreeRTOS heap memory available for the idle and/or + * timer tasks to be created. See the memory management section on the + * FreeRTOS web site for more details (this is standard text that is not + * really applicable to the Win32 simulator port). */ + for( ; ; ) + { + __debugbreak(); + } +} +/*-----------------------------------------------------------*/ + +/* Called by FreeRTOS+TCP when the network connects or disconnects. Disconnect + * events are only received if implemented in the MAC driver. */ +void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent ) +{ + uint32_t ulIPAddress, ulNetMask, ulGatewayAddress, ulDNSServerAddress; + char cBuffer[ 16 ]; + static BaseType_t xTasksAlreadyCreated = pdFALSE; + + /* If the network has just come up...*/ + if( eNetworkEvent == eNetworkUp ) + { + /* Create the tasks that use the IP stack if they have not already been + * created. */ + if( xTasksAlreadyCreated == pdFALSE ) + { + /* Demos that use the network are created after the network is + * up. */ + LogInfo( ( "---------STARTING DEMO---------\r\n" ) ); + vStartSimpleHTTPDemo(); + xTasksAlreadyCreated = pdTRUE; + } + + /* Print out the network configuration, which may have come from a DHCP + * server. */ + FreeRTOS_GetAddressConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress ); + FreeRTOS_inet_ntoa( ulIPAddress, cBuffer ); + LogInfo( ( "\r\n\r\nIP Address: %s\r\n", cBuffer ) ); + + FreeRTOS_inet_ntoa( ulNetMask, cBuffer ); + LogInfo( ( "Subnet Mask: %s\r\n", cBuffer ) ); + + FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer ); + LogInfo( ( "Gateway Address: %s\r\n", cBuffer ) ); + + FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer ); + LogInfo( ( "DNS Server Address: %s\r\n\r\n\r\n", cBuffer ) ); + } +} +/*-----------------------------------------------------------*/ + +void vAssertCalled( const char * pcFile, + uint32_t ulLine ) +{ + volatile uint32_t ulBlockVariable = 0UL; + volatile char * pcFileName = ( volatile char * ) pcFile; + volatile uint32_t ulLineNumber = ulLine; + + ( void ) pcFileName; + ( void ) ulLineNumber; + + printf( "vAssertCalled( %s, %u\n", pcFile, ulLine ); + + /* Setting ulBlockVariable to a non-zero value in the debugger will allow + * this function to be exited. */ + taskDISABLE_INTERRUPTS(); + { + while( ulBlockVariable == 0UL ) + { + __debugbreak(); + } + } + taskENABLE_INTERRUPTS(); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxRand( void ) +{ + const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL; + + /* + * Utility function to generate a pseudo random number. + * + * !!!NOTE!!! + * This is not a secure method of generating a random number. Production + * devices should use a True Random Number Generator (TRNG). + */ + ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement; + return( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL ); +} +/*-----------------------------------------------------------*/ + +static void prvSRand( UBaseType_t ulSeed ) +{ + /* Utility function to seed the pseudo random number generator. */ + ulNextRand = ulSeed; +} +/*-----------------------------------------------------------*/ + +static void prvMiscInitialisation( void ) +{ + time_t xTimeNow; + uint32_t ulLoggingIPAddress; + + ulLoggingIPAddress = FreeRTOS_inet_addr_quick( configUDP_LOGGING_ADDR0, configUDP_LOGGING_ADDR1, configUDP_LOGGING_ADDR2, configUDP_LOGGING_ADDR3 ); + vLoggingInit( xLogToStdout, xLogToFile, xLogToUDP, ulLoggingIPAddress, configPRINT_PORT ); + + /* + * Seed random number generator. + * + * !!!NOTE!!! + * This is not a secure method of generating a random number. Production + * devices should use a True Random Number Generator (TRNG). + */ + time( &xTimeNow ); + LogDebug( ( "Seed for randomizer: %lu\n", xTimeNow ) ); + prvSRand( ( uint32_t ) xTimeNow ); + LogDebug( ( "Random numbers: %08X %08X %08X %08X\n", ipconfigRAND32(), ipconfigRAND32(), ipconfigRAND32(), ipconfigRAND32() ) ); +} +/*-----------------------------------------------------------*/ + +#if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) || ( ipconfigDHCP_REGISTER_HOSTNAME == 1 ) + + const char * pcApplicationHostnameHook( void ) + { + /* Assign the name "FreeRTOS" to this network node. This function will + * be called during the DHCP: the machine will be registered with an IP + * address plus this name. */ + return mainHOST_NAME; + } + +#endif +/*-----------------------------------------------------------*/ + +#if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) + + BaseType_t xApplicationDNSQueryHook( const char * pcName ) + { + BaseType_t xReturn; + + /* Determine if a name lookup is for this node. Two names are given + * to this node: that returned by pcApplicationHostnameHook() and that set + * by mainDEVICE_NICK_NAME. */ + if( _stricmp( pcName, pcApplicationHostnameHook() ) == 0 ) + { + xReturn = pdPASS; + } + else if( _stricmp( pcName, mainDEVICE_NICK_NAME ) == 0 ) + { + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + + return xReturn; + } + +#endif /* if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) */ +/*-----------------------------------------------------------*/ + +/* + * Callback that provides the inputs necessary to generate a randomized TCP + * Initial Sequence Number per RFC 6528. THIS IS ONLY A DUMMY IMPLEMENTATION + * THAT RETURNS A PSEUDO RANDOM NUMBER SO IS NOT INTENDED FOR USE IN PRODUCTION + * SYSTEMS. + */ +extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress, + uint16_t usSourcePort, + uint32_t ulDestinationAddress, + uint16_t usDestinationPort ) +{ + ( void ) ulSourceAddress; + ( void ) usSourcePort; + ( void ) ulDestinationAddress; + ( void ) usDestinationPort; + + return uxRand(); +} +/*-----------------------------------------------------------*/ + +/* + * Set *pulNumber to a random number, and return pdTRUE. When the random number + * generator is broken, it shall return pdFALSE. + * The macros ipconfigRAND32() and configRAND32() are not in use + * anymore in FreeRTOS+TCP. + * + * THIS IS ONLY A DUMMY IMPLEMENTATION THAT RETURNS A PSEUDO RANDOM NUMBER SO IS + * NOT INTENDED FOR USE IN PRODUCTION SYSTEMS. + */ +BaseType_t xApplicationGetRandomNumber( uint32_t * pulNumber ) +{ + *pulNumber = uxRand(); + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an + * implementation of vApplicationGetIdleTaskMemory() to provide the memory that is + * used by the Idle task. */ +void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer, + StackType_t ** ppxIdleTaskStackBuffer, + uint32_t * pulIdleTaskStackSize ) +{ + /* If the buffers to be provided to the Idle task are declared inside this + * function then they must be declared static - otherwise they will be allocated on + * the stack and so not exists after this function exits. */ + static StaticTask_t xIdleTaskTCB; + static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; + + /* Pass out a pointer to the StaticTask_t structure in which the Idle task's + * state will be stored. */ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + + /* Pass out the array that will be used as the Idle task's stack. */ + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + + /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. + * Note that, as the array is necessarily of type StackType_t, + * configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; +} +/*-----------------------------------------------------------*/ + +/* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the + * application must provide an implementation of vApplicationGetTimerTaskMemory() + * to provide the memory that is used by the Timer service task. */ +void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer, + StackType_t ** ppxTimerTaskStackBuffer, + uint32_t * pulTimerTaskStackSize ) +{ + /* If the buffers to be provided to the Timer task are declared inside this + * function then they must be declared static - otherwise they will be allocated on + * the stack and so not exists after this function exits. */ + static StaticTask_t xTimerTaskTCB; + static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; + + /* Pass out a pointer to the StaticTask_t structure in which the Timer + * task's state will be stored. */ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + + /* Pass out the array that will be used as the Timer task's stack. */ + *ppxTimerTaskStackBuffer = uxTimerTaskStack; + + /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. + * Note that, as the array is necessarily of type StackType_t, + * configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Http_Demo_Helpers/http_demo_utils.c b/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Http_Demo_Helpers/http_demo_utils.c new file mode 100644 index 0000000000..824c3131dc --- /dev/null +++ b/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Http_Demo_Helpers/http_demo_utils.c @@ -0,0 +1,196 @@ +/* + * FreeRTOS Kernel V10.3.0 + * 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 + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * 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, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * 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 + * 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. + */ + +/* Standard includes. */ +#include + +#include "http_demo_utils.h" + +/* Exponential backoff retry include. */ +#include "exponential_backoff.h" + +/* Parser utilities. */ +#include "http_parser.h" + +/*-----------------------------------------------------------*/ + +BaseType_t connectToServerWithBackoffRetries( TransportConnect_t connectFunction, + NetworkContext_t * pxNetworkContext ) +{ + BaseType_t xReturn = pdFAIL; + /* Status returned by the retry utilities. */ + RetryUtilsStatus_t xRetryUtilsStatus = RetryUtilsSuccess; + /* Struct containing the next backoff time. */ + RetryUtilsParams_t xReconnectParams; + + assert( connectFunction != NULL ); + + /* Initialize reconnect attempts and interval */ + RetryUtils_ParamsReset( &xReconnectParams ); + xReconnectParams.maxRetryAttempts = MAX_RETRY_ATTEMPTS; + + /* Attempt to connect to the HTTP server. If connection fails, retry after a + * timeout. The timeout value will exponentially increase until either the + * maximum timeout value is reached or the set number of attempts are + * exhausted.*/ + do + { + xReturn = connectFunction( pxNetworkContext ); + + if( xReturn != pdPASS ) + { + LogWarn( ( "Connection to the HTTP server failed. " + "Retrying connection with backoff and jitter." ) ); + LogInfo( ( "Retry attempt %lu out of maximum retry attempts %lu.", + ( xReconnectParams.attemptsDone + 1 ), + MAX_RETRY_ATTEMPTS ) ); + xRetryUtilsStatus = RetryUtils_BackoffAndSleep( &xReconnectParams ); + } + } while( ( xReturn == pdFAIL ) && ( xRetryUtilsStatus == RetryUtilsSuccess ) ); + + if( xReturn == pdFAIL ) + { + LogError( ( "Connection to the server failed, all attempts exhausted." ) ); + } + + return xReturn; +} + +/*-----------------------------------------------------------*/ + +HTTPStatus_t getUrlPath( const char * pcUrl, + size_t xUrlLen, + const char ** pcPath, + size_t * pxPathLen ) +{ + /* http-parser status. Initialized to 1 to signify failure. */ + int lParserStatus = 1; + struct http_parser_url xUrlParser; + HTTPStatus_t xHTTPStatus = HTTPSuccess; + + /* Sets all members in xUrlParser to 0. */ + http_parser_url_init( &xUrlParser ); + + if( ( pcUrl == NULL ) || ( pcPath == NULL ) || ( pxPathLen == NULL ) ) + { + LogError( ( "NULL parameter passed to getUrlPath()." ) ); + xHTTPStatus = HTTPInvalidParameter; + } + + if( xHTTPStatus == HTTPSuccess ) + { + lParserStatus = http_parser_parse_url( pcUrl, xUrlLen, 0, &xUrlParser ); + + if( lParserStatus != 0 ) + { + LogError( ( "Error parsing the input URL %.*s. Error code: %d.", + ( int32_t ) xUrlLen, + pcUrl, + lParserStatus ) ); + xHTTPStatus = HTTPParserInternalError; + } + } + + if( xHTTPStatus == HTTPSuccess ) + { + *pxPathLen = ( size_t ) ( xUrlParser.field_data[ UF_PATH ].len ); + + if( *pxPathLen == 0 ) + { + xHTTPStatus = HTTPNoResponse; + *pcPath = NULL; + } + else + { + *pcPath = &pcUrl[ xUrlParser.field_data[ UF_PATH ].off ]; + } + } + + if( xHTTPStatus != HTTPSuccess ) + { + LogError( ( "Error parsing the path from URL %s. Error code: %d", + pcUrl, + xHTTPStatus ) ); + } + + return xHTTPStatus; +} + +/*-----------------------------------------------------------*/ + +HTTPStatus_t getUrlAddress( const char * pcUrl, + size_t xUrlLen, + const char ** pcAddress, + size_t * pxAddressLen ) +{ + /* http-parser status. Initialized to 1 to signify failure. */ + int lParserStatus = 1; + struct http_parser_url xUrlParser; + HTTPStatus_t xHTTPStatus = HTTPSuccess; + + /* Sets all members in xUrlParser to 0. */ + http_parser_url_init( &xUrlParser ); + + if( ( pcUrl == NULL ) || ( pcAddress == NULL ) || ( pxAddressLen == NULL ) ) + { + LogError( ( "NULL parameter passed to getUrlAddress()." ) ); + xHTTPStatus = HTTPInvalidParameter; + } + + if( xHTTPStatus == HTTPSuccess ) + { + lParserStatus = http_parser_parse_url( pcUrl, xUrlLen, 0, &xUrlParser ); + + if( lParserStatus != 0 ) + { + LogError( ( "Error parsing the input URL %.*s. Error code: %d.", + ( int32_t ) xUrlLen, + pcUrl, + lParserStatus ) ); + xHTTPStatus = HTTPParserInternalError; + } + } + + if( xHTTPStatus == HTTPSuccess ) + { + *pxAddressLen = ( size_t ) ( xUrlParser.field_data[ UF_HOST ].len ); + + if( *pxAddressLen == 0 ) + { + xHTTPStatus = HTTPNoResponse; + *pcAddress = NULL; + } + else + { + *pcAddress = &pcUrl[ xUrlParser.field_data[ UF_HOST ].off ]; + } + } + + if( xHTTPStatus != HTTPSuccess ) + { + LogError( ( "Error parsing the address from URL %s. Error code %d", + pcUrl, + xHTTPStatus ) ); + } + + return xHTTPStatus; +} diff --git a/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Http_Demo_Helpers/http_demo_utils.h b/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Http_Demo_Helpers/http_demo_utils.h new file mode 100644 index 0000000000..3d64421a29 --- /dev/null +++ b/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Http_Demo_Helpers/http_demo_utils.h @@ -0,0 +1,126 @@ +/* + * FreeRTOS Kernel V10.3.0 + * 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 + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * 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, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * 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 + * 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. + */ + +#ifndef HTTP_DEMO_UTILS_H +#define HTTP_DEMO_UTILS_H + +/* Standard includes. */ +#include +#include +#include + +/* Kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Transport interface implementation include header for TLS. */ +#include "using_mbedtls.h" + +/* HTTP API header. */ +#include "core_http_client.h" + +/** + * @brief Function pointer for establishing connection to a server. + * + * @param[out] pxNetworkContext Implementation-defined network context. + * + * @return pdFAIL on failure; pdPASS on successful connection. + */ +typedef BaseType_t ( * TransportConnect_t )( NetworkContext_t * pxNetworkContext ); + +/** + * @brief Connect to a server with reconnection retries. + * + * If connection fails, retry is attempted after a timeout. The timeout value + * will exponentially increase until either the maximum timeout value is reached + * or the set number of attempts are exhausted. + * + * @param[in] connectFunction Function pointer for establishing connection to a + * server. + * @param[out] pxNetworkContext Implementation-defined network context. + * + * @return pdFAIL on failure; pdPASS on successful connection. + */ +BaseType_t connectToServerWithBackoffRetries( TransportConnect_t connectFunction, + NetworkContext_t * pxNetworkContext ); + +/** + * @brief Retrieve the path from the input URL. + * + * This function retrieves the location and length of the path from within the + * input the URL. The query is not included in the length returned. + * + * The URL MUST start with "http://" or "https://" to find the path. + * + * For example, if pcUrl is: + * "https://www.somewebsite.com/path/to/item.txt?optionalquery=stuff" + * + * Then pcPath and pxPathLen will be the following: + * *pcPath = "/path/to/item.txt?optionalquery=stuff" + * *pxPathLen = 17 + * + * @param[in] pcUrl URL string to parse. + * @param[in] xUrlLen The length of the URL string input. + * @param[out] pcPath pointer within input url that the path starts at. + * @param[out] pxPathLen Length of the path. + * + * @return The status of the parsing attempt: + * HTTPSuccess if the path was successfully parsed, + * HTTPParserInternalError if there was an error parsing the URL, + * or HTTPNoResponse if the path was not found. + */ +HTTPStatus_t getUrlPath( const char * pcUrl, + size_t xUrlLen, + const char ** pcPath, + size_t * pxPathLen ); + +/** + * @brief Retrieve the Address from the input URL. + * + * This function retrieves the location and length of the address from within + * the input URL. The path and query are not included in the length returned. + * + * The URL MUST start with "http://" or "https://" to find the address. + * + * For example, if pcUrl is: + * "https://www.somewebsite.com/path/to/item.txt?optionalquery=stuff" + * + * Then pcAddress and pxAddressLen will be the following: + * *pcAddress = "www.somewebsite.com/path/to/item.txt?optionalquery=stuff" + * *pxAddressLen = 19 + * + * @param[in] pcUrl URL string to parse. + * @param[in] xUrlLen The length of the URL string input. + * @param[out] pcAddress pointer within input url that the address starts at. + * @param[out] pxAddressLen Length of the address. + * + * @return The status of the parsing attempt: + * HTTPSuccess if the path was successfully parsed, + * HTTPParserInternalError if there was an error parsing the URL, + * or HTTPNoResponse if the path was not found. + */ +HTTPStatus_t getUrlAddress( const char * pcUrl, + size_t xUrlLen, + const char ** pcAddress, + size_t * pxAddressLen ); + +#endif /* ifndef HTTP_DEMO_UTILS_H */ diff --git a/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Http_Demo_Helpers/presigned_url_generator/README.md b/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Http_Demo_Helpers/presigned_url_generator/README.md new file mode 100644 index 0000000000..db5fe1a816 --- /dev/null +++ b/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Http_Demo_Helpers/presigned_url_generator/README.md @@ -0,0 +1,55 @@ +# Presigned S3 URLs Generator + +`presigned_url_gen.py` generates pre-signed URLs for S3 HTTP GET and PUT request access. + +### Dependencies + +* Python 3+ +* boto3 +* argparse + +### Prerequisites + +1. Install the dependencies. + ```sh + pip install boto3 argparse + ``` + +1. You will need an AWS Account with S3 access before beginning. You must install and configure the AWS CLI in order to + use this script. + For information on AWS S3 please see: https://docs.aws.amazon.com/AmazonS3/latest/dev/Welcome.html + For AWS CLI installation information please see: https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html + For AWS CLI configuration information please see: https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html + + ```sh + aws configure + ``` + +### Usage + +1. Run `presigned_url_gen.py` with your s3 bucket name and s3 object key. + ```sh + ./presigned_urls_gen.py --bucket --key + ``` + An example expected output: + ``` + #define democonfigS3_PRESIGNED_GET_URL "https://aws-s3-endpoint/object-key.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ABABABABABABABABABAB%2F20201027%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20201027T194726Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=SomeHash12345UrlABcdEFgfIjK" + #define democonfigS3_PRESIGNED_PUT_URL "https://aws-s3-endpoint/object-key.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ABABABABABABABABABAB%2F20201027%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20201027T194726Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=SomeHash12345UrlLMnmOPqrStUvW" + ``` +1. Copy and paste the output to `demo_config.h` for macros `democonfigS3_PRESIGNED_GET_URL` and `democonfigS3_PRESIGNED_PUT_URL`. + ```c + #define democonfigS3_PRESIGNED_GET_URL "https://aws-s3-endpoint/object-key.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ABABABABABABABABABAB%2F20201027%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20201027T194726Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=SomeHash12345UrlABcdEFgfIjK" + #define democonfigS3_PRESIGNED_PUT_URL "https://aws-s3-endpoint/object-key.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ABABABABABABABABABAB%2F20201027%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20201027T194726Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=SomeHash12345UrlLMnmOPqrStUvW" + ``` + +### Parameters + +#### --bucket +The name of the S3 bucket from which the demo will download or upload. + +#### --key +The name of the existing object you wish to download (GET), +or the name of the object you wish to upload (PUT). + +#### --region +Optional parameter for the AWS region in which the bucket is located. \ No newline at end of file diff --git a/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Http_Demo_Helpers/presigned_url_generator/presigned_urls_gen.py b/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Http_Demo_Helpers/presigned_url_generator/presigned_urls_gen.py new file mode 100644 index 0000000000..b829436e07 --- /dev/null +++ b/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Http_Demo_Helpers/presigned_url_generator/presigned_urls_gen.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 + +import boto3 +from botocore.client import Config +import argparse + + +def get_presigned_urls(bucket_name, key_name, region_name) -> None: + """ + Prints the presigned GET and PUT URLs assigned to the demo specific C + macros, for the given object key in the given S3 bucket. If the region + parameter is not defined, boto3 will use the one configured using AWS CLI. + The URLs are presigned with AWS's Signature Version 4. + Args: + bucket_name (str): S3 bucket + key_name (str): S3 object key + region_name (str): S3 bucket's region + """ + + # Get the service client. + # SigV2 is being deprecated. If the boto3 installation in the current Python environment has an older version of + # the package, then this configuration forces the use of SigV4. + s3 = boto3.client("s3", config=Config(signature_version="s3v4", region_name=region_name)) + + client_method_dict = {"GET": "get_object", "PUT": "put_object"} + + # Generate the URL to get 'key-name' from 'bucket-name' + for method in client_method_dict.keys(): + url = s3.generate_presigned_url( + ClientMethod=client_method_dict[method], + Params={"Bucket": bucket_name, "Key": key_name}, + ) + print("#define democonfigS3_PRESIGNED_" + method + "_URL" + " " + '"' + url + '"\n') + + +def main(): + """ + Generate demo C macro strings, on the console, for the input S3 bucket and object key. + """ + parser = argparse.ArgumentParser(description="S3 Presigned URL Generator. See README.md") + parser.add_argument( + "--bucket", + action="store", + required=True, + dest="bucket_name", + help="The name of the S3 bucket of interest.", + ) + parser.add_argument( + "--key", + action="store", + required=True, + dest="key_name", + help="The name of the S3 Object in the bucket. This is referred to as a 'key'", + ) + parser.add_argument( + "--region", + action="store", + required=False, + dest="region_name", + help="The region in which the S3 bucket of interest is created.", + ) + args = parser.parse_args() + + get_presigned_urls(args.bucket_name, args.key_name, args.region_name) + + +if __name__ == "__main__": # pragma: no cover + main() diff --git a/FreeRTOS-Plus/Source/Application-Protocols/coreHTTP b/FreeRTOS-Plus/Source/Application-Protocols/coreHTTP new file mode 160000 index 0000000000..0882657628 --- /dev/null +++ b/FreeRTOS-Plus/Source/Application-Protocols/coreHTTP @@ -0,0 +1 @@ +Subproject commit 0882657628eb7df12dc957f9b122601fd3054a68