diff --git a/README.md b/README.md index aa77024..0b73373 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ You should have the following ready before beginning with any board: * Enter `https://adafruit.github.io/arduino-board-index/package_adafruit_index.json` into Additional Board Manager URLs field. You can add multiple URLs, separating them with commas. * Open Boards Manager from Tools > Board menu and install `Arduino SAMD Boards` and `Adafruit SAMD Boards` 1.0.7 or later. * Select your `Adafruit Feather M0` from Tools > Board menu after installation -2. Install the [Adafruit WINC1500 wifi library](https://learn.adafruit.com/adafruit-feather-m0-wifi-atwinc1500/using-the-wifi-module) +2. Install the `WiFi101` library from the Arduino IDE Library Manager. 3. Install the `RTCZero` library from the Arduino IDE Library Manager. 4. Install the `NTPClient` library from the Arduino IDE Library Manager. 5. Open the `simplesample_http` example from the Arduino IDE File->Examples->AzureIoTHub menu. diff --git a/examples/simplesample_http/simplesample_http.c b/examples/simplesample_http/simplesample_http.c new file mode 100644 index 0000000..ace5f65 --- /dev/null +++ b/examples/simplesample_http/simplesample_http.c @@ -0,0 +1,259 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include + +#include +#include + +/* This sample uses the _LL APIs of iothub_client for example purposes. +That does not mean that HTTP only works with the _LL APIs. +Simply changing the using the convenience layer (functions not having _LL) +and removing calls to _DoWork will yield the same results. */ + +#ifdef ARDUINO +#include "AzureIoTHub.h" +#else +#include "azure_c_shared_utility/threadapi.h" +#include "azure_c_shared_utility/platform.h" +#include "serializer.h" +#include "iothub_client_ll.h" +#include "iothubtransporthttp.h" +#endif + +#ifdef MBED_BUILD_TIMESTAMP +#include "certs.h" +#endif // MBED_BUILD_TIMESTAMP + +/*String containing Hostname, Device Id & Device Key in the format: */ +/* "HostName=;DeviceId=;SharedAccessKey=" */ +static const char* connectionString = "[device connection string]"; + +// Define the Model +BEGIN_NAMESPACE(WeatherStation); + +DECLARE_MODEL(ContosoAnemometer, +WITH_DATA(ascii_char_ptr, DeviceId), +WITH_DATA(int, WindSpeed), +WITH_DATA(float, Temperature), +WITH_DATA(float, Humidity), +WITH_ACTION(TurnFanOn), +WITH_ACTION(TurnFanOff), +WITH_ACTION(SetAirResistance, int, Position) +); + +END_NAMESPACE(WeatherStation); + +static char propText[1024]; + +EXECUTE_COMMAND_RESULT TurnFanOn(ContosoAnemometer* device) +{ + (void)device; + (void)printf("Turning fan on.\r\n"); + return EXECUTE_COMMAND_SUCCESS; +} + +EXECUTE_COMMAND_RESULT TurnFanOff(ContosoAnemometer* device) +{ + (void)device; + (void)printf("Turning fan off.\r\n"); + return EXECUTE_COMMAND_SUCCESS; +} + +EXECUTE_COMMAND_RESULT SetAirResistance(ContosoAnemometer* device, int Position) +{ + (void)device; + (void)printf("Setting Air Resistance Position to %d.\r\n", Position); + return EXECUTE_COMMAND_SUCCESS; +} + +void sendCallback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* userContextCallback) +{ + unsigned int messageTrackingId = (unsigned int)(uintptr_t)userContextCallback; + + (void)printf("Message Id: %u Received.\r\n", messageTrackingId); + + (void)printf("Result Call Back Called! Result is: %s \r\n", ENUM_TO_STRING(IOTHUB_CLIENT_CONFIRMATION_RESULT, result)); +} + +static void sendMessage(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, const unsigned char* buffer, size_t size) +{ + static unsigned int messageTrackingId; + IOTHUB_MESSAGE_HANDLE messageHandle = IoTHubMessage_CreateFromByteArray(buffer, size); + if (messageHandle == NULL) + { + printf("unable to create a new IoTHubMessage\r\n"); + } + else + { + if (IoTHubClient_LL_SendEventAsync(iotHubClientHandle, messageHandle, sendCallback, (void*)(uintptr_t)messageTrackingId) != IOTHUB_CLIENT_OK) + { + printf("failed to hand over the message to IoTHubClient"); + } + else + { + printf("IoTHubClient accepted the message for delivery\r\n"); + } + IoTHubMessage_Destroy(messageHandle); + } + free((void*)buffer); + messageTrackingId++; +} + +/*this function "links" IoTHub to the serialization library*/ +static IOTHUBMESSAGE_DISPOSITION_RESULT IoTHubMessage(IOTHUB_MESSAGE_HANDLE message, void* userContextCallback) +{ + IOTHUBMESSAGE_DISPOSITION_RESULT result; + const unsigned char* buffer; + size_t size; + if (IoTHubMessage_GetByteArray(message, &buffer, &size) != IOTHUB_MESSAGE_OK) + { + printf("unable to IoTHubMessage_GetByteArray\r\n"); + result = IOTHUBMESSAGE_ABANDONED; + } + else + { + /*buffer is not zero terminated*/ + char* temp = malloc(size + 1); + if (temp == NULL) + { + printf("failed to malloc\r\n"); + result = IOTHUBMESSAGE_ABANDONED; + } + else + { + EXECUTE_COMMAND_RESULT executeCommandResult; + + (void)memcpy(temp, buffer, size); + temp[size] = '\0'; + executeCommandResult = EXECUTE_COMMAND(userContextCallback, temp); + result = + (executeCommandResult == EXECUTE_COMMAND_ERROR) ? IOTHUBMESSAGE_ABANDONED : + (executeCommandResult == EXECUTE_COMMAND_SUCCESS) ? IOTHUBMESSAGE_ACCEPTED : + IOTHUBMESSAGE_REJECTED; + free(temp); + } + } + return result; +} + +void simplesample_http_run(void) +{ + if (platform_init() != 0) + { + printf("Failed to initialize the platform.\r\n"); + } + else + { + if (serializer_init(NULL) != SERIALIZER_OK) + { + (void)printf("Failed on serializer_init\r\n"); + } + else + { + IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle = IoTHubClient_LL_CreateFromConnectionString(connectionString, HTTP_Protocol); + int avgWindSpeed = 10; + float minTemperature = 20.0; + float minHumidity = 60.0; + + srand((unsigned int)time(NULL)); + + if (iotHubClientHandle == NULL) + { + (void)printf("Failed on IoTHubClient_LL_Create\r\n"); + } + else + { + // Because it can poll "after 9 seconds" polls will happen + // effectively at ~10 seconds. + // Note that for scalabilty, the default value of minimumPollingTime + // is 25 minutes. For more information, see: + // https://azure.microsoft.com/documentation/articles/iot-hub-devguide/#messaging + unsigned int minimumPollingTime = 9; + ContosoAnemometer* myWeather; + + if (IoTHubClient_LL_SetOption(iotHubClientHandle, "MinimumPollingTime", &minimumPollingTime) != IOTHUB_CLIENT_OK) + { + printf("failure to set option \"MinimumPollingTime\"\r\n"); + } + +#ifdef MBED_BUILD_TIMESTAMP + // For mbed add the certificate information + if (IoTHubClient_LL_SetOption(iotHubClientHandle, "TrustedCerts", certificates) != IOTHUB_CLIENT_OK) + { + (void)printf("failure to set option \"TrustedCerts\"\r\n"); + } +#endif // MBED_BUILD_TIMESTAMP + + myWeather = CREATE_MODEL_INSTANCE(WeatherStation, ContosoAnemometer); + if (myWeather == NULL) + { + (void)printf("Failed on CREATE_MODEL_INSTANCE\r\n"); + } + else + { + if (IoTHubClient_LL_SetMessageCallback(iotHubClientHandle, IoTHubMessage, myWeather) != IOTHUB_CLIENT_OK) + { + printf("unable to IoTHubClient_SetMessageCallback\r\n"); + } + else + { + myWeather->DeviceId = "myFirstDevice"; + myWeather->WindSpeed = avgWindSpeed + (rand() % 4 + 2); + myWeather->Temperature = minTemperature + (rand() % 10); + myWeather->Humidity = minHumidity + (rand() % 20); + { + unsigned char* destination; + size_t destinationSize; + if (SERIALIZE(&destination, &destinationSize, myWeather->DeviceId, myWeather->WindSpeed, myWeather->Temperature, myWeather->Humidity) != CODEFIRST_OK) + { + (void)printf("Failed to serialize\r\n"); + } + else + { + IOTHUB_MESSAGE_HANDLE messageHandle = IoTHubMessage_CreateFromByteArray(destination, destinationSize); + if (messageHandle == NULL) + { + printf("unable to create a new IoTHubMessage\r\n"); + } + else + { + MAP_HANDLE propMap = IoTHubMessage_Properties(messageHandle); + (void)sprintf_s(propText, sizeof(propText), myWeather->Temperature > 28 ? "true" : "false"); + if (Map_AddOrUpdate(propMap, "temperatureAlert", propText) != MAP_OK) + { + printf("ERROR: Map_AddOrUpdate Failed!\r\n"); + } + + if (IoTHubClient_LL_SendEventAsync(iotHubClientHandle, messageHandle, sendCallback, (void*)1) != IOTHUB_CLIENT_OK) + { + printf("failed to hand over the message to IoTHubClient"); + } + else + { + printf("IoTHubClient accepted the message for delivery\r\n"); + } + + IoTHubMessage_Destroy(messageHandle); + } + free(destination); + } + } + + /* wait for commands */ + while (1) + { + IoTHubClient_LL_DoWork(iotHubClientHandle); + ThreadAPI_Sleep(100); + } + } + + DESTROY_MODEL_INSTANCE(myWeather); + } + IoTHubClient_LL_Destroy(iotHubClientHandle); + } + serializer_deinit(); + } + platform_deinit(); + } +} diff --git a/examples/simplesample_http/simplesample_http.h b/examples/simplesample_http/simplesample_http.h new file mode 100644 index 0000000..baf6975 --- /dev/null +++ b/examples/simplesample_http/simplesample_http.h @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef SIMPLESAMPLEHTTP_H +#define SIMPLESAMPLEHTTP_H + +#ifdef __cplusplus +extern "C" { +#endif + + void simplesample_http_run(void); + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLESAMPLEHTTP_H */ diff --git a/examples/simplesample_http/simplesample_http.ino b/examples/simplesample_http/simplesample_http.ino index 3b8b212..bc3e9c9 100644 --- a/examples/simplesample_http/simplesample_http.ino +++ b/examples/simplesample_http/simplesample_http.ino @@ -15,12 +15,6 @@ #include #include #include -#elif ARDUINO_SAMD_FEATHER_M0 -// for Adafruit WINC1500 -#include -#include -#include -#include #else #include #include @@ -35,8 +29,6 @@ #define WINC_IRQ 7 #define WINC_RST 4 #define WINC_EN 2 // or, tie EN to VCC -// Setup the WINC1500 connection with the pins above and the default hardware SPI. -Adafruit_WINC1500 WiFi(WINC_CS, WINC_IRQ, WINC_RST); #endif #include @@ -68,9 +60,14 @@ void initSerial() { void initWifi() { #ifdef ARDUINO_SAMD_FEATHER_M0 + //Configure pins for Adafruit ATWINC1500 Feather + Serial.println(F("WINC1500 on FeatherM0 detected.")); + Serial.println(F("Setting pins for WiFi101 library (WINC1500 on FeatherM0)")); + WiFi.setPins(WINC_CS, WINC_IRQ, WINC_RST, WINC_EN); // for the Adafruit WINC1500 we need to enable the chip pinMode(WINC_EN, OUTPUT); digitalWrite(WINC_EN, HIGH); + Serial.println(F("Enabled WINC1500 interface for FeatherM0")); #endif // check for the presence of the shield : @@ -97,11 +94,8 @@ void initWifi() { void initTime() { #if defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_FEATHER_M0) -#ifdef ARDUINO_SAMD_FEATHER_M0 - Adafruit_WINC1500UDP ntpUdp; // for Adafruit WINC1500 -#else WiFiUDP ntpUdp; -#endif + NTPClient ntpClient(ntpUdp); ntpClient.begin(); diff --git a/library.properties b/library.properties index f8046ba..4add6ac 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=AzureIoTUtility -version=1.0.36 +version=1.0.39 author=Microsoft maintainer=Microsoft sentence=Azure C shared utility library for Arduino. For the Arduino MKR1000 or Zero and WiFi Shield 101, Adafruit Huzzah and Feather M0, or SparkFun Thing. diff --git a/src/AzureIoTUtility.h b/src/AzureIoTUtility.h index 0e985bd..85366ef 100644 --- a/src/AzureIoTUtility.h +++ b/src/AzureIoTUtility.h @@ -7,6 +7,6 @@ #include "azure_c_shared_utility/lock.h" #include "azure_c_shared_utility/threadapi.h" -#define AzureIoTUtilityVersion "1.0.36" +#define AzureIoTUtilityVersion "1.0.39" #endif //AZUREIOTUTILITY_H diff --git a/src/adapters/sslClient_arduino.cpp b/src/adapters/sslClient_arduino.cpp index 0032358..446a474 100644 --- a/src/adapters/sslClient_arduino.cpp +++ b/src/adapters/sslClient_arduino.cpp @@ -13,11 +13,6 @@ static WiFiClientSecure sslClient; // for ESP8266 #include "WiFi.h" #include "WiFiClientSecure.h" static WiFiClientSecure sslClient; // for ESP32 -#elif ARDUINO_SAMD_FEATHER_M0 -#include "Adafruit_WINC1500.h" -#include "Adafruit_WINC1500Client.h" -#include "Adafruit_WINC1500SSLClient.h" -static Adafruit_WINC1500SSLClient sslClient; // for Adafruit WINC1500 #else #include "WiFi101.h" #include "WiFiSSLClient.h" diff --git a/src/azure_c_shared_utility/aziotsharedutil.def b/src/azure_c_shared_utility/aziotsharedutil.def index 6b37bcb..315dfa9 100644 --- a/src/azure_c_shared_utility/aziotsharedutil.def +++ b/src/azure_c_shared_utility/aziotsharedutil.def @@ -1,6 +1,7 @@ LIBRARY aziotsharedutil EXPORTS BUFFER_append + BUFFER_append_build BUFFER_build BUFFER_clone BUFFER_content @@ -11,6 +12,7 @@ EXPORTS BUFFER_new BUFFER_pre_build BUFFER_prepend + BUFFER_shrink BUFFER_size BUFFER_u_char BUFFER_unbuild @@ -148,9 +150,12 @@ EXPORTS STRING_new_with_memory STRING_quote STRING_sprintf + STRING_replace THREADAPI_RESULTStringStorage THREADAPI_RESULTStrings THREADAPI_RESULT_FromString + TLSIO_STATE_FromString + TLSIO_STATEStrings ThreadAPI_Create ThreadAPI_Exit ThreadAPI_Join @@ -181,7 +186,12 @@ EXPORTS VECTOR_push_back VECTOR_size connectionstringparser_parse + connectionstringparser_parse_from_char + connectionstringparser_splitHostName + connectionstringparser_splitHostName_from_char consolelogger_log + consolelogger_log_with_GetLastError + gb_rand gballoc_calloc gballoc_deinit gballoc_free @@ -205,6 +215,7 @@ EXPORTS mallocAndStrcpy_s platform_deinit platform_get_default_tlsio + platform_get_platform_info platform_init singlylinkedlist_add singlylinkedlist_create @@ -214,6 +225,8 @@ EXPORTS singlylinkedlist_get_next_item singlylinkedlist_item_get_value singlylinkedlist_remove + singlylinkedlist_remove_if + singlylinkedlist_foreach size_tToString socketio_close socketio_create @@ -235,7 +248,27 @@ EXPORTS tlsio_schannel_send tlsio_schannel_setoption unsignedIntToString + utf8_checker_is_valid_utf8 + uws_client_close_async + uws_client_close_handshake_async + uws_client_create + uws_client_create_with_io + uws_client_destroy + uws_client_dowork + uws_client_open_async + uws_client_retrieve_options + uws_client_send_frame_async + uws_client_set_option + uws_frame_encoder_encode + wsio_close + wsio_create + wsio_destroy + wsio_dowork wsio_get_interface_description + wsio_open + wsio_retrieveoptions + wsio_send + wsio_setoption x509_schannel_create x509_schannel_destroy x509_schannel_get_certificate_context @@ -249,4 +282,6 @@ EXPORTS xio_setoption xlogging_dump_buffer xlogging_get_log_function + xlogging_get_log_function_GetLastError xlogging_set_log_function + xlogging_set_log_function_GetLastError diff --git a/src/azure_c_shared_utility/buffer.c b/src/azure_c_shared_utility/buffer.c index 03672e2..e6a295a 100644 --- a/src/azure_c_shared_utility/buffer.c +++ b/src/azure_c_shared_utility/buffer.c @@ -541,6 +541,29 @@ int BUFFER_prepend(BUFFER_HANDLE handle1, BUFFER_HANDLE handle2) return result; } +int BUFFER_fill(BUFFER_HANDLE handle, unsigned char fill_char) +{ + int result; + if (handle == NULL) + { + /* Codes_SRS_BUFFER_07_002: [ If handle is NULL BUFFER_fill shall return a non-zero value. ] */ + LogError("Invalid parameter specified, handle == NULL."); + result = __FAILURE__; + } + else + { + size_t index; + /* Codes_SRS_BUFFER_07_001: [ BUFFER_fill shall fill the supplied BUFFER_HANDLE with the supplied fill character. ] */ + BUFFER* buffer_data = (BUFFER*)handle; + for (index = 0; index < buffer_data->size; index++) + { + buffer_data->buffer[index] = fill_char; + } + result = 0; + } + return result; +} + /* Codes_SRS_BUFFER_07_025: [BUFFER_u_char shall return a pointer to the underlying unsigned char*.] */ unsigned char* BUFFER_u_char(BUFFER_HANDLE handle) diff --git a/src/azure_c_shared_utility/buffer_.h b/src/azure_c_shared_utility/buffer_.h index d71abce..e5bfb27 100644 --- a/src/azure_c_shared_utility/buffer_.h +++ b/src/azure_c_shared_utility/buffer_.h @@ -31,6 +31,7 @@ MOCKABLE_FUNCTION(, int, BUFFER_content, BUFFER_HANDLE, handle, const unsigned c MOCKABLE_FUNCTION(, int, BUFFER_size, BUFFER_HANDLE, handle, size_t*, size); MOCKABLE_FUNCTION(, int, BUFFER_append, BUFFER_HANDLE, handle1, BUFFER_HANDLE, handle2); MOCKABLE_FUNCTION(, int, BUFFER_prepend, BUFFER_HANDLE, handle1, BUFFER_HANDLE, handle2); +MOCKABLE_FUNCTION(, int, BUFFER_fill, BUFFER_HANDLE, handle, unsigned char, fill_char); MOCKABLE_FUNCTION(, unsigned char*, BUFFER_u_char, BUFFER_HANDLE, handle); MOCKABLE_FUNCTION(, size_t, BUFFER_length, BUFFER_HANDLE, handle); MOCKABLE_FUNCTION(, BUFFER_HANDLE, BUFFER_clone, BUFFER_HANDLE, handle); diff --git a/src/azure_c_shared_utility/connection_string_parser.c b/src/azure_c_shared_utility/connection_string_parser.c index eef3ca4..46c422d 100644 --- a/src/azure_c_shared_utility/connection_string_parser.c +++ b/src/azure_c_shared_utility/connection_string_parser.c @@ -25,12 +25,12 @@ MAP_HANDLE connectionstringparser_parse_from_char(const char* connection_string) else { result = connectionstringparser_parse(connString); + STRING_delete(connString); } return result; } - /* Codes_SRS_CONNECTIONSTRINGPARSER_01_001: [connectionstringparser_parse shall parse all key value pairs from the connection_string passed in as argument and return a new map that holds the key/value pairs.] */ MAP_HANDLE connectionstringparser_parse(STRING_HANDLE connection_string) { diff --git a/src/azure_c_shared_utility/crt_abstractions.h b/src/azure_c_shared_utility/crt_abstractions.h index 7eab496..cc86919 100644 --- a/src/azure_c_shared_utility/crt_abstractions.h +++ b/src/azure_c_shared_utility/crt_abstractions.h @@ -12,11 +12,11 @@ #include #include extern "C" { -#else +#else // __cplusplus #include #include #include -#endif +#endif // __cplusplus #ifdef _MSC_VER @@ -27,7 +27,7 @@ typedef bool _Bool; #else /*galileo apparently has _Bool and bool as built in types*/ #endif -#endif +#endif // QUARKGALILEO #ifndef _WIN32_WCE #define HAS_STDBOOL @@ -35,10 +35,10 @@ typedef bool _Bool; #include /*because C++ doesn't do anything about _Bool... */ #define _Bool bool -#else +#else // __cplusplus #include -#endif -#else +#endif // __cplusplus +#else // _WIN32_WCE /* WINCE does not support bool as C datatype */ #define __bool_true_false_are_defined 1 @@ -48,40 +48,42 @@ typedef bool _Bool; #ifdef __cplusplus #define _CSTDBOOL_ -#else +#else // __cplusplus typedef unsigned char bool; #define false 0 #define true 1 -#endif -#endif -#else +#endif // __cplusplus +#endif // _WIN32_WCE + +#else // _MSC_VER + #if defined __STDC_VERSION__ #if ((__STDC_VERSION__ == 199901L) || (__STDC_VERSION__ == 201000L) || (__STDC_VERSION__ == 201112L)) /*C99 compiler or C11*/ #define HAS_STDBOOL #include -#endif -#endif -#endif +#endif // ((__STDC_VERSION__ == 199901L) || (__STDC_VERSION__ == 201000L) || (__STDC_VERSION__ == 201112L)) +#endif // __STDC_VERSION__ +#endif // _MSC_VER #ifndef HAS_STDBOOL #ifdef __cplusplus #define _Bool bool -#else +#else // __cplusplus typedef unsigned char _Bool; typedef unsigned char bool; #define false 0 #define true 1 -#endif -#endif +#endif // __cplusplus +#endif // HAS_STDBOOL /* Codes_SRS_CRT_ABSTRACTIONS_99_001:[The module shall not redefine the secure functions implemented by Microsoft CRT.] */ /* Codes_SRS_CRT_ABSTRACTIONS_99_040 : [The module shall still compile when building on a Microsoft platform.] */ /* Codes_SRS_CRT_ABSTRACTIONS_99_002: [CRTAbstractions module shall expose the following API]*/ #ifdef _MSC_VER -#else +#else // _MSC_VER #include "inttypes.h" /* Adding definitions from errno.h & crtdefs.h */ @@ -97,7 +99,7 @@ extern int strcpy_s(char* dst, size_t dstSizeInBytes, const char* src); extern int strcat_s(char* dst, size_t dstSizeInBytes, const char* src); extern int strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t maxCount); extern int sprintf_s(char* dst, size_t dstSizeInBytes, const char* format, ...); -#endif +#endif // _MSC_VER extern unsigned long long strtoull_s(const char* nptr, char** endPtr, int base); extern float strtof_s(const char* nptr, char** endPtr); @@ -105,7 +107,7 @@ extern long double strtold_s(const char* nptr, char** endPtr); #ifdef _MSC_VER #define stricmp _stricmp -#endif +#endif // _MSC_VER MOCKABLE_FUNCTION(, int, mallocAndStrcpy_s, char**, destination, const char*, source); MOCKABLE_FUNCTION(, int, unsignedIntToString, char*, destination, size_t, destinationSize, unsigned int, value); @@ -122,26 +124,26 @@ MOCKABLE_FUNCTION(, int, size_tToString, char*, destination, size_t, destination #ifdef _MSC_VER #define ISNAN _isnan -#else +#else // _MSC_VER #if defined __STDC_VERSION__ #if ((__STDC_VERSION__ == 199901L) || (__STDC_VERSION__ == 201000L) || (__STDC_VERSION__ == 201112L)) /*C99 compiler or C11*/ #define ISNAN isnan -#else +#else // ((__STDC_VERSION__ == 199901L) || (__STDC_VERSION__ == 201000L) || (__STDC_VERSION__ == 201112L)) #error update this file to contain the latest C standard. -#endif -#else +#endif // ((__STDC_VERSION__ == 199901L) || (__STDC_VERSION__ == 201000L) || (__STDC_VERSION__ == 201112L)) +#else // __STDC_VERSION__ #ifdef __cplusplus /*C++ defines isnan... in C11*/ extern "C++" { #define ISNAN std::isnan } -#else +#else // __cplusplus #error unknown (or C89) compiler, provide ISNAN with the same meaning as isnan in C99 standard -#endif +#endif // __cplusplus -#endif -#endif +#endif // __STDC_VERSION__ +#endif // _MSC_VER #ifdef _MSC_VER #define INT64_PRINTF "%I64d" @@ -150,20 +152,20 @@ extern "C++" { #if ((__STDC_VERSION__ == 199901L) || (__STDC_VERSION__ == 201000L) || (__STDC_VERSION__ == 201112L)) /*C99 compiler or C11*/ #define INT64_PRINTF "%" PRId64 "" -#else +#else // ((__STDC_VERSION__ == 199901L) || (__STDC_VERSION__ == 201000L) || (__STDC_VERSION__ == 201112L)) #error update this file to contain the latest C standard. -#endif -#else +#endif // ((__STDC_VERSION__ == 199901L) || (__STDC_VERSION__ == 201000L) || (__STDC_VERSION__ == 201112L)) +#else // __STDC_VERSION__ #ifdef __cplusplus #define INT64_PRINTF "%" PRId64 "" -#else +#else // __cplusplus #error unknown (or C89) compiler, provide INT64_PRINTF with the same meaning as PRIdN in C99 standard -#endif -#endif -#endif +#endif // __cplusplus +#endif // __STDC_VERSION__ +#endif // _MSC_VER #ifdef __cplusplus } -#endif +#endif // __cplusplus #endif /* CRT_ABSTRACTIONS_H */ diff --git a/src/azure_c_shared_utility/shared_util_options.h b/src/azure_c_shared_utility/shared_util_options.h index be04969..7c2d09e 100644 --- a/src/azure_c_shared_utility/shared_util_options.h +++ b/src/azure_c_shared_utility/shared_util_options.h @@ -20,6 +20,8 @@ extern "C" static const char* OPTION_HTTP_PROXY = "proxy_data"; static const char* OPTION_HTTP_TIMEOUT = "timeout"; + static const char* OPTION_TRUSTED_CERT = "TrustedCerts"; + static const char* SU_OPTION_X509_CERT = "x509certificate"; static const char* SU_OPTION_X509_PRIVATE_KEY = "x509privatekey"; diff --git a/src/azure_c_shared_utility/singlylinkedlist.c b/src/azure_c_shared_utility/singlylinkedlist.c index 0b68877..c87adcf 100644 --- a/src/azure_c_shared_utility/singlylinkedlist.c +++ b/src/azure_c_shared_utility/singlylinkedlist.c @@ -5,6 +5,7 @@ #include "azure_c_shared_utility/gballoc.h" #include "azure_c_shared_utility/singlylinkedlist.h" #include "azure_c_shared_utility/optimize_size.h" +#include "azure_c_shared_utility/xlogging.h" typedef struct LIST_ITEM_INSTANCE_TAG { @@ -59,6 +60,7 @@ LIST_ITEM_HANDLE singlylinkedlist_add(SINGLYLINKEDLIST_HANDLE list, const void* if ((list == NULL) || (item == NULL)) { + LogError("Invalid argument (list=%p, item=%p)", list, item); result = NULL; } else @@ -105,6 +107,7 @@ int singlylinkedlist_remove(SINGLYLINKEDLIST_HANDLE list, LIST_ITEM_HANDLE item) if ((list == NULL) || (item == NULL)) { + LogError("Invalid argument (list=%p, item=%p)", list, item); result = __FAILURE__; } else @@ -156,7 +159,8 @@ LIST_ITEM_HANDLE singlylinkedlist_get_head_item(SINGLYLINKEDLIST_HANDLE list) if (list == NULL) { /* Codes_SRS_LIST_01_009: [If the list argument is NULL, singlylinkedlist_get_head_item shall return NULL.] */ - result = NULL; + LogError("Invalid argument (list=NULL)"); + result = NULL; } else { @@ -176,6 +180,7 @@ LIST_ITEM_HANDLE singlylinkedlist_get_next_item(LIST_ITEM_HANDLE item_handle) if (item_handle == NULL) { + LogError("Invalid argument (list is NULL)"); /* Codes_SRS_LIST_01_019: [If item_handle is NULL then singlylinkedlist_get_next_item shall return NULL.] */ result = NULL; } @@ -194,6 +199,7 @@ const void* singlylinkedlist_item_get_value(LIST_ITEM_HANDLE item_handle) if (item_handle == NULL) { + LogError("Invalid argument (item_handle is NULL)"); /* Codes_SRS_LIST_01_021: [If item_handle is NULL, singlylinkedlist_item_get_value shall return NULL.] */ result = NULL; } @@ -213,6 +219,7 @@ LIST_ITEM_HANDLE singlylinkedlist_find(SINGLYLINKEDLIST_HANDLE list, LIST_MATCH_ if ((list == NULL) || (match_function == NULL)) { + LogError("Invalid argument (list=%p, match_function=%p)", list, match_function); /* Codes_SRS_LIST_01_012: [If the list or the match_function argument is NULL, singlylinkedlist_find shall return NULL.] */ result = NULL; } @@ -249,3 +256,103 @@ LIST_ITEM_HANDLE singlylinkedlist_find(SINGLYLINKEDLIST_HANDLE list, LIST_MATCH_ return result; } + +int singlylinkedlist_remove_if(SINGLYLINKEDLIST_HANDLE list, LIST_CONDITION_FUNCTION condition_function, const void* match_context) +{ + int result; + /* Codes_SRS_LIST_09_001: [ If the list or the condition_function argument is NULL, singlylinkedlist_remove_if shall return non-zero value. ] */ + if ((list == NULL) || + (condition_function == NULL)) + { + LogError("Invalid argument (list=%p, condition_function=%p)", list, condition_function); + result = __FAILURE__; + } + else + { + LIST_INSTANCE* list_instance = (LIST_INSTANCE*)list; + LIST_ITEM_INSTANCE* current_item = list_instance->head; + LIST_ITEM_INSTANCE* next_item = NULL; + LIST_ITEM_INSTANCE* previous_item = NULL; + + /* Codes_SRS_LIST_09_002: [ singlylinkedlist_remove_if shall iterate through all items in a list and remove all that satisfies a certain condition function. ] */ + while (current_item != NULL) + { + bool continue_processing = false; + + next_item = (LIST_ITEM_INSTANCE*)current_item->next; + + /* Codes_SRS_LIST_09_003: [ singlylinkedlist_remove_if shall determine whether an item satisfies the condition criteria by invoking the condition function for that item. ] */ + /* Codes_SRS_LIST_09_004: [ If the condition function returns true, singlylinkedlist_find shall consider that item as to be removed. ] */ + if (condition_function(current_item->item, match_context, &continue_processing) == true) + { + if (previous_item != NULL) + { + previous_item->next = next_item; + } + else + { + list_instance->head = next_item; + } + + free(current_item); + } + /* Codes_SRS_LIST_09_005: [ If the condition function returns false, singlylinkedlist_find shall consider that item as not to be removed. ] */ + else + { + previous_item = current_item; + } + + /* Codes_SRS_LIST_09_006: [ If the condition function returns continue_processing as false, singlylinkedlist_remove_if shall stop iterating through the list and return. ] */ + if (continue_processing == false) + { + break; + } + + current_item = next_item; + } + + /* Codes_SRS_LIST_09_007: [ If no errors occur, singlylinkedlist_remove_if shall return zero. ] */ + result = 0; + } + + return result; +} + +int singlylinkedlist_foreach(SINGLYLINKEDLIST_HANDLE list, LIST_ACTION_FUNCTION action_function, const void* action_context) +{ + int result; + + /* Codes_SRS_LIST_09_008: [ If the list or the action_function argument is NULL, singlylinkedlist_foreach shall return non-zero value. ] */ + if ((list == NULL) || + (action_function == NULL)) + { + LogError("Invalid argument (list=%p, action_function=%p)", list, action_function); + result = __FAILURE__; + } + else + { + LIST_INSTANCE* list_instance = (LIST_INSTANCE*)list; + LIST_ITEM_INSTANCE* list_item = list_instance->head; + + while (list_item != NULL) + { + bool continue_processing = false; + + /* Codes_SRS_LIST_09_009: [ singlylinkedlist_foreach shall iterate through all items in a list and invoke action_function for each one of them. ] */ + action_function(list_item->item, action_context, &continue_processing); + + /* Codes_SRS_LIST_09_010: [ If the condition function returns continue_processing as false, singlylinkedlist_foreach shall stop iterating through the list and return. ] */ + if (continue_processing == false) + { + break; + } + + list_item = (LIST_ITEM_INSTANCE*)list_item->next; + } + + /* Codes_SRS_LIST_09_011: [ If no errors occur, singlylinkedlist_foreach shall return zero. ] */ + result = 0; + } + + return result; +} \ No newline at end of file diff --git a/src/azure_c_shared_utility/singlylinkedlist.h b/src/azure_c_shared_utility/singlylinkedlist.h index 5ef5225..9cb2ccd 100644 --- a/src/azure_c_shared_utility/singlylinkedlist.h +++ b/src/azure_c_shared_utility/singlylinkedlist.h @@ -15,7 +15,29 @@ extern "C" { typedef struct SINGLYLINKEDLIST_INSTANCE_TAG* SINGLYLINKEDLIST_HANDLE; typedef struct LIST_ITEM_INSTANCE_TAG* LIST_ITEM_HANDLE; + +/** +* @brief Function passed to singlylinkedlist_find, which returns whichever first list item that matches it. +* @param list_item Current list node being evaluated. +* @param match_context Context passed to singlylinkedlist_find. +* @returns True to indicate that the current list node is the one to be returned, or false to continue traversing the list. +*/ typedef bool (*LIST_MATCH_FUNCTION)(LIST_ITEM_HANDLE list_item, const void* match_context); +/** +* @brief Function passed to singlylinkedlist_remove_if, which is used to define if an item of the list should be removed or not. +* @param item Value of the current list node being evaluated for removal. +* @param match_context Context passed to singlylinkedlist_remove_if. +* @param continue_processing Indicates if singlylinkedlist_remove_if shall continue iterating through the next nodes of the list or stop. +* @returns True to indicate that the current list node shall be removed, or false to not to. +*/ +typedef bool (*LIST_CONDITION_FUNCTION)(const void* item, const void* match_context, bool* continue_processing); +/** +* @brief Function passed to singlylinkedlist_foreach, which is called for the value of each node of the list. +* @param item Value of the current list node being processed. +* @param action_context Context passed to singlylinkedlist_foreach. +* @param continue_processing Indicates if singlylinkedlist_foreach shall continue iterating through the next nodes of the list or stop. +*/ +typedef void (*LIST_ACTION_FUNCTION)(const void* item, const void* action_context, bool* continue_processing); MOCKABLE_FUNCTION(, SINGLYLINKEDLIST_HANDLE, singlylinkedlist_create); MOCKABLE_FUNCTION(, void, singlylinkedlist_destroy, SINGLYLINKEDLIST_HANDLE, list); @@ -25,6 +47,8 @@ MOCKABLE_FUNCTION(, LIST_ITEM_HANDLE, singlylinkedlist_get_head_item, SINGLYLINK MOCKABLE_FUNCTION(, LIST_ITEM_HANDLE, singlylinkedlist_get_next_item, LIST_ITEM_HANDLE, item_handle); MOCKABLE_FUNCTION(, LIST_ITEM_HANDLE, singlylinkedlist_find, SINGLYLINKEDLIST_HANDLE, list, LIST_MATCH_FUNCTION, match_function, const void*, match_context); MOCKABLE_FUNCTION(, const void*, singlylinkedlist_item_get_value, LIST_ITEM_HANDLE, item_handle); +MOCKABLE_FUNCTION(, int, singlylinkedlist_remove_if, SINGLYLINKEDLIST_HANDLE, list, LIST_CONDITION_FUNCTION, condition_function, const void*, match_context); +MOCKABLE_FUNCTION(, int, singlylinkedlist_foreach, SINGLYLINKEDLIST_HANDLE, list, LIST_ACTION_FUNCTION, action_function, const void*, action_context); #ifdef __cplusplus } diff --git a/src/azure_c_shared_utility/strings.c b/src/azure_c_shared_utility/strings.c index 0b7d6d5..2fac434 100644 --- a/src/azure_c_shared_utility/strings.c +++ b/src/azure_c_shared_utility/strings.c @@ -24,7 +24,7 @@ static const char hexToASCII[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8' typedef struct STRING_TAG { char* s; -}STRING; +} STRING; /*this function will allocate a new string with just '\0' in it*/ /*return NULL if it fails*/ @@ -137,7 +137,7 @@ STRING_HANDLE STRING_construct_sprintf(const char* format, ...) if (format != NULL) { va_list arg_list; - int length; + int length; va_start(arg_list, format); /* Codes_SRS_STRING_07_041: [STRING_construct_sprintf shall determine the size of the resulting string and allocate the necessary memory.] */ @@ -534,7 +534,7 @@ int STRING_sprintf(STRING_HANDLE handle, const char* format, ...) else { va_list arg_list; - int s2Length; + int s2Length; va_start(arg_list, format); s2Length = vsnprintf(buf, maxBufSize, format, arg_list); @@ -553,7 +553,7 @@ int STRING_sprintf(STRING_HANDLE handle, const char* format, ...) else { STRING* s1 = (STRING*)handle; - char* temp; + char* temp; size_t s1Length = strlen(s1->s); temp = (char*)realloc(s1->s, s1Length + s2Length + 1); if (temp != NULL) @@ -807,3 +807,36 @@ STRING_HANDLE STRING_from_byte_array(const unsigned char* source, size_t size) } return (STRING_HANDLE)result; } + +int STRING_replace(STRING_HANDLE handle, char target, char replace) +{ + int result; + if (handle == NULL) + { + /* Codes_SRS_STRING_07_046: [ If handle is NULL STRING_replace shall return a non-zero value. ] */ + result = __FAILURE__; + } + else if (target == replace) + { + /* Codes_SRS_STRING_07_048: [ If target and replace are equal STRING_replace, shall do nothing shall return zero. ] */ + result = 0; + } + else + { + size_t length; + size_t index; + /* Codes_SRS_STRING_07_047: [ STRING_replace shall replace all instances of target with replace. ] */ + STRING* str_value = (STRING*)handle; + length = strlen(str_value->s); + for (index = 0; index < length; index++) + { + if (str_value->s[index] == target) + { + str_value->s[index] = replace; + } + } + /* Codes_SRS_STRING_07_049: [ On success STRING_replace shall return zero. ] */ + result = 0; + } + return result; +} diff --git a/src/azure_c_shared_utility/strings.h b/src/azure_c_shared_utility/strings.h index b8e1994..65426ff 100644 --- a/src/azure_c_shared_utility/strings.h +++ b/src/azure_c_shared_utility/strings.h @@ -33,6 +33,7 @@ MOCKABLE_FUNCTION(, const char*, STRING_c_str, STRING_HANDLE, handle); MOCKABLE_FUNCTION(, int, STRING_empty, STRING_HANDLE, handle); MOCKABLE_FUNCTION(, size_t, STRING_length, STRING_HANDLE, handle); MOCKABLE_FUNCTION(, int, STRING_compare, STRING_HANDLE, s1, STRING_HANDLE, s2); +MOCKABLE_FUNCTION(, int, STRING_replace, STRING_HANDLE, handle, char, target, char, replace); extern STRING_HANDLE STRING_construct_sprintf(const char* format, ...); extern int STRING_sprintf(STRING_HANDLE s1, const char* format, ...); diff --git a/src/azure_c_shared_utility/tls_config.h b/src/azure_c_shared_utility/tls_config.h index 718c85b..b989950 100644 --- a/src/azure_c_shared_utility/tls_config.h +++ b/src/azure_c_shared_utility/tls_config.h @@ -1,6 +1,8 @@ #ifndef __TLS_CONFIG_H__ #define __TLS_CONFIG_H__ +// DEPRECATED: This file will be removed from the tree. + // WolfSSL or mbedTLS //#define USE_WOLF_SSL #define USE_MBED_TLS diff --git a/src/azure_c_shared_utility/uws_client.c b/src/azure_c_shared_utility/uws_client.c index 375f1fb..0ab1917 100644 --- a/src/azure_c_shared_utility/uws_client.c +++ b/src/azure_c_shared_utility/uws_client.c @@ -1680,6 +1680,11 @@ static void on_underlying_io_send_complete(void* context, IO_SEND_RESULT send_re } } +static bool find_list_node(LIST_ITEM_HANDLE list_item, const void* match_context) +{ + return list_item == (LIST_ITEM_HANDLE)match_context; +} + int uws_client_send_frame_async(UWS_CLIENT_HANDLE uws_client, unsigned char frame_type, const unsigned char* buffer, size_t size, bool is_final, ON_WS_SEND_FRAME_COMPLETE on_ws_send_frame_complete, void* on_ws_send_frame_complete_context) { int result; @@ -1771,9 +1776,16 @@ int uws_client_send_frame_async(UWS_CLIENT_HANDLE uws_client, unsigned char fram { /* Codes_SRS_UWS_CLIENT_01_058: [ If `xio_send` fails, `uws_client_send_frame_async` shall fail and return a non-zero value. ]*/ LogError("Could not send bytes through the underlying IO"); - (void)singlylinkedlist_remove(uws_client->pending_sends, new_pending_send_list_item); - free(ws_pending_send); - result = __FAILURE__; + + /* Codes_SRS_UWS_CLIENT_09_001: [ If `xio_send` fails and the message is still queued, it shall be de-queued and destroyed. ] */ + if (singlylinkedlist_find(uws_client->pending_sends, find_list_node, new_pending_send_list_item) != NULL) + { + // Guards against double free in case the underlying I/O invoked 'on_underlying_io_send_complete' within xio_send. + (void)singlylinkedlist_remove(uws_client->pending_sends, new_pending_send_list_item); + free(ws_pending_send); + } + + result = __FAILURE__; } else {