├── .github └── issue_template.md ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── SECURITY.md ├── azure-pipelines.yml ├── build_all ├── iothub_client_sample_mqtt.c └── iothub_client_sample_mqtt.h ├── component.mk ├── devdoc ├── platform_openssl_compact_requirements.md └── tlsio_openssl_compact_requirements.md ├── jenkins ├── ubuntu1510_c.sh ├── ubuntu1604_c.sh └── windows_c.cmd ├── pal ├── inc │ ├── sntp_os.h │ ├── socket_async_os.h │ └── tlsio_pal.h └── src │ ├── platform_openssl_compact.c │ └── tlsio_openssl_compact.c ├── sample ├── Makefile └── main │ ├── Kconfig.projbuild │ ├── azure_main.c │ └── component.mk ├── sdk_tests ├── CMakeLists.txt └── tlsio_openssl_compact_ut │ ├── CMakeLists.txt │ ├── callbacks.h │ ├── gballoc_ut_impl_1.h │ ├── gballoc_ut_impl_2.h │ ├── main.c │ ├── openssl │ └── ssl.h │ ├── ssl_impl.h │ ├── test_defines.h │ └── tlsio_openssl_compact_ut.c └── thirdpartynotice.txt /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | # WARNING: THIS REPO IS GOING TO BE RETIRED ON JULY 1ST, 2018. 2 | BUT DON’T WORRY! Espressif has taken ownership of this port for the Azure IoT. 3 | Please start using the code from the following repo: 4 | • https://github.com/espressif/esp32-azure 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # .NET Core 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | **/Properties/launchSettings.json 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # Visual Studio code coverage results 117 | *.coverage 118 | *.coveragexml 119 | 120 | # NCrunch 121 | _NCrunch_* 122 | .*crunch*.local.xml 123 | nCrunchTemp_* 124 | 125 | # MightyMoose 126 | *.mm.* 127 | AutoTest.Net/ 128 | 129 | # Web workbench (sass) 130 | .sass-cache/ 131 | 132 | # Installshield output folder 133 | [Ee]xpress/ 134 | 135 | # DocProject is a documentation generator add-in 136 | DocProject/buildhelp/ 137 | DocProject/Help/*.HxT 138 | DocProject/Help/*.HxC 139 | DocProject/Help/*.hhc 140 | DocProject/Help/*.hhk 141 | DocProject/Help/*.hhp 142 | DocProject/Help/Html2 143 | DocProject/Help/html 144 | 145 | # Click-Once directory 146 | publish/ 147 | 148 | # Publish Web Output 149 | *.[Pp]ublish.xml 150 | *.azurePubxml 151 | # TODO: Comment the next line if you want to checkin your web deploy settings 152 | # but database connection strings (with potential passwords) will be unencrypted 153 | *.pubxml 154 | *.publishproj 155 | 156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 157 | # checkin your Azure Web App publish settings, but sensitive information contained 158 | # in these scripts will be unencrypted 159 | PublishScripts/ 160 | 161 | # NuGet Packages 162 | *.nupkg 163 | # The packages folder can be ignored because of Package Restore 164 | **/packages/* 165 | # except build/, which is used as an MSBuild target. 166 | !**/packages/build/ 167 | # Uncomment if necessary however generally it will be regenerated when needed 168 | #!**/packages/repositories.config 169 | # NuGet v3's project.json files produces more ignorable files 170 | *.nuget.props 171 | *.nuget.targets 172 | 173 | # Microsoft Azure Build Output 174 | csx/ 175 | *.build.csdef 176 | 177 | # Microsoft Azure Emulator 178 | ecf/ 179 | rcf/ 180 | 181 | # Windows Store app package directories and files 182 | AppPackages/ 183 | BundleArtifacts/ 184 | Package.StoreAssociation.xml 185 | _pkginfo.txt 186 | 187 | # Visual Studio cache files 188 | # files ending in .cache can be ignored 189 | *.[Cc]ache 190 | # but keep track of directories ending in .cache 191 | !*.[Cc]ache/ 192 | 193 | # Others 194 | ClientBin/ 195 | ~$* 196 | *~ 197 | *.dbmdl 198 | *.dbproj.schemaview 199 | *.jfm 200 | *.pfx 201 | *.publishsettings 202 | orleans.codegen.cs 203 | 204 | # Since there are multiple workflows, uncomment next line to ignore bower_components 205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 206 | #bower_components/ 207 | 208 | # RIA/Silverlight projects 209 | Generated_Code/ 210 | 211 | # Backup & report files from converting an old project file 212 | # to a newer Visual Studio version. Backup files are not needed, 213 | # because we have git ;-) 214 | _UpgradeReport_Files/ 215 | Backup*/ 216 | UpgradeLog*.XML 217 | UpgradeLog*.htm 218 | 219 | # SQL Server files 220 | *.mdf 221 | *.ldf 222 | *.ndf 223 | 224 | # Business Intelligence projects 225 | *.rdl.data 226 | *.bim.layout 227 | *.bim_*.settings 228 | 229 | # Microsoft Fakes 230 | FakesAssemblies/ 231 | 232 | # GhostDoc plugin setting file 233 | *.GhostDoc.xml 234 | 235 | # Node.js Tools for Visual Studio 236 | .ntvs_analysis.dat 237 | node_modules/ 238 | 239 | # Typescript v1 declaration files 240 | typings/ 241 | 242 | # Visual Studio 6 build log 243 | *.plg 244 | 245 | # Visual Studio 6 workspace options file 246 | *.opt 247 | 248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 249 | *.vbw 250 | 251 | # Visual Studio LightSwitch build output 252 | **/*.HTMLClient/GeneratedArtifacts 253 | **/*.DesktopClient/GeneratedArtifacts 254 | **/*.DesktopClient/ModelManifest.xml 255 | **/*.Server/GeneratedArtifacts 256 | **/*.Server/ModelManifest.xml 257 | _Pvt_Extensions 258 | 259 | # Paket dependency manager 260 | .paket/paket.exe 261 | paket-files/ 262 | 263 | # FAKE - F# Make 264 | .fake/ 265 | 266 | # JetBrains Rider 267 | .idea/ 268 | *.sln.iml 269 | 270 | # CodeRush 271 | .cr/ 272 | 273 | # Python Tools for Visual Studio (PTVS) 274 | __pycache__/ 275 | *.pyc 276 | 277 | # Cake - Uncomment if you are using it 278 | # tools/** 279 | # !tools/packages.config 280 | 281 | # Telerik's JustMock configuration file 282 | *.jmconfig 283 | 284 | # BizTalk build output 285 | *.btp.cs 286 | *.btm.cs 287 | *.odx.cs 288 | *.xsd.cs 289 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "sdk"] 2 | path = sdk 3 | url = https://github.com/Azure/azure-iot-sdk-c.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #Copyright (c) Microsoft. All rights reserved. 2 | #Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | cmake_minimum_required(VERSION 2.8.11) 5 | 6 | project(azure_external_unit_tests) 7 | 8 | # Set up the C SDK options to build as little as possible 9 | option(skip_samples "set skip_samples to ON to skip building samples (default is OFF)[if possible, they are always build]" ON) 10 | option(compileOption_C "passes a string to the command line of the C compiler" OFF) 11 | option(compileOption_CXX "passes a string to the command line of the C++ compiler" OFF) 12 | option(no_logging "disable logging" OFF) 13 | option(run_e2e_tests "set run_e2e_tests to ON to run e2e tests (default is OFF)" OFF) 14 | option(run_unittests "set run_unittests to ON to run unittests (default is OFF)" OFF) 15 | option(use_cppunittest "set use_cppunittest to ON to build CppUnitTest tests on Windows (default is ON)" ON) 16 | 17 | # include the sdk for its header files and libs 18 | set(run_unittests OFF) 19 | include("sdk/c-utility/configs/azure_iot_external_pal_unit_test_setup.cmake") 20 | 21 | # Configure this external repo 22 | # Currently this CMakeLists.txt file is only used for unit tests 23 | # EXTERNAL_PAL_REPO_DIR contains this top-level CMakeLists.txt 24 | set(EXTERNAL_PAL_REPO_DIR ${CMAKE_CURRENT_LIST_DIR}) 25 | include_directories(${SHARED_UTIL_PAL_INC_FOLDER}) 26 | 27 | 28 | set(run_unittests ON) 29 | add_subdirectory(sdk_tests) 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-iot-pal-esp32/8b0d93e50f31b1c269b63416e0776de82440bdf7/README.md -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Starter pipeline 2 | # Start with a minimal pipeline that you can customize to build and deploy your code. 3 | # Add steps that build, run tests, deploy, and more: 4 | # https://aka.ms/yaml 5 | 6 | trigger: 7 | - master 8 | 9 | pool: 10 | vmImage: ubuntu-latest 11 | 12 | steps: 13 | - script: echo Hello, world! 14 | displayName: 'Run a one-line script' 15 | 16 | - script: | 17 | echo Add other tasks to build, test, and deploy your project. 18 | echo See https://aka.ms/yaml 19 | displayName: 'Run a multi-line script' 20 | -------------------------------------------------------------------------------- /build_all/iothub_client_sample_mqtt.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #include 5 | #include 6 | 7 | #include "iothub_client.h" 8 | #include "iothub_message.h" 9 | #include "azure_c_shared_utility/threadapi.h" 10 | #include "azure_c_shared_utility/crt_abstractions.h" 11 | #include "azure_c_shared_utility/platform.h" 12 | #include "azure_c_shared_utility/shared_util_options.h" 13 | #include "iothubtransportmqtt.h" 14 | #include "iothub_client_options.h" 15 | 16 | #ifdef MBED_BUILD_TIMESTAMP 17 | #define SET_TRUSTED_CERT_IN_SAMPLES 18 | #endif // MBED_BUILD_TIMESTAMP 19 | 20 | #ifdef SET_TRUSTED_CERT_IN_SAMPLES 21 | #include "certs.h" 22 | #endif // SET_TRUSTED_CERT_IN_SAMPLES 23 | 24 | /*String containing Hostname, Device Id & Device Key in the format: */ 25 | /* "HostName=;DeviceId=;SharedAccessKey=" */ 26 | /* "HostName=;DeviceId=;SharedAccessSignature=" */ 27 | static const char* connectionString = "HostName=royspr-m07f130.azure-devices.net;DeviceId=TestDevice01;SharedAccessKey=3s04a6jr99+Oog8KeqG2MnN9igkqu3G+c3JJOLW2tM8="; 28 | 29 | static int callbackCounter; 30 | static char msgText[1024]; 31 | static char propText[1024]; 32 | static bool g_continueRunning; 33 | #define MESSAGE_COUNT 5 34 | #define DOWORK_LOOP_NUM 3 35 | 36 | 37 | typedef struct EVENT_INSTANCE_TAG 38 | { 39 | IOTHUB_MESSAGE_HANDLE messageHandle; 40 | size_t messageTrackingId; // For tracking the messages within the user callback. 41 | } EVENT_INSTANCE; 42 | 43 | static IOTHUBMESSAGE_DISPOSITION_RESULT ReceiveMessageCallback(IOTHUB_MESSAGE_HANDLE message, void* userContextCallback) 44 | { 45 | int* counter = (int*)userContextCallback; 46 | const char* buffer; 47 | size_t size; 48 | MAP_HANDLE mapProperties; 49 | const char* messageId; 50 | const char* correlationId; 51 | const char* userDefinedContentType; 52 | const char* userDefinedContentEncoding; 53 | 54 | // Message properties 55 | if ((messageId = IoTHubMessage_GetMessageId(message)) == NULL) 56 | { 57 | messageId = ""; 58 | } 59 | 60 | if ((correlationId = IoTHubMessage_GetCorrelationId(message)) == NULL) 61 | { 62 | correlationId = ""; 63 | } 64 | 65 | if ((userDefinedContentType = IoTHubMessage_GetContentTypeSystemProperty(message)) == NULL) 66 | { 67 | userDefinedContentType = ""; 68 | } 69 | 70 | if ((userDefinedContentEncoding = IoTHubMessage_GetContentEncodingSystemProperty(message)) == NULL) 71 | { 72 | userDefinedContentEncoding = ""; 73 | } 74 | 75 | // Message content 76 | if (IoTHubMessage_GetByteArray(message, (const unsigned char**)&buffer, &size) != IOTHUB_MESSAGE_OK) 77 | { 78 | (void)printf("unable to retrieve the message data\r\n"); 79 | } 80 | else 81 | { 82 | (void)printf("Received Message [%d]\r\n Message ID: %s\r\n Correlation ID: %s\r\n Content-Type: %s\r\n Content-Encoding: %s\r\n Data: <<<%.*s>>> & Size=%d\r\n", 83 | *counter, messageId, correlationId, userDefinedContentType, userDefinedContentEncoding, (int)size, buffer, (int)size); 84 | // If we receive the work 'quit' then we stop running 85 | if (size == (strlen("quit") * sizeof(char)) && memcmp(buffer, "quit", size) == 0) 86 | { 87 | g_continueRunning = false; 88 | } 89 | } 90 | 91 | // Retrieve properties from the message 92 | mapProperties = IoTHubMessage_Properties(message); 93 | if (mapProperties != NULL) 94 | { 95 | const char*const* keys; 96 | const char*const* values; 97 | size_t propertyCount = 0; 98 | if (Map_GetInternals(mapProperties, &keys, &values, &propertyCount) == MAP_OK) 99 | { 100 | if (propertyCount > 0) 101 | { 102 | size_t index; 103 | 104 | printf(" Message Properties:\r\n"); 105 | for (index = 0; index < propertyCount; index++) 106 | { 107 | (void)printf("\tKey: %s Value: %s\r\n", keys[index], values[index]); 108 | } 109 | (void)printf("\r\n"); 110 | } 111 | } 112 | } 113 | 114 | /* Some device specific action code goes here... */ 115 | (*counter)++; 116 | return IOTHUBMESSAGE_ACCEPTED; 117 | } 118 | 119 | static void SendConfirmationCallback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* userContextCallback) 120 | { 121 | EVENT_INSTANCE* eventInstance = (EVENT_INSTANCE*)userContextCallback; 122 | (void)printf("Confirmation[%d] received for message tracking id = %zu with result = %s\r\n", callbackCounter, eventInstance->messageTrackingId, ENUM_TO_STRING(IOTHUB_CLIENT_CONFIRMATION_RESULT, result)); 123 | /* Some device specific action code goes here... */ 124 | callbackCounter++; 125 | IoTHubMessage_Destroy(eventInstance->messageHandle); 126 | } 127 | 128 | void iothub_client_sample_mqtt_run(void) 129 | { 130 | IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle; 131 | 132 | EVENT_INSTANCE messages[MESSAGE_COUNT]; 133 | 134 | g_continueRunning = true; 135 | srand((unsigned int)time(NULL)); 136 | double avgWindSpeed = 10.0; 137 | double minTemperature = 20.0; 138 | double minHumidity = 60.0; 139 | 140 | callbackCounter = 0; 141 | int receiveContext = 0; 142 | 143 | if (platform_init() != 0) 144 | { 145 | (void)printf("Failed to initialize the platform.\r\n"); 146 | } 147 | else 148 | { 149 | if ((iotHubClientHandle = IoTHubClient_LL_CreateFromConnectionString(connectionString, MQTT_Protocol)) == NULL) 150 | { 151 | (void)printf("ERROR: iotHubClientHandle is NULL!\r\n"); 152 | } 153 | else 154 | { 155 | bool traceOn = true; 156 | IoTHubClient_LL_SetOption(iotHubClientHandle, OPTION_LOG_TRACE, &traceOn); 157 | 158 | #ifdef SET_TRUSTED_CERT_IN_SAMPLES 159 | // For mbed add the certificate information 160 | if (IoTHubClient_LL_SetOption(iotHubClientHandle, OPTION_TRUSTED_CERT, certificates) != IOTHUB_CLIENT_OK) 161 | { 162 | printf("failure to set option \"TrustedCerts\"\r\n"); 163 | } 164 | #endif // SET_TRUSTED_CERT_IN_SAMPLES 165 | 166 | /* Setting Message call back, so we can receive Commands. */ 167 | if (IoTHubClient_LL_SetMessageCallback(iotHubClientHandle, ReceiveMessageCallback, &receiveContext) != IOTHUB_CLIENT_OK) 168 | { 169 | (void)printf("ERROR: IoTHubClient_LL_SetMessageCallback..........FAILED!\r\n"); 170 | } 171 | else 172 | { 173 | (void)printf("IoTHubClient_LL_SetMessageCallback...successful.\r\n"); 174 | 175 | /* Now that we are ready to receive commands, let's send some messages */ 176 | size_t iterator = 0; 177 | double temperature = 0; 178 | double humidity = 0; 179 | do 180 | { 181 | if (iterator < MESSAGE_COUNT) 182 | { 183 | temperature = minTemperature + (rand() % 10); 184 | humidity = minHumidity + (rand() % 20); 185 | sprintf_s(msgText, sizeof(msgText), "{\"deviceId\":\"myFirstDevice\",\"windSpeed\":%.2f,\"temperature\":%.2f,\"humidity\":%.2f}", avgWindSpeed + (rand() % 4 + 2), temperature, humidity); 186 | if ((messages[iterator].messageHandle = IoTHubMessage_CreateFromByteArray((const unsigned char*)msgText, strlen(msgText))) == NULL) 187 | { 188 | (void)printf("ERROR: iotHubMessageHandle is NULL!\r\n"); 189 | } 190 | else 191 | { 192 | 193 | (void)IoTHubMessage_SetMessageId(messages[iterator].messageHandle, "MSG_ID"); 194 | (void)IoTHubMessage_SetCorrelationId(messages[iterator].messageHandle, "CORE_ID"); 195 | (void)IoTHubMessage_SetContentTypeSystemProperty(messages[iterator].messageHandle, "application%2Fjson"); 196 | (void)IoTHubMessage_SetContentEncodingSystemProperty(messages[iterator].messageHandle, "utf-8"); 197 | 198 | messages[iterator].messageTrackingId = iterator; 199 | MAP_HANDLE propMap = IoTHubMessage_Properties(messages[iterator].messageHandle); 200 | (void)sprintf_s(propText, sizeof(propText), temperature > 28 ? "true" : "false"); 201 | if (Map_AddOrUpdate(propMap, "temperatureAlert", propText) != MAP_OK) 202 | { 203 | (void)printf("ERROR: Map_AddOrUpdate Failed!\r\n"); 204 | } 205 | 206 | if (IoTHubClient_LL_SendEventAsync(iotHubClientHandle, messages[iterator].messageHandle, SendConfirmationCallback, &messages[iterator]) != IOTHUB_CLIENT_OK) 207 | { 208 | (void)printf("ERROR: IoTHubClient_LL_SendEventAsync..........FAILED!\r\n"); 209 | } 210 | else 211 | { 212 | (void)printf("IoTHubClient_LL_SendEventAsync accepted message [%d] for transmission to IoT Hub.\r\n", (int)iterator); 213 | } 214 | } 215 | 216 | } 217 | IoTHubClient_LL_DoWork(iotHubClientHandle); 218 | ThreadAPI_Sleep(1); 219 | 220 | iterator++; 221 | } while (g_continueRunning); 222 | 223 | (void)printf("iothub_client_sample_mqtt has gotten quit message, call DoWork %d more time to complete final sending...\r\n", DOWORK_LOOP_NUM); 224 | size_t index = 0; 225 | for (index = 0; index < DOWORK_LOOP_NUM; index++) 226 | { 227 | IoTHubClient_LL_DoWork(iotHubClientHandle); 228 | ThreadAPI_Sleep(1); 229 | } 230 | } 231 | IoTHubClient_LL_Destroy(iotHubClientHandle); 232 | } 233 | platform_deinit(); 234 | } 235 | } 236 | 237 | int main(void) 238 | { 239 | iothub_client_sample_mqtt_run(); 240 | return 0; 241 | } 242 | -------------------------------------------------------------------------------- /build_all/iothub_client_sample_mqtt.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #ifndef IOTHUB_CLIENT_SAMPLE_MQTT_H 5 | #define IOTHUB_CLIENT_SAMPLE_MQTT_H 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | void iothub_client_sample_mqtt_run(void); 12 | 13 | #ifdef __cplusplus 14 | } 15 | #endif 16 | 17 | #endif /* IOTHUB_CLIENT_SAMPLE_MQTT_H */ 18 | -------------------------------------------------------------------------------- /component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Component Makefile 3 | # 4 | 5 | # Component configuration in preprocessor defines 6 | CFLAGS += -DUSE_LWIP_SOCKET_FOR_AZURE_IOT 7 | 8 | 9 | COMPONENT_ADD_INCLUDEDIRS := \ 10 | pal \ 11 | pal/inc \ 12 | sdk/c-utility/inc \ 13 | sdk/c-utility/inc/azure_c_shared_utility \ 14 | sdk/c-utility/pal/inc \ 15 | sdk/c-utility/pal/freertos \ 16 | sdk/c-utility/pal/generic \ 17 | sdk/iothub_client/inc \ 18 | sdk/serializer/inc \ 19 | sdk/umqtt/inc \ 20 | sdk/umqtt/inc/azure_umqtt_c \ 21 | sdk/deps/parson 22 | 23 | COMPONENT_OBJS = \ 24 | sdk/c-utility/pal/freertos/lock.o \ 25 | sdk/c-utility/pal/dns_async.o \ 26 | sdk/c-utility/pal/socket_async.o \ 27 | sdk/c-utility/pal/freertos/threadapi.o \ 28 | sdk/c-utility/pal/freertos/tickcounter.o \ 29 | sdk/c-utility/pal/lwip/sntp_lwip.o \ 30 | sdk/c-utility/pal/tlsio_options.o \ 31 | sdk/c-utility/adapters/agenttime.o \ 32 | \ 33 | pal/src/platform_openssl_compact.o \ 34 | pal/src/tlsio_openssl_compact.o \ 35 | \ 36 | sdk/c-utility/src/xlogging.o \ 37 | sdk/c-utility/src/singlylinkedlist.o \ 38 | sdk/c-utility/src/buffer.o \ 39 | sdk/c-utility/src/consolelogger.o \ 40 | sdk/c-utility/src/constbuffer.o \ 41 | sdk/c-utility/src/constmap.o \ 42 | sdk/c-utility/src/crt_abstractions.o \ 43 | sdk/c-utility/src/doublylinkedlist.o \ 44 | sdk/c-utility/src/gballoc.o \ 45 | sdk/c-utility/src/gb_stdio.o \ 46 | sdk/c-utility/src/gb_time.o \ 47 | sdk/c-utility/src/hmac.o \ 48 | sdk/c-utility/src/hmacsha256.o \ 49 | sdk/c-utility/src/httpapiex.o \ 50 | sdk/c-utility/src/httpapiexsas.o \ 51 | sdk/c-utility/src/httpheaders.o \ 52 | sdk/c-utility/src/map.o \ 53 | sdk/c-utility/src/optionhandler.o \ 54 | sdk/c-utility/src/sastoken.o \ 55 | sdk/c-utility/src/sha1.o \ 56 | sdk/c-utility/src/sha224.o \ 57 | sdk/c-utility/src/sha384-512.o \ 58 | sdk/c-utility/src/strings.o \ 59 | sdk/c-utility/src/string_tokenizer.o \ 60 | sdk/c-utility/src/urlencode.o \ 61 | sdk/c-utility/src/usha.o \ 62 | sdk/c-utility/src/vector.o \ 63 | sdk/c-utility/src/xio.o \ 64 | sdk/c-utility/src/base64.o \ 65 | \ 66 | \ 67 | sdk/iothub_client/src/iothub_client_ll.o \ 68 | sdk/iothub_client/src/iothub_client_ll_uploadtoblob.o \ 69 | sdk/iothub_client/src/iothub_client_authorization.o \ 70 | sdk/iothub_client/src/iothub_client_retry_control.o \ 71 | sdk/iothub_client/src/iothub_client_diagnostic.o \ 72 | sdk/iothub_client/src/iothub_message.o \ 73 | sdk/iothub_client/src/iothubtransport.o \ 74 | sdk/iothub_client/src/iothubtransportmqtt.o \ 75 | sdk/iothub_client/src/iothubtransport_mqtt_common.o \ 76 | sdk/iothub_client/src/version.o \ 77 | \ 78 | \ 79 | sdk/umqtt/src/mqtt_client.o \ 80 | sdk/umqtt/src/mqtt_codec.o \ 81 | sdk/umqtt/src/mqtt_message.o \ 82 | \ 83 | \ 84 | sdk/deps/parson/parson.o \ 85 | \ 86 | sdk/serializer/src/codefirst.o \ 87 | sdk/serializer/src/agenttypesystem.o \ 88 | sdk/serializer/src/commanddecoder.o \ 89 | sdk/serializer/src/datamarshaller.o \ 90 | sdk/serializer/src/datapublisher.o \ 91 | sdk/serializer/src/dataserializer.o \ 92 | sdk/serializer/src/iotdevice.o \ 93 | sdk/serializer/src/jsondecoder.o \ 94 | sdk/serializer/src/jsonencoder.o \ 95 | sdk/serializer/src/methodreturn.o \ 96 | sdk/serializer/src/multitree.o \ 97 | sdk/serializer/src/schema.o \ 98 | sdk/serializer/src/schemalib.o \ 99 | sdk/serializer/src/schemaserializer.o \ 100 | \ 101 | \ 102 | 103 | COMPONENT_SRCDIRS := \ 104 | pal/src \ 105 | sdk/c-utility/pal \ 106 | sdk/c-utility/pal/freertos \ 107 | sdk/c-utility/pal/lwip \ 108 | sdk/c-utility/src \ 109 | sdk/c-utility/adapters \ 110 | sdk/umqtt/src \ 111 | sdk/iothub_client/src \ 112 | sdk/serializer/src \ 113 | sdk/deps/parson 114 | -------------------------------------------------------------------------------- /devdoc/platform_openssl_compact_requirements.md: -------------------------------------------------------------------------------- 1 | platform_openssl_compact 2 | ============= 3 | 4 | ## Overview 5 | 6 | **platform_openssl_compact** implements the **platform** adapter for the Azure IoT C SDK. This implementation 7 | uses a version of the **tlsio** adapter for OpenSSL which is aimed at embedded applications. 8 | 9 | Unlike non-micro systems such as Windows and Linux, embedded systems typically 10 | require explicit NTP initialization, so platform_openssl_compact performs NTP 11 | initialization and deinitialization using the interfaces in `azure-c-shared-utility/inc/azure_c_shared_utility/sntp.h`. 12 | 13 | ## References 14 | [sntp.h](https://github.com/Azure/azure-c-shared-utility/tree/master/inc/azure_c_shared_utility/sntp.h) 15 | 16 | ### Standard 17 | 18 | **SRS_PLATFORM_OPENSSL_COMPACT_30_001: [** The platform_openssl_compact shall implement the interface provided in the `platfom.h`. 19 | 20 | 21 | ```c 22 | int platform_init(); 23 | void platform_deinit(); 24 | const IO_INTERFACE_DESCRIPTION* platform_get_default_tlsio(); 25 | ``` 26 | **]** 27 | 28 | **SRS_PLATFORM_OPENSSL_COMPACT_30_002: [** The platform_openssl_compact shall use the tlsio functions defined in 'xio.h'. 29 | ```c 30 | typedef OPTIONHANDLER_HANDLE (*IO_RETRIEVEOPTIONS)(CONCRETE_IO_HANDLE concrete_io); 31 | typedef CONCRETE_IO_HANDLE(*IO_CREATE)(void* io_create_parameters); 32 | typedef void(*IO_DESTROY)(CONCRETE_IO_HANDLE concrete_io); 33 | typedef int(*IO_OPEN)(CONCRETE_IO_HANDLE concrete_io, ON_IO_OPEN_COMPLETE on_io_open_complete, void* on_io_open_complete_context, ON_BYTES_RECEIVED on_bytes_received, void* on_bytes_received_context, ON_IO_ERROR on_io_error, void* on_io_error_context); 34 | typedef int(*IO_CLOSE)(CONCRETE_IO_HANDLE concrete_io, ON_IO_CLOSE_COMPLETE on_io_close_complete, void* callback_context); 35 | typedef int(*IO_SEND)(CONCRETE_IO_HANDLE concrete_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context); 36 | typedef void(*IO_DOWORK)(CONCRETE_IO_HANDLE concrete_io); 37 | typedef int(*IO_SETOPTION)(CONCRETE_IO_HANDLE concrete_io, const char* optionName, const void* value); 38 | 39 | typedef struct IO_INTERFACE_DESCRIPTION_TAG 40 | { 41 | IO_RETRIEVEOPTIONS concrete_io_retrieveoptions; 42 | IO_CREATE concrete_io_create; 43 | IO_DESTROY concrete_io_destroy; 44 | IO_OPEN concrete_io_open; 45 | IO_CLOSE concrete_io_close; 46 | IO_SEND concrete_io_send; 47 | IO_DOWORK concrete_io_dowork; 48 | IO_SETOPTION concrete_io_setoption; 49 | } IO_INTERFACE_DESCRIPTION; 50 | ``` 51 | **]** 52 | 53 | **SRS_PLATFORM_OPENSSL_COMPACT_30_003: [** The platform_openssl_compact shall use the sntp functions defined in 'sntp.h'. 54 | ```c 55 | int SNTP_SetServerName(const char*, serverName); 56 | int SNTP_Init(); 57 | void SNTP_Deinit(); 58 | ``` 59 | **]** 60 | 61 | ### platform_init 62 | 63 | The `platform_init` call performs initialization for the compact (microcontroller) version of the OpenSSL tlsio adapter plus sntp client initialization. 64 | 65 | ```c 66 | int platform_init(); 67 | ``` 68 | 69 | **SRS_PLATFORM_OPENSSL_COMPACT_30_004: [** The platform_init shall initialize the tlsio adapter. **]** 70 | 71 | **SRS_PLATFORM_OPENSSL_COMPACT_30_005: [** The platform_init shall initialize the sntp client. **]** 72 | 73 | 74 | ### platform_deinit 75 | 76 | ```c 77 | int platform_deinit(); 78 | ``` 79 | 80 | **SRS_PLATFORM_OPENSSL_COMPACT_30_006: [** The platform_deinit shall deinitialize the sntp client. (The OpenSSL micro tlsio adapter requires no deinitialization.) **]** 81 | 82 | 83 | ### platform_get_default_tlsio 84 | 85 | ```c 86 | const IO_INTERFACE_DESCRIPTION* platform_get_default_tlsio(void); 87 | ``` 88 | 89 | **SRS_PLATFORM_OPENSSL_COMPACT_30_007: [** The platform_get_default_tlsio shall return a set of tlsio functions provided by the OpenSSL micro tlsio implementation. **]** 90 | -------------------------------------------------------------------------------- /devdoc/tlsio_openssl_compact_requirements.md: -------------------------------------------------------------------------------- 1 | # tlsio_openssl_compact 2 | 3 | 4 | ## Overview 5 | 6 | The tlsio_openssl_compact adapter implements a tlsio adapter for compact OpenSSL platforms such as Espressif's ESP32. 7 | 8 | 9 | ## References 10 | 11 | [tlsio base specification](https://github.com/Azure/azure-c-shared-utility/blob/master/devdoc/tlsio_requirements.md) 12 | 13 | [OpenSSL](https://www.openssl.org/) 14 | 15 | ## Base Specification 16 | 17 | The tlsio_openssl_compact adapter conforms to the 18 | [tlsio base specification](https://github.com/Azure/azure-c-shared-utility/blob/master/devdoc/tlsio_requirements.md) and 19 | additionally implements the additional requirements below. 20 | 21 | 22 | ## API Calls 23 | 24 | 25 | ### tlsio_setoption 26 | 27 | **SRS_TLSIO_OPENSSL_COMPACT_30_520 [** The `tlsio_setoption` shall do nothing and return __FAILURE__. **]** 28 | 29 | 30 | ### tlsio_retrieveoptions 31 | 32 | **SRS_TLSIO_OPENSSL_COMPACT_30_560: [** The `tlsio_retrieveoptions` shall return an empty options handler. **]** 33 | 34 | 35 | -------------------------------------------------------------------------------- /jenkins/ubuntu1510_c.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) Microsoft. All rights reserved. 3 | # Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | 5 | build_root=$(cd "$(dirname "$0")/.." && pwd) 6 | cd $build_root/sdk/c-utility/build_all/linux 7 | 8 | # -- C -- 9 | ./build.sh --run-unittests --run_valgrind --build-root $build_root "$@" #-x 10 | [ $? -eq 0 ] || exit $? 11 | 12 | -------------------------------------------------------------------------------- /jenkins/ubuntu1604_c.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) Microsoft. All rights reserved. 3 | # Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | 5 | build_root=$(cd "$(dirname "$0")/.." && pwd) 6 | cd $build_root/sdk/c-utility/build_all/linux 7 | 8 | # -- C -- 9 | ./build.sh --run-unittests --run_valgrind --build-root $build_root "$@" #-x 10 | [ $? -eq 0 ] || exit $? 11 | 12 | -------------------------------------------------------------------------------- /jenkins/windows_c.cmd: -------------------------------------------------------------------------------- 1 | @REM Copyright (c) Microsoft. All rights reserved. 2 | @REM Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | setlocal 5 | 6 | set build-root=%~dp0.. 7 | rem // resolve to fully qualified path 8 | for %%i in ("%build-root%") do set build-root=%%~fi 9 | 10 | echo %build-root% 11 | 12 | REM -- C -- 13 | cd %build-root%\sdk\c-utility\build_all\windows 14 | 15 | call build.cmd %* --build-root %build-root% --solution-name azure_external_unit_tests 16 | if errorlevel 1 goto :eof 17 | cd %build-root% -------------------------------------------------------------------------------- /pal/inc/sntp_os.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | //This file pulls in OS-specific header files to allow compilation of socket_async.c under 5 | // most OS's except for Windows. 6 | 7 | // For ESP32 lwIP systems which use the ESP-IDF's non-standard lwIP include structure 8 | // Tested with: 9 | // ESP32 10 | 11 | #ifndef LWIP_SNTP_OS_H 12 | #define LWIP_SNTP_OS_H 13 | 14 | #include "apps/sntp/sntp.h" 15 | 16 | #endif // LWIP_SNTP_OS_H -------------------------------------------------------------------------------- /pal/inc/socket_async_os.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | //This file pulls in OS-specific header files to allow compilation of socket_async.c under 5 | // most OS's except for Windows. 6 | 7 | // For lwIP systems 8 | // Tested with: 9 | // ESP32 10 | 11 | #ifndef SOCKET_ASYNC_OS_H 12 | #define SOCKET_ASYNC_OS_H 13 | 14 | #include "lwip/sockets.h" 15 | #include "lwip/netdb.h" 16 | 17 | #endif // SOCKET_ASYNC_OS_H -------------------------------------------------------------------------------- /pal/inc/tlsio_pal.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #ifndef TLSIO_PAL_H 5 | #define TLSIO_PAL_H 6 | 7 | #include "azure_c_shared_utility/tlsio.h" 8 | #include "azure_c_shared_utility/umock_c_prod.h" 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif /* __cplusplus */ 13 | 14 | MOCKABLE_FUNCTION(, const IO_INTERFACE_DESCRIPTION*, tlsio_pal_get_interface_description); 15 | 16 | #ifdef __cplusplus 17 | } 18 | #endif /* __cplusplus */ 19 | 20 | #endif /* TLSIO_PAL_H */ 21 | -------------------------------------------------------------------------------- /pal/src/platform_openssl_compact.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #include "azure_c_shared_utility/platform.h" 5 | #include "sntp.h" 6 | #include "tlsio_pal.h" 7 | #include "azure_c_shared_utility/xlogging.h" 8 | 9 | static const char* const ntpServer = "pool.ntp.org"; 10 | 11 | /* Codes_SRS_PLATFORM_OPENSSL_COMPACT_30_004: [ The platform_init shall initialize the tlsio adapter. ] */ 12 | /* Codes_SRS_PLATFORM_OPENSSL_COMPACT_30_005: [ The platform_init shall initialize the sntp client. ] */ 13 | int platform_init(void) 14 | { 15 | // SNTP_SetServerName logs any necessary errors 16 | int result; 17 | if (SNTP_SetServerName(ntpServer) != 0) 18 | { 19 | LogError("Failed SNTP_SetServerName"); 20 | result = __FAILURE__; 21 | } 22 | else 23 | { 24 | } 25 | if (SNTP_Init() != 0) 26 | { 27 | LogError("Failed SNTP_Init"); 28 | result = __FAILURE__; 29 | } 30 | else 31 | { 32 | result = 0; 33 | } 34 | return result; 35 | } 36 | 37 | /* Codes_SRS_PLATFORM_OPENSSL_COMPACT_30_008: [ The platform_get_default_tlsio shall return a set of tlsio functions provided by the OpenSSL micro tlsio implementation. ] */ 38 | const IO_INTERFACE_DESCRIPTION* platform_get_default_tlsio(void) 39 | { 40 | return tlsio_pal_get_interface_description(); 41 | } 42 | 43 | STRING_HANDLE platform_get_platform_info(void) 44 | { 45 | return STRING_construct("(openssl_compact)"); 46 | } 47 | 48 | /* Codes_SRS_PLATFORM_OPENSSL_COMPACT_30_006: [ The platform_deinit shall deinitialize the sntp client. ] */ 49 | /* Codes_SRS_PLATFORM_OPENSSL_COMPACT_30_007: [ The platform_deinit shall deinitialize the tlsio adapter. ] */ 50 | void platform_deinit(void) 51 | { 52 | SNTP_Deinit(); 53 | 54 | // The tlsio adapter for this platform does not need (or support) deinitialization 55 | } 56 | -------------------------------------------------------------------------------- /pal/src/tlsio_openssl_compact.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #include 5 | 6 | #include "openssl/ssl.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include "socket_async.h" 12 | #include "dns_async.h" 13 | #include "tlsio_pal.h" 14 | #include "azure_c_shared_utility/gballoc.h" 15 | #include "azure_c_shared_utility/xlogging.h" 16 | #include "azure_c_shared_utility/agenttime.h" 17 | #include "azure_c_shared_utility/singlylinkedlist.h" 18 | #include "azure_c_shared_utility/crt_abstractions.h" 19 | #include "azure_c_shared_utility/tlsio_options.h" 20 | 21 | typedef struct 22 | { 23 | unsigned char* bytes; 24 | size_t size; 25 | size_t unsent_size; 26 | ON_SEND_COMPLETE on_send_complete; 27 | void* callback_context; 28 | } PENDING_TRANSMISSION; 29 | 30 | #define MAX_VALID_PORT 0xffff 31 | 32 | // The TLSIO_RECEIVE_BUFFER_SIZE has very little effect on performance, and is kept small 33 | // to minimize memory consumption. 34 | #define TLSIO_RECEIVE_BUFFER_SIZE 64 35 | 36 | 37 | typedef enum TLSIO_STATE_TAG 38 | { 39 | TLSIO_STATE_CLOSED, 40 | TLSIO_STATE_OPENING_WAITING_DNS, 41 | TLSIO_STATE_OPENING_WAITING_SOCKET, 42 | TLSIO_STATE_OPENING_WAITING_SSL, 43 | TLSIO_STATE_OPEN, 44 | TLSIO_STATE_ERROR, 45 | } TLSIO_STATE; 46 | 47 | bool is_an_opening_state(TLSIO_STATE state) 48 | { 49 | return state == TLSIO_STATE_OPENING_WAITING_DNS || 50 | state == TLSIO_STATE_OPENING_WAITING_SOCKET || 51 | state == TLSIO_STATE_OPENING_WAITING_SSL; 52 | } 53 | 54 | // This structure definition is mirrored in the unit tests, so if you change 55 | // this struct, keep it in sync with the one in tlsio_openssl_compact_ut.c 56 | typedef struct TLS_IO_INSTANCE_TAG 57 | { 58 | ON_BYTES_RECEIVED on_bytes_received; 59 | ON_IO_ERROR on_io_error; 60 | ON_IO_OPEN_COMPLETE on_open_complete; 61 | void* on_bytes_received_context; 62 | void* on_io_error_context; 63 | void* on_open_complete_context; 64 | SSL* ssl; 65 | SSL_CTX* ssl_context; 66 | TLSIO_STATE tlsio_state; 67 | DNS_ASYNC_HANDLE dns; 68 | char* hostname; 69 | uint16_t port; 70 | SOCKET_ASYNC_HANDLE sock; 71 | SINGLYLINKEDLIST_HANDLE pending_transmission_list; 72 | TLSIO_OPTIONS options; 73 | } TLS_IO_INSTANCE; 74 | 75 | /* Codes_SRS_TLSIO_30_005: [ The phrase "enter TLSIO_STATE_EXT_ERROR" means the adapter shall call the on_io_error function and pass the on_io_error_context that was supplied in tlsio_open_async. ]*/ 76 | static void enter_tlsio_error_state(TLS_IO_INSTANCE* tls_io_instance) 77 | { 78 | if (tls_io_instance->tlsio_state != TLSIO_STATE_ERROR) 79 | { 80 | tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; 81 | tls_io_instance->on_io_error(tls_io_instance->on_io_error_context); 82 | } 83 | } 84 | 85 | /* Codes_SRS_TLSIO_30_005: [ When the adapter enters TLSIO_STATE_EXT_ERROR it shall call the on_io_error function and pass the on_io_error_context that were supplied in tlsio_open . ]*/ 86 | static void enter_open_error_state(TLS_IO_INSTANCE* tls_io_instance) 87 | { 88 | // save instance variables in case the framework destroys this object before we exit 89 | ON_IO_OPEN_COMPLETE on_open_complete = tls_io_instance->on_open_complete; 90 | void* on_open_complete_context = tls_io_instance->on_open_complete_context; 91 | enter_tlsio_error_state(tls_io_instance); 92 | on_open_complete(on_open_complete_context, IO_OPEN_ERROR); 93 | } 94 | 95 | // Return true if a message was available to remove 96 | static bool process_and_destroy_head_message(TLS_IO_INSTANCE* tls_io_instance, IO_SEND_RESULT send_result) 97 | { 98 | bool result; 99 | LIST_ITEM_HANDLE head_pending_io; 100 | if (send_result == IO_SEND_ERROR) 101 | { 102 | /* Codes_SRS_TLSIO_30_095: [ If the send process fails before sending all of the bytes in an enqueued message, the tlsio_dowork shall call the message's on_send_complete along with its associated callback_context and IO_SEND_ERROR. ]*/ 103 | enter_tlsio_error_state(tls_io_instance); 104 | } 105 | head_pending_io = singlylinkedlist_get_head_item(tls_io_instance->pending_transmission_list); 106 | if (head_pending_io != NULL) 107 | { 108 | PENDING_TRANSMISSION* head_message = (PENDING_TRANSMISSION*)singlylinkedlist_item_get_value(head_pending_io); 109 | // Must remove the item from the list before calling the callback because 110 | // SRS_TLSIO_30_091: [ If tlsio_dowork is able to send all the bytes in an enqueued message, it shall first dequeue the message then call the messages's on_send_complete along with its associated callback_context and IO_SEND_OK . ] 111 | if (singlylinkedlist_remove(tls_io_instance->pending_transmission_list, head_pending_io) != 0) 112 | { 113 | // This particular situation is a bizarre and unrecoverable internal error 114 | /* Codes_SRS_TLSIO_30_094: [ If the send process encounters an internal error or calls on_send_complete with IO_SEND_ERROR due to either failure or timeout, it shall also call on_io_error and pass in the associated on_io_error_context. ]*/ 115 | enter_tlsio_error_state(tls_io_instance); 116 | LogError("Failed to remove message from list"); 117 | } 118 | // on_send_complete is checked for NULL during PENDING_TRANSMISSION creation 119 | /* Codes_SRS_TLSIO_30_095: [ If the send process fails before sending all of the bytes in an enqueued message, the tlsio_dowork shall call the message's on_send_complete along with its associated callback_context and IO_SEND_ERROR. ]*/ 120 | head_message->on_send_complete(head_message->callback_context, send_result); 121 | 122 | free(head_message->bytes); 123 | free(head_message); 124 | result = true; 125 | } 126 | else 127 | { 128 | result = false; 129 | } 130 | return result; 131 | } 132 | 133 | static void internal_close(TLS_IO_INSTANCE* tls_io_instance) 134 | { 135 | /* Codes_SRS_TLSIO_30_009: [ The phrase "enter TLSIO_STATE_EXT_CLOSING" means the adapter shall iterate through any unsent messages in the queue and shall delete each message after calling its on_send_complete with the associated callback_context and IO_SEND_CANCELLED. ]*/ 136 | /* Codes_SRS_TLSIO_30_006: [ The phrase "enter TLSIO_STATE_EXT_CLOSED" means the adapter shall forcibly close any existing connections then call the on_io_close_complete function and pass the on_io_close_complete_context that was supplied in tlsio_close_async. ]*/ 137 | /* Codes_SRS_TLSIO_30_051: [ On success, if the underlying TLS does not support asynchronous closing, then the adapter shall enter TLSIO_STATE_EXT_CLOSED immediately after entering TLSIO_STATE_EX_CLOSING. ]*/ 138 | if (tls_io_instance->tlsio_state == TLSIO_STATE_OPEN) 139 | { 140 | // From the OpenSSL manual pages: "According to the TLS standard, it is acceptable 141 | // for an application to only send its shutdown alert and then close the 142 | // underlying connection without waiting for the peer's response...". It goes 143 | // on to say that waiting for shutdown only makes sense if the underlying 144 | // connection is being re-used, which we do not do. So there's no need 145 | // to wait for shutdown. The SSL_shutdown result is not logged because the 146 | // return values are of no interest for unidirectional shutdown, which is 147 | // what we use. 148 | (void)SSL_shutdown(tls_io_instance->ssl); 149 | } 150 | 151 | if (tls_io_instance->dns != NULL) 152 | { 153 | dns_async_destroy(tls_io_instance->dns); 154 | tls_io_instance->dns = NULL; 155 | } 156 | if (tls_io_instance->ssl != NULL) 157 | { 158 | SSL_free(tls_io_instance->ssl); 159 | tls_io_instance->ssl = NULL; 160 | } 161 | if (tls_io_instance->ssl_context != NULL) 162 | { 163 | SSL_CTX_free(tls_io_instance->ssl_context); 164 | tls_io_instance->ssl_context = NULL; 165 | } 166 | if (tls_io_instance->sock >= 0) 167 | { 168 | // The underlying socket API does not support waiting for close 169 | // to complete, so it isn't possible to do so. 170 | socket_async_destroy(tls_io_instance->sock); 171 | tls_io_instance->sock = -1; 172 | } 173 | 174 | while (process_and_destroy_head_message(tls_io_instance, IO_SEND_CANCELLED)); 175 | // singlylinkedlist_destroy gets called in the main destroy 176 | 177 | tls_io_instance->on_bytes_received = NULL; 178 | tls_io_instance->on_io_error = NULL; 179 | tls_io_instance->on_bytes_received_context = NULL; 180 | tls_io_instance->on_io_error_context = NULL; 181 | tls_io_instance->tlsio_state = TLSIO_STATE_CLOSED; 182 | tls_io_instance->on_open_complete = NULL; 183 | tls_io_instance->on_open_complete_context = NULL; 184 | } 185 | 186 | // This method tests for hard errors returned from either SSL_write or SSL_connect. 187 | // Returns 188 | // 0 for SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE 189 | // The actual error for other errors (real failures) 190 | static int is_hard_ssl_error(SSL* ssl, int callReturn) 191 | { 192 | int result = SSL_get_error(ssl, callReturn); 193 | if (result == SSL_ERROR_WANT_READ || result == SSL_ERROR_WANT_WRITE) 194 | { 195 | result = 0; 196 | } 197 | return result; 198 | } 199 | 200 | static void tlsio_openssl_destroy(CONCRETE_IO_HANDLE tls_io) 201 | { 202 | if (tls_io == NULL) 203 | { 204 | /* Codes_SRS_TLSIO_30_020: [ If tlsio_handle is NULL, tlsio_destroy shall do nothing. ]*/ 205 | LogError("NULL tlsio"); 206 | } 207 | else 208 | { 209 | TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io; 210 | if (tls_io_instance->tlsio_state != TLSIO_STATE_CLOSED) 211 | { 212 | /* Codes_SRS_TLSIO_30_022: [ If the adapter is in any state other than TLSIO_STATE_EX_CLOSED when tlsio_destroy is called, the adapter shall enter TLSIO_STATE_EX_CLOSING and then enter TLSIO_STATE_EX_CLOSED before completing the destroy process. ]*/ 213 | LogError("tlsio_openssl_destroy called while not in TLSIO_STATE_CLOSED."); 214 | internal_close(tls_io_instance); 215 | } 216 | /* Codes_SRS_TLSIO_30_021: [ The tlsio_destroy shall release all allocated resources and then release tlsio_handle. ]*/ 217 | if (tls_io_instance->hostname != NULL) 218 | { 219 | free(tls_io_instance->hostname); 220 | } 221 | 222 | tlsio_options_release_resources(&tls_io_instance->options); 223 | 224 | if (tls_io_instance->pending_transmission_list != NULL) 225 | { 226 | /* Pending messages were cleared in internal_close */ 227 | singlylinkedlist_destroy(tls_io_instance->pending_transmission_list); 228 | } 229 | 230 | free(tls_io_instance); 231 | } 232 | } 233 | 234 | /* Codes_SRS_TLSIO_30_010: [ The tlsio_create shall allocate and initialize all necessary resources and return an instance of the tlsio_openssl_compact. ]*/ 235 | static CONCRETE_IO_HANDLE tlsio_openssl_create(void* io_create_parameters) 236 | { 237 | TLS_IO_INSTANCE* result; 238 | 239 | if (io_create_parameters == NULL) 240 | { 241 | /* Codes_SRS_TLSIO_30_013: [ If the io_create_parameters value is NULL, tlsio_create shall log an error and return NULL. ]*/ 242 | LogError("NULL tls_io_config"); 243 | result = NULL; 244 | } 245 | else 246 | { 247 | /* Codes_SRS_TLSIO_30_012: [ The tlsio_create shall receive the connection configuration as a TLSIO_CONFIG* in io_create_parameters. ]*/ 248 | TLSIO_CONFIG* tls_io_config = (TLSIO_CONFIG*)io_create_parameters; 249 | if (tls_io_config->hostname == NULL) 250 | { 251 | /* Codes_SRS_TLSIO_30_014: [ If the hostname member of io_create_parameters value is NULL, tlsio_create shall log an error and return NULL. ]*/ 252 | LogError("NULL tls_io_config->hostname"); 253 | result = NULL; 254 | } 255 | else if (tls_io_config->port < 0 || tls_io_config->port > MAX_VALID_PORT) 256 | { 257 | /* Codes_SRS_TLSIO_30_015: [ If the port member of io_create_parameters value is less than 0 or greater than 0xffff, tlsio_create shall log an error and return NULL. ]*/ 258 | LogError("tls_io_config->port out of range"); 259 | result = NULL; 260 | } 261 | else 262 | { 263 | result = malloc(sizeof(TLS_IO_INSTANCE)); 264 | if (result == NULL) 265 | { 266 | /* Codes_SRS_TLSIO_30_011: [ If any resource allocation fails, tlsio_create shall return NULL. ]*/ 267 | LogError("malloc failed"); 268 | } 269 | else 270 | { 271 | int ms_result; 272 | memset(result, 0, sizeof(TLS_IO_INSTANCE)); 273 | result->port = (uint16_t)tls_io_config->port; 274 | result->tlsio_state = TLSIO_STATE_CLOSED; 275 | result->sock = SOCKET_ASYNC_INVALID_SOCKET; 276 | result->hostname = NULL; 277 | result->dns = NULL; 278 | result->pending_transmission_list = NULL; 279 | // No options are currently supported 280 | tlsio_options_initialize(&result->options, TLSIO_OPTION_BIT_NONE); 281 | /* Codes_SRS_TLSIO_30_016: [ tlsio_create shall make a copy of the hostname member of io_create_parameters to allow deletion of hostname immediately after the call. ]*/ 282 | ms_result = mallocAndStrcpy_s(&result->hostname, tls_io_config->hostname); 283 | if (ms_result != 0) 284 | { 285 | /* Codes_SRS_TLSIO_30_011: [ If any resource allocation fails, tlsio_create shall return NULL. ]*/ 286 | LogError("malloc failed"); 287 | tlsio_openssl_destroy(result); 288 | result = NULL; 289 | } 290 | else 291 | { 292 | // Create the message queue 293 | result->pending_transmission_list = singlylinkedlist_create(); 294 | if (result->pending_transmission_list == NULL) 295 | { 296 | /* Codes_SRS_TLSIO_30_011: [ If any resource allocation fails, tlsio_create shall return NULL. ]*/ 297 | LogError("Failed singlylinkedlist_create"); 298 | tlsio_openssl_destroy(result); 299 | result = NULL; 300 | } 301 | } 302 | } 303 | } 304 | } 305 | 306 | return (CONCRETE_IO_HANDLE)result; 307 | } 308 | 309 | 310 | static int tlsio_openssl_open_async(CONCRETE_IO_HANDLE tls_io, 311 | ON_IO_OPEN_COMPLETE on_io_open_complete, void* on_io_open_complete_context, 312 | ON_BYTES_RECEIVED on_bytes_received, void* on_bytes_received_context, 313 | ON_IO_ERROR on_io_error, void* on_io_error_context) 314 | { 315 | 316 | int result; 317 | if (on_io_open_complete == NULL) 318 | { 319 | /* Codes_SRS_TLSIO_30_031: [ If the on_io_open_complete parameter is NULL, tlsio_open shall log an error and return FAILURE. ]*/ 320 | LogError("Required parameter on_io_open_complete is NULL"); 321 | result = __FAILURE__; 322 | } 323 | else 324 | { 325 | if (tls_io == NULL) 326 | { 327 | /* Codes_SRS_TLSIO_30_030: [ If the tlsio_handle parameter is NULL, tlsio_open shall log an error and return FAILURE. ]*/ 328 | result = __FAILURE__; 329 | LogError("NULL tlsio"); 330 | } 331 | else 332 | { 333 | if (on_bytes_received == NULL) 334 | { 335 | /* Codes_SRS_TLSIO_30_032: [ If the on_bytes_received parameter is NULL, tlsio_open shall log an error and return FAILURE. ]*/ 336 | LogError("Required parameter on_bytes_received is NULL"); 337 | result = __FAILURE__; 338 | } 339 | else 340 | { 341 | if (on_io_error == NULL) 342 | { 343 | /* Codes_SRS_TLSIO_30_033: [ If the on_io_error parameter is NULL, tlsio_open shall log an error and return FAILURE. ]*/ 344 | LogError("Required parameter on_io_error is NULL"); 345 | result = __FAILURE__; 346 | } 347 | else 348 | { 349 | TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io; 350 | 351 | if (tls_io_instance->tlsio_state != TLSIO_STATE_CLOSED) 352 | { 353 | /* Codes_SRS_TLSIO_30_037: [ If the adapter is in any state other than TLSIO_STATE_EXT_CLOSED when tlsio_open is called, it shall log an error, and return FAILURE. ]*/ 354 | LogError("Invalid tlsio_state. Expected state is TLSIO_STATE_CLOSED."); 355 | result = __FAILURE__; 356 | } 357 | else 358 | { 359 | tls_io_instance->dns = dns_async_create(tls_io_instance->hostname, NULL); 360 | if (tls_io_instance->dns == NULL) 361 | { 362 | /* Codes_SRS_TLSIO_30_038: [ If tlsio_open fails to enter TLSIO_STATE_EX_OPENING it shall return FAILURE. ]*/ 363 | LogError("dns_async_create failed"); 364 | result = __FAILURE__; 365 | } 366 | else 367 | { 368 | /* Codes_SRS_TLSIO_30_034: [ The tlsio_open shall store the provided on_bytes_received, on_bytes_received_context, on_io_error, on_io_error_context, on_io_open_complete, and on_io_open_complete_context parameters for later use as specified and tested per other line entries in this document. ]*/ 369 | tls_io_instance->on_bytes_received = on_bytes_received; 370 | tls_io_instance->on_bytes_received_context = on_bytes_received_context; 371 | 372 | tls_io_instance->on_io_error = on_io_error; 373 | tls_io_instance->on_io_error_context = on_io_error_context; 374 | 375 | tls_io_instance->on_open_complete = on_io_open_complete; 376 | tls_io_instance->on_open_complete_context = on_io_open_complete_context; 377 | 378 | /* Codes_SRS_TLSIO_30_035: [ On tlsio_open success the adapter shall enter TLSIO_STATE_EX_OPENING and return 0. ]*/ 379 | // All the real work happens in dowork 380 | tls_io_instance->tlsio_state = TLSIO_STATE_OPENING_WAITING_DNS; 381 | result = 0; 382 | } 383 | } 384 | } 385 | } 386 | } 387 | /* Codes_SRS_TLSIO_30_039: [ On failure, tlsio_open_async shall not call on_io_open_complete. ]*/ 388 | } 389 | 390 | return result; 391 | } 392 | 393 | // This implementation does not have asynchronous close, but uses the _async name for consistency with the spec 394 | static int tlsio_openssl_close_async(CONCRETE_IO_HANDLE tls_io, ON_IO_CLOSE_COMPLETE on_io_close_complete, void* callback_context) 395 | { 396 | int result; 397 | 398 | if (tls_io == NULL) 399 | { 400 | /* Codes_SRS_TLSIO_30_050: [ If the tlsio_handle parameter is NULL, tlsio_openssl_close_async shall log an error and return FAILURE. ]*/ 401 | LogError("NULL tlsio"); 402 | result = __FAILURE__; 403 | } 404 | else 405 | { 406 | if (on_io_close_complete == NULL) 407 | { 408 | /* Codes_SRS_TLSIO_30_055: [ If the on_io_close_complete parameter is NULL, tlsio_openssl_close_async shall log an error and return FAILURE. ]*/ 409 | LogError("NULL on_io_close_complete"); 410 | result = __FAILURE__; 411 | } 412 | else 413 | { 414 | TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io; 415 | 416 | if (tls_io_instance->tlsio_state != TLSIO_STATE_OPEN && 417 | tls_io_instance->tlsio_state != TLSIO_STATE_ERROR) 418 | { 419 | /* Codes_SRS_TLSIO_30_053: [ If the adapter is in any state other than TLSIO_STATE_EXT_OPEN or TLSIO_STATE_EXT_ERROR then tlsio_close_async shall log that tlsio_close_async has been called and then continue normally. ]*/ 420 | // LogInfo rather than LogError because this is an unusual but not erroneous situation 421 | LogInfo("tlsio_openssl_close has been called when in neither TLSIO_STATE_OPEN nor TLSIO_STATE_ERROR."); 422 | } 423 | 424 | if (is_an_opening_state(tls_io_instance->tlsio_state)) 425 | { 426 | /* Codes_SRS_TLSIO_30_057: [ On success, if the adapter is in TLSIO_STATE_EXT_OPENING, it shall call on_io_open_complete with the on_io_open_complete_context supplied in tlsio_open_async and IO_OPEN_CANCELLED. This callback shall be made before changing the internal state of the adapter. ]*/ 427 | tls_io_instance->on_open_complete(tls_io_instance->on_open_complete_context, IO_OPEN_CANCELLED); 428 | } 429 | // This adapter does not support asynchronous closing 430 | /* Codes_SRS_TLSIO_30_056: [ On success the adapter shall enter TLSIO_STATE_EX_CLOSING. ]*/ 431 | /* Codes_SRS_TLSIO_30_051: [ On success, if the underlying TLS does not support asynchronous closing, then the adapter shall enter TLSIO_STATE_EX_CLOSED immediately after entering TLSIO_STATE_EX_CLOSING. ]*/ 432 | /* Codes_SRS_TLSIO_30_052: [ On success tlsio_close shall return 0. ]*/ 433 | internal_close(tls_io_instance); 434 | on_io_close_complete(callback_context); 435 | result = 0; 436 | } 437 | } 438 | /* Codes_SRS_TLSIO_30_054: [ On failure, the adapter shall not call on_io_close_complete. ]*/ 439 | 440 | return result; 441 | } 442 | 443 | static void dowork_read(TLS_IO_INSTANCE* tls_io_instance) 444 | { 445 | // TRANSFER_BUFFER_SIZE is not very important because if the message is bigger 446 | // then the framework just calls dowork repeatedly until it gets everything. So 447 | // a bigger buffer would just use memory without buying anything. 448 | // Putting this buffer in a small function also allows it to exist on the stack 449 | // rather than adding to heap fragmentation. 450 | unsigned char buffer[TLSIO_RECEIVE_BUFFER_SIZE]; 451 | int rcv_bytes; 452 | 453 | if (tls_io_instance->tlsio_state == TLSIO_STATE_OPEN) 454 | { 455 | // SSL_read is not checked for errors because the "no data" condition is reported as a 456 | // failure, but the docs do not guarantee that it will always be the same failure, 457 | // so we have no reliable way to distinguish "no data" from something else. 458 | // 459 | // Pump all of the bytes currently available out 460 | rcv_bytes = SSL_read(tls_io_instance->ssl, buffer, sizeof(buffer)); 461 | while (rcv_bytes > 0) 462 | { 463 | // tls_io_instance->on_bytes_received was already checked for NULL 464 | // in the call to tlsio_openssl_open_async 465 | /* Codes_SRS_TLSIO_30_100: [ As long as the TLS connection is able to provide received data, tlsio_dowork shall repeatedly read this data and call on_bytes_received with the pointer to the buffer containing the data, the number of bytes received, and the on_bytes_received_context. ]*/ 466 | tls_io_instance->on_bytes_received(tls_io_instance->on_bytes_received_context, buffer, rcv_bytes); 467 | rcv_bytes = SSL_read(tls_io_instance->ssl, buffer, sizeof(buffer)); 468 | } 469 | /* Codes_SRS_TLSIO_30_102: [ If the TLS connection receives no data then tlsio_dowork shall not call the on_bytes_received callback. ]*/ 470 | } 471 | } 472 | 473 | 474 | static int create_ssl(TLS_IO_INSTANCE* tls_io_instance) 475 | { 476 | int result; 477 | int ret; 478 | 479 | tls_io_instance->ssl_context = SSL_CTX_new(TLSv1_2_client_method()); 480 | if (tls_io_instance->ssl_context == NULL) 481 | { 482 | /* Codes_SRS_TLSIO_30_082: [ If the connection process fails for any reason, tlsio_dowork shall log an error, call on_io_open_complete with the on_io_open_complete_context parameter provided in tlsio_open and IO_OPEN_ERROR, and enter TLSIO_STATE_EX_ERROR. ]*/ 483 | result = __FAILURE__; 484 | LogError("create new SSL CTX failed"); 485 | } 486 | else 487 | { 488 | tls_io_instance->ssl = SSL_new(tls_io_instance->ssl_context); 489 | if (tls_io_instance->ssl == NULL) 490 | { 491 | /* Codes_SRS_TLSIO_30_082: [ If the connection process fails for any reason, tlsio_dowork shall log an error, call on_io_open_complete with the on_io_open_complete_context parameter provided in tlsio_open and IO_OPEN_ERROR, and enter TLSIO_STATE_EX_ERROR. ]*/ 492 | result = __FAILURE__; 493 | LogError("SSL_new failed"); 494 | } 495 | else 496 | { 497 | // returns 1 on success 498 | ret = SSL_set_fd(tls_io_instance->ssl, tls_io_instance->sock); 499 | if (ret != 1) 500 | { 501 | /* Codes_SRS_TLSIO_30_082: [ If the connection process fails for any reason, tlsio_dowork shall log an error, call on_io_open_complete with the on_io_open_complete_context parameter provided in tlsio_open and IO_OPEN_ERROR, and enter TLSIO_STATE_EX_ERROR. ]*/ 502 | result = __FAILURE__; 503 | LogError("SSL_set_fd failed"); 504 | } 505 | else 506 | { 507 | result = 0; 508 | } 509 | } 510 | } 511 | 512 | return result; 513 | } 514 | 515 | static void dowork_send(TLS_IO_INSTANCE* tls_io_instance) 516 | { 517 | LIST_ITEM_HANDLE first_pending_io = singlylinkedlist_get_head_item(tls_io_instance->pending_transmission_list); 518 | if (first_pending_io != NULL) 519 | { 520 | PENDING_TRANSMISSION* pending_message = (PENDING_TRANSMISSION*)singlylinkedlist_item_get_value(first_pending_io); 521 | uint8_t* buffer = ((uint8_t*)pending_message->bytes) + 522 | pending_message->size - pending_message->unsent_size; 523 | int write_result = SSL_write(tls_io_instance->ssl, buffer, pending_message->unsent_size); 524 | // https://wiki.openssl.org/index.php/Manual:SSL_write(3) 525 | 526 | if (write_result > 0) 527 | { 528 | pending_message->unsent_size -= write_result; 529 | if (pending_message->unsent_size == 0) 530 | { 531 | /* Codes_SRS_TLSIO_30_091: [ If tlsio_openssl_compact_dowork is able to send all the bytes in an enqueued message, it shall call the messages's on_send_complete along with its associated callback_context and IO_SEND_OK. ]*/ 532 | // The whole message has been sent successfully 533 | process_and_destroy_head_message(tls_io_instance, IO_SEND_OK); 534 | } 535 | else 536 | { 537 | /* Codes_SRS_TLSIO_30_093: [ If the TLS connection was not able to send an entire enqueued message at once, subsequent calls to tlsio_dowork shall continue to send the remaining bytes. ]*/ 538 | // Repeat the send on the next pass with the rest of the message 539 | // This empty else compiles to nothing but helps readability 540 | } 541 | } 542 | else 543 | { 544 | // SSL_write returned non-success. It may just be busy, or it may be broken. 545 | int hard_error = is_hard_ssl_error(tls_io_instance->ssl, write_result); 546 | if (hard_error != 0) 547 | { 548 | /* Codes_SRS_TLSIO_30_002: [ The phrase "destroy the failed message" means that the adapter shall remove the message from the queue and destroy it after calling the message's on_send_complete along with its associated callback_context and IO_SEND_ERROR. ]*/ 549 | /* Codes_SRS_TLSIO_30_005: [ When the adapter enters TLSIO_STATE_EXT_ERROR it shall call the on_io_error function and pass the on_io_error_context that were supplied in tlsio_open . ]*/ 550 | /* Codes_SRS_TLSIO_30_095: [ If the send process fails before sending all of the bytes in an enqueued message, tlsio_dowork shall destroy the failed message and enter TLSIO_STATE_EX_ERROR. ]*/ 551 | // This is an unexpected error, and we need to bail out. Probably lost internet connection. 552 | LogInfo("Error from SSL_write: %d", hard_error); 553 | process_and_destroy_head_message(tls_io_instance, IO_SEND_ERROR); 554 | } 555 | } 556 | } 557 | else 558 | { 559 | /* Codes_SRS_TLSIO_30_096: [ If there are no enqueued messages available, tlsio_openssl_compact_dowork shall do nothing. ]*/ 560 | } 561 | } 562 | 563 | static void dowork_poll_dns(TLS_IO_INSTANCE* tls_io_instance) 564 | { 565 | bool dns_is_complete = dns_async_is_lookup_complete(tls_io_instance->dns); 566 | 567 | if (dns_is_complete) 568 | { 569 | uint32_t host_ipV4_address = dns_async_get_ipv4(tls_io_instance->dns); 570 | dns_async_destroy(tls_io_instance->dns); 571 | tls_io_instance->dns = NULL; 572 | if (host_ipV4_address == 0) 573 | { 574 | // Transition to TSLIO_STATE_ERROR 575 | /* Codes_SRS_TLSIO_30_082: [ If the connection process fails for any reason, tlsio_dowork shall log an error, call on_io_open_complete with the on_io_open_complete_context parameter provided in tlsio_open and IO_OPEN_ERROR, and enter TLSIO_STATE_EX_ERROR. ]*/ 576 | // The DNS failure has already been logged 577 | enter_open_error_state(tls_io_instance); 578 | } 579 | else 580 | { 581 | SOCKET_ASYNC_HANDLE sock = socket_async_create(host_ipV4_address, tls_io_instance->port, false, NULL); 582 | if (sock < 0) 583 | { 584 | // This is a communication interruption rather than a program bug 585 | /* Codes_SRS_TLSIO_30_082: [ If the connection process fails for any reason, tlsio_dowork shall log an error, call on_io_open_complete with the on_io_open_complete_context parameter provided in tlsio_open and IO_OPEN_ERROR, and enter TLSIO_STATE_EX_ERROR. ]*/ 586 | LogInfo("Could not open the socket"); 587 | enter_open_error_state(tls_io_instance); 588 | } 589 | else 590 | { 591 | // The socket has been created successfully, so now wait for it to 592 | // finish the TCP handshake. 593 | tls_io_instance->sock = sock; 594 | tls_io_instance->tlsio_state = TLSIO_STATE_OPENING_WAITING_SOCKET; 595 | } 596 | } 597 | } 598 | } 599 | 600 | static void dowork_poll_socket(TLS_IO_INSTANCE* tls_io_instance) 601 | { 602 | bool is_complete; 603 | int result = socket_async_is_create_complete(tls_io_instance->sock, &is_complete); 604 | if (result != 0) 605 | { 606 | // Transition to TSLIO_STATE_ERROR 607 | LogInfo("socket_async_is_create_complete failure"); 608 | enter_open_error_state(tls_io_instance); 609 | } 610 | else 611 | { 612 | if (is_complete) 613 | { 614 | // Attempt to transition to TLSIO_STATE_OPENING_WAITING_SSL 615 | int create_ssl_result = create_ssl(tls_io_instance); 616 | if (create_ssl_result != 0) 617 | { 618 | // Transition to TSLIO_STATE_ERROR 619 | // create_ssl already did error logging 620 | enter_open_error_state(tls_io_instance); 621 | } 622 | else 623 | { 624 | tls_io_instance->tlsio_state = TLSIO_STATE_OPENING_WAITING_SSL; 625 | } 626 | } 627 | } 628 | } 629 | 630 | static void dowork_poll_open_ssl(TLS_IO_INSTANCE* tls_io_instance) 631 | { 632 | // https://www.openssl.org/docs/man1.0.2/ssl/SSL_connect.html 633 | 634 | // "If the underlying BIO is non - blocking, SSL_connect() will also 635 | // return when the underlying BIO could not satisfy the needs of 636 | // SSL_connect() to continue the handshake, indicating the 637 | // problem by the return value -1. In this case a call to 638 | // SSL_get_error() with the return value of SSL_connect() will 639 | // yield SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE.The calling 640 | // process then must repeat the call after taking appropriate 641 | // action to satisfy the needs of SSL_connect().The action 642 | // depends on the underlying BIO. When using a non - blocking 643 | // socket, nothing is to be done, but select() can be used to 644 | // check for the required condition." 645 | 646 | int connect_result = SSL_connect(tls_io_instance->ssl); 647 | 648 | // The following note applies to the Espressif ESP32 implementation 649 | // of OpenSSL: 650 | // The manual pages say that 0 is a failure, 651 | // but by experiment, 0 is the success result, at least when using 652 | // SSL_set_fd instead of custom BIO. 653 | // https://www.openssl.org/docs/man1.0.2/ssl/SSL_connect.html 654 | // Update: Later versions of the Espressif SDK seem to adhere to the 655 | // documentation. 656 | if (connect_result == 1) 657 | { 658 | /* Codes_SRS_TLSIO_30_080: [ The tlsio_dowork shall establish a TLS connection using the hostName and port provided during tlsio_open. ]*/ 659 | // Connect succeeded 660 | tls_io_instance->tlsio_state = TLSIO_STATE_OPEN; 661 | /* Codes_SRS_TLSIO_30_007: [ The phrase "enter TLSIO_STATE_EXT_OPEN" means the adapter shall call the on_io_open_complete function and pass IO_OPEN_OK and the on_io_open_complete_context that was supplied in tlsio_open . ]*/ 662 | /* Codes_SRS_TLSIO_30_083: [ If tlsio_dowork successfully opens the TLS connection it shall enter TLSIO_STATE_EX_OPEN. ]*/ 663 | tls_io_instance->on_open_complete(tls_io_instance->on_open_complete_context, IO_OPEN_OK); 664 | } 665 | else 666 | { 667 | int hard_error = is_hard_ssl_error(tls_io_instance->ssl, connect_result); 668 | if (hard_error != 0) 669 | { 670 | LogInfo("Hard error from SSL_connect: %d", hard_error); 671 | enter_open_error_state(tls_io_instance); 672 | } 673 | } 674 | } 675 | 676 | static void tlsio_openssl_dowork(CONCRETE_IO_HANDLE tls_io) 677 | { 678 | if (tls_io == NULL) 679 | { 680 | /* Codes_SRS_TLSIO_30_070: [ If the tlsio_handle parameter is NULL, tlsio_dowork shall do nothing except log an error. ]*/ 681 | LogError("NULL tlsio"); 682 | } 683 | else 684 | { 685 | TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io; 686 | 687 | // This switch statement handles all of the state transitions during the opening process 688 | switch (tls_io_instance->tlsio_state) 689 | { 690 | case TLSIO_STATE_CLOSED: 691 | /* Codes_SRS_TLSIO_30_075: [ If the adapter is in TLSIO_STATE_EXT_CLOSED then tlsio_dowork shall do nothing. ]*/ 692 | // Waiting to be opened, nothing to do 693 | break; 694 | case TLSIO_STATE_OPENING_WAITING_DNS: 695 | dowork_poll_dns(tls_io_instance); 696 | break; 697 | case TLSIO_STATE_OPENING_WAITING_SOCKET: 698 | dowork_poll_socket(tls_io_instance); 699 | break; 700 | case TLSIO_STATE_OPENING_WAITING_SSL: 701 | dowork_poll_open_ssl(tls_io_instance); 702 | break; 703 | case TLSIO_STATE_OPEN: 704 | dowork_read(tls_io_instance); 705 | dowork_send(tls_io_instance); 706 | break; 707 | case TLSIO_STATE_ERROR: 708 | /* Codes_SRS_TLSIO_30_071: [ If the adapter is in TLSIO_STATE_EXT_ERROR then tlsio_dowork shall do nothing. ]*/ 709 | // There's nothing valid to do here but wait to be retried 710 | break; 711 | default: 712 | LogError("Unexpected internal tlsio state"); 713 | break; 714 | } 715 | } 716 | } 717 | 718 | static int tlsio_openssl_send_async(CONCRETE_IO_HANDLE tls_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context) 719 | { 720 | int result; 721 | if (on_send_complete == NULL) 722 | { 723 | /* Codes_SRS_TLSIO_30_062: [ If the on_send_complete is NULL, tlsio_openssl_compact_send shall log the error and return FAILURE. ]*/ 724 | result = __FAILURE__; 725 | LogError("NULL on_send_complete"); 726 | } 727 | else 728 | { 729 | if (tls_io == NULL) 730 | { 731 | /* Codes_SRS_TLSIO_30_060: [ If the tlsio_handle parameter is NULL, tlsio_openssl_compact_send shall log an error and return FAILURE. ]*/ 732 | result = __FAILURE__; 733 | LogError("NULL tlsio"); 734 | } 735 | else 736 | { 737 | if (buffer == NULL) 738 | { 739 | /* Codes_SRS_TLSIO_30_061: [ If the buffer is NULL, tlsio_openssl_compact_send shall log the error and return FAILURE. ]*/ 740 | result = __FAILURE__; 741 | LogError("NULL buffer"); 742 | } 743 | else 744 | { 745 | if (size == 0) 746 | { 747 | /* Codes_SRS_TLSIO_30_067: [ If the size is 0, tlsio_send shall log the error and return FAILURE. ]*/ 748 | result = __FAILURE__; 749 | LogError("0 size"); 750 | } 751 | else 752 | { 753 | TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io; 754 | if (tls_io_instance->tlsio_state != TLSIO_STATE_OPEN) 755 | { 756 | /* Codes_SRS_TLSIO_30_065: [ If tlsio_openssl_compact_open has not been called or the opening process has not been completed, tlsio_openssl_compact_send shall log an error and return FAILURE. ]*/ 757 | result = __FAILURE__; 758 | LogError("tlsio_openssl_send_async without a prior successful open"); 759 | } 760 | else 761 | { 762 | PENDING_TRANSMISSION* pending_transmission = (PENDING_TRANSMISSION*)malloc(sizeof(PENDING_TRANSMISSION)); 763 | if (pending_transmission == NULL) 764 | { 765 | /* Codes_SRS_TLSIO_30_064: [ If the supplied message cannot be enqueued for transmission, tlsio_openssl_compact_send shall log an error and return FAILURE. ]*/ 766 | result = __FAILURE__; 767 | LogError("malloc failed"); 768 | } 769 | else 770 | { 771 | /* Codes_SRS_TLSIO_30_063: [ The tlsio_openssl_compact_send shall enqueue for transmission the on_send_complete, the callback_context, the size, and the contents of buffer. ]*/ 772 | pending_transmission->bytes = (unsigned char*)malloc(size); 773 | 774 | if (pending_transmission->bytes == NULL) 775 | { 776 | /* Codes_SRS_TLSIO_30_064: [ If the supplied message cannot be enqueued for transmission, tlsio_openssl_compact_send shall log an error and return FAILURE. ]*/ 777 | LogError("malloc failed"); 778 | free(pending_transmission); 779 | result = __FAILURE__; 780 | } 781 | else 782 | { 783 | pending_transmission->size = size; 784 | pending_transmission->unsent_size = size; 785 | pending_transmission->on_send_complete = on_send_complete; 786 | pending_transmission->callback_context = callback_context; 787 | (void)memcpy(pending_transmission->bytes, buffer, size); 788 | 789 | if (singlylinkedlist_add(tls_io_instance->pending_transmission_list, pending_transmission) == NULL) 790 | { 791 | /* Codes_SRS_TLSIO_30_064: [ If the supplied message cannot be enqueued for transmission, tlsio_openssl_compact_send shall log an error and return FAILURE. ]*/ 792 | LogError("Unable to add socket to pending list."); 793 | free(pending_transmission->bytes); 794 | free(pending_transmission); 795 | result = __FAILURE__; 796 | } 797 | else 798 | { 799 | /* Codes_SRS_TLSIO_30_063: [ On success, tlsio_send shall enqueue for transmission the on_send_complete , the callback_context , the size , and the contents of buffer and then return 0. ]*/ 800 | dowork_send(tls_io_instance); 801 | result = 0; 802 | } 803 | } 804 | } 805 | } 806 | } 807 | } 808 | } 809 | /* Codes_SRS_TLSIO_30_066: [ On failure, on_send_complete shall not be called. ]*/ 810 | } 811 | return result; 812 | } 813 | 814 | static int tlsio_openssl_setoption(CONCRETE_IO_HANDLE tls_io, const char* optionName, const void* value) 815 | { 816 | TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io; 817 | /* Codes_SRS_TLSIO_30_120: [ If the tlsio_handle parameter is NULL, tlsio_openssl_compact_setoption shall do nothing except log an error and return FAILURE. ]*/ 818 | int result; 819 | if (tls_io_instance == NULL) 820 | { 821 | LogError("NULL tlsio"); 822 | result = __FAILURE__; 823 | } 824 | else 825 | { 826 | /* Codes_SRS_TLSIO_30_121: [ If the optionName parameter is NULL, tlsio_openssl_compact_setoption shall do nothing except log an error and return FAILURE. ]*/ 827 | /* Codes_SRS_TLSIO_30_122: [ If the value parameter is NULL, tlsio_openssl_compact_setoption shall do nothing except log an error and return FAILURE. ]*/ 828 | /* Codes_SRS_TLSIO_OPENSSL_COMPACT_30_520 [ The tlsio_setoption shall do nothing and return FAILURE. ]*/ 829 | TLSIO_OPTIONS_RESULT options_result = tlsio_options_set(&tls_io_instance->options, optionName, value); 830 | if (options_result != TLSIO_OPTIONS_RESULT_SUCCESS) 831 | { 832 | LogError("Failed tlsio_options_set"); 833 | result = __FAILURE__; 834 | } 835 | else 836 | { 837 | result = 0; 838 | } 839 | } 840 | return result; 841 | } 842 | 843 | /* Codes_SRS_TLSIO_OPENSSL_COMPACT_30_560: [ The tlsio_retrieveoptions shall do nothing and return an empty options handler. ]*/ 844 | static OPTIONHANDLER_HANDLE tlsio_openssl_retrieveoptions(CONCRETE_IO_HANDLE tls_io) 845 | { 846 | TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io; 847 | /* Codes_SRS_TLSIO_30_160: [ If the tlsio_handle parameter is NULL, tlsio_openssl_compact_retrieveoptions shall do nothing except log an error and return FAILURE. ]*/ 848 | OPTIONHANDLER_HANDLE result; 849 | if (tls_io_instance == NULL) 850 | { 851 | LogError("NULL tlsio"); 852 | result = NULL; 853 | } 854 | else 855 | { 856 | result = tlsio_options_retrieve_options(&tls_io_instance->options, tlsio_openssl_setoption); 857 | } 858 | return result; 859 | } 860 | 861 | /* Codes_SRS_TLSIO_30_008: [ The tlsio_get_interface_description shall return the VTable IO_INTERFACE_DESCRIPTION. ]*/ 862 | static const IO_INTERFACE_DESCRIPTION tlsio_openssl_interface_description = 863 | { 864 | tlsio_openssl_retrieveoptions, 865 | tlsio_openssl_create, 866 | tlsio_openssl_destroy, 867 | tlsio_openssl_open_async, 868 | tlsio_openssl_close_async, 869 | tlsio_openssl_send_async, 870 | tlsio_openssl_dowork, 871 | tlsio_openssl_setoption 872 | }; 873 | 874 | /* Codes_SRS_TLSIO_30_001: [ The tlsio_openssl_compact shall implement and export all the Concrete functions in the VTable IO_INTERFACE_DESCRIPTION defined in the xio.h. ]*/ 875 | const IO_INTERFACE_DESCRIPTION* tlsio_pal_get_interface_description(void) 876 | { 877 | return &tlsio_openssl_interface_description; 878 | } 879 | -------------------------------------------------------------------------------- /sample/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a 3 | # project subdirectory. 4 | # 5 | 6 | PROJECT_NAME := esp32 7 | 8 | include $(IDF_PATH)/make/project.mk 9 | -------------------------------------------------------------------------------- /sample/main/Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "Example Configuration" 2 | 3 | config WIFI_SSID 4 | string "WiFi SSID" 5 | default "myssid" 6 | help 7 | SSID (network name) for the example to connect to. 8 | 9 | config WIFI_PASSWORD 10 | string "WiFi Password" 11 | default "myssid" 12 | help 13 | WiFi password (WPA or WPA2) for the example to use. 14 | 15 | Can be left blank if the network has no security set. 16 | 17 | endmenu 18 | -------------------------------------------------------------------------------- /sample/main/azure_main.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #include 5 | 6 | #include "freertos/FreeRTOS.h" 7 | #include "freertos/task.h" 8 | #include "freertos/event_groups.h" 9 | 10 | #include "esp_system.h" 11 | #include "esp_system.h" 12 | #include "esp_wifi.h" 13 | #include "esp_event_loop.h" 14 | #include "esp_log.h" 15 | 16 | #include "nvs_flash.h" 17 | #include "iothub_client_sample_mqtt.h" 18 | 19 | 20 | 21 | #define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID 22 | #define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD 23 | 24 | /* FreeRTOS event group to signal when we are connected & ready to make a request */ 25 | static EventGroupHandle_t wifi_event_group; 26 | 27 | /* The event group allows multiple bits for each event, 28 | but we only care about one event - are we connected 29 | to the AP with an IP? */ 30 | const int CONNECTED_BIT = BIT0; 31 | 32 | static const char *TAG = "azure"; 33 | 34 | static esp_err_t event_handler(void *ctx, system_event_t *event) 35 | { 36 | switch(event->event_id) { 37 | case SYSTEM_EVENT_STA_START: 38 | esp_wifi_connect(); 39 | break; 40 | case SYSTEM_EVENT_STA_GOT_IP: 41 | xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); 42 | break; 43 | case SYSTEM_EVENT_STA_DISCONNECTED: 44 | /* This is a workaround as ESP32 WiFi libs don't currently 45 | auto-reassociate. */ 46 | esp_wifi_connect(); 47 | xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); 48 | break; 49 | default: 50 | break; 51 | } 52 | return ESP_OK; 53 | } 54 | 55 | static void initialise_wifi(void) 56 | { 57 | tcpip_adapter_init(); 58 | wifi_event_group = xEventGroupCreate(); 59 | ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) ); 60 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); 61 | ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); 62 | ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); 63 | wifi_config_t wifi_config = { 64 | .sta = { 65 | .ssid = EXAMPLE_WIFI_SSID, 66 | .password = EXAMPLE_WIFI_PASS, 67 | }, 68 | }; 69 | ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid); 70 | ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); 71 | ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) ); 72 | ESP_ERROR_CHECK( esp_wifi_start() ); 73 | } 74 | 75 | void azure_task(void *pvParameter) 76 | { 77 | ESP_LOGI(TAG, "Waiting for WiFi access point ..."); 78 | xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 79 | false, true, portMAX_DELAY); 80 | ESP_LOGI(TAG, "Connected to access point success"); 81 | 82 | 83 | iothub_client_sample_mqtt_run(); 84 | while(1) 85 | { 86 | vTaskDelay(1000); 87 | } 88 | 89 | 90 | } 91 | 92 | void app_main() 93 | { 94 | nvs_flash_init(); 95 | initialise_wifi(); 96 | xTaskCreate(&azure_task, "azure_task", 8192, NULL, 5, NULL); 97 | } 98 | -------------------------------------------------------------------------------- /sample/main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # "main" pseudo-component makefile. 3 | # 4 | # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) 5 | 6 | -------------------------------------------------------------------------------- /sdk_tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #Copyright (c) Microsoft. All rights reserved. 2 | #Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #this is CMakeLists.txt for the folder tests of C shared utility 5 | set(SHARED_UTIL_REAL_TEST_FOLDER ${CMAKE_CURRENT_LIST_DIR}/real_test_files CACHE INTERNAL "this is what needs to be included when doing test sources" FORCE) 6 | message(STATUS "including external unit test directory " ${CMAKE_CURRENT_LIST_DIR}) 7 | if(NOT DEFINED MACOSX) 8 | add_subdirectory(tlsio_openssl_compact_ut) 9 | endif() 10 | -------------------------------------------------------------------------------- /sdk_tests/tlsio_openssl_compact_ut/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #Copyright (c) Microsoft. All rights reserved. 2 | #Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | cmake_minimum_required(VERSION 2.8.11) 5 | 6 | compileAsC11() 7 | set(theseTestsName tlsio_openssl_compact_ut) 8 | 9 | set(${theseTestsName}_test_files 10 | ${theseTestsName}.c 11 | ) 12 | 13 | set(${theseTestsName}_c_files 14 | ${SHARED_UTIL_PAL_FOLDER}/tlsio_options.c 15 | ${SHARED_UTIL_SRC_FOLDER}/vector.c 16 | ${SHARED_UTIL_SRC_FOLDER}/optionhandler.c 17 | ${SHARED_UTIL_SRC_FOLDER}/singlylinkedlist.c 18 | ${SHARED_UTIL_SRC_FOLDER}/crt_abstractions.c 19 | ${EXTERNAL_PAL_REPO_DIR}/pal/src/tlsio_openssl_compact.c 20 | ) 21 | 22 | set(${theseTestsName}_h_files 23 | ssl_impl.h 24 | test_defines.h 25 | gballoc_ut_impl_1.h 26 | gballoc_ut_impl_2.h 27 | callbacks.h 28 | ) 29 | 30 | include_directories(.) 31 | include_directories(${EXTERNAL_PAL_REPO_DIR}/pal/inc) 32 | 33 | build_c_test_artifacts(${theseTestsName} ON "tests/azure_c_shared_utility_tests") 34 | -------------------------------------------------------------------------------- /sdk_tests/tlsio_openssl_compact_ut/callbacks.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) Microsoft.All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | // This file is made an integral part of tlsio_openssl_compact.c with a #include. It 5 | // is broken out for readability. 6 | 7 | #ifndef CALLBACKS_H 8 | #define CALLBACKS_H 9 | 10 | 11 | #define MAX_MESSAGE_COUNT 3 12 | 13 | // Keep track of whether callbacks were performed as expected 14 | static int on_io_open_complete_call_count; 15 | static bool on_io_open_complete_context_ok; 16 | static IO_OPEN_RESULT on_io_open_complete_result; 17 | 18 | static int on_io_error_call_count; 19 | static bool on_io_error_context_ok; 20 | 21 | static int on_io_close_call_count; 22 | static bool on_io_close_context_ok; 23 | 24 | static int on_io_send_complete_call_count; 25 | static bool on_io_send_complete_context_ok; 26 | static IO_SEND_RESULT on_io_send_complete_result[MAX_MESSAGE_COUNT]; 27 | 28 | static int on_bytes_received_call_count; 29 | static bool on_bytes_received_context_ok; 30 | 31 | // Context pointers for the callbacks 32 | #define IO_OPEN_COMPLETE_CONTEXT (void*)55 33 | #define IO_ERROR_CONTEXT (void*)66 34 | #define IO_BYTES_RECEIVED_CONTEXT (void*)77 35 | #define IO_CLOSE_COMPLETE_CONTEXT (void*)231 36 | #define IO_SEND_COMPLETE_CONTEXT (void*)7658 37 | 38 | static void reset_callback_context_records() 39 | { 40 | int i; 41 | on_io_open_complete_call_count = 0; 42 | on_io_open_complete_context_ok = true; 43 | on_io_open_complete_result = (IO_OPEN_RESULT)-1; 44 | on_io_error_call_count = 0; 45 | on_io_error_context_ok = true; 46 | on_io_close_call_count = 0; 47 | on_io_close_context_ok = true; 48 | on_io_send_complete_call_count = 0; 49 | on_io_send_complete_context_ok = true; 50 | for (i = 0; i < MAX_MESSAGE_COUNT; i++) 51 | { 52 | on_io_send_complete_result[i] = (IO_SEND_RESULT)-1; 53 | } 54 | on_bytes_received_call_count = 0; 55 | on_bytes_received_context_ok = true; 56 | } 57 | 58 | // Callbacks used by the tlsio adapter 59 | 60 | static void on_io_open_complete(void* context, IO_OPEN_RESULT open_result) 61 | { 62 | bool result_valid = open_result == IO_OPEN_OK || open_result == IO_OPEN_ERROR || open_result == IO_OPEN_CANCELLED; 63 | ASSERT_IS_TRUE_WITH_MSG(result_valid, "Invalid IO_OPEN_RESULT"); 64 | on_io_open_complete_call_count++; 65 | on_io_open_complete_result = open_result; 66 | if (context != IO_OPEN_COMPLETE_CONTEXT) 67 | { 68 | on_io_open_complete_context_ok = false; 69 | } 70 | } 71 | 72 | static void on_io_send_complete(void* context, IO_SEND_RESULT send_result) 73 | { 74 | on_io_send_complete_result[on_io_send_complete_call_count] = send_result; 75 | on_io_send_complete_call_count++; 76 | if (context != IO_SEND_COMPLETE_CONTEXT) 77 | { 78 | on_io_send_complete_context_ok = false; 79 | } 80 | } 81 | 82 | static void on_io_close_complete(void* context) 83 | { 84 | on_io_close_call_count++; 85 | if (context != IO_CLOSE_COMPLETE_CONTEXT) 86 | { 87 | on_io_close_context_ok = false; 88 | } 89 | } 90 | 91 | static void on_bytes_received(void* context, const unsigned char* buffer, size_t size) 92 | { 93 | size_t i; 94 | on_bytes_received_call_count++; 95 | 96 | for (i = 0; i < size; i++) 97 | { 98 | ASSERT_BYTE_RECEIVED(buffer[i]); 99 | } 100 | if (context != IO_BYTES_RECEIVED_CONTEXT) 101 | { 102 | on_bytes_received_context_ok = false; 103 | } 104 | } 105 | 106 | static void on_io_error(void* context) 107 | { 108 | on_io_error_call_count = true; 109 | if (context != IO_ERROR_CONTEXT) 110 | { 111 | on_io_error_context_ok = false; 112 | } 113 | } 114 | 115 | static void ASSERT_IO_ERROR_CALLBACK(bool called) 116 | { 117 | int count = called ? 1 : 0; 118 | ASSERT_ARE_EQUAL_WITH_MSG(int, count, on_io_error_call_count, "io_error_callback count mismatch"); 119 | if (count > 0) 120 | { 121 | ASSERT_IS_TRUE_WITH_MSG(on_io_error_context_ok, "io_error_callback missing context"); 122 | } 123 | } 124 | 125 | static void ASSERT_IO_OPEN_CALLBACK(bool called, int open_result) 126 | { 127 | if (called) 128 | { 129 | ASSERT_ARE_EQUAL_WITH_MSG(int, 1, on_io_open_complete_call_count, "on_io_open_complete_callback count mismatch"); 130 | ASSERT_ARE_EQUAL_WITH_MSG(int, on_io_open_complete_result, open_result, "on_io_open_complete result mismatch"); 131 | ASSERT_IS_TRUE_WITH_MSG(on_io_open_complete_context_ok, "io_open_complete_context not passed"); 132 | } 133 | else 134 | { 135 | ASSERT_ARE_EQUAL_WITH_MSG(int, 0, on_io_open_complete_call_count, "unexpected on_io_open_complete_callback"); 136 | } 137 | } 138 | 139 | static void ASSERT_IO_SEND_CALLBACK(bool called, int send_result) 140 | { 141 | if (called) 142 | { 143 | ASSERT_ARE_EQUAL_WITH_MSG(int, 1, on_io_send_complete_call_count, "on_io_send_complete_callback count mismatch"); 144 | ASSERT_ARE_EQUAL_WITH_MSG(int, on_io_send_complete_result[0], send_result, "on_io_send_complete result mismatch"); 145 | ASSERT_IS_TRUE_WITH_MSG(on_io_send_complete_context_ok, "io_send_complete_context not passed"); 146 | } 147 | else 148 | { 149 | ASSERT_ARE_EQUAL_WITH_MSG(int, 0, on_io_open_complete_call_count, "unexpected on_io_open_complete_callback"); 150 | } 151 | } 152 | 153 | static void ASSERT_IO_SEND_ABANDONED(int count) 154 | { 155 | int i; 156 | ASSERT_ARE_EQUAL_WITH_MSG(int, count, on_io_send_complete_call_count, "on_io_send_complete_callback count mismatch"); 157 | ASSERT_IS_TRUE_WITH_MSG(on_io_send_complete_context_ok, "io_send_complete_context not passed"); 158 | for (i = 0; i < on_io_send_complete_call_count; i++) 159 | { 160 | ASSERT_ARE_EQUAL_WITH_MSG(int, IO_SEND_CANCELLED, on_io_send_complete_result[i], "send result should be IO_SEND_CANCELLED"); 161 | } 162 | } 163 | 164 | static void ASSERT_IO_CLOSE_CALLBACK(bool called) 165 | { 166 | if (called) 167 | { 168 | ASSERT_ARE_EQUAL_WITH_MSG(int, 1, on_io_close_call_count, "on_io_close_complete_callback count mismatch"); 169 | ASSERT_IS_TRUE_WITH_MSG(on_io_close_context_ok, "io_close_complete_context not passed"); 170 | } 171 | else 172 | { 173 | ASSERT_ARE_EQUAL_WITH_MSG(int, 0, on_io_close_call_count, "unexpected on_io_close_complete_callback"); 174 | } 175 | } 176 | 177 | static void ASSERT_BYTES_RECEIVED_CALLBACK(bool called, size_t message_size) 178 | { 179 | if (called) 180 | { 181 | ASSERT_ARE_EQUAL_WITH_MSG(size_t, message_size, fake_read_bytes_received, "bytes_received count mismatch"); 182 | ASSERT_IS_TRUE_WITH_MSG(on_bytes_received_context_ok, "bytes_received_context not passed"); 183 | } 184 | else 185 | { 186 | ASSERT_ARE_EQUAL_WITH_MSG(int, 0, on_bytes_received_call_count, "unexpected bytes_received_callback"); 187 | } 188 | } 189 | 190 | static void ASSERT_NO_CALLBACKS() 191 | { 192 | ASSERT_IO_ERROR_CALLBACK(false); 193 | ASSERT_IO_OPEN_CALLBACK(false, IO_OPEN_ERROR); 194 | ASSERT_IO_SEND_CALLBACK(false, IO_SEND_ERROR); 195 | ASSERT_IO_CLOSE_CALLBACK(false); 196 | ASSERT_BYTES_RECEIVED_CALLBACK(false, 0); 197 | } 198 | 199 | #endif // CALLBACKS_H 200 | -------------------------------------------------------------------------------- /sdk_tests/tlsio_openssl_compact_ut/gballoc_ut_impl_1.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) Microsoft.All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | // This file is made an integral part of a unit test implementation with a #include. It 5 | // is broken out for reuse and readability. 6 | 7 | #ifndef GBALLOC_UT_IMPL_1_H 8 | #define GBALLOC_UT_IMPL_1_H 9 | 10 | // These functions add memory leak checking to the unit test itself rather than 11 | // relying on Valgrind, which is inconvenient for troubleshooting. 12 | static void add_gballoc_memory_block(void* block); 13 | static void remove_gballoc_memory_block(void* block); 14 | 15 | /** 16 | * The gballoc.h will replace the malloc, free, and realloc by the my_gballoc functions, in this case, 17 | * if you define these mock functions after include the gballoc.h, you will create an infinity recursion, 18 | * so, places the my_gballoc functions before the #include "azure_c_shared_utility/gballoc.h" 19 | */ 20 | static void* my_gballoc_malloc(size_t size) 21 | { 22 | void* result = malloc(size); 23 | add_gballoc_memory_block(result); 24 | return result; 25 | } 26 | 27 | static void* my_gballoc_realloc(void* ptr, size_t size) 28 | { 29 | void* result; 30 | remove_gballoc_memory_block(ptr); 31 | result = realloc(ptr, size); 32 | add_gballoc_memory_block(result); 33 | return result; 34 | } 35 | 36 | static void my_gballoc_free(void* ptr) 37 | { 38 | remove_gballoc_memory_block(ptr); 39 | free(ptr); 40 | } 41 | 42 | #endif // GBALLOC_UT_IMPL_1_H 43 | 44 | 45 | -------------------------------------------------------------------------------- /sdk_tests/tlsio_openssl_compact_ut/gballoc_ut_impl_2.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) Microsoft.All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | // This file is made an integral part of a unit test implementation with a #include. It 5 | // is broken out for reuse and readability. 6 | 7 | #ifndef GBALLOC_UT_IMPL_2_H 8 | #define GBALLOC_UT_IMPL_2_H 9 | 10 | #include 11 | 12 | // This adds memory checking to the gballoc mocking 13 | // NOTE: Using ASSERTs wouuld be nice, but this file must preceed their definition 14 | // to avoid the malloc infinite recursion problem 15 | 16 | 17 | #ifndef GBALLOC_UT_IMPL_MAX_ALLOCS 18 | #define GBALLOC_UT_IMPL_MAX_ALLOCS 1000 19 | #endif 20 | 21 | static void* memory_blocks[GBALLOC_UT_IMPL_MAX_ALLOCS]; 22 | static uint32_t memory_block_count; 23 | 24 | 25 | static void init_gballoc_checks() 26 | { 27 | uint32_t i; 28 | memory_block_count = 0; 29 | for (i = 0; i < GBALLOC_UT_IMPL_MAX_ALLOCS; i++) 30 | { 31 | memory_blocks[i] = NULL; 32 | } 33 | } 34 | 35 | static void add_gballoc_memory_block(void* block) 36 | { 37 | if (block != NULL) 38 | { 39 | if (memory_block_count < GBALLOC_UT_IMPL_MAX_ALLOCS) 40 | { 41 | memory_blocks[memory_block_count] = block; 42 | memory_block_count++; 43 | } 44 | else 45 | { 46 | ASSERT_FAIL("GBALLOC_UT_IMPL_MAX_ALLOCS is too small in add_gballoc_memory_block"); 47 | } 48 | } 49 | } 50 | 51 | static void remove_gballoc_memory_block(void* block) 52 | { 53 | if (block != NULL) 54 | { 55 | bool found = false; 56 | uint32_t i; 57 | for (i = 0; i < memory_block_count; i++) 58 | { 59 | if (memory_blocks[i] == block) 60 | { 61 | memory_blocks[i] = NULL; 62 | found = true; 63 | break; 64 | } 65 | } 66 | if (!found) 67 | { 68 | ASSERT_FAIL("unknown block in remove_gballoc_memory_block"); 69 | } 70 | } 71 | } 72 | 73 | static void assert_gballoc_checks() 74 | { 75 | uint32_t i; 76 | for (i = 0; i < memory_block_count; i++) 77 | { 78 | if (memory_blocks[i] != NULL) 79 | { 80 | ASSERT_FAIL("undeleted memory block"); 81 | } 82 | } 83 | } 84 | 85 | #endif // GBALLOC_UT_IMPL_2_H 86 | -------------------------------------------------------------------------------- /sdk_tests/tlsio_openssl_compact_ut/main.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #include "testrunnerswitcher.h" 5 | 6 | int main(void) 7 | { 8 | size_t failedTestCount = 0; 9 | /** 10 | * Identify the test suite to run here. 11 | */ 12 | RUN_TEST_SUITE(tlsio_openssl_compact_unittests, failedTestCount); 13 | 14 | return failedTestCount; 15 | } 16 | -------------------------------------------------------------------------------- /sdk_tests/tlsio_openssl_compact_ut/openssl/ssl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #ifndef OPEN_SSL_H 5 | #define OPEN_SSL_H 6 | 7 | #ifdef __cplusplus 8 | 9 | extern "C" { 10 | #include 11 | #else 12 | #include 13 | #endif /* __cplusplus */ 14 | 15 | #include "azure_c_shared_utility/umock_c_prod.h" 16 | 17 | // This header mocks the small subset of the the OpenSSL ssl.h needed for tlsio_openssl_compact testing 18 | 19 | typedef void SSL; 20 | typedef void SSL_CTX; 21 | 22 | #define SSL_ERROR_WANT_READ 2 23 | #define SSL_ERROR_WANT_WRITE 3 24 | 25 | int TLSv1_2_client_method(); 26 | void SSL_CTX_set_default_read_buffer_len(SSL_CTX* dummy, int dummy2); 27 | 28 | 29 | MOCKABLE_FUNCTION(, void, SSL_free, SSL*, ssl); 30 | MOCKABLE_FUNCTION(, void, SSL_CTX_free, SSL_CTX*, ctx); 31 | MOCKABLE_FUNCTION(, SSL_CTX*, SSL_CTX_new, int, dummy); 32 | MOCKABLE_FUNCTION(, SSL*, SSL_new, SSL_CTX*, dummy); 33 | MOCKABLE_FUNCTION(, int, SSL_set_fd, SSL*, dummy, int, dummy2); 34 | MOCKABLE_FUNCTION(, int, SSL_connect, SSL*, dummy); 35 | MOCKABLE_FUNCTION(, int, SSL_write, SSL*, dummy, uint8_t*, buffer, size_t, size); 36 | MOCKABLE_FUNCTION(, int, SSL_read, SSL*, dummy, uint8_t*, buffer, size_t, size); 37 | MOCKABLE_FUNCTION(, int, SSL_shutdown, SSL*, dummy); 38 | MOCKABLE_FUNCTION(, int, SSL_get_error, SSL_CTX*, dummy, int, last_value); 39 | 40 | #ifdef __cplusplus 41 | } 42 | #endif /* __cplusplus */ 43 | 44 | #endif // OPEN_SSL_H 45 | -------------------------------------------------------------------------------- /sdk_tests/tlsio_openssl_compact_ut/ssl_impl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | // This file is made an integral part of tlsio_openssl_compact.c with a #include. It 5 | // is broken out for readability. 6 | 7 | #ifndef SSL_ERRORS_H 8 | #define SSL_ERRORS_H 9 | 10 | // 11 | #define SSL_ERROR__plus__WANT_READ -2 12 | #define SSL_ERROR__plus__WANT_WRITE -3 13 | #define SSL_ERROR__plus__HARD_FAIL -4 14 | 15 | #define SSL_ERROR_HARD_FAIL 99 16 | #define SSL_Good_Ptr (void*)22 17 | #define SSL_Good_Context_Ptr (SSL_CTX*)33 18 | #define SSL_Good_Socket 44 19 | #define SSL_CONNECT_SUCCESS 1 20 | #define SSL_SET_FD_SUCCESS 1 21 | #define SSL_SET_FD_FAILURE 0 22 | #define SSL_READ_NO_DATA 0 23 | 24 | #define SSL_Get_IPv4_OK (uint32_t)0x11223344 25 | #define SSL_Get_IPv4_FAIL 0 26 | 27 | #define SSL_good_port_number 447 28 | #define SSL_port_number_too_low -1 29 | #define SSL_port_number_too_high 0xffff + 1 30 | #define SSL_good_host_name "fakehost.com" 31 | #define SSL_good_old_host_name "fakehost.com" 32 | uint8_t* SSL_send_buffer = (uint8_t*)"111111112222222233333333"; 33 | size_t SSL_send_message_size = sizeof(SSL_send_buffer) - 1; 34 | 35 | #define DOWORK_RECV_XFER_BUFFER_SIZE 64 36 | #define SSL_TEST_MESSAGE_SIZE 64 37 | #define SSL_WRITE_MAX_TEST_SIZE 60 38 | #define SSL_SHORT_SENT_MESSAGE_SIZE 30 39 | #define SSL_FAIL_ME_SENT_MESSAGE_SIZE 1700 40 | #define SSL_SHORT_RECEIVED_MESSAGE_SIZE 15 41 | #define SSL_LONG_RECEIVED_MESSAGE_SIZE 1500 42 | 43 | static size_t fake_read_byte_out_count = 0; 44 | static size_t fake_read_current_byte_out_count = 0; 45 | static size_t fake_read_bytes_received = 0; 46 | 47 | 48 | // The fact that SSL_get_error requires the previous error allows a mocking strategy that 49 | // permits encoding the extended error into the main failure 50 | static int my_SSL_get_error(SSL* ssl, int callReturn) 51 | { 52 | (void)ssl; 53 | switch (callReturn) 54 | { 55 | case SSL_ERROR__plus__WANT_READ: 56 | return SSL_ERROR_WANT_READ; 57 | case SSL_ERROR__plus__WANT_WRITE: 58 | return SSL_ERROR_WANT_WRITE; 59 | case SSL_ERROR__plus__HARD_FAIL: 60 | return SSL_ERROR_HARD_FAIL; 61 | } 62 | // This foolish-looking code dances around conflicting warnings 63 | // in the C and C++ compilers about no return path 64 | if (callReturn <= 0) 65 | { 66 | ASSERT_FAIL("bad enum"); 67 | } 68 | return 0; 69 | } 70 | 71 | static void init_fake_read(size_t byte_count) 72 | { 73 | fake_read_byte_out_count = byte_count; 74 | fake_read_current_byte_out_count = 0; 75 | fake_read_bytes_received = 0; 76 | } 77 | 78 | static void ASSERT_BYTE_RECEIVED(uint8_t byte) 79 | { 80 | ASSERT_ARE_EQUAL(size_t, (size_t)byte, (size_t)(fake_read_bytes_received % 256)); 81 | fake_read_bytes_received++; 82 | } 83 | 84 | int my_SSL_read(SSL* ssl, uint8_t* buffer, size_t size) 85 | { 86 | size_t bytes_to_receive; 87 | size_t i; 88 | (void)size; 89 | ASSERT_ARE_EQUAL(size_t, (size_t)ssl, (size_t)SSL_Good_Ptr); 90 | bytes_to_receive = fake_read_byte_out_count - fake_read_current_byte_out_count; 91 | bytes_to_receive = bytes_to_receive <= size ? bytes_to_receive : size; 92 | for (i = 0; i < bytes_to_receive; i++) 93 | { 94 | buffer[i] = (uint8_t)(fake_read_current_byte_out_count % 256); 95 | fake_read_current_byte_out_count++; 96 | } 97 | return (int)bytes_to_receive; 98 | } 99 | 100 | int my_SSL_write(SSL* ssl, uint8_t* buffer, size_t size) 101 | { 102 | int result; 103 | // "Send" no more than SSL_WRITE_MAX_TEST_SIZE bytes 104 | (void)buffer; // not used 105 | ASSERT_ARE_EQUAL(size_t, (size_t)ssl, (size_t)SSL_Good_Ptr); 106 | if (size == SSL_FAIL_ME_SENT_MESSAGE_SIZE) 107 | { 108 | result = SSL_ERROR__plus__HARD_FAIL; 109 | } 110 | else 111 | { 112 | if (size > SSL_WRITE_MAX_TEST_SIZE) 113 | { 114 | result = SSL_WRITE_MAX_TEST_SIZE; 115 | } 116 | else 117 | { 118 | result = (int)size; 119 | } 120 | } 121 | return result; 122 | } 123 | 124 | ///////////////////////////////////////////////////////////////////// 125 | // Empty functions. These must be available to call, but they have no effect 126 | int TLSv1_2_client_method() { return 0; } 127 | void SSL_CTX_set_default_read_buffer_len(SSL_CTX* dummy, int dummy2) { (void)dummy; (void)dummy2; } 128 | 129 | // End of empty functions 130 | ///////////////////////////////////////////////////////////////////// 131 | 132 | #endif // SSL_ERRORS_H 133 | -------------------------------------------------------------------------------- /sdk_tests/tlsio_openssl_compact_ut/test_defines.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | // This file is made an integral part of tlsio_openssl_compact.c with a #include. It 5 | // is broken out for readability. 6 | 7 | #ifndef TEST_DEFINES_H 8 | #define TEST_DEFINES_H 9 | 10 | #define GOOD_DNS_ASYNC_HANDLE (void*)0x12345678 11 | 12 | #define SETOPTION_PV_COUNT 3 13 | #define OPEN_PV_COUNT 4 14 | #define SEND_PV_COUNT 4 15 | #define CLOSE_PV_COUNT 2 16 | 17 | static TLSIO_CONFIG good_config = { SSL_good_host_name, SSL_good_port_number, NULL, NULL }; 18 | static TLSIO_CONFIG tlsio_config = { NULL, SSL_good_port_number, NULL, NULL }; 19 | 20 | static bool bool_true = true; 21 | static bool bool_false = false; 22 | static size_t sizeof_bool = sizeof(bool); 23 | 24 | typedef struct 25 | { 26 | TLSIO_CONFIG* config; 27 | const char* fail_msg; 28 | } create_parameters_t; 29 | 30 | void populate_create_parameters(create_parameters_t* p, TLSIO_CONFIG* config, const char* hostname, int port, const char* fail_msg) 31 | { 32 | p->config = config; 33 | if (config != NULL) 34 | { 35 | config->hostname = hostname; 36 | config->port = port; 37 | config->underlying_io_interface = NULL; 38 | config->underlying_io_parameters = NULL; 39 | } 40 | p->fail_msg = fail_msg; 41 | } 42 | 43 | #endif // TEST_DEFINES_H 44 | -------------------------------------------------------------------------------- /sdk_tests/tlsio_openssl_compact_ut/tlsio_openssl_compact_ut.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | #else 8 | #endif 9 | 10 | /** 11 | * Include the C standards here. 12 | */ 13 | #ifdef __cplusplus 14 | #include 15 | #include 16 | #include 17 | #else 18 | #include 19 | #include 20 | #include 21 | #include 22 | #endif 23 | 24 | /** 25 | * The gballoc.h will replace the malloc, free, and realloc by the my_gballoc functions, in this case, 26 | * if you define these mock functions after include the gballoc.h, you will create an infinity recursion, 27 | * so, places the my_gballoc functions before the #include "azure_c_shared_utility/gballoc.h" 28 | */ 29 | #include "gballoc_ut_impl_1.h" 30 | 31 | /** 32 | * Include the mockable headers here. 33 | * These are the headers that contains the functions that you will replace to execute the test. 34 | */ 35 | #define ENABLE_MOCKS 36 | #include "azure_c_shared_utility/gballoc.h" 37 | #include "dns_async.h" 38 | #include "socket_async.h" 39 | #include "openssl/ssl.h" 40 | 41 | static int my_socket_async_is_create_complete(SOCKET_ASYNC_HANDLE sock, bool* is_complete) 42 | { 43 | (void)sock; 44 | *is_complete = true; 45 | return 0; 46 | } 47 | #undef ENABLE_MOCKS 48 | 49 | /** 50 | * Include the test tools. 51 | */ 52 | #include "tlsio_pal.h" 53 | #include "testrunnerswitcher.h" 54 | #include "umock_c.h" 55 | #include "umocktypes_charptr.h" 56 | #include "umocktypes_bool.h" 57 | #include "umocktypes_stdint.h" 58 | #include "umock_c_negative_tests.h" 59 | #include "azure_c_shared_utility/macro_utils.h" 60 | #include "azure_c_shared_utility/xio.h" 61 | #include "azure_c_shared_utility/tlsio.h" 62 | 63 | const IO_INTERFACE_DESCRIPTION* tlsio_id; 64 | // These "headers" are actually source files that are broken out of this file for readability 65 | //#include "unit_test_api.h" 66 | #include "ssl_impl.h" 67 | #include "callbacks.h" 68 | #include "test_defines.h" 69 | #include "gballoc_ut_impl_2.h" 70 | 71 | DEFINE_ENUM_STRINGS(UMOCK_C_ERROR_CODE, UMOCK_C_ERROR_CODE_VALUES) 72 | 73 | static void on_umock_c_error(UMOCK_C_ERROR_CODE error_code) 74 | { 75 | char temp_str[256]; 76 | (void)snprintf(temp_str, sizeof(temp_str), "umock_c reported error :%s", ENUM_TO_STRING(UMOCK_C_ERROR_CODE, error_code)); 77 | ASSERT_FAIL(temp_str); 78 | } 79 | 80 | /** 81 | * This is necessary for the test suite, just keep as is. 82 | */ 83 | static TEST_MUTEX_HANDLE g_testByTest; 84 | static TEST_MUTEX_HANDLE g_dllByDll; 85 | static bool negative_mocks_used = false; 86 | 87 | 88 | BEGIN_TEST_SUITE(tlsio_openssl_compact_unittests) 89 | 90 | TEST_SUITE_INITIALIZE(a) 91 | { 92 | int result; 93 | size_t type_size; 94 | TEST_INITIALIZE_MEMORY_DEBUG(g_dllByDll); 95 | g_testByTest = TEST_MUTEX_CREATE(); 96 | ASSERT_IS_NOT_NULL(g_testByTest); 97 | tlsio_id = tlsio_pal_get_interface_description(); 98 | 99 | (void)umock_c_init(on_umock_c_error); 100 | 101 | result = umocktypes_charptr_register_types(); 102 | ASSERT_ARE_EQUAL(int, 0, result); 103 | result = umocktypes_bool_register_types(); 104 | ASSERT_ARE_EQUAL(int, 0, result); 105 | umocktypes_stdint_register_types(); 106 | ASSERT_ARE_EQUAL(int, 0, result); 107 | 108 | REGISTER_UMOCK_ALIAS_TYPE(SSL, void*); 109 | REGISTER_UMOCK_ALIAS_TYPE(SSL_CTX, void*); 110 | REGISTER_UMOCK_ALIAS_TYPE(SOCKET_ASYNC_OPTIONS_HANDLE, void*); 111 | REGISTER_UMOCK_ALIAS_TYPE(SOCKET_ASYNC_HANDLE, int); 112 | REGISTER_UMOCK_ALIAS_TYPE(DNS_ASYNC_HANDLE, void*); 113 | type_size = sizeof(time_t); 114 | if (type_size == sizeof(uint64_t)) 115 | { 116 | REGISTER_UMOCK_ALIAS_TYPE(time_t, uint64_t); 117 | } 118 | else if (type_size == sizeof(uint32_t)) 119 | { 120 | REGISTER_UMOCK_ALIAS_TYPE(time_t, uint32_t); 121 | } 122 | else 123 | { 124 | ASSERT_FAIL("Bad size_t size"); 125 | } 126 | 127 | REGISTER_GLOBAL_MOCK_RETURNS(dns_async_create, GOOD_DNS_ASYNC_HANDLE, NULL); 128 | REGISTER_GLOBAL_MOCK_RETURNS(dns_async_is_lookup_complete, true, false); 129 | REGISTER_GLOBAL_MOCK_RETURNS(dns_async_get_ipv4, SSL_Get_IPv4_OK, SSL_Get_IPv4_FAIL); 130 | 131 | REGISTER_GLOBAL_MOCK_RETURNS(socket_async_create, SSL_Good_Socket, -1); 132 | REGISTER_GLOBAL_MOCK_HOOK(socket_async_is_create_complete, my_socket_async_is_create_complete); 133 | 134 | REGISTER_GLOBAL_MOCK_RETURNS(SSL_new, SSL_Good_Ptr, NULL); 135 | REGISTER_GLOBAL_MOCK_RETURNS(SSL_CTX_new, SSL_Good_Context_Ptr, NULL); 136 | REGISTER_GLOBAL_MOCK_RETURNS(SSL_set_fd, SSL_SET_FD_SUCCESS, SSL_SET_FD_FAILURE); 137 | REGISTER_GLOBAL_MOCK_RETURNS(SSL_connect, SSL_CONNECT_SUCCESS, SSL_ERROR__plus__HARD_FAIL); 138 | REGISTER_GLOBAL_MOCK_RETURNS(SSL_get_error, SSL_ERROR_WANT_READ, SSL_ERROR_HARD_FAIL); 139 | REGISTER_GLOBAL_MOCK_HOOK(SSL_write, my_SSL_write); 140 | REGISTER_GLOBAL_MOCK_HOOK(SSL_read, my_SSL_read); 141 | REGISTER_GLOBAL_MOCK_HOOK(SSL_get_error, my_SSL_get_error); 142 | 143 | /** 144 | * Or you can combine, for example, in the success case malloc will call my_gballoc_malloc, and for 145 | * the failed cases, it will return NULL. 146 | */ 147 | REGISTER_GLOBAL_MOCK_HOOK(gballoc_malloc, my_gballoc_malloc); 148 | REGISTER_GLOBAL_MOCK_FAIL_RETURN(gballoc_malloc, NULL); 149 | REGISTER_GLOBAL_MOCK_HOOK(gballoc_free, my_gballoc_free); 150 | 151 | tlsio_config.hostname = SSL_good_old_host_name; 152 | } 153 | 154 | static void use_negative_mocks() 155 | { 156 | int negativeTestsInitResult = umock_c_negative_tests_init(); 157 | negative_mocks_used = true; 158 | ASSERT_ARE_EQUAL(int, 0, negativeTestsInitResult); 159 | } 160 | 161 | /** 162 | * The test suite will call this function to cleanup your machine. 163 | * It is called only once, after all tests is done. 164 | */ 165 | TEST_SUITE_CLEANUP(TestClassCleanup) 166 | { 167 | umock_c_deinit(); 168 | 169 | TEST_MUTEX_DESTROY(g_testByTest); 170 | TEST_DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); 171 | } 172 | 173 | /** 174 | * The test suite will call this function to prepare the machine for the new test. 175 | * It is called before execute each test. 176 | */ 177 | TEST_FUNCTION_INITIALIZE(initialize) 178 | { 179 | if (TEST_MUTEX_ACQUIRE(g_testByTest)) 180 | { 181 | ASSERT_FAIL("Could not acquire test serialization mutex."); 182 | } 183 | 184 | umock_c_reset_all_calls(); 185 | reset_callback_context_records(); 186 | init_gballoc_checks(); 187 | } 188 | 189 | /** 190 | * The test suite will call this function to cleanup your machine for the next test. 191 | * It is called after execute each test. 192 | */ 193 | TEST_FUNCTION_CLEANUP(cleans) 194 | { 195 | if (negative_mocks_used) 196 | { 197 | negative_mocks_used = false; 198 | umock_c_negative_tests_deinit(); 199 | } 200 | TEST_MUTEX_RELEASE(g_testByTest); 201 | } 202 | 203 | static void open_helper(CONCRETE_IO_HANDLE tlsio) 204 | { 205 | int open_result; 206 | reset_callback_context_records(); 207 | open_result = tlsio_id->concrete_io_open(tlsio, on_io_open_complete, IO_OPEN_COMPLETE_CONTEXT, on_bytes_received, 208 | IO_BYTES_RECEIVED_CONTEXT, on_io_error, IO_ERROR_CONTEXT); 209 | ASSERT_ARE_EQUAL(int, open_result, 0); 210 | 211 | // Pump dowork until it opens 212 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_dns (done) 213 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_socket (done) 214 | ASSERT_IO_OPEN_CALLBACK(false, IO_OPEN_ERROR); 215 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_open_ssl (finishes Open) 216 | ASSERT_IO_OPEN_CALLBACK(true, IO_OPEN_OK); 217 | } 218 | 219 | /* Tests_SRS_TLSIO_30_201: [ The "high-level retry sequence" shall succeed after an injected fault which causes on_io_error to be called. ]*/ 220 | TEST_FUNCTION(tlsio_openssl_compact__retry_open_after_io_failure__succeeds) 221 | { 222 | int send_result; 223 | int open_result; 224 | ///arrange 225 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 226 | reset_callback_context_records(); 227 | open_helper(tlsio); 228 | 229 | // Queue up the message to eventually fail on 230 | STRICT_EXPECTED_CALL(SSL_write(SSL_Good_Ptr, IGNORED_PTR_ARG, SSL_FAIL_ME_SENT_MESSAGE_SIZE)).SetReturn(SSL_ERROR__plus__WANT_WRITE); 231 | send_result = tlsio_id->concrete_io_send(tlsio, SSL_send_buffer, 232 | SSL_FAIL_ME_SENT_MESSAGE_SIZE, on_io_send_complete, IO_SEND_COMPLETE_CONTEXT); 233 | ASSERT_ARE_EQUAL(int, 0, send_result); 234 | 235 | umock_c_reset_all_calls(); 236 | reset_callback_context_records(); 237 | // Make sure the io fails 238 | tlsio_id->concrete_io_dowork(tlsio); 239 | ASSERT_IO_ERROR_CALLBACK(true); 240 | 241 | // Close the error'd tlsio 242 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, IO_CLOSE_COMPLETE_CONTEXT); 243 | ASSERT_IO_CLOSE_CALLBACK(true); 244 | 245 | // Retry the open 246 | open_result = tlsio_id->concrete_io_open(tlsio, on_io_open_complete, IO_OPEN_COMPLETE_CONTEXT, on_bytes_received, 247 | IO_BYTES_RECEIVED_CONTEXT, on_io_error, IO_ERROR_CONTEXT); 248 | ASSERT_ARE_EQUAL(int, open_result, 0); 249 | 250 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_dns (done) 251 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_socket (done) 252 | 253 | reset_callback_context_records(); 254 | 255 | ///act 256 | // dowork_poll_open_ssl (done) 257 | tlsio_id->concrete_io_dowork(tlsio); 258 | 259 | ///assert 260 | // Check that we got the on_open callback for our retry 261 | ASSERT_IO_OPEN_CALLBACK(true, IO_OPEN_OK); 262 | 263 | ///cleanup 264 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 265 | tlsio_id->concrete_io_destroy(tlsio); 266 | assert_gballoc_checks(); 267 | } 268 | 269 | /* Tests_SRS_TLSIO_30_200: [ The "high-level retry sequence" shall succeed after an injected fault which causes on_io_open_complete to return with IO_OPEN_ERROR. ]*/ 270 | TEST_FUNCTION(tlsio_openssl_compact__retry_open_after_open_failure__succeeds) 271 | { 272 | ///arrange 273 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 274 | int open_result = tlsio_id->concrete_io_open(tlsio, on_io_open_complete, IO_OPEN_COMPLETE_CONTEXT, on_bytes_received, 275 | IO_BYTES_RECEIVED_CONTEXT, on_io_error, IO_ERROR_CONTEXT); 276 | ASSERT_ARE_EQUAL(int, open_result, 0); 277 | ASSERT_IO_OPEN_CALLBACK(false, IO_OPEN_ERROR); 278 | umock_c_reset_all_calls(); 279 | 280 | // dowork_poll_open_ssl (done) Fail the SSL_connect call 281 | STRICT_EXPECTED_CALL(SSL_connect(SSL_Good_Ptr)).SetReturn(SSL_ERROR__plus__HARD_FAIL); 282 | 283 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_dns (done) 284 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_socket (done) 285 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_open_ssl (done) 286 | ASSERT_IO_OPEN_CALLBACK(true, IO_OPEN_ERROR); 287 | 288 | // Close the error'd tlsio 289 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 290 | 291 | // Retry the open 292 | umock_c_reset_all_calls(); 293 | open_result = tlsio_id->concrete_io_open(tlsio, on_io_open_complete, IO_OPEN_COMPLETE_CONTEXT, on_bytes_received, 294 | IO_BYTES_RECEIVED_CONTEXT, on_io_error, IO_ERROR_CONTEXT); 295 | ASSERT_ARE_EQUAL(int, open_result, 0); 296 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_dns (done) 297 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_socket (done) 298 | reset_callback_context_records(); 299 | 300 | ///act 301 | tlsio_id->concrete_io_dowork(tlsio); 302 | 303 | ///assert 304 | // Check that we got the on_open callback for our retry 305 | ASSERT_IO_OPEN_CALLBACK(true, IO_OPEN_OK); 306 | 307 | ///cleanup 308 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 309 | tlsio_id->concrete_io_destroy(tlsio); 310 | assert_gballoc_checks(); 311 | } 312 | 313 | /* Tests_SRS_TLSIO_30_050: [ If the tlsio_handle parameter is NULL, tlsio_close shall log an error and return FAILURE. ]*/ 314 | /* Tests_SRS_TLSIO_30_055: [ If the on_io_close_complete parameter is NULL, tlsio_close shall log an error and return FAILURE. ]*/ 315 | /* Tests_SRS_TLSIO_30_054: [ On failure, the adapter shall not call on_io_close_complete. ]*/ 316 | TEST_FUNCTION(tlsio_openssl_compact__close_parameter_validation__fails) 317 | { 318 | int k; 319 | bool p0[CLOSE_PV_COUNT]; 320 | ON_IO_CLOSE_COMPLETE p1[CLOSE_PV_COUNT]; 321 | const char* fm[CLOSE_PV_COUNT]; 322 | int i; 323 | 324 | ///arrange 325 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 326 | 327 | umock_c_reset_all_calls(); 328 | 329 | k = 0; 330 | p0[k] = false; p1[k] = on_io_close_complete; fm[k] = "Unexpected close success when tlsio_handle is NULL"; /* */ k++; 331 | p0[k] = true; p1[k] = NULL; /* */ fm[k] = "Unexpected close success when on_io_close_complete is NULL"; k++; 332 | 333 | // Cycle through each failing combo of parameters 334 | for (i = 0; i < CLOSE_PV_COUNT; i++) 335 | { 336 | int close_result; 337 | reset_callback_context_records(); 338 | ///arrange 339 | 340 | ///act 341 | close_result = tlsio_id->concrete_io_close(p0[i] ? tlsio : NULL, p1[i], IO_CLOSE_COMPLETE_CONTEXT); 342 | 343 | ///assert 344 | ASSERT_ARE_NOT_EQUAL_WITH_MSG(int, 0, close_result, fm[i]); 345 | ASSERT_IO_CLOSE_CALLBACK(false); 346 | } 347 | 348 | ///cleanup 349 | tlsio_id->concrete_io_destroy(tlsio); 350 | assert_gballoc_checks(); 351 | } 352 | 353 | /* Tests_SRS_TLSIO_30_009: [ The phrase "enter TLSIO_STATE_EXT_CLOSING" means the adapter shall iterate through any unsent messages in the queue and shall delete each message after calling its on_send_complete with the associated callback_context and IO_SEND_CANCELLED . ]*/ 354 | /* Tests_SRS_TLSIO_30_056: [ On success the adapter shall enter TLSIO_STATE_EX_CLOSING. ]*/ 355 | TEST_FUNCTION(tlsio_openssl_compact__close_with_unsent_messages__succeeds) 356 | { 357 | ///arrange 358 | int send_result; 359 | int close_result; 360 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 361 | reset_callback_context_records(); 362 | open_helper(tlsio); 363 | 364 | // Make sure the arrangement is correct 365 | ASSERT_IO_OPEN_CALLBACK(true, IO_OPEN_OK); 366 | 367 | STRICT_EXPECTED_CALL(SSL_write(SSL_Good_Ptr, IGNORED_PTR_ARG, SSL_SHORT_SENT_MESSAGE_SIZE)).SetReturn(SSL_ERROR__plus__WANT_WRITE); 368 | STRICT_EXPECTED_CALL(SSL_write(SSL_Good_Ptr, IGNORED_PTR_ARG, SSL_SHORT_SENT_MESSAGE_SIZE)).SetReturn(SSL_ERROR__plus__WANT_WRITE); 369 | send_result = tlsio_id->concrete_io_send(tlsio, SSL_send_buffer, 370 | SSL_SHORT_SENT_MESSAGE_SIZE, on_io_send_complete, IO_SEND_COMPLETE_CONTEXT); 371 | ASSERT_ARE_EQUAL(int, send_result, 0); 372 | send_result = tlsio_id->concrete_io_send(tlsio, SSL_send_buffer, 373 | SSL_SHORT_SENT_MESSAGE_SIZE, on_io_send_complete, IO_SEND_COMPLETE_CONTEXT); 374 | ASSERT_ARE_EQUAL(int, send_result, 0); 375 | 376 | 377 | umock_c_reset_all_calls(); 378 | STRICT_EXPECTED_CALL(SSL_shutdown(SSL_Good_Ptr)); 379 | STRICT_EXPECTED_CALL(SSL_free(SSL_Good_Ptr)); 380 | STRICT_EXPECTED_CALL(SSL_CTX_free(SSL_Good_Context_Ptr)); 381 | STRICT_EXPECTED_CALL(socket_async_destroy(SSL_Good_Socket)); 382 | // Message 1 delete 383 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); 384 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); 385 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); 386 | // Message 2 delete 387 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); 388 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); 389 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); 390 | reset_callback_context_records(); 391 | // End of arrange 392 | 393 | ///act 394 | close_result = tlsio_id->concrete_io_close(tlsio, on_io_close_complete, IO_CLOSE_COMPLETE_CONTEXT); 395 | 396 | ///assert 397 | ASSERT_ARE_EQUAL(int, 0, close_result); 398 | ASSERT_IO_CLOSE_CALLBACK(true); 399 | ASSERT_IO_SEND_ABANDONED(2); // 2 messages in this test 400 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 401 | 402 | 403 | ///cleanup 404 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 405 | tlsio_id->concrete_io_destroy(tlsio); 406 | assert_gballoc_checks(); 407 | } 408 | 409 | /* Tests_SSRS_TLSIO_30_053: [ If the adapter is in any state other than TLSIO_STATE_EXT_OPEN or TLSIO_STATE_EXT_ERROR then tlsio_close_async shall log that tlsio_close_async has been called and then continue normally. ]*/ 410 | TEST_FUNCTION(tlsio_openssl_compact__close_while_closed__succeeds) 411 | { 412 | CONCRETE_IO_HANDLE tlsio; 413 | int close_result; 414 | ///arrange 415 | reset_callback_context_records(); 416 | tlsio_id = tlsio_pal_get_interface_description(); 417 | tlsio = tlsio_id->concrete_io_create(&good_config); 418 | ASSERT_IO_OPEN_CALLBACK(false, IO_OPEN_OK); 419 | umock_c_reset_all_calls(); 420 | reset_callback_context_records(); 421 | 422 | ///act 423 | close_result = tlsio_id->concrete_io_close(tlsio, on_io_close_complete, IO_CLOSE_COMPLETE_CONTEXT); 424 | 425 | ///assert 426 | ASSERT_ARE_EQUAL(int, 0, close_result); 427 | ASSERT_IO_CLOSE_CALLBACK(true); 428 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 429 | 430 | ///cleanup 431 | tlsio_id->concrete_io_destroy(tlsio); 432 | assert_gballoc_checks(); 433 | } 434 | 435 | /* Tests_SRS_TLSIO_30_009: [ The phrase "enter TLSIO_STATE_EXT_CLOSING" means the adapter shall iterate through any unsent messages in the queue and shall delete each message after calling its on_send_complete with the associated callback_context and IO_SEND_CANCELLED. ]*/ 436 | /* Tests_SRS_TLSIO_30_006: [ The phrase "enter TLSIO_STATE_EXT_CLOSED" means the adapter shall forcibly close any existing connections then call the on_io_close_complete function and pass the on_io_close_complete_context that was supplied in tlsio_close_async. ]*/ 437 | /* Tests_SRS_TLSIO_30_056: [ On success the adapter shall enter TLSIO_STATE_EX_CLOSING. ]*/ 438 | /* Tests_SRS_TLSIO_30_051: [ On success, if the underlying TLS does not support asynchronous closing, then the adapter shall enter TLSIO_STATE_EX_CLOSED immediately after entering TLSIO_STATE_EX_CLOSING. ]*/ 439 | /* Tests_SRS_TLSIO_30_052: [ On success tlsio_close shall return 0. ]*/ 440 | // For this case, tlsio_openssl_compact_open has been called previously 441 | TEST_FUNCTION(tlsio_openssl_compact__close_after_open__succeeds) 442 | { 443 | int close_result; 444 | ///arrange 445 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 446 | reset_callback_context_records(); 447 | open_helper(tlsio); 448 | 449 | // Make sure the arrangement is correct 450 | ASSERT_IO_OPEN_CALLBACK(true, IO_OPEN_OK); 451 | 452 | umock_c_reset_all_calls(); 453 | STRICT_EXPECTED_CALL(SSL_shutdown(SSL_Good_Ptr)); 454 | STRICT_EXPECTED_CALL(SSL_free(SSL_Good_Ptr)); 455 | STRICT_EXPECTED_CALL(SSL_CTX_free(SSL_Good_Context_Ptr)); 456 | STRICT_EXPECTED_CALL(socket_async_destroy(SSL_Good_Socket)); 457 | reset_callback_context_records(); 458 | // End of arrange 459 | 460 | ///act 461 | close_result = tlsio_id->concrete_io_close(tlsio, on_io_close_complete, IO_CLOSE_COMPLETE_CONTEXT); 462 | 463 | ///assert 464 | ASSERT_ARE_EQUAL(int, 0, close_result); 465 | ASSERT_IO_CLOSE_CALLBACK(true); 466 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 467 | 468 | ///cleanup 469 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 470 | tlsio_id->concrete_io_destroy(tlsio); 471 | assert_gballoc_checks(); 472 | } 473 | 474 | /* Tests_SRS_TLSIO_30_053: [ If the adapter is in any state other than TLSIO_STATE_EXT_OPEN or TLSIO_STATE_EXT_ERROR then tlsio_close_async shall log that tlsio_close_async has been called and then continue normally. ]*/ 475 | /* Tests_SRS_TLSIO_30_057: [ On success, if the adapter is in TLSIO_STATE_EXT_OPENING, it shall call on_io_open_complete with the on_io_open_complete_context supplied in tlsio_open_async and IO_OPEN_CANCELLED. This callback shall be made before changing the internal state of the adapter. ]*/ 476 | TEST_FUNCTION(tlsio_openssl_compact__close_while_opening__succeeds) 477 | { 478 | int open_result; 479 | CONCRETE_IO_HANDLE tlsio; 480 | int close_result; 481 | ///arrange 482 | reset_callback_context_records(); 483 | tlsio = tlsio_id->concrete_io_create(&good_config); 484 | open_result = tlsio_id->concrete_io_open(tlsio, on_io_open_complete, IO_OPEN_COMPLETE_CONTEXT, on_bytes_received, 485 | IO_BYTES_RECEIVED_CONTEXT, on_io_error, IO_ERROR_CONTEXT); 486 | ASSERT_ARE_EQUAL(int, open_result, 0); 487 | ASSERT_IO_OPEN_CALLBACK(false, IO_OPEN_ERROR); 488 | umock_c_reset_all_calls(); 489 | 490 | // dowork_poll_dns (waiting) 491 | STRICT_EXPECTED_CALL(dns_async_is_lookup_complete(GOOD_DNS_ASYNC_HANDLE)).SetReturn(false); 492 | 493 | // dowork_poll_dns (done) 494 | STRICT_EXPECTED_CALL(dns_async_is_lookup_complete(GOOD_DNS_ASYNC_HANDLE)); 495 | STRICT_EXPECTED_CALL(dns_async_get_ipv4(GOOD_DNS_ASYNC_HANDLE)); 496 | STRICT_EXPECTED_CALL(dns_async_destroy(GOOD_DNS_ASYNC_HANDLE)); 497 | STRICT_EXPECTED_CALL(socket_async_create(SSL_Get_IPv4_OK, SSL_good_port_number, false, NULL)); 498 | 499 | // dowork_poll_socket (waiting) 500 | STRICT_EXPECTED_CALL(socket_async_is_create_complete(SSL_Good_Socket, IGNORED_PTR_ARG)).CopyOutArgumentBuffer_is_complete(&bool_false, sizeof_bool); 501 | 502 | // dowork_poll_socket (done) 503 | STRICT_EXPECTED_CALL(socket_async_is_create_complete(SSL_Good_Socket, IGNORED_PTR_ARG)).CopyOutArgumentBuffer_is_complete(&bool_true, sizeof_bool); 504 | STRICT_EXPECTED_CALL(SSL_CTX_new(IGNORED_NUM_ARG)); 505 | STRICT_EXPECTED_CALL(SSL_new(IGNORED_PTR_ARG)); 506 | STRICT_EXPECTED_CALL(SSL_set_fd(IGNORED_PTR_ARG, IGNORED_NUM_ARG)); 507 | 508 | // dowork_poll_open_ssl (waiting SSL_ERROR_WANT_READ) 509 | STRICT_EXPECTED_CALL(SSL_connect(SSL_Good_Ptr)).SetReturn(SSL_ERROR__plus__WANT_READ); 510 | STRICT_EXPECTED_CALL(SSL_get_error(SSL_Good_Ptr, SSL_ERROR__plus__WANT_READ)); 511 | 512 | // dowork_poll_open_ssl (waiting SSL_ERROR_WANT_WRITE) 513 | STRICT_EXPECTED_CALL(SSL_connect(SSL_Good_Ptr)).SetReturn(SSL_ERROR__plus__WANT_WRITE); 514 | STRICT_EXPECTED_CALL(SSL_get_error(SSL_Good_Ptr, SSL_ERROR__plus__WANT_WRITE)); 515 | 516 | // dowork_poll_open_ssl (done) 517 | 518 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_dns (waiting) 519 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_dns (done) 520 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_socket (waiting) 521 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_socket (done) 522 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_open_ssl (waiting SSL_ERROR_WANT_READ) 523 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_open_ssl (waiting SSL_ERROR_WANT_WRITE) 524 | 525 | // Make sure the arrangement is correct so far 526 | ASSERT_IO_OPEN_CALLBACK(false, IO_OPEN_OK); 527 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 528 | 529 | umock_c_reset_all_calls(); 530 | STRICT_EXPECTED_CALL(SSL_free(SSL_Good_Ptr)); 531 | STRICT_EXPECTED_CALL(SSL_CTX_free(SSL_Good_Context_Ptr)); 532 | STRICT_EXPECTED_CALL(socket_async_destroy(SSL_Good_Socket)); 533 | reset_callback_context_records(); 534 | // End of arrange 535 | 536 | ///act 537 | close_result = tlsio_id->concrete_io_close(tlsio, on_io_close_complete, IO_CLOSE_COMPLETE_CONTEXT); 538 | 539 | ///assert 540 | ASSERT_ARE_EQUAL(int, 0, close_result); 541 | ASSERT_IO_OPEN_CALLBACK(true, IO_OPEN_CANCELLED); 542 | ASSERT_IO_CLOSE_CALLBACK(true); 543 | 544 | ///cleanup 545 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 546 | tlsio_id->concrete_io_destroy(tlsio); 547 | assert_gballoc_checks(); 548 | } 549 | 550 | /* Tests_SRS_TLSIO_30_063: [ The tlsio_openssl_compact_send shall enqueue for transmission the on_send_complete, the callback_context, the size, and the contents of buffer. ]*/ 551 | TEST_FUNCTION(tlsio_openssl_compact__send__succeeds) 552 | { 553 | int send_result; 554 | ///arrange 555 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 556 | open_helper(tlsio); 557 | reset_callback_context_records(); 558 | umock_c_reset_all_calls(); 559 | 560 | STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)); // PENDING_SOCKET_IO 561 | STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)); // message bytes 562 | STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)); // singlylinkedlist_add 563 | 564 | ///act 565 | send_result = tlsio_id->concrete_io_send(tlsio, SSL_send_buffer, 566 | SSL_send_message_size, on_io_send_complete, IO_SEND_COMPLETE_CONTEXT); 567 | 568 | ///assert 569 | ASSERT_ARE_EQUAL_WITH_MSG(int, send_result, 0, "Unexpected send failure"); 570 | 571 | ///cleanup 572 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 573 | tlsio_id->concrete_io_destroy(tlsio); 574 | assert_gballoc_checks(); 575 | } 576 | 577 | /* Tests_SRS_TLSIO_30_064: [ If the supplied message cannot be enqueued for transmission, tlsio_openssl_compact_send shall log an error and return FAILURE. ]*/ 578 | /* Tests_SRS_TLSIO_30_066: [ On failure, on_send_complete shall not be called. ]*/ 579 | TEST_FUNCTION(tlsio_openssl_compact__send_unhappy_paths__fails) 580 | { 581 | ///arrange 582 | size_t i; 583 | use_negative_mocks(); 584 | 585 | STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)); // PENDING_TRANSMISSION 586 | STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)); // message bytes 587 | STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)); // singlylinkedlist_add 588 | umock_c_negative_tests_snapshot(); 589 | 590 | for (i = 0; i < umock_c_negative_tests_call_count(); i++) 591 | { 592 | int send_result; 593 | ///arrange 594 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 595 | open_helper(tlsio); 596 | reset_callback_context_records(); 597 | 598 | umock_c_reset_all_calls(); 599 | 600 | umock_c_negative_tests_reset(); 601 | umock_c_negative_tests_fail_call(i); 602 | 603 | ///act 604 | send_result = tlsio_id->concrete_io_send(tlsio, SSL_send_buffer, 605 | SSL_send_message_size, on_io_send_complete, IO_SEND_COMPLETE_CONTEXT); 606 | 607 | ///assert 608 | ASSERT_ARE_NOT_EQUAL_WITH_MSG(int, send_result, 0, "Unexpected send success on unhappy path"); 609 | ASSERT_IO_SEND_CALLBACK(false, IO_SEND_ERROR); 610 | 611 | ///cleanup 612 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 613 | tlsio_id->concrete_io_destroy(tlsio); 614 | } 615 | 616 | ///cleanup 617 | assert_gballoc_checks(); 618 | } 619 | 620 | /* Tests_SRS_TLSIO_30_060: [ If the tlsio_handle parameter is NULL, tlsio_openssl_compact_send shall log an error and return FAILURE. ]*/ 621 | /* Tests_SRS_TLSIO_30_061: [ If the buffer is NULL, tlsio_openssl_compact_send shall log the error and return FAILURE. ]*/ 622 | /* Tests_SRS_TLSIO_30_062: [ If the on_send_complete is NULL, tlsio_openssl_compact_send shall log the error and return FAILURE. ]*/ 623 | /* Tests_SRS_TLSIO_30_067: [ If the size is 0, tlsio_send shall log the error and return FAILURE. ]*/ 624 | /* Tests_SRS_TLSIO_30_066: [ On failure, on_send_complete shall not be called. ]*/ 625 | TEST_FUNCTION(tlsio_openssl_compact__send_parameter_validation__fails) 626 | { 627 | // Parameters arrays 628 | bool p0[SEND_PV_COUNT]; 629 | const void* p1[SEND_PV_COUNT]; 630 | size_t p2[SEND_PV_COUNT]; 631 | ON_SEND_COMPLETE p3[SEND_PV_COUNT]; 632 | const char* fm[SEND_PV_COUNT]; 633 | int k; 634 | int i; 635 | 636 | ///arrange 637 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 638 | open_helper(tlsio); 639 | 640 | k = 0; 641 | p0[k] = false; p1[k] = SSL_send_buffer; p2[k] = SSL_send_message_size; p3[k] = on_io_send_complete; fm[k] = "Unexpected send success when tlsio_handle is NULL"; k++; 642 | p0[k] = true; p1[k] = NULL; /* */ p2[k] = SSL_send_message_size; p3[k] = on_io_send_complete; fm[k] = "Unexpected send success when send buffer is NULL"; k++; 643 | p0[k] = true; p1[k] = SSL_send_buffer; p2[k] = 0; /* */ p3[k] = on_io_send_complete; fm[k] = "Unexpected send success when size is 0"; k++; 644 | p0[k] = true; p1[k] = SSL_send_buffer; p2[k] = SSL_send_message_size; p3[k] = NULL; /* */ fm[k] = "Unexpected send success when on_send_complete is NULL"; k++; 645 | 646 | // Cycle through each failing combo of parameters 647 | for (i = 0; i < SEND_PV_COUNT; i++) 648 | { 649 | int send_result; 650 | ///arrange 651 | reset_callback_context_records(); 652 | 653 | ///act 654 | send_result = tlsio_id->concrete_io_send(p0[i] ? tlsio : NULL, p1[i], p2[i], p3[i], IO_SEND_COMPLETE_CONTEXT); 655 | 656 | ///assert 657 | ASSERT_ARE_NOT_EQUAL_WITH_MSG(int, send_result, 0, fm[i]); 658 | ASSERT_IO_SEND_CALLBACK(false, IO_SEND_ERROR); 659 | 660 | ///cleanup 661 | } 662 | 663 | ///cleanup 664 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 665 | tlsio_id->concrete_io_destroy(tlsio); 666 | assert_gballoc_checks(); 667 | } 668 | 669 | /* Tests_SRS_TLSIO_30_065: [ If tlsio_openssl_compact_open has not been called or the opening process has not been completed, tlsio_openssl_compact_send shall log an error and return FAILURE. ]*/ 670 | /* Tests_SRS_TLSIO_30_066: [ On failure, on_send_complete shall not be called. ]*/ 671 | TEST_FUNCTION(tlsio_openssl_compact__send_not_open__fails) 672 | { 673 | int send_result; 674 | ///arrange 675 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 676 | reset_callback_context_records(); 677 | 678 | ///act 679 | send_result = tlsio_id->concrete_io_send(tlsio, SSL_send_buffer, 680 | SSL_send_message_size, on_io_send_complete, IO_SEND_COMPLETE_CONTEXT); 681 | 682 | ///assert 683 | ASSERT_ARE_NOT_EQUAL_WITH_MSG(int, send_result, 0, "Unexpected success in sending from wrong state"); 684 | ASSERT_IO_SEND_CALLBACK(false, IO_SEND_ERROR); 685 | 686 | ///cleanup 687 | tlsio_id->concrete_io_destroy(tlsio); 688 | assert_gballoc_checks(); 689 | } 690 | 691 | /* Tests_SRS_TLSIO_30_071: [ If the adapter is in TLSIO_STATE_EXT_ERROR then tlsio_dowork shall do nothing. ]*/ 692 | TEST_FUNCTION(tlsio_openssl_compact__dowork_send_post_error_do_nothing__succeeds) 693 | { 694 | int send_result; 695 | ///arrange 696 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 697 | open_helper(tlsio); 698 | 699 | // Queue up two messages, one to fail and one that should be ignored by the dowork 700 | STRICT_EXPECTED_CALL(SSL_write(SSL_Good_Ptr, IGNORED_PTR_ARG, SSL_SHORT_SENT_MESSAGE_SIZE)).SetReturn(SSL_ERROR__plus__WANT_WRITE); 701 | STRICT_EXPECTED_CALL(SSL_write(SSL_Good_Ptr, IGNORED_PTR_ARG, SSL_SHORT_SENT_MESSAGE_SIZE)).SetReturn(SSL_ERROR__plus__WANT_WRITE); 702 | send_result = tlsio_id->concrete_io_send(tlsio, SSL_send_buffer, 703 | SSL_SHORT_SENT_MESSAGE_SIZE, on_io_send_complete, IO_SEND_COMPLETE_CONTEXT); 704 | ASSERT_ARE_EQUAL(int, send_result, 0); 705 | send_result = tlsio_id->concrete_io_send(tlsio, SSL_send_buffer, 706 | SSL_SHORT_SENT_MESSAGE_SIZE, on_io_send_complete, IO_SEND_COMPLETE_CONTEXT); 707 | ASSERT_ARE_EQUAL(int, send_result, 0); 708 | 709 | reset_callback_context_records(); 710 | init_fake_read(0); 711 | umock_c_reset_all_calls(); 712 | 713 | STRICT_EXPECTED_CALL(SSL_read(SSL_Good_Ptr, IGNORED_PTR_ARG, IGNORED_NUM_ARG)); 714 | STRICT_EXPECTED_CALL(SSL_write(SSL_Good_Ptr, IGNORED_PTR_ARG, SSL_SHORT_SENT_MESSAGE_SIZE)).SetReturn(SSL_ERROR__plus__HARD_FAIL); 715 | STRICT_EXPECTED_CALL(SSL_get_error(SSL_Good_Ptr, IGNORED_NUM_ARG)); 716 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_NUM_ARG)); 717 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_NUM_ARG)); 718 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_NUM_ARG)); 719 | 720 | tlsio_id->concrete_io_dowork(tlsio); 721 | 722 | ASSERT_IO_SEND_CALLBACK(true, IO_SEND_ERROR); 723 | ASSERT_IO_ERROR_CALLBACK(true); 724 | 725 | reset_callback_context_records(); 726 | umock_c_reset_all_calls(); 727 | 728 | ///act 729 | tlsio_id->concrete_io_dowork(tlsio); 730 | 731 | ///assert 732 | ASSERT_NO_CALLBACKS(); 733 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 734 | 735 | ///cleanup 736 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 737 | tlsio_id->concrete_io_destroy(tlsio); 738 | assert_gballoc_checks(); 739 | } 740 | 741 | /* Tests_SRS_TLSIO_30_002: [ The phrase "destroy the failed message" means that the adapter shall remove the message from the queue and destroy it after calling the message's on_send_complete along with its associated callback_context and IO_SEND_ERROR. ]*/ 742 | /* Tests_SRS_TLSIO_30_005: [ When the adapter enters TLSIO_STATE_EXT_ERROR it shall call the on_io_error function and pass the on_io_error_context that were supplied in tlsio_open . ]*/ 743 | /* Tests_SRS_TLSIO_30_095: [ If the send process fails before sending all of the bytes in an enqueued message, tlsio_dowork shall destroy the failed message and enter TLSIO_STATE_EX_ERROR. ]*/ 744 | TEST_FUNCTION(tlsio_openssl_compact__dowork_send_unhappy_path__fails) 745 | { 746 | int send_result; 747 | ///arrange 748 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 749 | open_helper(tlsio); 750 | 751 | STRICT_EXPECTED_CALL(SSL_write(SSL_Good_Ptr, IGNORED_PTR_ARG, SSL_SHORT_SENT_MESSAGE_SIZE)).SetReturn(SSL_ERROR__plus__WANT_WRITE); 752 | send_result = tlsio_id->concrete_io_send(tlsio, SSL_send_buffer, 753 | SSL_SHORT_SENT_MESSAGE_SIZE, on_io_send_complete, IO_SEND_COMPLETE_CONTEXT); 754 | ASSERT_ARE_EQUAL(int, send_result, 0); 755 | 756 | init_fake_read(0); 757 | reset_callback_context_records(); 758 | umock_c_reset_all_calls(); 759 | 760 | STRICT_EXPECTED_CALL(SSL_read(SSL_Good_Ptr, IGNORED_PTR_ARG, IGNORED_NUM_ARG)); 761 | STRICT_EXPECTED_CALL(SSL_write(SSL_Good_Ptr, IGNORED_PTR_ARG, SSL_SHORT_SENT_MESSAGE_SIZE)).SetReturn(SSL_ERROR__plus__HARD_FAIL); 762 | STRICT_EXPECTED_CALL(SSL_get_error(SSL_Good_Ptr, IGNORED_NUM_ARG)); 763 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_NUM_ARG)); 764 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_NUM_ARG)); 765 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_NUM_ARG)); 766 | 767 | ///act 768 | tlsio_id->concrete_io_dowork(tlsio); 769 | 770 | ///assert 771 | ASSERT_IO_SEND_CALLBACK(true, IO_SEND_ERROR); 772 | ASSERT_IO_ERROR_CALLBACK(true); 773 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 774 | 775 | ///cleanup 776 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 777 | tlsio_id->concrete_io_destroy(tlsio); 778 | assert_gballoc_checks(); 779 | } 780 | 781 | /* Tests_SRS_TLSIO_30_093: [ If the TLS connection was not able to send an entire enqueued message at once, subsequent calls to tlsio_dowork shall continue to send the remaining bytes. ]*/ 782 | TEST_FUNCTION(tlsio_openssl_compact__dowork_send_big_message__succeeds) 783 | { 784 | int send_result; 785 | ///arrange 786 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 787 | open_helper(tlsio); 788 | 789 | STRICT_EXPECTED_CALL(SSL_write(SSL_Good_Ptr, IGNORED_PTR_ARG, SSL_TEST_MESSAGE_SIZE)).SetReturn(SSL_ERROR__plus__WANT_WRITE); 790 | send_result = tlsio_id->concrete_io_send(tlsio, SSL_send_buffer, 791 | SSL_TEST_MESSAGE_SIZE, on_io_send_complete, IO_SEND_COMPLETE_CONTEXT); 792 | ASSERT_ARE_EQUAL(int, send_result, 0); 793 | ASSERT_IO_ERROR_CALLBACK(false); 794 | 795 | init_fake_read(0); 796 | reset_callback_context_records(); 797 | umock_c_reset_all_calls(); 798 | 799 | STRICT_EXPECTED_CALL(SSL_read(SSL_Good_Ptr, IGNORED_PTR_ARG, IGNORED_NUM_ARG)); 800 | STRICT_EXPECTED_CALL(SSL_write(SSL_Good_Ptr, IGNORED_PTR_ARG, SSL_TEST_MESSAGE_SIZE)); 801 | 802 | STRICT_EXPECTED_CALL(SSL_read(SSL_Good_Ptr, IGNORED_PTR_ARG, IGNORED_NUM_ARG)); 803 | STRICT_EXPECTED_CALL(SSL_write(SSL_Good_Ptr, IGNORED_PTR_ARG, SSL_TEST_MESSAGE_SIZE - SSL_WRITE_MAX_TEST_SIZE)); 804 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_NUM_ARG)); 805 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_NUM_ARG)); 806 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_NUM_ARG)); 807 | tlsio_id->concrete_io_dowork(tlsio); 808 | ASSERT_IO_ERROR_CALLBACK(false); 809 | 810 | ///act 811 | tlsio_id->concrete_io_dowork(tlsio); 812 | 813 | ///assert 814 | ASSERT_IO_SEND_CALLBACK(true, IO_SEND_OK); 815 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 816 | ASSERT_IO_ERROR_CALLBACK(false); 817 | 818 | ///cleanup 819 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 820 | tlsio_id->concrete_io_destroy(tlsio); 821 | assert_gballoc_checks(); 822 | } 823 | 824 | /* Tests_SRS_TLSIO_30_091: [ If tlsio_openssl_compact_dowork is able to send all the bytes in an enqueued message, it shall call the messages's on_send_complete along with its associated callback_context and IO_SEND_OK. ]*/ 825 | TEST_FUNCTION(tlsio_openssl_compact__dowork_send__succeeds) 826 | { 827 | int send_result; 828 | ///arrange 829 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 830 | open_helper(tlsio); 831 | 832 | STRICT_EXPECTED_CALL(SSL_write(SSL_Good_Ptr, IGNORED_PTR_ARG, SSL_SHORT_SENT_MESSAGE_SIZE)).SetReturn(SSL_ERROR__plus__WANT_WRITE); 833 | send_result = tlsio_id->concrete_io_send(tlsio, SSL_send_buffer, 834 | SSL_SHORT_SENT_MESSAGE_SIZE, on_io_send_complete, IO_SEND_COMPLETE_CONTEXT); 835 | ASSERT_ARE_EQUAL(int, send_result, 0); 836 | ASSERT_IO_ERROR_CALLBACK(false); 837 | 838 | init_fake_read(0); 839 | reset_callback_context_records(); 840 | umock_c_reset_all_calls(); 841 | 842 | STRICT_EXPECTED_CALL(SSL_read(SSL_Good_Ptr, IGNORED_PTR_ARG, IGNORED_NUM_ARG)); 843 | STRICT_EXPECTED_CALL(SSL_write(SSL_Good_Ptr, IGNORED_PTR_ARG, SSL_SHORT_SENT_MESSAGE_SIZE)); 844 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_NUM_ARG)); 845 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_NUM_ARG)); 846 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_NUM_ARG)); 847 | 848 | ///act 849 | tlsio_id->concrete_io_dowork(tlsio); 850 | 851 | ///assert 852 | ASSERT_IO_SEND_CALLBACK(true, IO_SEND_OK); 853 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 854 | ASSERT_IO_ERROR_CALLBACK(false); 855 | 856 | ///cleanup 857 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 858 | tlsio_id->concrete_io_destroy(tlsio); 859 | assert_gballoc_checks(); 860 | } 861 | 862 | /* Tests_SRS_TLSIO_30_096: [ If there are no enqueued messages available, tlsio_openssl_compact_dowork shall do nothing. ]*/ 863 | TEST_FUNCTION(tlsio_openssl_compact__dowork_send_empty_queue__succeeds) 864 | { 865 | ///arrange 866 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 867 | open_helper(tlsio); 868 | 869 | init_fake_read(0); 870 | reset_callback_context_records(); 871 | umock_c_reset_all_calls(); 872 | 873 | // We do expect an empty read when we call dowork 874 | STRICT_EXPECTED_CALL(SSL_read(SSL_Good_Ptr, IGNORED_PTR_ARG, IGNORED_NUM_ARG)); 875 | 876 | ///act 877 | tlsio_id->concrete_io_dowork(tlsio); 878 | 879 | ///assert 880 | // Verify we got no callback for 0 messages 881 | ASSERT_IO_SEND_CALLBACK(false, IO_SEND_OK); 882 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 883 | ASSERT_IO_ERROR_CALLBACK(false); 884 | 885 | ///cleanup 886 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 887 | tlsio_id->concrete_io_destroy(tlsio); 888 | assert_gballoc_checks(); 889 | } 890 | 891 | /* Tests_SRS_TLSIO_30_102: [ If the TLS connection receives no data then tlsio_dowork shall not call the on_bytes_received callback. ]*/ 892 | TEST_FUNCTION(tlsio_openssl_compact__dowork_receive_no_data__succeeds) 893 | { 894 | ///arrange 895 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 896 | open_helper(tlsio); 897 | 898 | init_fake_read(0); 899 | reset_callback_context_records(); 900 | umock_c_reset_all_calls(); 901 | 902 | STRICT_EXPECTED_CALL(SSL_read(SSL_Good_Ptr, IGNORED_PTR_ARG, IGNORED_NUM_ARG)); 903 | 904 | ///act 905 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_dns (done) 906 | 907 | ///assert 908 | // Verify we got no callback for 0 bytes 909 | ASSERT_BYTES_RECEIVED_CALLBACK(false, 0); 910 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 911 | ASSERT_IO_ERROR_CALLBACK(false); 912 | 913 | ///cleanup 914 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 915 | tlsio_id->concrete_io_destroy(tlsio); 916 | assert_gballoc_checks(); 917 | } 918 | 919 | /* Tests_SRS_TLSIO_30_100: [ As long as the TLS connection is able to provide received data, tlsio_dowork shall repeatedly read this data and call on_bytes_received with the pointer to the buffer containing the data, the number of bytes received, and the on_bytes_received_context. ]*/ 920 | TEST_FUNCTION(tlsio_openssl_compact__dowork_receive_short_message__succeeds) 921 | { 922 | ///arrange 923 | // Create 924 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 925 | open_helper(tlsio); 926 | 927 | init_fake_read(SSL_SHORT_RECEIVED_MESSAGE_SIZE); 928 | reset_callback_context_records(); 929 | umock_c_reset_all_calls(); 930 | 931 | STRICT_EXPECTED_CALL(SSL_read(SSL_Good_Ptr, IGNORED_PTR_ARG, IGNORED_NUM_ARG)); // Gets some data 932 | STRICT_EXPECTED_CALL(SSL_read(SSL_Good_Ptr, IGNORED_PTR_ARG, IGNORED_NUM_ARG)); // Gets zero bytes 933 | 934 | ///act 935 | tlsio_id->concrete_io_dowork(tlsio); 936 | 937 | ///assert 938 | // Verify we got the bytes and their callback context 939 | ASSERT_BYTES_RECEIVED_CALLBACK(true, SSL_SHORT_RECEIVED_MESSAGE_SIZE); 940 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 941 | ASSERT_IO_ERROR_CALLBACK(false); 942 | 943 | ///cleanup 944 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 945 | tlsio_id->concrete_io_destroy(tlsio); 946 | assert_gballoc_checks(); 947 | } 948 | 949 | /* Tests_SRS_TLSIO_30_100: [ As long as the TLS connection is able to provide received data, tlsio_dowork shall repeatedly read this data and call on_bytes_received with the pointer to the buffer containing the data, the number of bytes received, and the on_bytes_received_context. ]*/ 950 | TEST_FUNCTION(tlsio_openssl_compact__dowork_receive_long_message__succeeds) 951 | { 952 | ///arrange 953 | // Create 954 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 955 | open_helper(tlsio); 956 | 957 | init_fake_read(SSL_LONG_RECEIVED_MESSAGE_SIZE); 958 | reset_callback_context_records(); 959 | umock_c_reset_all_calls(); 960 | 961 | ///act 962 | tlsio_id->concrete_io_dowork(tlsio); 963 | 964 | ///assert 965 | // Verify we got the bytes and their callback context 966 | ASSERT_BYTES_RECEIVED_CALLBACK(true, SSL_LONG_RECEIVED_MESSAGE_SIZE); 967 | ASSERT_IO_ERROR_CALLBACK(false); 968 | 969 | ///cleanup 970 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 971 | tlsio_id->concrete_io_destroy(tlsio); 972 | assert_gballoc_checks(); 973 | } 974 | 975 | /* Tests_SRS_TLSIO_30_075: [ If the adapter is in TLSIO_STATE_EXT_CLOSED then tlsio_dowork shall do nothing. ]*/ 976 | TEST_FUNCTION(tlsio_openssl_compact__dowork_post_close__succeeds) 977 | { 978 | CONCRETE_IO_HANDLE tlsio; 979 | int open_result; 980 | ///arrange 981 | // Create 982 | reset_callback_context_records(); 983 | tlsio = tlsio_id->concrete_io_create(&good_config); 984 | open_result = tlsio_id->concrete_io_open(tlsio, on_io_open_complete, IO_OPEN_COMPLETE_CONTEXT, on_bytes_received, 985 | IO_BYTES_RECEIVED_CONTEXT, on_io_error, IO_ERROR_CONTEXT); 986 | ASSERT_ARE_EQUAL(int, open_result, 0); 987 | ASSERT_IO_OPEN_CALLBACK(false, IO_OPEN_ERROR); 988 | 989 | // Pump dowork until it opens 990 | STRICT_EXPECTED_CALL(socket_async_is_create_complete(SSL_Good_Socket, IGNORED_PTR_ARG)).CopyOutArgumentBuffer_is_complete(&bool_true, sizeof_bool); 991 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_dns (done) 992 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_socket (done) 993 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_open_ssl (done) 994 | ASSERT_IO_OPEN_CALLBACK(true, IO_OPEN_OK); 995 | 996 | // close it 997 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, IO_CLOSE_COMPLETE_CONTEXT); 998 | ASSERT_IO_CLOSE_CALLBACK(true); 999 | reset_callback_context_records(); 1000 | umock_c_reset_all_calls(); 1001 | 1002 | ///act 1003 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_dns (done) 1004 | 1005 | ///assert 1006 | // Verify that the dowork did nothing 1007 | ASSERT_NO_CALLBACKS(); 1008 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 1009 | 1010 | ///cleanup 1011 | tlsio_id->concrete_io_destroy(tlsio); 1012 | assert_gballoc_checks(); 1013 | } 1014 | 1015 | 1016 | /* Tests_SRS_TLSIO_30_082: [ If the connection process fails for any reason, tlsio_dowork shall log an error, call on_io_open_complete with the on_io_open_complete_context parameter provided in tlsio_open and IO_OPEN_ERROR, and enter TLSIO_STATE_EX_ERROR. ]*/ 1017 | TEST_FUNCTION(tlsio_openssl_compact__dowork_open_unhappy_paths__fails) 1018 | { 1019 | int k; 1020 | bool fails[100]; 1021 | size_t i; 1022 | ///arrange 1023 | k = 0; 1024 | use_negative_mocks(); 1025 | 1026 | // dowork_poll_dns (waiting) 1027 | fails[k++] = false; STRICT_EXPECTED_CALL(dns_async_is_lookup_complete(GOOD_DNS_ASYNC_HANDLE)).SetReturn(false); 1028 | 1029 | // dowork_poll_dns (done) 1030 | fails[k++] = false; STRICT_EXPECTED_CALL(dns_async_is_lookup_complete(GOOD_DNS_ASYNC_HANDLE)); 1031 | fails[k++] = true; STRICT_EXPECTED_CALL(dns_async_get_ipv4(GOOD_DNS_ASYNC_HANDLE)); 1032 | fails[k++] = false; STRICT_EXPECTED_CALL(dns_async_destroy(GOOD_DNS_ASYNC_HANDLE)); 1033 | fails[k++] = true; STRICT_EXPECTED_CALL(socket_async_create(SSL_Get_IPv4_OK, SSL_good_port_number, false, NULL)); 1034 | 1035 | // dowork_poll_socket (waiting) 1036 | fails[k++] = false; STRICT_EXPECTED_CALL(socket_async_is_create_complete(SSL_Good_Socket, IGNORED_PTR_ARG)).CopyOutArgumentBuffer_is_complete(&bool_false, sizeof_bool); 1037 | 1038 | // dowork_poll_socket (done) 1039 | fails[k++] = false; STRICT_EXPECTED_CALL(socket_async_is_create_complete(SSL_Good_Socket, IGNORED_PTR_ARG)).CopyOutArgumentBuffer_is_complete(&bool_true, sizeof_bool); 1040 | fails[k++] = true; STRICT_EXPECTED_CALL(SSL_CTX_new(IGNORED_NUM_ARG)); 1041 | fails[k++] = true; STRICT_EXPECTED_CALL(SSL_new(IGNORED_PTR_ARG)); 1042 | fails[k++] = true; STRICT_EXPECTED_CALL(SSL_set_fd(IGNORED_PTR_ARG, IGNORED_NUM_ARG)); 1043 | 1044 | // dowork_poll_open_ssl (timeout) 1045 | fails[k++] = false; STRICT_EXPECTED_CALL(SSL_connect(SSL_Good_Ptr)).SetReturn(SSL_ERROR__plus__WANT_READ); 1046 | fails[k++] = false; STRICT_EXPECTED_CALL(SSL_get_error(SSL_Good_Ptr, SSL_ERROR__plus__WANT_READ)); 1047 | 1048 | // dowork_poll_open_ssl (hard failure) 1049 | fails[k++] = true; STRICT_EXPECTED_CALL(SSL_connect(SSL_Good_Ptr)); 1050 | 1051 | umock_c_negative_tests_snapshot(); 1052 | 1053 | for (i = 0; i < umock_c_negative_tests_call_count(); i++) 1054 | { 1055 | CONCRETE_IO_HANDLE tlsio; 1056 | int open_result; 1057 | reset_callback_context_records(); 1058 | tlsio = tlsio_id->concrete_io_create(&good_config); 1059 | open_result = tlsio_id->concrete_io_open(tlsio, on_io_open_complete, IO_OPEN_COMPLETE_CONTEXT, on_bytes_received, 1060 | IO_BYTES_RECEIVED_CONTEXT, on_io_error, IO_ERROR_CONTEXT); 1061 | ASSERT_ARE_EQUAL(int, open_result, 0); 1062 | ASSERT_IO_OPEN_CALLBACK(false, IO_OPEN_ERROR); 1063 | umock_c_reset_all_calls(); 1064 | 1065 | umock_c_negative_tests_reset(); 1066 | if (fails[i]) 1067 | { 1068 | umock_c_negative_tests_fail_call(i); 1069 | } 1070 | tlsio_id->concrete_io_dowork(tlsio); 1071 | tlsio_id->concrete_io_dowork(tlsio); 1072 | tlsio_id->concrete_io_dowork(tlsio); 1073 | tlsio_id->concrete_io_dowork(tlsio); 1074 | tlsio_id->concrete_io_dowork(tlsio); 1075 | 1076 | ///act 1077 | tlsio_id->concrete_io_dowork(tlsio); 1078 | 1079 | ///assert 1080 | // A few of the iterations have no failures 1081 | ASSERT_IO_OPEN_CALLBACK(true, fails[i] ? IO_OPEN_ERROR : IO_OPEN_OK); 1082 | 1083 | ///cleanup 1084 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 1085 | tlsio_id->concrete_io_destroy(tlsio); 1086 | } 1087 | 1088 | ///cleanup 1089 | assert_gballoc_checks(); 1090 | } 1091 | 1092 | /* Tests_SRS_TLSIO_30_080: [ The tlsio_dowork shall establish a TLS connection using the hostName and port provided during tlsio_open. ]*/ 1093 | /* Tests_SRS_TLSIO_30_007: [ The phrase "enter TLSIO_STATE_EXT_OPEN" means the adapter shall call the on_io_open_complete function and pass IO_OPEN_OK and the on_io_open_complete_context that was supplied in tlsio_open . ]*/ 1094 | /* Tests_SRS_TLSIO_30_083: [ If tlsio_dowork successfully opens the TLS connection it shall enter TLSIO_STATE_EX_OPEN. ]*/ 1095 | TEST_FUNCTION(tlsio_openssl_compact__dowork_open__succeeds) 1096 | { 1097 | CONCRETE_IO_HANDLE tlsio; 1098 | int open_result; 1099 | ///arrange 1100 | reset_callback_context_records(); 1101 | tlsio = tlsio_id->concrete_io_create(&good_config); 1102 | open_result = tlsio_id->concrete_io_open(tlsio, on_io_open_complete, IO_OPEN_COMPLETE_CONTEXT, on_bytes_received, 1103 | IO_BYTES_RECEIVED_CONTEXT, on_io_error, IO_ERROR_CONTEXT); 1104 | ASSERT_ARE_EQUAL(int, open_result, 0); 1105 | ASSERT_IO_OPEN_CALLBACK(false, IO_OPEN_ERROR); 1106 | umock_c_reset_all_calls(); 1107 | 1108 | // dowork_poll_dns (waiting) 1109 | STRICT_EXPECTED_CALL(dns_async_is_lookup_complete(GOOD_DNS_ASYNC_HANDLE)).SetReturn(false); 1110 | 1111 | // dowork_poll_dns (done) 1112 | STRICT_EXPECTED_CALL(dns_async_is_lookup_complete(GOOD_DNS_ASYNC_HANDLE)); 1113 | STRICT_EXPECTED_CALL(dns_async_get_ipv4(GOOD_DNS_ASYNC_HANDLE)); 1114 | STRICT_EXPECTED_CALL(dns_async_destroy(GOOD_DNS_ASYNC_HANDLE)); 1115 | STRICT_EXPECTED_CALL(socket_async_create(SSL_Get_IPv4_OK, SSL_good_port_number, false, NULL)); 1116 | 1117 | // dowork_poll_socket (waiting) 1118 | STRICT_EXPECTED_CALL(socket_async_is_create_complete(SSL_Good_Socket, IGNORED_PTR_ARG)).CopyOutArgumentBuffer_is_complete(&bool_false, sizeof_bool); 1119 | 1120 | // dowork_poll_socket (done) 1121 | STRICT_EXPECTED_CALL(socket_async_is_create_complete(SSL_Good_Socket, IGNORED_PTR_ARG)).CopyOutArgumentBuffer_is_complete(&bool_true, sizeof_bool); 1122 | STRICT_EXPECTED_CALL(SSL_CTX_new(IGNORED_NUM_ARG)); 1123 | STRICT_EXPECTED_CALL(SSL_new(IGNORED_PTR_ARG)); 1124 | STRICT_EXPECTED_CALL(SSL_set_fd(IGNORED_PTR_ARG, IGNORED_NUM_ARG)); 1125 | 1126 | // dowork_poll_open_ssl (waiting SSL_ERROR_WANT_READ) 1127 | STRICT_EXPECTED_CALL(SSL_connect(SSL_Good_Ptr)).SetReturn(SSL_ERROR__plus__WANT_READ); 1128 | STRICT_EXPECTED_CALL(SSL_get_error(SSL_Good_Ptr, SSL_ERROR__plus__WANT_READ)); 1129 | 1130 | // dowork_poll_open_ssl (waiting SSL_ERROR_WANT_WRITE) 1131 | STRICT_EXPECTED_CALL(SSL_connect(SSL_Good_Ptr)).SetReturn(SSL_ERROR__plus__WANT_WRITE); 1132 | STRICT_EXPECTED_CALL(SSL_get_error(SSL_Good_Ptr, SSL_ERROR__plus__WANT_WRITE)); 1133 | 1134 | // dowork_poll_open_ssl (done) 1135 | STRICT_EXPECTED_CALL(SSL_connect(SSL_Good_Ptr)).SetReturn(SSL_CONNECT_SUCCESS); 1136 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_dns (waiting) 1137 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_dns (done) 1138 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_socket (waiting) 1139 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_socket (done) 1140 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_open_ssl (waiting SSL_ERROR_WANT_READ) 1141 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_open_ssl (waiting SSL_ERROR_WANT_WRITE) 1142 | ASSERT_IO_OPEN_CALLBACK(false, IO_OPEN_OK); 1143 | 1144 | ///act 1145 | tlsio_id->concrete_io_dowork(tlsio); // dowork_poll_open_ssl (done) 1146 | 1147 | ///assert 1148 | // Check that we got the on_open callback 1149 | ASSERT_IO_OPEN_CALLBACK(true, IO_OPEN_OK); 1150 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 1151 | 1152 | ///cleanup 1153 | tlsio_id->concrete_io_close(tlsio, on_io_close_complete, NULL); 1154 | tlsio_id->concrete_io_destroy(tlsio); 1155 | assert_gballoc_checks(); 1156 | } 1157 | 1158 | /* Tests_SRS_TLSIO_30_075: [ If the adapter is in TLSIO_STATE_EXT_CLOSED then tlsio_dowork shall do nothing. ]*/ 1159 | TEST_FUNCTION(tlsio_openssl_compact__dowork_pre_open__succeeds) 1160 | { 1161 | ///arrange 1162 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 1163 | umock_c_reset_all_calls(); 1164 | reset_callback_context_records(); 1165 | 1166 | ///act 1167 | tlsio_id->concrete_io_dowork(tlsio); 1168 | 1169 | ///assert 1170 | ASSERT_NO_CALLBACKS(); 1171 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 1172 | 1173 | ///cleanup 1174 | tlsio_id->concrete_io_destroy(tlsio); 1175 | assert_gballoc_checks(); 1176 | } 1177 | 1178 | /* Tests_SRS_TLSIO_30_070: [ If the tlsio_handle parameter is NULL, tlsio_dowork shall do nothing except log an error. ]*/ 1179 | TEST_FUNCTION(tlsio_openssl_compact__dowork_parameter_validation__fails) 1180 | { 1181 | ///arrange 1182 | 1183 | ///act 1184 | tlsio_id->concrete_io_dowork(NULL); 1185 | 1186 | ///assert 1187 | ASSERT_NO_CALLBACKS(); 1188 | 1189 | ///cleanup 1190 | assert_gballoc_checks(); 1191 | } 1192 | 1193 | /* Tests_SRS_TLSIO_30_035: [ On tlsio_open success the adapter shall enter TLSIO_STATE_EX_OPENING and return 0. ]*/ 1194 | /* Tests_SRS_TLSIO_30_034: [ The tlsio_open shall store the provided on_bytes_received, on_bytes_received_context, on_io_error, on_io_error_context, on_io_open_complete, and on_io_open_complete_context parameters for later use as specified and tested per other line entries in this document. ]*/ 1195 | TEST_FUNCTION(tlsio_openssl_compact__open__succeeds) 1196 | { 1197 | int open_result; 1198 | ///arrange 1199 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 1200 | umock_c_reset_all_calls(); 1201 | reset_callback_context_records(); 1202 | 1203 | STRICT_EXPECTED_CALL(dns_async_create(IGNORED_PTR_ARG, NULL)); 1204 | 1205 | ///act 1206 | open_result = tlsio_id->concrete_io_open(tlsio, on_io_open_complete, IO_OPEN_COMPLETE_CONTEXT, on_bytes_received, 1207 | IO_BYTES_RECEIVED_CONTEXT, on_io_error, IO_ERROR_CONTEXT); 1208 | 1209 | ///assert 1210 | ASSERT_ARE_EQUAL(int, open_result, 0); 1211 | // Should not have made any callbacks yet 1212 | ASSERT_IO_OPEN_CALLBACK(false, IO_OPEN_ERROR); 1213 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 1214 | // Ensure that the callbacks were stored properly in the internal instance 1215 | 1216 | ///cleanup 1217 | tlsio_id->concrete_io_destroy(tlsio); 1218 | assert_gballoc_checks(); 1219 | } 1220 | 1221 | /* Tests_SRS_TLSIO_30_038: [ If tlsio_open fails to enter TLSIO_STATE_EX_OPENING it shall return FAILURE. ]*/ 1222 | /* Tests_SRS_TLSIO_30_039: [ On failure, tlsio_open_async shall not call on_io_open_complete. ]*/ 1223 | TEST_FUNCTION(tlsio_openssl_compact__open_unhappy_path__fails) 1224 | { 1225 | int open_result; 1226 | ///arrange 1227 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 1228 | umock_c_reset_all_calls(); 1229 | reset_callback_context_records(); 1230 | 1231 | STRICT_EXPECTED_CALL(dns_async_create(IGNORED_PTR_ARG, NULL)).SetReturn(NULL); 1232 | 1233 | ///act 1234 | open_result = tlsio_id->concrete_io_open(tlsio, on_io_open_complete, IO_OPEN_COMPLETE_CONTEXT, on_bytes_received, 1235 | IO_BYTES_RECEIVED_CONTEXT, on_io_error, IO_ERROR_CONTEXT); 1236 | 1237 | ///assert 1238 | ASSERT_ARE_NOT_EQUAL(int, open_result, 0); 1239 | // Should not get a callback 1240 | ASSERT_IO_OPEN_CALLBACK(false, IO_OPEN_ERROR); 1241 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 1242 | 1243 | ///cleanup 1244 | tlsio_id->concrete_io_destroy(tlsio); 1245 | assert_gballoc_checks(); 1246 | } 1247 | 1248 | /* Tests_SRS_TLSIO_30_037: [ If the adapter is in any state other than TLSIO_STATE_EXT_CLOSED when tlsio_open is called, it shall log an error, and return FAILURE. ]*/ 1249 | /* Tests_SRS_TLSIO_30_039: [ On failure, tlsio_open_async shall not call on_io_open_complete. ]*/ 1250 | TEST_FUNCTION(tlsio_openssl_compact__open_wrong_state__fails) 1251 | { 1252 | int open_result_2; 1253 | ///arrange 1254 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 1255 | int open_result = tlsio_id->concrete_io_open(tlsio, on_io_open_complete, IO_OPEN_COMPLETE_CONTEXT, on_bytes_received, 1256 | IO_BYTES_RECEIVED_CONTEXT, on_io_error, IO_ERROR_CONTEXT); 1257 | ASSERT_ARE_EQUAL(int, open_result, 0); 1258 | reset_callback_context_records(); 1259 | 1260 | ///act 1261 | open_result_2 = tlsio_id->concrete_io_open(tlsio, on_io_open_complete, IO_OPEN_COMPLETE_CONTEXT, on_bytes_received, 1262 | IO_BYTES_RECEIVED_CONTEXT, on_io_error, IO_ERROR_CONTEXT); 1263 | 1264 | ///assert 1265 | ASSERT_ARE_NOT_EQUAL_WITH_MSG(int, open_result_2, 0, "Unexpected 2nd open success"); 1266 | ASSERT_IO_OPEN_CALLBACK(false, IO_OPEN_ERROR); 1267 | 1268 | ///cleanup 1269 | tlsio_id->concrete_io_destroy(tlsio); 1270 | assert_gballoc_checks(); 1271 | } 1272 | 1273 | /* Tests_SRS_TLSIO_30_030: [ If the tlsio_handle parameter is NULL, tlsio_open shall log an error and return FAILURE. ]*/ 1274 | /* Tests_SRS_TLSIO_30_031: [ If the on_io_open_complete parameter is NULL, tlsio_open shall log an error and return FAILURE. ]*/ 1275 | /* Tests_SRS_TLSIO_30_032: [ If the on_bytes_received parameter is NULL, tlsio_open shall log an error and return FAILURE. ]*/ 1276 | /* Tests_SRS_TLSIO_30_033: [ If the on_io_error parameter is NULL, tlsio_openss_open shall log an error and return FAILURE. ]*/ 1277 | /* Tests_SRS_TLSIO_30_039: [ On failure, tlsio_open_async shall not call on_io_open_complete. ]*/ 1278 | TEST_FUNCTION(tlsio_openssl_compact__open_parameter_validation_fails__fails) 1279 | { 1280 | ///arrange 1281 | 1282 | // Parameters arrays 1283 | bool p0[OPEN_PV_COUNT]; 1284 | ON_IO_OPEN_COMPLETE p1[OPEN_PV_COUNT]; 1285 | ON_BYTES_RECEIVED p2[OPEN_PV_COUNT]; 1286 | ON_IO_ERROR p3[OPEN_PV_COUNT]; 1287 | const char* fm[OPEN_PV_COUNT]; 1288 | int i; 1289 | 1290 | int k = 0; 1291 | p0[k] = false; p1[k] = on_io_open_complete; p2[k] = on_bytes_received; p3[k] = on_io_error; fm[k] = "Unexpected open success when tlsio_handle is NULL"; /* */ k++; 1292 | p0[k] = true; p1[k] = NULL; /* */ p2[k] = on_bytes_received; p3[k] = on_io_error; fm[k] = "Unexpected open success when on_io_open_complete is NULL"; k++; 1293 | p0[k] = true; p1[k] = on_io_open_complete; p2[k] = NULL; /* */ p3[k] = on_io_error; fm[k] = "Unexpected open success when on_bytes_received is NULL"; k++; 1294 | p0[k] = true; p1[k] = on_io_open_complete; p2[k] = on_bytes_received; p3[k] = NULL; /* */ fm[k] = "Unexpected open success when on_io_error is NULL"; /* */ k++; 1295 | 1296 | // Cycle through each failing combo of parameters 1297 | for (i = 0; i < OPEN_PV_COUNT; i++) 1298 | { 1299 | CONCRETE_IO_HANDLE tlsio; 1300 | int open_result; 1301 | ///arrange 1302 | reset_callback_context_records(); 1303 | tlsio = tlsio_id->concrete_io_create(&good_config); 1304 | 1305 | ///act 1306 | open_result = tlsio_id->concrete_io_open(p0[i] ? tlsio : NULL, p1[i], IO_OPEN_COMPLETE_CONTEXT, p2[i], 1307 | IO_BYTES_RECEIVED_CONTEXT, p3[i], IO_ERROR_CONTEXT); 1308 | 1309 | ///assert 1310 | ASSERT_ARE_NOT_EQUAL_WITH_MSG(int, open_result, 0, fm[i]); 1311 | ASSERT_IO_OPEN_CALLBACK(false, IO_OPEN_ERROR); 1312 | 1313 | ///cleanup 1314 | tlsio_id->concrete_io_destroy(tlsio); 1315 | } 1316 | assert_gballoc_checks(); 1317 | } 1318 | 1319 | /* Tests_SRS_TLSIO_OPENSSL_COMPACT_30_520 [ The tlsio_setoption shall do nothing and return __FAILURE__. ]*/ 1320 | TEST_FUNCTION(tlsio_openssl_compact__setoption__succeeds) 1321 | { 1322 | int result; 1323 | ///arrange 1324 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 1325 | ASSERT_IS_NOT_NULL(tlsio); 1326 | umock_c_reset_all_calls(); 1327 | 1328 | ///act 1329 | result = tlsio_id->concrete_io_setoption(tlsio, "fake name", "fake value"); 1330 | 1331 | ///assert 1332 | ASSERT_ARE_NOT_EQUAL(int, 0, result); 1333 | 1334 | ///cleanup 1335 | tlsio_id->concrete_io_destroy(tlsio); 1336 | assert_gballoc_checks(); 1337 | } 1338 | 1339 | /* Tests_SRS_TLSIO_30_120: [ If the tlsio_handle parameter is NULL, tlsio_openssl_compact_setoption shall do nothing except log an error and return FAILURE. ]*/ 1340 | /* Tests_SRS_TLSIO_30_121: [ If the optionName parameter is NULL, tlsio_openssl_compact_setoption shall do nothing except log an error and return FAILURE. ]*/ 1341 | /* Tests_SRS_TLSIO_30_122: [ If the value parameter is NULL, tlsio_openssl_compact_setoption shall do nothing except log an error and return FAILURE. ]*/ 1342 | TEST_FUNCTION(tlsio_openssl_compact__setoption_parameter_validation__fails) 1343 | { 1344 | int k; 1345 | // Parameters arrays 1346 | bool p0[SETOPTION_PV_COUNT]; 1347 | const char* p1[SETOPTION_PV_COUNT]; 1348 | const char* p2[SETOPTION_PV_COUNT]; 1349 | const char* fm[SETOPTION_PV_COUNT]; 1350 | int i; 1351 | 1352 | ///arrange 1353 | umock_c_reset_all_calls(); 1354 | 1355 | k = 0; 1356 | p0[k] = false; p1[k] = "fake name"; p2[k] = "fake value"; fm[k] = "Unexpected setoption success when tlsio_handle is NULL"; /* */ k++; 1357 | p0[k] = true; p1[k] = NULL; /* */ p2[k] = "fake value"; fm[k] = "Unexpected setoption success when option_name is NULL"; /* */ k++; 1358 | p0[k] = true; p1[k] = "fake name"; p2[k] = NULL; /* */ fm[k] = "Unexpected setoption success when option_value is NULL"; /* */ k++; 1359 | 1360 | 1361 | // Cycle through each failing combo of parameters 1362 | for (i = 0; i < SETOPTION_PV_COUNT; i++) 1363 | { 1364 | int result; 1365 | ///arrange 1366 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 1367 | ASSERT_IS_NOT_NULL(tlsio); 1368 | 1369 | ///act 1370 | result = tlsio_id->concrete_io_setoption(p0[i] ? tlsio : NULL, p1[i], p2[i]); 1371 | 1372 | ///assert 1373 | ASSERT_ARE_NOT_EQUAL_WITH_MSG(int, 0, result, fm[i]); 1374 | 1375 | ///cleanup 1376 | tlsio_id->concrete_io_destroy(tlsio); 1377 | } 1378 | assert_gballoc_checks(); 1379 | } 1380 | 1381 | /* Tests_SRS_TLSIO_30_160: [ If the tlsio_handle parameter is NULL, tlsio_openssl_compact_retrieveoptions shall do nothing except log an error and return FAILURE. ]*/ 1382 | TEST_FUNCTION(tlsio_openssl_compact__retrieveoptions_parameter_validation__fails) 1383 | { 1384 | ///arrange 1385 | 1386 | ///act 1387 | OPTIONHANDLER_HANDLE result = tlsio_id->concrete_io_retrieveoptions(NULL); 1388 | 1389 | ///assert 1390 | ASSERT_IS_NULL((void*)result); 1391 | 1392 | ///cleanup 1393 | assert_gballoc_checks(); 1394 | } 1395 | 1396 | /* Tests_SRS_TLSIO_OPENSSL_COMPACT_30_560: [ The tlsio_retrieveoptions shall return an empty options handler. ]*/ 1397 | TEST_FUNCTION(tlsio_openssl_compact__retrieveoptions__succeeds) 1398 | { 1399 | OPTIONHANDLER_HANDLE result; 1400 | ///arrange 1401 | CONCRETE_IO_HANDLE tlsio = tlsio_id->concrete_io_create(&good_config); 1402 | ASSERT_IS_NOT_NULL(tlsio); 1403 | umock_c_reset_all_calls(); 1404 | 1405 | ///act 1406 | result = tlsio_id->concrete_io_retrieveoptions(tlsio); 1407 | 1408 | ///assert 1409 | ASSERT_IS_NOT_NULL((void*)result); 1410 | 1411 | ///cleanup 1412 | tlsio_id->concrete_io_destroy(tlsio); 1413 | OptionHandler_Destroy(result); 1414 | assert_gballoc_checks(); 1415 | } 1416 | 1417 | /* Tests_SRS_TLSIO_30_013: [ If the io_create_parameters value is NULL, tlsio_openssl_compact_create shall log an error and return NULL. ]*/ 1418 | /* Tests_SRS_TLSIO_30_014: [ If the hostname member of io_create_parameters value is NULL, tlsio_create shall log an error and return NULL. ]*/ 1419 | /* Tests_SRS_TLSIO_30_015: [ If the port member of io_create_parameters value is less than 0 or greater than 0xffff, tlsio_create shall log an error and return NULL. ]*/ 1420 | TEST_FUNCTION(tlsio_openssl_compact__create_parameter_validation_fails__fails) 1421 | { 1422 | ///arrange 1423 | TLSIO_CONFIG config[4]; 1424 | create_parameters_t p[4]; 1425 | int i; 1426 | // config hostname port number failure message 1427 | populate_create_parameters(p + 0, NULL, /* */ SSL_good_host_name, SSL_good_port_number, "Should fail with NULL config"); 1428 | populate_create_parameters(p + 1, config + 1, NULL, /* */ SSL_good_port_number, "Should fail with NULL hostname"); 1429 | populate_create_parameters(p + 2, config + 2, SSL_good_host_name, SSL_port_number_too_low, "Should fail with port number too low"); 1430 | populate_create_parameters(p + 3, config + 3, SSL_good_host_name, SSL_port_number_too_high, "Should fail with port number too high"); 1431 | 1432 | // Cycle through each failing combo of parameters 1433 | for (i = 0; i < sizeof(config) / sizeof(TLSIO_CONFIG); i++) 1434 | { 1435 | ///act 1436 | CONCRETE_IO_HANDLE result = tlsio_id->concrete_io_create(p[i].config); 1437 | 1438 | ///assert 1439 | ASSERT_IS_NULL_WITH_MSG(result, p[i].fail_msg); 1440 | } 1441 | assert_gballoc_checks(); 1442 | } 1443 | 1444 | /* Tests_SRS_TLSIO_30_011: [ If any resource allocation fails, tlsio_create shall return NULL. ]*/ 1445 | TEST_FUNCTION(tlsio_openssl_compact__create_unhappy_paths__fails) 1446 | { 1447 | size_t i; 1448 | ///arrange 1449 | use_negative_mocks(); 1450 | 1451 | STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)); // concrete_io struct 1452 | STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)); // copy hostname 1453 | STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)); // singlylinkedlist_create 1454 | umock_c_negative_tests_snapshot(); 1455 | 1456 | for (i = 0; i < umock_c_negative_tests_call_count(); i++) 1457 | { 1458 | CONCRETE_IO_HANDLE result; 1459 | umock_c_negative_tests_reset(); 1460 | umock_c_negative_tests_fail_call(i); 1461 | 1462 | ///act 1463 | result = tlsio_id->concrete_io_create(&good_config); 1464 | 1465 | ///assert 1466 | ASSERT_IS_NULL(result); 1467 | } 1468 | 1469 | ///cleanup 1470 | assert_gballoc_checks(); 1471 | } 1472 | 1473 | /* Tests_SRS_TLSIO_30_010: [ The tlsio_create shall allocate and initialize all necessary resources and return an instance of the tlsio_openssl_compact. ]*/ 1474 | /* Tests_SRS_TLSIO_30_016: [ tlsio_create shall make a copy of the hostname member of io_create_parameters to allow deletion of hostname immediately after the call. ]*/ 1475 | /* Tests_SRS_TLSIO_30_012: [ The tlsio_create shall receive the connection configuration as a TLSIO_CONFIG* in io_create_parameters. ]*/ 1476 | TEST_FUNCTION(tlsio_openssl_compact__create__succeeds) 1477 | { 1478 | CONCRETE_IO_HANDLE result; 1479 | ///arrange 1480 | 1481 | STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)); // concrete_io struct 1482 | STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)); // copy hostname 1483 | STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)); // singlylinkedlist_create 1484 | // 1485 | 1486 | ///act 1487 | result = tlsio_id->concrete_io_create(&good_config); 1488 | 1489 | ///assert 1490 | ASSERT_IS_NOT_NULL(result); 1491 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 1492 | 1493 | ///cleanup 1494 | tlsio_id->concrete_io_destroy(result); 1495 | assert_gballoc_checks(); 1496 | } 1497 | 1498 | 1499 | /* Tests_SRS_TLSIO_30_022: [ If the adapter is in any state other than TLSIO_STATE_EX_CLOSED when tlsio_destroy is called, the adapter shall enter TLSIO_STATE_EX_CLOSING and then enter TLSIO_STATE_EX_CLOSED before completing the destroy process. ]*/ 1500 | TEST_FUNCTION(tlsio_openssl_compact__destroy_with_unsent_messages__succeeds) 1501 | { 1502 | CONCRETE_IO_HANDLE tlsio; 1503 | int send_result; 1504 | ///arrange 1505 | reset_callback_context_records(); 1506 | tlsio = tlsio_id->concrete_io_create(&good_config); 1507 | open_helper(tlsio); 1508 | 1509 | // Make sure the arrangement is correct 1510 | ASSERT_IO_OPEN_CALLBACK(true, IO_OPEN_OK); 1511 | 1512 | STRICT_EXPECTED_CALL(SSL_write(SSL_Good_Ptr, IGNORED_PTR_ARG, SSL_SHORT_SENT_MESSAGE_SIZE)).SetReturn(SSL_ERROR__plus__WANT_WRITE); 1513 | STRICT_EXPECTED_CALL(SSL_write(SSL_Good_Ptr, IGNORED_PTR_ARG, SSL_SHORT_SENT_MESSAGE_SIZE)).SetReturn(SSL_ERROR__plus__WANT_WRITE); 1514 | send_result = tlsio_id->concrete_io_send(tlsio, SSL_send_buffer, 1515 | SSL_SHORT_SENT_MESSAGE_SIZE, on_io_send_complete, IO_SEND_COMPLETE_CONTEXT); 1516 | ASSERT_ARE_EQUAL(int, send_result, 0); 1517 | send_result = tlsio_id->concrete_io_send(tlsio, SSL_send_buffer, 1518 | SSL_SHORT_SENT_MESSAGE_SIZE, on_io_send_complete, IO_SEND_COMPLETE_CONTEXT); 1519 | ASSERT_ARE_EQUAL(int, send_result, 0); 1520 | 1521 | 1522 | umock_c_reset_all_calls(); 1523 | STRICT_EXPECTED_CALL(SSL_shutdown(SSL_Good_Ptr)); 1524 | STRICT_EXPECTED_CALL(SSL_free(SSL_Good_Ptr)); 1525 | STRICT_EXPECTED_CALL(SSL_CTX_free(SSL_Good_Context_Ptr)); 1526 | STRICT_EXPECTED_CALL(socket_async_destroy(SSL_Good_Socket)); 1527 | // Message 1 delete 1528 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); 1529 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); 1530 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); 1531 | // Message 2 delete 1532 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); 1533 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); 1534 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); 1535 | // Close and delete tlsio 1536 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); 1537 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); 1538 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); 1539 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); 1540 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); 1541 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); 1542 | // End of arrange 1543 | 1544 | ///act 1545 | tlsio_id->concrete_io_destroy(tlsio); 1546 | 1547 | ///assert 1548 | ASSERT_IO_SEND_ABANDONED(2); // 2 messages in this test 1549 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 1550 | 1551 | 1552 | ///cleanup 1553 | assert_gballoc_checks(); 1554 | } 1555 | 1556 | /* Tests_SRS_TLSIO_30_020: [ If tlsio_handle is NULL, tlsio_destroy shall do nothing. ]*/ 1557 | TEST_FUNCTION(tlsio_openssl_compact__destroy_parameter_validation__fails) 1558 | { 1559 | ///arrange 1560 | 1561 | ///act 1562 | tlsio_id->concrete_io_destroy(NULL); 1563 | 1564 | ///assert 1565 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 1566 | 1567 | ///cleanup 1568 | assert_gballoc_checks(); 1569 | } 1570 | 1571 | /* Tests_SRS_TLSIO_30_021: [ The tlsio__destroy shall release all allocated resources and then release tlsio_handle. ]*/ 1572 | TEST_FUNCTION(tlsio_openssl_compact__destroy_unopened__succeeds) 1573 | { 1574 | ///arrange 1575 | CONCRETE_IO_HANDLE result = tlsio_id->concrete_io_create(&good_config); 1576 | ASSERT_IS_NOT_NULL(result); 1577 | umock_c_reset_all_calls(); 1578 | 1579 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_NUM_ARG)); // copy hostname 1580 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_NUM_ARG)); // singlylinkedlist_create 1581 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_NUM_ARG)); // concrete_io struct 1582 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_NUM_ARG)); // tlsio_options 1583 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_NUM_ARG)); // tlsio_options 1584 | STRICT_EXPECTED_CALL(gballoc_free(IGNORED_NUM_ARG)); // tlsio_options 1585 | 1586 | ///act 1587 | tlsio_id->concrete_io_destroy(result); 1588 | 1589 | ///assert 1590 | ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); 1591 | 1592 | ///cleanup 1593 | assert_gballoc_checks(); 1594 | } 1595 | 1596 | /* Tests_SRS_TLSIO_30_008: [ The tlsio_get_interface_description shall return the VTable IO_INTERFACE_DESCRIPTION. ]*/ 1597 | /* Tests_SRS_TLSIO_30_001: [ The tlsio_openssl_compact shall implement and export all the Concrete functions in the VTable IO_INTERFACE_DESCRIPTION defined in the xio.h. ] */ 1598 | TEST_FUNCTION(tlsio_openssl_compact__tlsio_get_interface_description) 1599 | { 1600 | ///act 1601 | const IO_INTERFACE_DESCRIPTION* tlsio_id_ut = tlsio_pal_get_interface_description(); 1602 | 1603 | ///assert 1604 | // Later specific tests will verify the identity of each function 1605 | ASSERT_IS_NOT_NULL(tlsio_id_ut->concrete_io_close); 1606 | ASSERT_IS_NOT_NULL(tlsio_id_ut->concrete_io_create); 1607 | ASSERT_IS_NOT_NULL(tlsio_id_ut->concrete_io_destroy); 1608 | ASSERT_IS_NOT_NULL(tlsio_id_ut->concrete_io_dowork); 1609 | ASSERT_IS_NOT_NULL(tlsio_id_ut->concrete_io_open); 1610 | ASSERT_IS_NOT_NULL(tlsio_id_ut->concrete_io_retrieveoptions); 1611 | ASSERT_IS_NOT_NULL(tlsio_id_ut->concrete_io_send); 1612 | ASSERT_IS_NOT_NULL(tlsio_id_ut->concrete_io_setoption); 1613 | assert_gballoc_checks(); 1614 | } 1615 | 1616 | END_TEST_SUITE(tlsio_openssl_compact_unittests) 1617 | -------------------------------------------------------------------------------- /thirdpartynotice.txt: -------------------------------------------------------------------------------- 1 | Third Party Notices for Azure IoT SDKs project 2 | 3 | This project incorporates material from the project(s) listed below (collectively, "Third Party Code"). 4 | Microsoft Corporation is not the original author of the Third Party Code. 5 | The original copyright notice and license, under which Microsoft Corporation received such Third Party Code, 6 | are set out below. This Third Party Code is licensed to you under their original license terms set forth below. 7 | Microsoft Corporation reserves all other rights not expressly granted, whether by implication, estoppel or otherwise. 8 | 9 | 10 | 1. ESP32 sample main file, obtained from https://github.com/ustccw/AzureESP32 11 | 12 | Content from the sample main file at https://github.com/ustccw/AzureESP32/blob/master/main/azure_main.c 13 | is copied into https://github.com/Azure/azure-iot-pal-esp32/blob/master/sample/main/azure_main.c 14 | for use in ESP32 samples. 15 | 16 | /* 17 | Public Domain 18 | */ 19 | --------------------------------------------------------------------------------