Merge branch 'master' into dawalton/updatecertdoc

This commit is contained in:
Dane Walton 2020-11-06 15:57:12 -08:00 коммит произвёл GitHub
Родитель 88c502cfd4 0d5a921729
Коммит 539039b393
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
166 изменённых файлов: 5621 добавлений и 2083 удалений

5
.github/ISSUE_TEMPLATE/config.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Azure IoT support and help options
url: https://aka.ms/IoTHelp
about: The main landing page for all Azure IoT support options.

12
.github/ISSUE_TEMPLATE/technical-question.md поставляемый
Просмотреть файл

@ -9,12 +9,16 @@ assignees: ''
------------------------------- delete below -------------------------------
Thank you for asking a technical question! If your question is "why doesn't my code work?", please submit a Bug issue instead.
Thank you for asking a technical question! If your question is "why doesn't my code work?", please see [submit a bug report](https://github.com/Azure/azure-iot-sdk-c/issues/new?assignees=&labels=bug&template=bug-report.md&title=) instead.
We also encourage users to submit technical questions related to the SDK on Stack Overflow.
For quick and reliable answers on your technical product questions from Microsoft engineers, Azure Most Valuable Professionals (MVPs), or our expert community, engage with us on [Microsoft Q&A](https://aka.ms/azureqa), Azures preferred destination for community support. Please tag your question with "azure-iot-sdk".
For Stack Overflow, simply submit a question with the tag "azure-iot-hub".
For answers on your developer questions from the largest community developer ecosystem, ask your question on Stack Overflow. We actively monitor all questions tagged wtih "azure-iot-sdk".
If your technical question requires submitting service logs, you can submit an Azure Support Ticket: https://docs.microsoft.com/en-us/azure/azure-supportability/how-to-create-azure-support-request
Additionally, if your technical question requires submitting service logs, you can submit an [Azure Support Ticket](https://docs.microsoft.com/en-us/azure/azure-supportability/how-to-create-azure-support-request).
If you have a question specifically on a Microsoft page you've read, please open an issue on the document itself. This ensures you get the fastest targeted response, and you can do this by scrolling to the bottom of the page to the **Feedback** section.
For more information on the support options available to you, please see [Azure IoT support and help options](https://aka.ms/IoTHelp).
------------------------------- delete above -------------------------------

14
.github/workflows/issuelabeler.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,14 @@
name: "Set Issue Label"
on:
issues:
types: [opened]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: Naturalclar/issue-action@v1.0.0
with:
keywords: '[""]'
labels: '["IoTSDK"]'
github-token: "${{ secrets.GITHUB_TOKEN }}"

Просмотреть файл

@ -103,7 +103,7 @@ else()
endif()
option(use_mbedtls "set use_mbedtls to ON to use mbedtls." OFF)
option(use_bearssl "set use_bearssl to ON to use bearssl." OFF)
option(use_wolfssl "set use_bearssl to ON to use bearssl." OFF)
option(use_wolfssl "set use_wolfssl to ON to use wolfssl." OFF)
# openssl samples on Windows need to have a trusted cert set
if ((WIN32 AND ${use_openssl}) OR ${use_wolfssl} OR ${use_mbedtls} OR ${use_bearssl})
@ -137,6 +137,8 @@ endif()
# Set Provisioning Information. This will also setup appropriate HSM
if (${use_prov_client})
set(use_prov_client_core ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_PROV_MODULE_FULL")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_PROV_MODULE_FULL")
if ("${hsm_custom_lib}" STREQUAL "")
if ((NOT ${hsm_type_x509}) AND (NOT ${hsm_type_sastoken}) AND (NOT ${hsm_type_symm_key}))
# If the cmake option did not explicitly configure an hsm type, then enable them all.

Просмотреть файл

@ -38,8 +38,10 @@ jobs:
ls
cd $(Build.SourcesDirectory)/testtools/UART_interface/
echo -e "exit\r\n\r\n\r\n" | cat > input.txt
python3 serial_connect.py -i input.txt -o output.txt -b 115200 -p $(ESP8266_PORT) -d esp8266 -s
python3 serial_connect.py -i input.txt -o output.txt -b 115200 -p $(ESP8266_PORT) -d esp8266 -s -t 30
rm input.txt
code=$(<exitcode.txt)
exit $code
failOnStderr: true
displayName: 'run_test'
@ -94,8 +96,10 @@ jobs:
ls
cd $(Build.SourcesDirectory)/testtools/UART_interface/
echo -e "exit\r\n\r\n\r\n" | cat > input.txt
python3 serial_connect.py -i input.txt -o output.txt -b 1000000 -p $(ESP32_PORT) -d esp32 -s
python3 serial_connect.py -i input.txt -o output.txt -b 1000000 -p $(ESP32_PORT) -d esp32 -s -t 30
rm input.txt
code=$(<exitcode.txt)
exit $code
failOnStderr: true
displayName: 'run_test'

Просмотреть файл

@ -38,7 +38,7 @@ PROJECT_NAME = "Microsoft Azure IoT Device SDK for C"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 1.3.8
PROJECT_NUMBER = 1.3.9
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a

@ -1 +1 @@
Subproject commit 1b5ccc54f700ece6316a738815f811fe884a4147
Subproject commit 91a3bb1bc48ebf92ed0023608b500f653194edee

2
deps/uhttp поставляемый

@ -1 +1 @@
Subproject commit 9e58167a7e1d2f0041b354d7f23723d113aac489
Subproject commit dd1a6bb6a4c68a495b9a6bd59060e4342c8b2842

Просмотреть файл

@ -1,119 +1,179 @@
# IoTHub C SDK Options
# IoT Hub C SDK Options
This document describes how to set the options available in the c sdk.
This document describes how you can set options for the Azure IoT Hub and Device Provisioning Service (DPS) client connections.
- [Setting an Options](#set_option)
- [IoThub Client Options](#IotHub_option)
- [Transport Options](#transport_option)
- [Example Code for Setting an Option](#set_option)
- [Common Transport Options](#general_options)
- [IoT Hub Device and Module Client Options](#IotHub_options)
- [MQTT, AMQP, and HTTP Specific Protocol Options](#protocol_specific_options)
- [Device Provisioning Service (DPS) Client Options](#provisioning_option)
- [File Upload Options](#upload-options)
<a name="set_option"></a>
## Setting an Option
## Example Code for Setting an Option
You will use a different API to set options, depending on whether you are using a device or module identity and whether you are using the convenience or lower layer APIs. The pattern is generally the same.
Setting an option in the c-sdk is dependant on which api set you are using:
```c
// Convience Layer
IOTHUB_CLIENT_RESULT IoTHubClient_SetOption(IOTHUB_CLIENT_HANDLE iotHubClientHandle, const char* optionName, const void* value)
// Convenience layer for device client
IOTHUB_CLIENT_RESULT IoTHubDeviceClient_SetOption(IOTHUB_DEVICE_CLIENT_HANDLE iotHubClientHandle, const char* optionName, const void* value);
// Single Thread API
IOTHUB_CLIENT_RESULT IoTHubClient_LL_SetOption(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, const char* optionName, const void* value)
// Lower layer for device client
IOTHUB_CLIENT_RESULT IoTHubDeviceClient_LL_SetOption(IOTHUB_DEVICE_CLIENT_LL_HANDLE iotHubClientHandle, const char* optionName, const void* value);
// Convenience layer for module client
IOTHUB_CLIENT_RESULT IoTHubModuleClient_SetOption(IOTHUB_MODULE_CLIENT_HANDLE iotHubModuleClientHandle, const char* optionName, const void* value);
// Lower layer for module client
IOTHUB_CLIENT_RESULT IoTHubModuleClient_LL_SetOption(IOTHUB_MODULE_CLIENT_LL_HANDLE iotHubModuleClientHandle, const char* optionName, const void* value);
```
An example of using a set option:
An example of setting an option:
```c
// IoT Hub Device Client
bool trace_on = true;
IoTHubClient_SetOption(sdk_handle, OPTION_LOG_TRACE, &trace_on);
IoTHubDeviceClient_SetOption(sdk_handle, OPTION_LOG_TRACE, &trace_on);
// Device Provisioning Service (DPS) Client
HTTP_PROXY_OPTIONS http_proxy;
memset(&http_proxy, 0, sizeof(HTTP_PROXY_OPTIONS));
http_proxy.host_address = PROXY_ADDRESS;
http_proxy.port = PROXY_PORT;
DPS_LL_SetOption(handle, OPTION_HTTP_PROXY, &http_proxy);
Prov_Device_LL_SetOption(handle, OPTION_HTTP_PROXY, &http_proxy);
```
## Available Options
<a name="general_options"></a>
<a name="IotHub_option"></a>
## Common Transport Options
You can use the options below for the IoT Hub Device Client, the IoT Hub Module Client, and for the Device Provisioning Client. These options are declared in [shared_util_options.h][shared-util-options-h].
### IoThub_Client
**NOTE: Uploading files to Azure (e.g. IoTHubDeviceClient_UploadToBlobAsync) does not support this complete set of options. See [here](#upload-options) for more.**
| Option Name | Option Define | Value Type | Description
|-----------------------------------|---------------------------------|--------------------|-------------------------------
| `"messageTimeout"` | OPTION_MESSAGE_TIMEOUT | tickcounter_ms_t* | (DEPRECATED) Timeout used for message on the message queue
| `"blob_upload_timeout_secs"` | OPTION_BLOB_UPLOAD_TIMEOUT_SECS | size_t* | Timeout in seconds of blob uploads
| `"product_info"` | OPTION_PRODUCT_INFO | const char* | User defined Product identifier sent to the IoThub service
| `"TrustedCerts"` | OPTION_TRUSTED_CERT | const char* | Azure Server certificate used to validate TLS connection to iothub
| `"retry_interval_sec"` | OPTION_RETRY_INTERVAL_SEC | int* | Amount of seconds between retries when using the interval retry policy
| `"TrustedCerts"` | OPTION_TRUSTED_CERT | const char* | Azure Server certificate used to validate TLS connection to IoT Hub. This is usually not required on operating systems that have built in certificates to trust, such as Windows and some Linux distributions. A typical use case is on an embedded system which does not trust any certificates or when connecting to a gateway whose certificates that are not otherwise trusted. See [here][gateway-sample] for a gateway sample.
| `"x509certificate"` | SU_OPTION_X509_CERT | const char* | Sets an RSA x509 certificate used for connection authentication. (Also available from [iothub_client_options.h][iothub-client-options-h] as `OPTION_X509_CERT`.)
| `"x509privatekey"` | SU_OPTION_X509_PRIVATE_KEY | const char* | Sets the private key for the RSA x509 certificate. (Also available from [iothub_client_options.h][iothub-client-options-h] as `OPTION_X509_PRIVATE_KEY`.)
| `"x509EccCertificate"` | OPTION_X509_ECC_CERT | const char* | Sets the ECC x509 certificate used for connection authentication
| `"x509EccAliasKey"` | OPTION_X509_ECC_KEY | const char* | Sets the private key for the ECC x509 certificate
| `"proxy_data"` | OPTION_HTTP_PROXY | [HTTP_PROXY_OPTIONS*][shared-util-options-h]| Http proxy data object used for proxy connection to IoT Hub
| `"tls_version"` | OPTION_TLS_VERSION | int* | TLS version to use for openssl, 10 for version 1.0, 11 for version 1.1, 12 for version 1.2. (**DEPRECATED**: TLS 1.0 and 1.1 are not secure and should not be used. This option is included only for backward compatibility.)
<a name="transport_option"></a>
### Standard Transport
<a name="IotHub_options"></a>
| Option Name | Option Define | Value Type | Description
|------------------------|---------------------------|--------------------|-------------------------------
| `"logtrace"` | OPTION_LOG_TRACE | bool* value | Turn on and off log tracing for the transport
| `"sas_token_lifetime"` | OPTION_SAS_TOKEN_LIFETIME | size_t* value | Length of time in seconds used for lifetime of sas token.
| `"x509certificate"` | OPTION_X509_CERT | const char* | Sets an RSA x509 certificate used for connection authentication
| `"x509privatekey"` | OPTION_X509_PRIVATE_KEY | const char* | Sets the private key for the RSA x509 certificate
| `"x509EccCertificate"` | OPTION_X509_ECC_CERT | const char* | Sets the ECC x509 certificate used for connection authentication
| `"x509EccAliasKey"` | OPTION_X509_ECC_KEY | const char* | Sets the private key for the ECC x509 certificate
| `"proxy_data"` | OPTION_HTTP_PROXY | [HTTP_PROXY_OPTIONS*][http-proxy-object]| Http proxy data object used for proxy connection to IoTHub
| `"tls_version"` | OPTION_TLS_VERSION | int* | TLS version to use for openssl, 10 for version 1.0, 11 for version 1.1, 12 for version 1.2
## IoT Hub Device and Module Client Options
You can use the options below for IoT Hub connections. These options are declared in [iothub_client_options.h][iothub-client-options-h].
### MQTT Transport
You may also use [common transport options](#general_options) options.
**NOTE: Uploading files to Azure (e.g. IoTHubDeviceClient_UploadToBlobAsync) does not support this complete set of options. See [here](#upload-options) for more.**
| Option Name | Option Define | Value Type | Description
|-----------------------------------|---------------------------------|--------------------|-------------------------------
| `"logtrace"` | OPTION_LOG_TRACE | bool* | Turn on and off log tracing for the transport
| `"messageTimeout"` | OPTION_MESSAGE_TIMEOUT | tickcounter_ms_t* | (DEPRECATED) Timeout used for message on the message queue
| `"product_info"` | OPTION_PRODUCT_INFO | const char* | User defined Product identifier sent to the IoT Hub service
| `"retry_interval_sec"` | OPTION_RETRY_INTERVAL_SEC | unsigned int* | Number of seconds between retries when using the interval retry policy. (Not supported for HTTP transport.)
| `"retry_max_delay_secs"` | OPTION_RETRY_MAX_DELAY_SECS | unsigned int* | Maximum number of seconds a retry delay when using linear backoff, exponential backoff, or exponential backoff with jitter policy. (Not supported for HTTP transport.)
| `"sas_token_lifetime"` | OPTION_SAS_TOKEN_LIFETIME | size_t* | Length of time in seconds used for lifetime of SAS token.
| `"do_work_freq_ms"` | OPTION_DO_WORK_FREQUENCY_IN_MS | [tickcounter_ms_t *][tick-counter-header] | Specifies how frequently the worker thread spun by the convenience layer will wake up, in milliseconds. The default is 1 millisecond. The maximum allowable value is 100. (Convenience layer APIs only)
<a name="protocol_specific_options"></a>
## MQTT, AMQP, and HTTP Specific Protocol Options
Some options are only supported by a given protocol (e.g. MQTT, AMQP, HTTP). These are declared in [iothub_client_options.h][iothub-client-options-h].
### MQTT Specific Options
| Option Name | Option Define | Value Type | Description
|---------------------------|-------------------------------|--------------------|-------------------------------
| `"auto_url_encode_decode"`| OPTION_AUTO_URL_ENCODE_DECODE | bool* | Turn on and off automatic URL Encoding and Decoding. **You are strongly encouraged to set this to true.** If you do not do so and send a property with a character that needs URL encoding to the server, it will result in hard to diagnose problems. The SDK cannot auto-enable this feature because it needs to maintain backwards compatibility with applications already doing their own URL encoding.
| `"keepalive"` | OPTION_KEEP_ALIVE | int* | Length of time to send `Keep Alives` to service for D2C Messages
| `"auto_url_encode_decode"`| OPTION_AUTO_URL_ENCODE_DECODE | bool* | Turn on and off automatic URL Encoding and Decoding.
| `"model_id"` | OPTION_MODEL_ID | const char* | [IoT Plug and Play][iot-pnp] model ID the device or module implements
### AMQP Transport
### AMQP Specific Options
| Option Name | Option Define | Value Type | Description
|------------------------------|---------------------------------|-------------------|-------------------------------
| `"cbs_request_timeout"` | OPTION_CBS_REQUEST_TIMEOUT | `size_t`* value | Amount of seconds to wait for a cbs request to complete
| `"sas_token_refresh_time"` | OPTION_SAS_TOKEN_REFRESH_TIME | `size_t`* value | Frequency in seconds that the SAS token is refreshed
| `"event_send_timeout_secs"` | OPTION_EVENT_SEND_TIMEOUT_SECS | `size_t`* value | Amount of seconds to wait for telemetry message to complete
| `"c2d_keep_alive_freq_secs"` | OPTION_C2D_KEEP_ALIVE_FREQ_SECS | `size_t`* value | Informs service of maximum period the client waits for keep-alive message
| `"cbs_request_timeout"` | OPTION_CBS_REQUEST_TIMEOUT | size_t* | Number of seconds to wait for a CBS request to complete
| `"sas_token_refresh_time"` | OPTION_SAS_TOKEN_REFRESH_TIME | size_t* | Frequency in seconds that the SAS token is refreshed
| `"event_send_timeout_secs"` | OPTION_EVENT_SEND_TIMEOUT_SECS | size_t* | Number of seconds to wait for telemetry message to complete
| `"c2d_keep_alive_freq_secs"` | OPTION_C2D_KEEP_ALIVE_FREQ_SECS | size_t* | Informs service of maximum period the client waits for keep-alive message
### HTTP Tansport
### HTTP Specific Options
| Option Name | Option Define | Value Type | Description
|------------------------------|---------------------------------|-------------------|-------------------------------
| `"Batching"` | OPTION_BATCHING | `bool`* value | Turn on and off message batching
| `"MinimumPollingTime"` | OPTION_MIN_POLLING_TIME | `unsigned int`* value | Minimum time in seconds allowed between 2 consecutive GET issues to the service
| `"timeout"` | OPTION_HTTP_TIMEOUT | `long`* value | When using curl the amount of time before the request times out, defaults to 242 seconds.
| `"Batching"` | OPTION_BATCHING | bool* | Turn on and off message batching
| `"MinimumPollingTime"` | OPTION_MIN_POLLING_TIME | unsigned int* | Minimum time in seconds allowed between 2 consecutive GET issues to the service
| `"timeout"` | OPTION_HTTP_TIMEOUT | long* | When using curl the amount of time before the request times out, defaults to 242 seconds.
### Advanced Compilation Options
<a name="provisioning_option"></a>
We recommend leaving the following settings at their defaults. Tuning them may allow optimizations for specific devices or scenarios but could also negatively impact RAM or EEPROM usage.
The options are presented only as compilation flags and must be appended to the CMake `compileOption_C` setting:
## Device Provisioning Service (DPS) Client Options
| Option Name | Option Define | Description
|------------------------------|---------------------------------------------------------|-------------------------------------------------------------
| `"XIO Receive Buffer"` | `-DcompileOption_C="-DXIO_RECEIVE_BUFFER_SIZE=<value>"` | Configure the internal XIO receive buffer.
You can use the options below to configure the DPS client. These are defined in [prov_device_ll_client.h][provisioning-device-ll-client-options-h] except for `PROV_OPTION_DO_WORK_FREQUENCY_IN_MS` which is defined in [prov_device_client.h][provisioning-device-client-options-h].
## Additional notes
You may also use [common transport options](#general_options).
### Batching and IoTHub Client SDK
| Option Name | Option Define | Value Type | Description
|------------------------------|---------------------------------|-------------------|-------------------------------
| `"logtrace"` | PROV_OPTION_LOG_TRACE | bool* | Turn on and off log tracing for the transport
| `"registration_id"` | PROV_REGISTRATION_ID | const char* | The registration ID of the device.
| `"provisioning_timeout"` | PROV_OPTION_TIMEOUT | long* | Maximum time to allow DPS to complete, in seconds.
| `"do_work_freq_ms"` | PROV_OPTION_DO_WORK_FREQUENCY_IN_MS | uint16_t * | Specifies how frequently the worker thread spun by the convenience layer will wake up, in milliseconds. The default is 1 millisecond. (Convenience layer APIs only)
Batching is the ability of a protocol to send multiple messages in one payload, rather than one at a time. This can result in less overhead, especially when sending multiple, small messages. This SDK supports various levels of batching when using IoTHubClient_SendEventAsync / IoTHubClient_LL_SendEventAsync.
<a name="upload-options"></a>
## File Upload Options
When you upload files to Azure with APIs like `IoTHubDeviceClient_LL_UploadToBlob`, most of the options described above are silently ignored. This is even though these APIs use the same IoT Hub handle as used for telemetry, device methods, and device twin. The reason the options are different is because the underlying transport is implemented differently for uploads.
The following options are supported when performing file uploads. They are declared in [iothub_client_options.h][iothub-client-options-h] and in [shared_util_options.h][shared-util-options-h].
| Option Name | Option Define | Value Type | Description
|------------------------------|---------------------------------|-------------------|-------------------------------
| `"blob_upload_timeout_secs"` | OPTION_BLOB_UPLOAD_TIMEOUT_SECS | size_t* | Timeout in seconds of initial connection establishment to IoT Hub. NOTE: This does not specify the end-to-end time of the upload, which is currently not configurable.
| `"CURLOPT_VERBOSE"` | OPTION_CURL_VERBOSE | bool* | Turn on and off verbosity at curl level. (Only available when using curl as underlying HTTP client.)
| `"x509certificate"` | OPTION_X509_CERT | const char* | Sets an RSA x509 certificate used for connection authentication
| `"x509privatekey"` | OPTION_X509_PRIVATE_KEY | const char* | Sets the private key for the RSA x509 certificate
| `"TrustedCerts"` | OPTION_TRUSTED_CERT | const char* | Azure Server certificate used to validate TLS connection to IoT Hub and Azure Storage
| `"proxy_data"` | OPTION_HTTP_PROXY | [HTTP_PROXY_OPTIONS*][shared-util-options-h] | Http proxy data object used for proxy connection to IoT Hub and Azure Storage
## Batching and IoT Hub Client SDK
Batching is the ability of a protocol to send multiple messages in one payload, rather than one at a time. This can result in less overhead, especially when sending multiple, small messages. This SDK supports various levels of batching when using IoTHubClient_LL_SendEventAsync.
- AMQP uses batching always.
- HTTP can optionally enable batching, using the "Batching" option referenced above.
- HTTP can optionally enable batching, using the "Batching" option.
- MQTT does not have a batching option.
None of the protocols has a windowing or Nagling concept; e.g. they do NOT wait a certain amount of time to attempt to queue up multiple messages to put into a single batch. Instead they just batch whatever is on the to-send queue. For customers using the lower-layer protocols (LL), they can force batching via
IoTHubClient_LL_SendEventAsync(msg1)
IoTHubClient_LL_SendEventAsync(msg2)
IoTHubClient_LL_DoWork()
[http-proxy-object]: https://github.com/Azure/azure-c-shared-utility/blob/506288cecb9ee4a205fa221dc4fd2e69a7ddaa7e/inc/azure_c_shared_utility/shared_util_options.h
None of the protocols has a windowing or Nagling concept. They do NOT wait a certain amount of time to attempt to queue up multiple messages to put into a single batch. Instead, they just batch whatever is on the to-send queue. For customers using the lower-layer protocols (LL), they can force batching by performing multiple `IoTHubDeviceClient_LL_SendEventAsync` calls before `IoTHubDeviceClient_LL_DoWork`.
```c
IOTHUB_DEVICE_CLIENT_LL_HANDLE iotHubClientHandle;
// Queues msg1 to be sent but does not perform any network I/O
IoTHubDeviceClient_LL_SendEventAsync(iotHubClientHandle, msg1, ...);
// Queues msg2 to be sent but does not perform any network I/O
IoTHubDeviceClient_LL_SendEventAsync(iotHubClientHandle, msg2, ...);
// Performs network I/O. If batching is enabled, the SDK will batch msg1 and msg2
IoTHubDeviceClient_LL_DoWork(iotHubClientHandle);
```
[iothub-client-options-h]: https://github.com/Azure/azure-iot-sdk-c/blob/master/iothub_client/inc/iothub_client_options.h
[shared-util-options-h]: https://github.com/Azure/azure-c-shared-utility/blob/master/inc/azure_c_shared_utility/shared_util_options.h
[provisioning-device-ll-client-options-h]: https://github.com/Azure/azure-iot-sdk-c/blob/master/provisioning_client/inc/azure_prov_client/prov_device_ll_client.h
[provisioning-device-client-options-h]: https://github.com/Azure/azure-iot-sdk-c/blob/master/provisioning_client/inc/azure_prov_client/prov_device_client.h
[iot-pnp]: https://aka.ms/iotpnp
[gateway-sample]: https://github.com/Azure/azure-iot-sdk-c/tree/master/iothub_client/samples/iotedge_downstream_device_sample
[tick-counter-header]: https://github.com/Azure/azure-c-shared-utility/blob/master/inc/azure_c_shared_utility/tickcounter.h

Просмотреть файл

@ -325,7 +325,7 @@ Here is a list of the specific options that apply to connection and messaging re
|Option|Value Type|Applicable To|Description|
|-|-|-|-|
|OPTION_MESSAGE_TIMEOUT|const tickcounter_ms_t*|Timeout for iothub client messages waiting to be sent to the IoTHub|See [description above](#Known-Issue:-Duplicated-Timeout-Control-for-Sending-Telemetry-Messages) for details.</br></br>The default value is zero (disabled).|
|"event_send_timeout_secs"|size_t*|AMQP and AMQP over WebSockets transports|Maximum ammount of time, in seconds, the AMQP protocol transport will wait for a Telemetry message to complete sending.</br></br>If reached, the callback function passed to IoTHubClient_LL_SendEventAsync or IoTHubClient_SendEventAsync is invoked with result IOTHUB_CLIENT_CONFIRMATION_MESSAGE_TIMEOUT.</br></br>The default value 5 minutes.|
|"event_send_timeout_secs"|size_t*|AMQP and AMQP over WebSockets transports|Maximum ammount of time, in seconds, the AMQP protocol transport will wait for a Telemetry message to complete sending.</br></br>If reached, the callback function passed to IoTHubDeviceClient_LL_SendEventAsync or IoTHubDeviceClient_SendEventAsync is invoked with result IOTHUB_CLIENT_CONFIRMATION_MESSAGE_TIMEOUT.</br></br>The default value 5 minutes.|
|OPTION_SERVICE_SIDE_KEEP_ALIVE_FREQ_SECS|size_t*|AMQP and AMQP over WebSockets transports|[See code comments](https://github.com/Azure/azure-iot-sdk-c/blob/2018-05-04/iothub_client/inc/iothub_client_options.h#L47).|
|OPTION_REMOTE_IDLE_TIMEOUT_RATIO|double*|AMQP and AMQP over WebSockets transports|[See code comments](https://github.com/Azure/azure-iot-sdk-c/blob/2018-05-04/iothub_client/inc/iothub_client_options.h#L59).|
|OPTION_KEEP_ALIVE|int*|MQTT and MQTT over WebSockets protocol transports|Frequency in seconds that the transport protocol will be sending MQTT pings to the Azure IoT Hub.</br></br>The lower this number, more responsive the device client (when using MQTT) will be to connection issues. However, slightly more data traffic it will generate.</br></br>The default value is 4 minutes.|

Просмотреть файл

@ -175,12 +175,12 @@ This section describes how to set up a development environment for the C SDK on
> To upgrade see "Upgrade CURL on Mac OS" steps below.
- Locate the tag name for the [latest release][latest-release] of the SDK.
> Our release tag names are date values in `yyyy-mm-dd` format.
> Our release tag names are date values in `lts_mm_yyyy` format.
- Clone the latest release of SDK to your local machine using the tag name you found:
```Shell
git clone -b <yyyy-mm-dd> https://github.com/Azure/azure-iot-sdk-c.git
git clone -b <lts_mm_yyyy> https://github.com/Azure/azure-iot-sdk-c.git
cd azure-iot-sdk-c
git submodule update --init
```
@ -248,12 +248,12 @@ We've tested the device SDK for C on macOS High Sierra, with XCode version 9.2.
> To upgrade see "Upgrade CURL on Mac OS" steps below.
- Locate the tag name for the [latest release][latest-release] of the SDK.
> Our release tag names are date values in `yyyy-mm-dd` format.
> Our release tag names are date values in `lts_mm_yyyy` format.
- Clone the latest release of SDK to your local machine using the tag name you found:
```Shell
git clone -b <yyyy-mm-dd> https://github.com/Azure/azure-iot-sdk-c.git
git clone -b <lts_mm_yyyy> https://github.com/Azure/azure-iot-sdk-c.git
cd azure-iot-sdk-c
git submodule update --init
```

Просмотреть файл

@ -24,6 +24,7 @@ vcpkg install azure-iot-sdk-c
vcpkg export azure-iot-sdk-c --nuget
# Open a C SDK sample (assuming repo was cloned as follows: git clone https://github.com/Azure/azure-iot-sdk-c.git azureiotsdk_sample)
# (Building the SDK and samples can be found here https://github.com/Azure/azure-iot-sdk-c/blob/master/doc/devbox_setup.md)
pushd azureiotsdk_sample\iothub_client\samples\iothub_ll_c2d_sample\windows
start iothub_ll_c2d_sample.sln
<hit F5 to build and run>

Просмотреть файл

@ -110,7 +110,7 @@ azure_uamqp_c
**SRS_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_015: [**`amqp_msgr_config` shall have "twin/" as send link target suffix and receive link source suffix**]**
**SRS_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_016: [**`amqp_msgr_config` shall have send and receive link attach properties set as "com.microsoft:client-version" = `twin_msgr->client_version`, "com.microsoft:channel-correlation-id" = `twin:<UUID>`, "com.microsoft:api-version" = "2016-11-14"**]**
**SRS_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_016: [**`amqp_msgr_config` shall have send and receive link attach properties set as "com.microsoft:client-version" = `twin_msgr->client_version`, "com.microsoft:channel-correlation-id" = `twin:<UUID>`, "com.microsoft:api-version" = "Current API version"**]**
**SRS_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_017: [**`amqp_msgr_config` shall be set with `on_amqp_messenger_state_changed_callback` and `on_amqp_messenger_subscription_changed_callback` callbacks**]**

Просмотреть файл

@ -126,7 +126,7 @@ int iothubtransportamqp_methods_subscribe(IOTHUBTRANSPORT_AMQP_METHODS_HANDLE io
**SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_150: [** A property key which shall be a symbol named `com.microsoft:api-version` shall be created by calling `amqp_create_symbol`. **]**
**SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_151: [** A property value of type string that shall contain the `2016-11-14` shall be created by calling `amqpvalue_create_string`. **]**
**SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_151: [** A property value of type string that shall contain the `Current API version` shall be created by calling `amqpvalue_create_string`. **]**
**SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_152: [** The `com.microsoft:api-version` shall be added to the link attach properties by calling `amqpvalue_set_map_value`. **]**

Просмотреть файл

@ -9,8 +9,7 @@ extern "C"
{
#endif
static const char* IOTHUB_API_VERSION = "2017-11-08-preview";
static const char* IOTHUB_API_VERSION = "2020-09-30";
static const char* SECURITY_INTERFACE_INTERNAL_ID = "iothub-interface-internal-id";
static const char* SECURITY_INTERFACE_INTERNAL_ID_VALUE = "security*azureiot*com^SecurityAgent^1*0*0";
static const char* SECURITY_INTERFACE_ID = "iothub-interface-id";

Просмотреть файл

@ -38,6 +38,7 @@ extern "C"
typedef void (*pfTransport_Twin_ReportedStateComplete_Callback)(uint32_t item_id, int status_code, void* ctx);
typedef void (*pfTransport_Twin_RetrievePropertyComplete_Callback)(DEVICE_TWIN_UPDATE_STATE update_state, const unsigned char* payLoad, size_t size, void* ctx);
typedef int (*pfTransport_DeviceMethod_Complete_Callback)(const char* method_name, const unsigned char* payLoad, size_t size, METHOD_HANDLE response_id, void* ctx);
typedef const char* (*pfTransport_GetOption_Model_Id_Callback)(void* ctx);
/** @brief This struct captures device configuration. */
typedef struct IOTHUB_DEVICE_CONFIG_TAG
@ -67,6 +68,7 @@ extern "C"
pfTransport_Twin_ReportedStateComplete_Callback twin_rpt_state_complete_cb;
pfTransport_Twin_RetrievePropertyComplete_Callback twin_retrieve_prop_complete_cb;
pfTransport_DeviceMethod_Complete_Callback method_complete_cb;
pfTransport_GetOption_Model_Id_Callback get_model_id_cb;
} TRANSPORT_CALLBACKS_INFO;
typedef STRING_HANDLE (*pfIoTHubTransport_GetHostname)(TRANSPORT_LL_HANDLE handle);

Просмотреть файл

@ -1,8 +1,16 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//**********************************************************************
// NOTE: THIS HEADER IS DEPRECATED
//
// Functions in this header will be maintained for backward compatability.
// New applications should use iothub_device_client.h.
//
//**********************************************************************
/** @file iothub_client.h
* @brief Extends the IoTHubCLient_LL module with additional features.
* @brief Extends the IoTHubClient_LL with additional features.
*
* @note DEPRECATED. New users use iothub_device_client.h for IoTHubClient APIs.
* @details IoTHubClient is a module that extends the IoTHubCLient_LL
@ -37,354 +45,109 @@ extern "C"
#endif
/**
* @brief Creates a IoT Hub client for communication with an existing
* IoT Hub using the specified connection string parameter.
*
* @param connectionString Pointer to a character string
* @param protocol Function pointer for protocol implementation
*
* Sample connection string:
* <blockquote>
* <pre>HostName=[IoT Hub name goes here].[IoT Hub suffix goes here, e.g., private.azure-devices-int.net];DeviceId=[Device ID goes here];SharedAccessKey=[Device key goes here];</pre>
* <pre>HostName=[IoT Hub name goes here].[IoT Hub suffix goes here, e.g., private.azure-devices-int.net];DeviceId=[Device ID goes here];SharedAccessSignature=SharedAccessSignature sr=[IoT Hub name goes here].[IoT Hub suffix goes here, e.g., private.azure-devices-int.net]/devices/[Device ID goes here]&sig=[SAS Token goes here]&se=[Expiry Time goes here];</pre>
* </blockquote>
*
* @return A non-NULL @c IOTHUB_CLIENT_HANDLE value that is used when
* invoking other functions for IoT Hub client and @c NULL on failure.
* @deprecated IoTHubClient_CreateFromConnectionString is deprecated. Use IoTHubDeviceClient_CreateFromConnectionString instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_HANDLE, IoTHubClient_CreateFromConnectionString, const char*, connectionString, IOTHUB_CLIENT_TRANSPORT_PROVIDER, protocol);
/**
* @brief Creates a IoT Hub client for communication with an existing IoT
* Hub using the specified parameters.
*
* @param config Pointer to an @c IOTHUB_CLIENT_CONFIG structure
*
* The API does not allow sharing of a connection across multiple
* devices. This is a blocking call.
*
* @return A non-NULL @c IOTHUB_CLIENT_HANDLE value that is used when
* invoking other functions for IoT Hub client and @c NULL on failure.
* @deprecated IoTHubClient_Create is deprecated. Use IoTHubDeviceClient_Create instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_HANDLE, IoTHubClient_Create, const IOTHUB_CLIENT_CONFIG*, config);
/**
* @brief Creates a IoT Hub client for communication with an existing IoT
* Hub using the specified parameters.
*
* @param transportHandle TRANSPORT_HANDLE which represents a connection.
* @param config Pointer to an @c IOTHUB_CLIENT_CONFIG structure
*
* The API allows sharing of a connection across multiple
* devices. This is a blocking call.
*
* @return A non-NULL @c IOTHUB_CLIENT_HANDLE value that is used when
* invoking other functions for IoT Hub client and @c NULL on failure.
* @deprecated IoTHubClient_CreateWithTransport is deprecated. Use IoTHubDeviceClient_CreateWithTransport instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_HANDLE, IoTHubClient_CreateWithTransport, TRANSPORT_HANDLE, transportHandle, const IOTHUB_CLIENT_CONFIG*, config);
/**
* @brief Creates a IoT Hub client for communication with an existing IoT
* Hub using the device auth module.
*
* @param iothub_uri Pointer to an ioThub hostname received in the registration process
* @param device_id Pointer to the device Id of the device
* @param protocol Function pointer for protocol implementation
*
* @return A non-NULL @c IOTHUB_CLIENT_LL_HANDLE value that is used when
* invoking other functions for IoT Hub client and @c NULL on failure.
* @deprecated IoTHubClient_CreateFromDeviceAuth is deprecated. Use IoTHubDeviceClient_CreateFromDeviceAuth instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_HANDLE, IoTHubClient_CreateFromDeviceAuth, const char*, iothub_uri, const char*, device_id, IOTHUB_CLIENT_TRANSPORT_PROVIDER, protocol);
/**
* @brief Disposes of resources allocated by the IoT Hub client. This is a
* blocking call.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @deprecated IoTHubClient_Destroy is deprecated. Use IoTHubDeviceClient_Destroy instead.
*/
MOCKABLE_FUNCTION(, void, IoTHubClient_Destroy, IOTHUB_CLIENT_HANDLE, iotHubClientHandle);
/**
* @brief Asynchronous call to send the message specified by @p eventMessageHandle.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param eventMessageHandle The handle to an IoT Hub message.
* @param eventConfirmationCallback The callback specified by the device for receiving
* confirmation of the delivery of the IoT Hub message.
* This callback can be expected to invoke the
* ::IoTHubClient_SendEventAsync function for the
* same message in an attempt to retry sending a failing
* message. The user can specify a @c NULL value here to
* indicate that no callback is required.
* @param userContextCallback User specified context that will be provided to the
* callback. This can be @c NULL.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubClient_Destroy function from within any callback.
* @remarks
* The IOTHUB_MESSAGE_HANDLE instance provided as argument is copied by the function,
* so this argument can be destroyed by the calling application right after IoTHubClient_SendEventAsync returns.
* The copy of @c eventMessageHandle is later destroyed by the iothub client when the message is effectively sent, if a failure sending it occurs, or if the client is destroyed.
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_SendEventAsync is deprecated. Use IoTHubDeviceClient_SendEventAsync instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_SendEventAsync, IOTHUB_CLIENT_HANDLE, iotHubClientHandle, IOTHUB_MESSAGE_HANDLE, eventMessageHandle, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK, eventConfirmationCallback, void*, userContextCallback);
/**
* @brief This function returns the current sending status for IoTHubClient.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param iotHubClientStatus The sending state is populated at the address pointed
* at by this parameter. The value will be set to
* @c IOTHUBCLIENT_SENDSTATUS_IDLE if there is currently
* no item to be sent and @c IOTHUBCLIENT_SENDSTATUS_BUSY
* if there are.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_GetSendStatus is deprecated. Use IoTHubDeviceClient_GetSendStatus instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_GetSendStatus, IOTHUB_CLIENT_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_STATUS*, iotHubClientStatus);
/**
* @brief Sets up the message callback to be invoked when IoT Hub issues a
* message to the device. This is a blocking call.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param messageCallback The callback specified by the device for receiving
* messages from IoT Hub.
* @param userContextCallback User specified context that will be provided to the
* callback. This can be @c NULL.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubClient_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_SetMessageCallback is deprecated. Use IoTHubDeviceClient_SetMessageCallback instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_SetMessageCallback, IOTHUB_CLIENT_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC, messageCallback, void*, userContextCallback);
/**
* @brief Sets up the connection status callback to be invoked representing the status of
* the connection to IOT Hub. This is a blocking call.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param connectionStatusCallback The callback specified by the device for receiving
* updates about the status of the connection to IoT Hub.
* @param userContextCallback User specified context that will be provided to the
* callback. This can be @c NULL.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubClient_LL_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_SetConnectionStatusCallback is deprecated. Use IoTHubDeviceClient_SetConnectionStatusCallback instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_SetConnectionStatusCallback, IOTHUB_CLIENT_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_CONNECTION_STATUS_CALLBACK, connectionStatusCallback, void*, userContextCallback);
/**
* @brief Sets up the connection status callback to be invoked representing the status of
* the connection to IOT Hub. This is a blocking call.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param retryPolicy The policy to use to reconnect to IoT Hub when a
* connection drops.
* @param retryTimeoutLimitInSeconds Maximum amount of time(seconds) to attempt reconnection when a
* connection drops to IOT Hub.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubClient_LL_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_SetRetryPolicy is deprecated. Use IoTHubDeviceClient_SetRetryPolicy instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_SetRetryPolicy, IOTHUB_CLIENT_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_RETRY_POLICY, retryPolicy, size_t, retryTimeoutLimitInSeconds);
/**
* @brief Sets up the connection status callback to be invoked representing the status of
* the connection to IOT Hub. This is a blocking call.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param retryPolicy Out parameter containing the policy to use to reconnect to IoT Hub.
* @param retryTimeoutLimitInSeconds Out parameter containing maximum amount of time in seconds to attempt reconnection
to IOT Hub.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubClient_LL_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_GetRetryPolicy is deprecated. Use IoTHubDeviceClient_GetRetryPolicy instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_GetRetryPolicy, IOTHUB_CLIENT_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_RETRY_POLICY*, retryPolicy, size_t*, retryTimeoutLimitInSeconds);
/**
* @brief This function returns in the out parameter @p lastMessageReceiveTime
* what was the value of the @c time function when the last message was
* received at the client.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param lastMessageReceiveTime Out parameter containing the value of @c time function
* when the last message was received.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_GetLastMessageReceiveTime is deprecated. Use IoTHubDeviceClient_GetLastMessageReceiveTime instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_GetLastMessageReceiveTime, IOTHUB_CLIENT_HANDLE, iotHubClientHandle, time_t*, lastMessageReceiveTime);
/**
* @brief This API sets a runtime option identified by parameter @p optionName
* to a value pointed to by @p value. @p optionName and the data type
* @p value is pointing to are specific for every option.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param optionName Name of the option.
* @param value The value.
*
* The options that can be set via this API are:
* - @b timeout - the maximum time in milliseconds a communication is
* allowed to use. @p value is a pointer to an @c unsigned @c int with
* the timeout value in milliseconds. This is only supported for the HTTP
* protocol as of now. When the HTTP protocol uses CURL, the meaning of
* the parameter is <em>total request time</em>. When the HTTP protocol uses
* winhttp, the meaning is the same as the @c dwSendTimeout and
* @c dwReceiveTimeout parameters of the
* <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384116(v=vs.85).aspx">
* WinHttpSetTimeouts</a> API.
* - @b CURLOPT_LOW_SPEED_LIMIT - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_LOW_SPEED_TIME - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_FORBID_REUSE - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_FRESH_CONNECT - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_VERBOSE - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b messageTimeout - the maximum time in milliseconds until a message
* is timeouted. The time starts at IoTHubClient_SendEventAsync. By default,
* messages do not expire. @p is a pointer to a uint64_t
* - @b svc2cl_keep_alive_timeout_secs - the AMQP service side keep alive interval in seconds.
* After the connection established the client requests the server to set the
* keep alive interval for given time.
* If it is not set then the default 240 sec applies.
* If it is set to zero the server will not send keep alive messages to the client.
* - @b cl2svc_keep_alive_send_ratio - the AMQP client side keep alive interval in seconds.
* After the connection established the server requests the client to set the
* keep alive interval for given time.
* If it is not set then the default ratio of 1/2 is applied.
* The ratio has to be greater than 0.0 and equal to or less than 0.9
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
* @deprecated IoTHubClient_SetOption is deprecated. Use IoTHubDeviceClient_SetOption instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_SetOption, IOTHUB_CLIENT_HANDLE, iotHubClientHandle, const char*, optionName, const void*, value);
/**
* @brief This API specifies a call back to be used when the device receives a state update.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param deviceTwinCallback The callback specified by the device client to be used for updating
* the desired state. The callback will be called in response to a
* request send by the IoTHub services. The payload will be passed to the
* callback, along with two version numbers:
* - Desired:
* - LastSeenReported:
* @param userContextCallback User specified context that will be provided to the
* callback. This can be @c NULL.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubClient_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_SetDeviceTwinCallback is deprecated. Use IoTHubDeviceClient_SetDeviceTwinCallback instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_SetDeviceTwinCallback, IOTHUB_CLIENT_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK, deviceTwinCallback, void*, userContextCallback);
/**
* @brief This API sends a report of the device's properties and their current values.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param reportedState The current device property values to be 'reported' to the IoTHub.
* @param reportedStateCallback The callback specified by the device client to be called with the
* result of the transaction.
* @param userContextCallback User specified context that will be provided to the
* callback. This can be @c NULL.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubClient_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_SendReportedState is deprecated. Use IoTHubDeviceClient_SendReportedState instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_SendReportedState, IOTHUB_CLIENT_HANDLE, iotHubClientHandle, const unsigned char*, reportedState, size_t, size, IOTHUB_CLIENT_REPORTED_STATE_CALLBACK, reportedStateCallback, void*, userContextCallback);
/**
* @brief This API sets callback for cloud to device method call.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param deviceMethodCallback The callback which will be called by IoTHub.
* @param userContextCallback User specified context that will be provided to the
* callback. This can be @c NULL.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_SetDeviceMethodCallback is deprecated. Use IoTHubDeviceClient_SetDeviceMethodCallback instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_SetDeviceMethodCallback, IOTHUB_CLIENT_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_DEVICE_METHOD_CALLBACK_ASYNC, deviceMethodCallback, void*, userContextCallback);
/**
* @brief This API sets callback for async cloud to device method call.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param inboundDeviceMethodCallback The callback which will be called by IoTHub.
* @param userContextCallback User specified context that will be provided to the
* callback. This can be @c NULL.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_SetDeviceMethodCallback_Ex is deprecated. Use IoTHubDeviceClient_SetDeviceMethodCallback instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_SetDeviceMethodCallback_Ex, IOTHUB_CLIENT_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK, inboundDeviceMethodCallback, void*, userContextCallback);
/**
* @brief This API responses to a asnyc method callback identified the methodId.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param methodId The methodId of the Device Method callback.
* @param response The response data for the method callback.
* @param response_size The size of the response data buffer.
* @param status_response The status response of the method callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_DeviceMethodResponse is deprecated. Use IoTHubDeviceClient_SetDeviceMethodCallback instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_DeviceMethodResponse, IOTHUB_CLIENT_HANDLE, iotHubClientHandle, METHOD_HANDLE, methodId, const unsigned char*, response, size_t, response_size, int, statusCode);
#ifndef DONT_USE_UPLOADTOBLOB
/**
* @brief IoTHubClient_UploadToBlobAsync uploads data from memory to a file in Azure Blob Storage.
*
* @param iotHubClientHandle The handle created by a call to the IoTHubClient_Create function.
* @param destinationFileName The name of the file to be created in Azure Blob Storage.
* @param source The source of data.
* @param size The size of data.
* @param iotHubClientFileUploadCallback A callback to be invoked when the file upload operation has finished.
* @param context A user-provided context to be passed to the file upload callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_UploadToBlobAsync is deprecated. Use IoTHubDeviceClient_UploadToBlobAsync instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_UploadToBlobAsync, IOTHUB_CLIENT_HANDLE, iotHubClientHandle, const char*, destinationFileName, const unsigned char*, source, size_t, size, IOTHUB_CLIENT_FILE_UPLOAD_CALLBACK, iotHubClientFileUploadCallback, void*, context);
/**
** DEPRECATED: Use IoTHubClient_UploadMultipleBlocksToBlobAsyncEx instead **
* @brief Uploads a file to a Blob storage in chunks, fed through the callback function provided by the user.
* @remarks This function allows users to upload large files in chunks, not requiring the whole file content to be passed in memory.
* @param iotHubClientHandle The handle created by a call to the IoTHubClient_Create function.
* @param destinationFileName The name of the file to be created in Azure Blob Storage.
* @param getDataCallback A callback to be invoked to acquire the file chunks to be uploaded, as well as to indicate the status of the upload of the previous block.
* @param context Any data provided by the user to serve as context on getDataCallback.
* @returns An IOTHUB_CLIENT_RESULT value indicating the success or failure of the API call.
** DEPRECATED: Use IoTHubClient_UploadMultipleBlocksToBlobAsyncEx instead **
* @deprecated IoTHubClient_UploadMultipleBlocksToBlobAsync is deprecated. Use IoTHubDeviceClient_UploadMultipleBlocksToBlobAsync instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_UploadMultipleBlocksToBlobAsync, IOTHUB_CLIENT_HANDLE, iotHubClientHandle, const char*, destinationFileName, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK, getDataCallback, void*, context);
/**
* @brief Uploads a file to a Blob storage in chunks, fed through the callback function provided by the user.
* @remarks This function allows users to upload large files in chunks, not requiring the whole file content to be passed in memory.
* @param iotHubClientHandle The handle created by a call to the IoTHubClient_Create function.
* @param destinationFileName The name of the file to be created in Azure Blob Storage.
* @param getDataCallbackEx A callback to be invoked to acquire the file chunks to be uploaded, as well as to indicate the status of the upload of the previous block.
* @param context Any data provided by the user to serve as context on getDataCallback.
* @returns An IOTHUB_CLIENT_RESULT value indicating the success or failure of the API call.*/
* @deprecated IoTHubClient_UploadMultipleBlocksToBlobAsyncEx is deprecated. Use IoTHubDeviceClient_UploadMultipleBlocksToBlobAsync instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_UploadMultipleBlocksToBlobAsyncEx, IOTHUB_CLIENT_HANDLE, iotHubClientHandle, const char*, destinationFileName, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK_EX, getDataCallbackEx, void*, context);
#endif /* DONT_USE_UPLOADTOBLOB */

Просмотреть файл

@ -1,16 +1,13 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
/** @file iothub_client_core.h
* @brief Extends the IoTHubClientCore_LL module with additional features.
*
* @details IoTHubClientCore is a module that extends the IoTHubClientCore_LL
* module with 2 features:
* - scheduling the work for the IoTHubCLient from a
* thread, so that the user does not need to create their
* own thread
* - thread-safe APIs
*/
//**********************************************************************
// NOTE: THIS HEADER IS FOR INTERNAL USE ONLY
//
// Applications should use iothub_device_client.h or iothub_module_client.h
// instead for the official API.
//
//**********************************************************************
#ifndef IOTHUB_CLIENT_CORE_H
#define IOTHUB_CLIENT_CORE_H

Просмотреть файл

@ -1,24 +1,13 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
/** @file iothub_client_core_ll.h
* @brief APIs that allow a user (usually a device) to communicate
* with an Azure IoTHub.
*
* @details IoTHubClientCore_LL is a module that allows a user (usually a
* device) to communicate with an Azure IoTHub. It can send events
* and receive messages. At any given moment in time there can only
* be at most 1 message callback function.
*
* This API surface contains a set of APIs that allows the user to
* interact with the lower layer portion of the IoTHubClient. These APIs
* contain @c _LL_ in their name, but retain the same functionality like the
* @c IoTHubClient_... APIs, with one difference. If the @c _LL_ APIs are
* used then the user is responsible for scheduling when the actual work done
* by the IoTHubClient happens (when the data is sent/received on/from the wire).
* This is useful for constrained devices where spinning a separate thread is
* often not desired.
*/
//**********************************************************************
// NOTE: THIS HEADER IS FOR INTERNAL USE ONLY
//
// Applications should use iothub_device_client_ll.h or iothub_module_client_ll.h
// instead for the official API.
//
//**********************************************************************
#ifndef IOTHUB_CLIENT_CORE_LL_H
#define IOTHUB_CLIENT_CORE_LL_H

Просмотреть файл

@ -1,11 +1,20 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//**********************************************************************
// NOTE: THIS HEADER IS DEPRECATED
//
// Functions in this header will be maintained for backward compatability.
// New applications should use iothub_device_client_ll.h.
//
//**********************************************************************
/** @file iothub_client_ll.h
* @brief APIs that allow a user (usually a device) to communicate
* with an Azure IoTHub.
*
* @details IoTHubClient_LL is a module that allows a user (usually a
* @details IoTHubClient_LL allows a user (usually a
* device) to communicate with an Azure IoTHub. It can send events
* and receive messages. At any given moment in time there can only
* be at most 1 message callback function.
@ -37,366 +46,116 @@ extern "C"
typedef struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA_TAG* IOTHUB_CLIENT_LL_HANDLE;
/**
* @deprecated IoTHubClient_LL_CreateFromConnectionString is deprecated. Use IoTHubDeviceClient_LL_CreateFromConnectionString instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_LL_HANDLE, IoTHubClient_LL_CreateFromConnectionString, const char*, connectionString, IOTHUB_CLIENT_TRANSPORT_PROVIDER, protocol);
/**
* @brief Creates a IoT Hub client for communication with an existing
* IoT Hub using the specified connection string parameter.
*
* @param connectionString Pointer to a character string
* @param protocol Function pointer for protocol implementation
*
* Sample connection string:
* <blockquote>
* <pre>HostName=[IoT Hub name goes here].[IoT Hub suffix goes here, e.g., private.azure-devices-int.net];DeviceId=[Device ID goes here];SharedAccessKey=[Device key goes here];</pre>
* </blockquote>
*
* @return A non-NULL @c IOTHUB_CLIENT_LL_HANDLE value that is used when
* invoking other functions for IoT Hub client and @c NULL on failure.
* @deprecated IoTHubClient_LL_Create is deprecated. Use IoTHubDeviceClient_LL_Create instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_LL_HANDLE, IoTHubClient_LL_CreateFromConnectionString, const char*, connectionString, IOTHUB_CLIENT_TRANSPORT_PROVIDER, protocol);
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_LL_HANDLE, IoTHubClient_LL_Create, const IOTHUB_CLIENT_CONFIG*, config);
/**
* @brief Creates a IoT Hub client for communication with an existing IoT
* Hub using the specified parameters.
*
* @param config Pointer to an @c IOTHUB_CLIENT_CONFIG structure
*
* The API does not allow sharing of a connection across multiple
* devices. This is a blocking call.
*
* @return A non-NULL @c IOTHUB_CLIENT_LL_HANDLE value that is used when
* invoking other functions for IoT Hub client and @c NULL on failure.
* @deprecated IoTHubClient_LL_CreateWithTransport is deprecated. Use IoTHubDeviceClient_LL_CreateWithTransport instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_LL_HANDLE, IoTHubClient_LL_Create, const IOTHUB_CLIENT_CONFIG*, config);
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_LL_HANDLE, IoTHubClient_LL_CreateWithTransport, const IOTHUB_CLIENT_DEVICE_CONFIG*, config);
/**
* @brief Creates a IoT Hub client for communication with an existing IoT
* Hub using an existing transport.
*
* @param config Pointer to an @c IOTHUB_CLIENT_DEVICE_CONFIG structure
*
* The API *allows* sharing of a connection across multiple
* devices. This is a blocking call.
*
* @return A non-NULL @c IOTHUB_CLIENT_LL_HANDLE value that is used when
* invoking other functions for IoT Hub client and @c NULL on failure.
* @deprecated IoTHubClient_LL_CreateFromDeviceAuth is deprecated. Use IoTHubDeviceClient_LL_CreateFromDeviceAuth instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_LL_HANDLE, IoTHubClient_LL_CreateWithTransport, const IOTHUB_CLIENT_DEVICE_CONFIG*, config);
/**
* @brief Creates a IoT Hub client for communication with an existing IoT
* Hub using the device auth module.
*
* @param iothub_uri Pointer to an ioThub hostname received in the registration process
* @param device_id Pointer to the device Id of the device
* @param device_auth_handle a device auth handle used to generate the connection string
* @param protocol Function pointer for protocol implementation
*
* @return A non-NULL @c IOTHUB_CLIENT_LL_HANDLE value that is used when
* invoking other functions for IoT Hub client and @c NULL on failure.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_LL_HANDLE, IoTHubClient_LL_CreateFromDeviceAuth, const char*, iothub_uri, const char*, device_id, IOTHUB_CLIENT_TRANSPORT_PROVIDER, protocol);
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_LL_HANDLE, IoTHubClient_LL_CreateFromDeviceAuth, const char*, iothub_uri, const char*, device_id, IOTHUB_CLIENT_TRANSPORT_PROVIDER, protocol);
/**
* @brief Disposes of resources allocated by the IoT Hub client. This is a
* blocking call.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @deprecated IoTHubClient_LL_Destroy is deprecatedDevice. Use IoTHubClient_LL_Destroy instead.
*/
MOCKABLE_FUNCTION(, void, IoTHubClient_LL_Destroy, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle);
MOCKABLE_FUNCTION(, void, IoTHubClient_LL_Destroy, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle);
/**
* @brief Asynchronous call to send the message specified by @p eventMessageHandle.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param eventMessageHandle The handle to an IoT Hub message.
* @param eventConfirmationCallback The callback specified by the device for receiving
* confirmation of the delivery of the IoT Hub message.
* This callback can be expected to invoke the
* ::IoTHubClient_LL_SendEventAsync function for the
* same message in an attempt to retry sending a failing
* message. The user can specify a @c NULL value here to
* indicate that no callback is required.
* @param userContextCallback User specified context that will be provided to the
* callback. This can be @c NULL.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubClient_LL_Destroy function from within any callback.
* @remarks
* The IOTHUB_MESSAGE_HANDLE instance provided as argument is copied by the function,
* so this argument can be destroyed by the calling application right after IoTHubClient_LL_SendEventAsync returns.
* The copy of @c eventMessageHandle is later destroyed by the iothub client when the message is effectively sent, if a failure sending it occurs, or if the client is destroyed.
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_LL_SendEventAsync is deprecated. Use IoTHubDeviceClient_LL_SendEventAsync instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_SendEventAsync, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_MESSAGE_HANDLE, eventMessageHandle, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK, eventConfirmationCallback, void*, userContextCallback);
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_SendEventAsync, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_MESSAGE_HANDLE, eventMessageHandle, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK, eventConfirmationCallback, void*, userContextCallback);
/**
* @brief This function returns the current sending status for IoTHubClient.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param iotHubClientStatus The sending state is populated at the address pointed
* at by this parameter. The value will be set to
* @c IOTHUBCLIENT_SENDSTATUS_IDLE if there is currently
* no item to be sent and @c IOTHUBCLIENT_SENDSTATUS_BUSY
* if there are.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_LL_GetSendStatus is deprecated. UseDevice IoTHubClient_LL_GetSendStatus instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_GetSendStatus, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_STATUS*, iotHubClientStatus);
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_GetSendStatus, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_STATUS*, iotHubClientStatus);
/**
* @brief Sets up the message callback to be invoked when IoT Hub issues a
* message to the device. This is a blocking call.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param messageCallback The callback specified by the device for receiving
* messages from IoT Hub.
* @param userContextCallback User specified context that will be provided to the
* callback. This can be @c NULL.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubClient_LL_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_LL_SetMessageCallback is deprecated. Use IoTHubDeviceClient_LL_SetMessageCallback instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_SetMessageCallback, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC, messageCallback, void*, userContextCallback);
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_SetMessageCallback, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC, messageCallback, void*, userContextCallback);
/**
* @brief Sets up the connection status callback to be invoked representing the status of
* the connection to IOT Hub. This is a blocking call.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param connectionStatusCallback The callback specified by the device for receiving
* updates about the status of the connection to IoT Hub.
* @param userContextCallback User specified context that will be provided to the
* callback. This can be @c NULL.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubClient_LL_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_LL_SetConnectionStatusCallback is deprecated. Use IoTHubDeviceClient_LL_SetConnectionStatusCallback instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_SetConnectionStatusCallback, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_CONNECTION_STATUS_CALLBACK, connectionStatusCallback, void*, userContextCallback);
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_SetConnectionStatusCallback, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_CONNECTION_STATUS_CALLBACK, connectionStatusCallback, void*, userContextCallback);
/**
* @brief Sets up the connection status callback to be invoked representing the status of
* the connection to IOT Hub. This is a blocking call.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param retryPolicy The policy to use to reconnect to IoT Hub when a
* connection drops.
* @param retryTimeoutLimitInSeconds Maximum amount of time(seconds) to attempt reconnection when a
* connection drops to IOT Hub.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubClient_LL_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_LL_SetRetryPolicy is deprecated. Use IoTHubDeviceClient_LL_SetRetryPolicy instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_SetRetryPolicy, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_RETRY_POLICY, retryPolicy, size_t, retryTimeoutLimitInSeconds);
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_SetRetryPolicy, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_RETRY_POLICY, retryPolicy, size_t, retryTimeoutLimitInSeconds);
/**
* @brief Sets up the connection status callback to be invoked representing the status of
* the connection to IOT Hub. This is a blocking call.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param retryPolicy Out parameter containing the policy to use to reconnect to IoT Hub.
* @param retryTimeoutLimitInSeconds Out parameter containing maximum amount of time in seconds to attempt reconnection
to IOT Hub.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubClient_LL_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_LL_GetRetryPolicy is deprecated. Use IoTHubDeviceClient_LL_GetRetryPolicy instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_GetRetryPolicy, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_RETRY_POLICY*, retryPolicy, size_t*, retryTimeoutLimitInSeconds);
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_GetRetryPolicy, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_RETRY_POLICY*, retryPolicy, size_t*, retryTimeoutLimitInSeconds);
/**
* @brief This function returns in the out parameter @p lastMessageReceiveTime
* what was the value of the @c time function when the last message was
* received at the client.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param lastMessageReceiveTime Out parameter containing the value of @c time function
* when the last message was received.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_LL_GetLastMessageReceiveTime is deprecated. Use IoTHubDeviceClient_LL_GetLastMessageReceiveTime instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_GetLastMessageReceiveTime, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, time_t*, lastMessageReceiveTime);
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_GetLastMessageReceiveTime, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, time_t*, lastMessageReceiveTime);
/**
* @brief This function is meant to be called by the user when work
* (sending/receiving) can be done by the IoTHubClient.
*
* @param iotHubClientHandle The handle created by a call to the create function.
*
* All IoTHubClient interactions (in regards to network traffic
* and/or user level callbacks) are the effect of calling this
* function and they take place synchronously inside _DoWork.
* @deprecated IoTHubClient_LL_DoWork is deprecateDeviced. Use IoTHubDeviceClient_LL_DoWork instead.
*/
MOCKABLE_FUNCTION(, void, IoTHubClient_LL_DoWork, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle);
MOCKABLE_FUNCTION(, void, IoTHubClient_LL_DoWork, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle);
/**
* @brief This API sets a runtime option identified by parameter @p optionName
* to a value pointed to by @p value. @p optionName and the data type
* @p value is pointing to are specific for every option.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param optionName Name of the option.
* @param value The value.
*
* The options that can be set via this API are:
* - @b timeout - the maximum time in milliseconds a communication is
* allowed to use. @p value is a pointer to an @c unsigned @c int with
* the timeout value in milliseconds. This is only supported for the HTTP
* protocol as of now. When the HTTP protocol uses CURL, the meaning of
* the parameter is <em>total request time</em>. When the HTTP protocol uses
* winhttp, the meaning is the same as the @c dwSendTimeout and
* @c dwReceiveTimeout parameters of the
* <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384116(v=vs.85).aspx">
* WinHttpSetTimeouts</a> API.
* - @b CURLOPT_LOW_SPEED_LIMIT - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_LOW_SPEED_TIME - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_FORBID_REUSE - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_FRESH_CONNECT - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_VERBOSE - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b keepalive - available for MQTT protocol. Integer value that sets the
* interval in seconds when pings are sent to the server.
* - @b logtrace - available for MQTT protocol. Boolean value that turns on and
* off the diagnostic logging.
* - @b sas_token_lifetime - available for MQTT & AMQP protocol. size_t value that that determines the
* sas token timeout length.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_LL_SetOption is deprecated. Device Use IoTHubDeviceClient_LL_SetOption instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_SetOption, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, const char*, optionName, const void*, value);
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_SetOption, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, const char*, optionName, const void*, value);
/**
* @brief This API specifies a call back to be used when the device receives a desired state update.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param deviceTwinCallback The callback specified by the device client to be used for updating
* the desired state. The callback will be called in response to patch
* request send by the IoTHub services. The payload will be passed to the
* callback, along with two version numbers:
* - Desired:
* - LastSeenReported:
* @param userContextCallback User specified context that will be provided to the
* callback. This can be @c NULL.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubClient_LL_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_LL_SetDeviceTwinCallback is deprecated. Use IoTHubDeviceClient_LL_SetDeviceTwinCallback instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_SetDeviceTwinCallback, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK, deviceTwinCallback, void*, userContextCallback);
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_SetDeviceTwinCallback, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK, deviceTwinCallback, void*, userContextCallback);
/**
* @brief This API sneds a report of the device's properties and their current values.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param reportedState The current device property values to be 'reported' to the IoTHub.
* @param reportedStateCallback The callback specified by the device client to be called with the
* result of the transaction.
* @param userContextCallback User specified context that will be provided to the
* callback. This can be @c NULL.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubClient_LL_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_LL_SendReportedState is deprecated. Use IoTHubDeviceClient_LL_SendReportedState instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_SendReportedState, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, const unsigned char*, reportedState, size_t, size, IOTHUB_CLIENT_REPORTED_STATE_CALLBACK, reportedStateCallback, void*, userContextCallback);
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_SendReportedState, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, const unsigned char*, reportedState, size_t, size, IOTHUB_CLIENT_REPORTED_STATE_CALLBACK, reportedStateCallback, void*, userContextCallback);
/**
* @brief This API sets callback for cloud to device method call.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param deviceMethodCallback The callback which will be called by IoTHub.
* @param userContextCallback User specified context that will be provided to the
* callback. This can be @c NULL.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_SetDeviceMethodCallback, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_DEVICE_METHOD_CALLBACK_ASYNC, deviceMethodCallback, void*, userContextCallback);
/**
* @deprecated IoTHubClient_LL_SetDeviceMethodCallback is deprecated. Use IoTHubDeviceClient_LL_SetDeviceMethodCallback instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_SetDeviceMethodCallback, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_DEVICE_METHOD_CALLBACK_ASYNC, deviceMethodCallback, void*, userContextCallback);
/**
* @brief This API sets callback for async cloud to device method call.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param inboundDeviceMethodCallback The callback which will be called by IoTHub.
* @param userContextCallback User specified context that will be provided to the
* callback. This can be @c NULL.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_SetDeviceMethodCallback_Ex, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK, inboundDeviceMethodCallback, void*, userContextCallback);
/**
* @deprecated IoTHubClient_LL_SetDeviceMethodCallback_Ex is deprecated. Use IoTHubDeviceClient_LL_SetDeviceMethodCallback instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_SetDeviceMethodCallback_Ex, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK, inboundDeviceMethodCallback, void*, userContextCallback);
/**
* @brief This API responses to a asnyc method callback identified the methodId.
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param methodId The methodId of the Device Method callback.
* @param response The response data for the method callback.
* @param response_size The size of the response data buffer.
* @param status_response The status response of the method callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_DeviceMethodResponse, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, METHOD_HANDLE, methodId, const unsigned char*, response, size_t, respSize, int, statusCode);
/**
* @deprecated IoTHubClient_LL_DeviceMethodResponse is deprecated. Use IoTHubDeviceClient_LL_SetDeviceMethodCallback instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_DeviceMethodResponse, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, METHOD_HANDLE, methodId, const unsigned char*, response, size_t, respSize, int, statusCode);
#ifndef DONT_USE_UPLOADTOBLOB
/**
* @brief This API uploads to Azure Storage the content pointed to by @p source having the size @p size
* under the blob name devicename/@pdestinationFileName
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param destinationFileName name of the file.
* @param source pointer to the source for file content (can be NULL)
* @param size the size of the source in memory (if @p source is NULL then size needs to be 0).
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @deprecated IoTHubClient_LL_UploadToBlob is deprecated. UsDevicee IoTHubDeviceClient_LL_UploadToBlob instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_UploadToBlob, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, const char*, destinationFileName, const unsigned char*, source, size_t, size);
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_UploadToBlob, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, const char*, destinationFileName, const unsigned char*, source, size_t, size);
/**
** DEPRECATED: Use IoTHubClient_LL_UploadMultipleBlocksToBlobAsyncEx instead **
* @brief This API uploads to Azure Storage the content provided block by block by @p getDataCallback
* under the blob name devicename/@pdestinationFileName
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param destinationFileName name of the file.
* @param getDataCallback A callback to be invoked to acquire the file chunks to be uploaded, as well as to indicate the status of the upload of the previous block.
* @param context Any data provided by the user to serve as context on getDataCallback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
** DEPRECATED: Use IoTHubClient_LL_UploadMultipleBlocksToBlobAsyncEx instead **
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_UploadMultipleBlocksToBlob, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, const char*, destinationFileName, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK, getDataCallback, void*, context);
/**
* @deprecated IoTHubClient_LL_UploadMultipleBlocksToBlob is deprecated. Use IoTHubDeviceClient_LL_UploadMultipleBlocksToBlob instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_UploadMultipleBlocksToBlob, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, const char*, destinationFileName, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK, getDataCallback, void*, context);
/**
* @brief This API uploads to Azure Storage the content provided block by block by @p getDataCallback
* under the blob name devicename/@pdestinationFileName
*
* @param iotHubClientHandle The handle created by a call to the create function.
* @param destinationFileName name of the file.
* @param getDataCallbackEx A callback to be invoked to acquire the file chunks to be uploaded, as well as to indicate the status of the upload of the previous block.
* @param context Any data provided by the user to serve as context on getDataCallback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_UploadMultipleBlocksToBlobEx, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, const char*, destinationFileName, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK_EX, getDataCallbackEx, void*, context);
/**
* @deprecated IoTHubClient_LL_UploadMultipleBlocksToBlobEx is deprecated. Use IoTHubDeviceClient_LL_UploadMultipleBlocksToBlob instead.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_UploadMultipleBlocksToBlobEx, IOTHUB_CLIENT_LL_HANDLE, iotHubClientHandle, const char*, destinationFileName, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK_EX, getDataCallbackEx, void*, context);
#endif /*DONT_USE_UPLOADTOBLOB*/

Просмотреть файл

@ -27,6 +27,8 @@ extern "C"
static STATIC_VAR_UNUSED const char* OPTION_KEEP_ALIVE = "keepalive";
static STATIC_VAR_UNUSED const char* OPTION_CONNECTION_TIMEOUT = "connect_timeout";
/* None of the OPTION_PROXY_* options below are implemented. Use OPTION_HTTP_PROXY
from shared_util_options.h in https://github.com/Azure/azure-c-shared-utility/ repo instead */
static STATIC_VAR_UNUSED const char* OPTION_PROXY_HOST = "proxy_address";
static STATIC_VAR_UNUSED const char* OPTION_PROXY_USERNAME = "proxy_username";
static STATIC_VAR_UNUSED const char* OPTION_PROXY_PASSWORD = "proxy_password";
@ -43,6 +45,11 @@ extern "C"
static STATIC_VAR_UNUSED const char* OPTION_BLOB_UPLOAD_TIMEOUT_SECS = "blob_upload_timeout_secs";
static STATIC_VAR_UNUSED const char* OPTION_PRODUCT_INFO = "product_info";
/*
* @brief Specifies the Digital Twin Model Id of the connection. Only valid for use with MQTT Transport
*/
static STATIC_VAR_UNUSED const char* OPTION_MODEL_ID = "model_id";
/*
* @brief Turns on automatic URL encoding of message properties + system properties. Only valid for use with MQTT Transport
*/

Просмотреть файл

@ -8,7 +8,7 @@
#ifndef IOTHUB_CLIENT_VERSION_H
#define IOTHUB_CLIENT_VERSION_H
#define IOTHUB_SDK_VERSION "1.3.8"
#define IOTHUB_SDK_VERSION "1.3.9"
#include "umock_c/umock_c_prod.h"

Просмотреть файл

@ -2,11 +2,11 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
/** @file iothub_device_client.h
* @brief Extends the IoTHubCLient_LL module with additional features.
* @brief Extends the IoTHubCLient_LL with additional features.
*
* @details IoTHubClient is a module that extends the IoTHubCLient_LL
* module with 2 features:
* - scheduling the work for the IoTHubCLient from a
* @details IoTHubDeviceClient extends the IoTHubDeviceClient_LL
* with 2 features:
* - scheduling the work for the IoTHubDeviceClient from a
* thread, so that the user does not need to create their
* own thread
* - thread-safe APIs
@ -84,7 +84,7 @@ extern "C"
/**
* @brief Creates a IoT Hub client for communication with an existing IoT
* Hub using the device auth module.
* Hub using the device auth.
*
* @param iothub_uri Pointer to an ioThub hostname received in the registration process
* @param device_id Pointer to the device Id of the device
@ -134,10 +134,12 @@ extern "C"
* @param iotHubClientHandle The handle created by a call to the create function.
* @param iotHubClientStatus The sending state is populated at the address pointed
* at by this parameter. The value will be set to
* @c IOTHUBCLIENT_SENDSTATUS_IDLE if there is currently
* no item to be sent and @c IOTHUBCLIENT_SENDSTATUS_BUSY
* @c IOTHUB_CLIENT_SEND_STATUS_IDLE if there is currently
* no item to be sent and @c IOTHUB_CLIENT_SEND_STATUS_BUSY
* if there are.
*
* @remark Does not return information related to uploads initiated by IoTHubDeviceClient_UploadToBlob or IoTHubDeviceClient_UploadMultipleBlocksToBlob.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubDeviceClient_GetSendStatus, IOTHUB_DEVICE_CLIENT_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_STATUS*, iotHubClientStatus);
@ -170,7 +172,9 @@ extern "C"
* callback. This can be @c NULL.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubDeviceClient_LL_Destroy function from within any callback.
* the ::IoTHubDeviceClient_Destroy function from within any callback.
*
* @remark Callback specified will not receive connection status change notifications for upload connections created with IoTHubDeviceClient_UploadToBlob or IoTHubDeviceClient_UploadMultipleBlocksToBlob.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
@ -187,7 +191,9 @@ extern "C"
* connection drops to IOT Hub.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubDeviceClient_LL_Destroy function from within any callback.
* the ::IoTHubDeviceClient_Destroy function from within any callback.
*
* @remark Uploads initiated by IoTHubDeviceClient_UploadToBlob or IoTHubDeviceClient_UploadMultipleBlocksToBlob do not have automatic retries and do not honor the retryPolicy settings.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
@ -203,7 +209,7 @@ extern "C"
* to IOT Hub.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubDeviceClient_LL_Destroy function from within any callback.
* the ::IoTHubDeviceClient_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
@ -231,45 +237,8 @@ extern "C"
* @param optionName Name of the option.
* @param value The value.
*
* The options that can be set via this API are:
* - @b timeout - the maximum time in milliseconds a communication is
* allowed to use. @p value is a pointer to an @c unsigned @c int with
* the timeout value in milliseconds. This is only supported for the HTTP
* protocol as of now. When the HTTP protocol uses CURL, the meaning of
* the parameter is <em>total request time</em>. When the HTTP protocol uses
* winhttp, the meaning is the same as the @c dwSendTimeout and
* @c dwReceiveTimeout parameters of the
* <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384116(v=vs.85).aspx">
* WinHttpSetTimeouts</a> API.
* - @b CURLOPT_LOW_SPEED_LIMIT - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_LOW_SPEED_TIME - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_FORBID_REUSE - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_FRESH_CONNECT - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_VERBOSE - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b messageTimeout - the maximum time in milliseconds until a message
* is timeouted. The time starts at IoTHubDeviceClient_SendEventAsync. By default,
* messages do not expire. @p is a pointer to a uint64_t
* - @b svc2cl_keep_alive_timeout_secs - the AMQP service side keep alive interval in seconds.
* After the connection established the client requests the server to set the
* keep alive interval for given time.
* If it is not set then the default 240 sec applies.
* If it is set to zero the server will not send keep alive messages to the client.
* - @b cl2svc_keep_alive_send_ratio - the AMQP client side keep alive interval in seconds.
* After the connection established the server requests the client to set the
* keep alive interval for given time.
* If it is not set then the default ratio of 1/2 is applied.
* The ratio has to be greater than 0.0 and equal to or less than 0.9
* @remarks Documentation for configuration options is available at https://github.com/Azure/azure-iot-sdk-c/blob/master/doc/Iothub_sdk_options.md.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubDeviceClient_SetOption, IOTHUB_DEVICE_CLIENT_HANDLE, iotHubClientHandle, const char*, optionName, const void*, value);
@ -321,7 +290,7 @@ extern "C"
* callback. This can be @c NULL.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubClient_LL_Destroy function from within any callback.
* the ::IoTHubDeviceClient_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/

Просмотреть файл

@ -5,7 +5,7 @@
* @brief APIs that allow a user (usually a device) to communicate
* with an Azure IoTHub.
*
* @details IoTHubDeviceClient_LL is a module that allows a user (usually a
* @details IoTHubDeviceClient_LL allows a user (usually a
* device) to communicate with an Azure IoTHub. It can send events
* and receive messages. At any given moment in time there can only
* be at most 1 message callback function.
@ -15,7 +15,7 @@
* contain @c _LL_ in their name, but retain the same functionality like the
* @c IoTHubDeviceClient_... APIs, with one difference. If the @c _LL_ APIs are
* used then the user is responsible for scheduling when the actual work done
* by the IoTHubClient happens (when the data is sent/received on/from the wire).
* by the IoTHubClient happens (when the data is sent/received on/from the network).
* This is useful for constrained devices where spinning a separate thread is
* often not desired.
*/
@ -87,7 +87,7 @@ typedef struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA_TAG* IOTHUB_DEVICE_CLIENT_LL_HA
/**
* @brief Creates a IoT Hub client for communication with an existing IoT
* Hub using the device auth module.
* Hub using the device auth.
*
* @param iothub_uri Pointer to an ioThub hostname received in the registration process
* @param device_id Pointer to the device Id of the device
@ -138,10 +138,12 @@ typedef struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA_TAG* IOTHUB_DEVICE_CLIENT_LL_HA
* @param iotHubClientHandle The handle created by a call to the create function.
* @param iotHubClientStatus The sending state is populated at the address pointed
* at by this parameter. The value will be set to
* @c IOTHUBCLIENT_SENDSTATUS_IDLE if there is currently
* no item to be sent and @c IOTHUBCLIENT_SENDSTATUS_BUSY
* @c IOTHUB_CLIENT_SEND_STATUS_IDLE if there is currently
* no item to be sent and @c IOTHUB_CLIENT_SEND_STATUS_BUSY
* if there are.
*
* @remark Does not return information related to uploads initiated by IoTHubDeviceClient_LL_UploadToBlob or IoTHubDeviceClient_LL_UploadMultipleBlocksToBlob.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubDeviceClient_LL_GetSendStatus, IOTHUB_DEVICE_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_STATUS*, iotHubClientStatus);
@ -176,6 +178,8 @@ typedef struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA_TAG* IOTHUB_DEVICE_CLIENT_LL_HA
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubDeviceClient_LL_Destroy function from within any callback.
*
* @remark Callback specified will not receive connection status change notifications for upload connections created with IoTHubDeviceClient_LL_UploadToBlob or IoTHubDeviceClient_LL_UploadMultipleBlocksToBlob.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubDeviceClient_LL_SetConnectionStatusCallback, IOTHUB_DEVICE_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_CONNECTION_STATUS_CALLBACK, connectionStatusCallback, void*, userContextCallback);
@ -193,6 +197,8 @@ typedef struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA_TAG* IOTHUB_DEVICE_CLIENT_LL_HA
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubDeviceClient_LL_Destroy function from within any callback.
*
* @remark Uploads initiated by IoTHubDeviceClient_LL_UploadToBlob or IoTHubDeviceClient_LL_UploadMultipleBlocksToBlob do not have automatic retries and do not honor the retryPolicy settings.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubDeviceClient_LL_SetRetryPolicy, IOTHUB_DEVICE_CLIENT_LL_HANDLE, iotHubClientHandle, IOTHUB_CLIENT_RETRY_POLICY, retryPolicy, size_t, retryTimeoutLimitInSeconds);
@ -228,7 +234,7 @@ typedef struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA_TAG* IOTHUB_DEVICE_CLIENT_LL_HA
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubDeviceClient_LL_GetLastMessageReceiveTime, IOTHUB_DEVICE_CLIENT_LL_HANDLE, iotHubClientHandle, time_t*, lastMessageReceiveTime);
/**
* @brief This function MUST be called by the user so work (sending/receiving data on the wire,
* @brief This function MUST be called by the user so work (sending/receiving data on the network,
* computing and enforcing timeout controls, managing the connection to the IoT Hub) can
* be done by the IoTHubClient.
* The recommended call frequency is at least once every 100 milliseconds.
@ -250,38 +256,7 @@ typedef struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA_TAG* IOTHUB_DEVICE_CLIENT_LL_HA
* @param optionName Name of the option.
* @param value The value.
*
* The options that can be set via this API are:
* - @b timeout - the maximum time in milliseconds a communication is
* allowed to use. @p value is a pointer to an @c unsigned @c int with
* the timeout value in milliseconds. This is only supported for the HTTP
* protocol as of now. When the HTTP protocol uses CURL, the meaning of
* the parameter is <em>total request time</em>. When the HTTP protocol uses
* winhttp, the meaning is the same as the @c dwSendTimeout and
* @c dwReceiveTimeout parameters of the
* <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384116(v=vs.85).aspx">
* WinHttpSetTimeouts</a> API.
* - @b CURLOPT_LOW_SPEED_LIMIT - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_LOW_SPEED_TIME - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_FORBID_REUSE - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_FRESH_CONNECT - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_VERBOSE - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b keepalive - available for MQTT protocol. Integer value that sets the
* interval in seconds when pings are sent to the server.
* - @b logtrace - available for MQTT protocol. Boolean value that turns on and
* off the diagnostic logging.
* - @b sas_token_lifetime - available for MQTT & AMQP protocol. size_t value that that determines the
* sas token timeout length.
* - @b OPTION_TRUSTED_CERT - Azure Server certificate used to validate TLS connection to iothub.
* @remarks Documentation for configuration options is available at https://github.com/Azure/azure-iot-sdk-c/blob/master/doc/Iothub_sdk_options.md.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
@ -373,6 +348,9 @@ typedef struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA_TAG* IOTHUB_DEVICE_CLIENT_LL_HA
* @param destinationFileName name of the file.
* @param source pointer to the source for file content (can be NULL)
* @param size the size of the source in memory (if @p source is NULL then size needs to be 0).
*
* @warning Other _LL_ functions such as IoTHubDeviceClient_LL_SendEventAsync queue work to be performed later and do not block. IoTHubDeviceClient_LL_UploadToBlob
* will block however until the upload is completed or fails, which may take a while.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
@ -387,6 +365,9 @@ typedef struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA_TAG* IOTHUB_DEVICE_CLIENT_LL_HA
* @param getDataCallbackEx A callback to be invoked to acquire the file chunks to be uploaded, as well as to indicate the status of the upload of the previous block.
* @param context Any data provided by the user to serve as context on getDataCallback.
*
* @warning Other _LL_ functions such as IoTHubDeviceClient_LL_SendEventAsync queue work to be performed later and do not block. IoTHubDeviceClient_LL_UploadMultipleBlocksToBlob
* will block however until the upload is completed or fails, which may take a while.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubDeviceClient_LL_UploadMultipleBlocksToBlob, IOTHUB_DEVICE_CLIENT_LL_HANDLE, iotHubClientHandle, const char*, destinationFileName, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK_EX, getDataCallbackEx, void*, context);

Просмотреть файл

@ -191,9 +191,13 @@ MOCKABLE_FUNCTION(, MAP_HANDLE, IoTHubMessage_Properties, IOTHUB_MESSAGE_HANDLE,
*
* @param iotHubMessageHandle Handle to the message.
*
* @param key name of the property to set. Note that when sending messages via the HTTP transport, this value must not contain spaces.
* @param key name of the property to set. Note that when sending messages via the HTTP transport, this value must not contain spaces.
*
* @param value of the property to set.
* @param value of the property to set.
*
* @b NOTE: The accepted character sets for the key name and value parameters are dependent on different factors, such as the protocol
* being used. For more information on the character sets accepted by Azure IoT Hub, see
* <a href="https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-messages-construct">Create and read IoT Hub messages</a>.
*
* @return An @c IOTHUB_MESSAGE_RESULT value indicating the result of setting the property.
*/
@ -251,7 +255,7 @@ MOCKABLE_FUNCTION(, const char*, IoTHubMessage_GetCorrelationId, IOTHUB_MESSAGE_
* @param iotHubMessageHandle Handle to the message.
* @param correlationId Pointer to the memory location of the messageId
*
* @return Returns IOTHUB_MESSAGE_OK if the messageId was set successfully
* @return Returns IOTHUB_MESSAGE_OK if the CorrelationId was set successfully
* or an error code otherwise.
*/
MOCKABLE_FUNCTION(, IOTHUB_MESSAGE_RESULT, IoTHubMessage_SetCorrelationId, IOTHUB_MESSAGE_HANDLE, iotHubMessageHandle, const char*, correlationId);
@ -294,7 +298,7 @@ MOCKABLE_FUNCTION(, const char*, IoTHubMessage_GetOutputName, IOTHUB_MESSAGE_HAN
* @param iotHubMessageHandle Handle to the message.
* @param outputName Pointer to the queue to output message to
*
* @return Returns IOTHUB_MESSAGE_OK if the DiagnosticData was set successfully
* @return Returns IOTHUB_MESSAGE_OK if the outputName was set successfully
* or an error code otherwise.
*/
MOCKABLE_FUNCTION(, IOTHUB_MESSAGE_RESULT, IoTHubMessage_SetOutputName, IOTHUB_MESSAGE_HANDLE, iotHubMessageHandle, const char*, outputName);
@ -317,7 +321,7 @@ MOCKABLE_FUNCTION(, const char*, IoTHubMessage_GetInputName, IOTHUB_MESSAGE_HAND
* @param iotHubMessageHandle Handle to the message.
* @param inputName Pointer to the queue to input message to
*
* @return Returns IOTHUB_MESSAGE_OK if the DiagnosticData was set successfully
* @return Returns IOTHUB_MESSAGE_OK if the inputName was set successfully
* or an error code otherwise.
*/
MOCKABLE_FUNCTION(, IOTHUB_MESSAGE_RESULT, IoTHubMessage_SetInputName, IOTHUB_MESSAGE_HANDLE, iotHubMessageHandle, const char*, inputName);
@ -339,12 +343,11 @@ MOCKABLE_FUNCTION(, const char*, IoTHubMessage_GetConnectionModuleId, IOTHUB_MES
* @param iotHubMessageHandle Handle to the message.
* @param connectionModuleId Pointer to the module ID of connector
*
* @return Returns IOTHUB_MESSAGE_OK if the DiagnosticData was set successfully
* @return Returns IOTHUB_MESSAGE_OK if the connectionModuleId was set successfully
* or an error code otherwise.
*/
MOCKABLE_FUNCTION(, IOTHUB_MESSAGE_RESULT, IoTHubMessage_SetConnectionModuleId, IOTHUB_MESSAGE_HANDLE, iotHubMessageHandle, const char*, connectionModuleId);
/**
* @brief Gets the connection device ID from the IOTHUB_MESSAGE_HANDLE. No new memory is allocated,
* the caller is not responsible for freeing the memory. The memory
@ -356,6 +359,49 @@ MOCKABLE_FUNCTION(, IOTHUB_MESSAGE_RESULT, IoTHubMessage_SetConnectionModuleId,
*/
MOCKABLE_FUNCTION(, const char*, IoTHubMessage_GetConnectionDeviceId, IOTHUB_MESSAGE_HANDLE, iotHubMessageHandle);
/**
* @brief Sets the message creation time in UTC.
*
* @param iotHubMessageHandle Handle to the message.
* @param messageCreationTimeUtc Pointer to the message creation time as null-terminated string
*
* @return Returns IOTHUB_MESSAGE_OK if the messageCreationTimeUtc was set successfully
* or an error code otherwise.
*/
MOCKABLE_FUNCTION(, IOTHUB_MESSAGE_RESULT, IoTHubMessage_SetMessageCreationTimeUtcSystemProperty, IOTHUB_MESSAGE_HANDLE, iotHubMessageHandle, const char*, messageCreationTimeUtc);
/**
* @brief Gets the message creation time in UTC from the IOTHUB_MESSAGE_HANDLE. No new memory is allocated,
* the caller is not responsible for freeing the memory. The memory
* is valid until IoTHubMessage_Destroy is called on the message.
*
* @param iotHubMessageHandle Handle to the message.
*
* @return A const char* pointing to the message creation time in UTC.
*/
MOCKABLE_FUNCTION(, const char*, IoTHubMessage_GetMessageCreationTimeUtcSystemProperty, IOTHUB_MESSAGE_HANDLE, iotHubMessageHandle);
/**
* @brief Sets the message user id. CAUTION: SDK user should not call it directly, it is for internal use only.
*
* @param iotHubMessageHandle Handle to the message.
* @param userId Pointer to the message user id as null-terminated string
*
* @return Returns IOTHUB_MESSAGE_OK if the userId was set successfully or an error code otherwise.
*/
MOCKABLE_FUNCTION(, IOTHUB_MESSAGE_RESULT, IoTHubMessage_SetMessageUserIdSystemProperty, IOTHUB_MESSAGE_HANDLE, iotHubMessageHandle, const char*, userId);
/**
* @brief Gets the message user id from the IOTHUB_MESSAGE_HANDLE. No new memory is allocated,
* the caller is not responsible for freeing the memory. The memory
* is valid until IoTHubMessage_Destroy is called on the message.
*
* @param iotHubMessageHandle Handle to the message.
*
* @return A const char* pointing to the message user id.
*/
MOCKABLE_FUNCTION(, const char*, IoTHubMessage_GetMessageUserIdSystemProperty, IOTHUB_MESSAGE_HANDLE, iotHubMessageHandle);
/**
* @brief Sets connection device Id. CAUTION: SDK user should not call it directly, it is for internal use only.
*

Просмотреть файл

@ -2,11 +2,11 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
/** @file iothub_module_client.h
* @brief Extends the IoTHubClient_LL module with additional features.
* @brief Extends the IoTHubModuleClient_LL module with additional features.
*
* @details IoTHubClient is a module that extends the IoTHubClient_LL
* module with 2 features:
* - scheduling the work for the IoTHubClient from a
* @details IoTHubModuleClient extends the IoTHubModuleClient_LL
* with 2 features:
* - scheduling the work for the IoTHubModuleClient from a
* thread, so that the user does not need to create their
* own thread
* - thread-safe APIs
@ -87,13 +87,13 @@ extern "C"
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubModuleClient_SendEventAsync, IOTHUB_MODULE_CLIENT_HANDLE, iotHubModuleClientHandle, IOTHUB_MESSAGE_HANDLE, eventMessageHandle, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK, eventConfirmationCallback, void*, userContextCallback);
/**
* @brief This function returns the current sending status for IoTHubClient.
* @brief This function returns the current sending status for IoTHubModuleClient.
*
* @param iotHubModuleClientHandle The handle created by a call to the create function.
* @param IoTHubClientStatus The sending state is populated at the address pointed
* at by this parameter. The value will be set to
* @c IoTHubClient_SENDSTATUS_IDLE if there is currently
* no item to be sent and @c IoTHubClient_SENDSTATUS_BUSY
* @c IOTHUB_CLIENT_SEND_STATUS_IDLE if there is currently
* no item to be sent and @c IOTHUB_CLIENT_SEND_STATUS_BUSY
* if there are.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
@ -128,7 +128,7 @@ extern "C"
* callback. This can be @c NULL.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubModuleClient_LL_Destroy function from within any callback.
* the ::IoTHubModuleClient_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
@ -145,7 +145,7 @@ extern "C"
* connection drops to IOT Hub.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubModuleClient_LL_Destroy function from within any callback.
* the ::IoTHubModuleClient_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
@ -161,7 +161,7 @@ extern "C"
to IOT Hub.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubModuleClient_LL_Destroy function from within any callback.
* the ::IoTHubModuleClient_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
@ -189,46 +189,10 @@ extern "C"
* @param optionName Name of the option.
* @param value The value.
*
* The options that can be set via this API are:
* - @b timeout - the maximum time in milliseconds a communication is
* allowed to use. @p value is a pointer to an @c unsigned @c int with
* the timeout value in milliseconds. This is only supported for the HTTP
* protocol as of now. When the HTTP protocol uses CURL, the meaning of
* the parameter is <em>total request time</em>. When the HTTP protocol uses
* winhttp, the meaning is the same as the @c dwSendTimeout and
* @c dwReceiveTimeout parameters of the
* <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384116(v=vs.85).aspx">
* WinHttpSetTimeouts</a> API.
* - @b CURLOPT_LOW_SPEED_LIMIT - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_LOW_SPEED_TIME - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_FORBID_REUSE - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_FRESH_CONNECT - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_VERBOSE - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b messageTimeout - the maximum time in milliseconds until a message
* is timeouted. The time starts at IoTHubModuleClient_SendEventAsync. By default,
* messages do not expire. @p is a pointer to a uint64_t
* - @b svc2cl_keep_alive_timeout_secs - the AMQP service side keep alive interval in seconds.
* After the connection established the client requests the server to set the
* keep alive interval for given time.
* If it is not set then the default 240 sec applies.
* If it is set to zero the server will not send keep alive messages to the client.
* - @b cl2svc_keep_alive_send_ratio - the AMQP client side keep alive interval in seconds.
* After the connection established the server requests the client to set the
* keep alive interval for given time.
* If it is not set then the default ratio of 1/2 is applied.
* The ratio has to be greater than 0.0 and equal to or less than 0.9
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*
* @remarks Documentation for configuration options is available at https://github.com/Azure/azure-iot-sdk-c/blob/master/doc/Iothub_sdk_options.md.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubModuleClient_SetOption, IOTHUB_MODULE_CLIENT_HANDLE, iotHubModuleClientHandle, const char*, optionName, const void*, value);
@ -306,7 +270,7 @@ extern "C"
* @param eventConfirmationCallback The callback specified by the module for receiving
* confirmation of the delivery of the IoT Hub message.
* This callback can be expected to invoke the
* ::IoTHubClient_SendEventAsync function for the
* IoTHubModuleClient_SendEventAsync function for the
* same message in an attempt to retry sending a failing
* message. The user can specify a @c NULL value here to
* indicate that no callback is required.
@ -314,7 +278,7 @@ extern "C"
* callback. This can be @c NULL.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubClient_Destroy function from within any callback.
* the IoTHubModuleClient_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
@ -322,7 +286,7 @@ extern "C"
/**
* @brief This API sets callback for method call that is directed to specified 'inputName' queue (e.g. messages from IoTHubClient_SendEventToOutputAsync)
* @brief This API sets callback for method call that is directed to specified 'inputName' queue (e.g. messages from IoTHubModuleClient_SendEventToOutputAsync)
*
* @param iotHubModuleClientHandle The handle created by a call to the create function.
* @param inputName The name of the queue to listen on for this moduleMethodCallback/userContextCallback.

Просмотреть файл

@ -5,17 +5,17 @@
* @brief APIs that allow a user (usually a module) to communicate
* with an Azure IoTHub.
*
* @details IoTHubModuleClient_LL is a module that allows a user (usually a
* @details IoTHubModuleClient_LL allows a user (usually a
* module) to communicate with an Azure IoTHub. It can send events
* and receive messages. At any given moment in time there can only
* be at most 1 message callback function.
*
* This API surface contains a set of APIs that allows the user to
* interact with the lower layer portion of the IoTHubClient. These APIs
* interact with the lower layer portion of the IoTHubModuleClient. These APIs
* contain @c _LL_ in their name, but retain the same functionality like the
* @c IoTHubModuleClient_... APIs, with one difference. If the @c _LL_ APIs are
* used then the user is responsible for scheduling when the actual work done
* by the IoTHubClient happens (when the data is sent/received on/from the wire).
* by the IoTHubModuleClient happens (when the data is sent/received on/from the network).
* This is useful for constrained devices where spinning a separate thread is
* often not desired.
*/
@ -100,13 +100,13 @@ extern "C"
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubModuleClient_LL_SendEventAsync, IOTHUB_MODULE_CLIENT_LL_HANDLE, iotHubModuleClientHandle, IOTHUB_MESSAGE_HANDLE, eventMessageHandle, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK, eventConfirmationCallback, void*, userContextCallback);
/**
* @brief This function returns the current sending status for IoTHubClient.
* @brief This function returns the current sending status for IoTHubModuleClient.
*
* @param iotHubModuleClientHandle The handle created by a call to the create function.
* @param iotHubClientStatus The sending state is populated at the address pointed
* at by this parameter. The value will be set to
* @c IOTHUBCLIENT_SENDSTATUS_IDLE if there is currently
* no item to be sent and @c IOTHUBCLIENT_SENDSTATUS_BUSY
* @c IOTHUB_CLIENT_SEND_STATUS_IDLE if there is currently
* no item to be sent and @c IOTHUB_CLIENT_SEND_STATUS_BUSY
* if there are.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
@ -196,11 +196,11 @@ extern "C"
/**
* @brief This function is meant to be called by the user when work
* (sending/receiving) can be done by the IoTHubClient.
* (sending/receiving) can be done by the IoTHubModuleClient.
*
* @param iotHubModuleClientHandle The handle created by a call to the create function.
*
* All IoTHubClient interactions (in regards to network traffic
* All IoTHubModuleClient interactions (in regards to network traffic
* and/or user level callbacks) are the effect of calling this
* function and they take place synchronously inside _DoWork.
*/
@ -215,39 +215,9 @@ extern "C"
* @param optionName Name of the option.
* @param value The value.
*
* The options that can be set via this API are:
* - @b timeout - the maximum time in milliseconds a communication is
* allowed to use. @p value is a pointer to an @c unsigned @c int with
* the timeout value in milliseconds. This is only supported for the HTTP
* protocol as of now. When the HTTP protocol uses CURL, the meaning of
* the parameter is <em>total request time</em>. When the HTTP protocol uses
* winhttp, the meaning is the same as the @c dwSendTimeout and
* @c dwReceiveTimeout parameters of the
* <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384116(v=vs.85).aspx">
* WinHttpSetTimeouts</a> API.
* - @b CURLOPT_LOW_SPEED_LIMIT - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_LOW_SPEED_TIME - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_FORBID_REUSE - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_FRESH_CONNECT - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b CURLOPT_VERBOSE - only available for HTTP protocol and only
* when CURL is used. It has the same meaning as CURL's option with the same
* name. @p value is pointer to a long.
* - @b keepalive - available for MQTT protocol. Integer value that sets the
* interval in seconds when pings are sent to the server.
* - @b logtrace - available for MQTT protocol. Boolean value that turns on and
* off the diagnostic logging.
* - @b sas_token_lifetime - available for MQTT & AMQP protocol. size_t value that that determines the
* sas token timeout length.
* @remarks Documentation for configuration options is available at https://github.com/Azure/azure-iot-sdk-c/blob/master/doc/Iothub_sdk_options.md.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubModuleClient_LL_SetOption, IOTHUB_MODULE_CLIENT_LL_HANDLE, iotHubModuleClientHandle, const char*, optionName, const void*, value);
@ -324,7 +294,7 @@ extern "C"
* @param eventConfirmationCallback The callback specified by the module for receiving
* confirmation of the delivery of the IoT Hub message.
* This callback can be expected to invoke the
* ::IoTHubClient_LL_SendEventAsync function for the
* IoTHubModuleClient_LL_SendEventAsync function for the
* same message in an attempt to retry sending a failing
* message. The user can specify a @c NULL value here to
* indicate that no callback is required.
@ -332,14 +302,14 @@ extern "C"
* callback. This can be @c NULL.
*
* @b NOTE: The application behavior is undefined if the user calls
* the ::IoTHubClient_LL_Destroy function from within any callback.
* the ::IoTHubModuleClient_LL_Destroy function from within any callback.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubModuleClient_LL_SendEventToOutputAsync, IOTHUB_MODULE_CLIENT_LL_HANDLE, iotHubModuleClientHandle, IOTHUB_MESSAGE_HANDLE, eventMessageHandle, const char*, outputName, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK, eventConfirmationCallback, void*, userContextCallback);
/**
* @brief This API sets callback for method call that is directed to specified 'inputName' queue (e.g. messages from IoTHubClient_SendEventToOutputAsync)
* @brief This API sets callback for method call that is directed to specified 'inputName' queue (e.g. messages from IoTHubModuleClient_LL_SendEventToOutputAsync)
*
* @param iotHubModuleClientHandle The handle created by a call to the create function.
* @param inputName The name of the queue to listen on for this moduleMethodCallback/userContextCallback.

Просмотреть файл

@ -1,7 +1,7 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
#this is CMakeLists.txt for samples. There's noithig here, except redirections to
#this is CMakeLists.txt for samples. There's nothing here, except redirections to
#individual protocol samples
usePermissiveRulesForSdkSamplesAndTests()
@ -51,3 +51,8 @@ endif()
if(${use_amqp} AND ${use_mqtt})
add_sample_directory(iothub_client_device_twin_and_methods_sample)
endif()
if(${use_mqtt})
# PnP only supports MQTT so only build the sample if MQTT is enabled.
add_subdirectory(pnp)
endif()

Просмотреть файл

@ -23,18 +23,6 @@ Change your current directory to the iOS sample directory.
`cd azure-iot-samples-ios/quickstart/sample-device/`
#### 3. Update the Podfile
Note: Make sure that XCode does not already have the sample project open. If
it does, the CocoaPods may not install properly.
Edit the Podfile in a text editor and ensure that the pods are specified with these versions or later:
`'AzureIoTHubClient', '=1.3.8a'`
`'AzureIoTUtility', '=1.3.8a'`
`'AzureIoTuMqtt', '=1.3.8a'`
`'AzureIoTuAmqp', '=1.3.8a'`
#### 3. Install the CocoaPods
Make sure that XCode does not already have the sample project open. If
@ -46,14 +34,14 @@ Run this command:
This will cause CocoaPods to read the `Podfile` and install the pods accordingly.
#### 5. Open the XCode workspace
#### 4. Open the XCode workspace
Double-click the `MQTT Client Sample.xcworkspace` workspace file (**not** the project file) to
open XCode and select your build target device (iPhone 7 simulator works well).
Make sure you open the workspace, and not the similarly-named (without the `WS` suffix) project.
#### 4. Modify your sample file
#### 5. Modify your sample file
1. Select the MQTT Cleint Sample project, open the MQTT Client Sample folder, and open the ViewController.swift
2. Add your iot device Connection String to the `private let connectionString` by replacing the empty quotes with your connection string.
@ -63,7 +51,7 @@ Make sure you open the workspace, and not the similarly-named (without the `WS`
* AMQP_Protocol
Note: HTTP_Protocol does work as well.
#### 5. Run the app in the simulator
#### 6. Run the app in the simulator
Start the project (command-R).

Просмотреть файл

@ -225,7 +225,7 @@ int main(void)
device_handle = IoTHubDeviceClient_CreateFromConnectionString(connectionString, protocol);
if (device_handle == NULL)
{
(void)printf("Failure creating device client handle. Hint: Check you connection string.\r\n");
(void)printf("Failure creating device client handle. Hint: Check your connection string.\r\n");
}
else
{

Просмотреть файл

@ -122,7 +122,7 @@ int main(void)
//IoTHubDeviceClient_SetOption(device_handle1, OPTION_LOG_TRACE, &traceOn);
//IoTHubDeviceClient_SetOption(device_handle2, OPTION_LOG_TRACE, &traceOn);
#ifdef SET_TRUSTED_CERT_IN_SAMPLES
// Setting the Trusted Certificate. This is only necessary on system without
// Setting the Trusted Certificate. This is only necessary on systems without
// built in certificate stores.
IoTHubDeviceClient_SetOption(device_handle1, OPTION_TRUSTED_CERT, certificates);
IoTHubDeviceClient_SetOption(device_handle2, OPTION_TRUSTED_CERT, certificates);
@ -131,15 +131,15 @@ int main(void)
/* Here subscribe for C2D methods */
if (IoTHubDeviceClient_SetDeviceMethodCallback(device_handle1, DeviceMethodCallback, (void*)deviceId1) != IOTHUB_CLIENT_OK)
{
(void)printf("ERROR: IoTHubClient_SetDeviceMethodCallback for the first device..........FAILED!\r\n");
(void)printf("ERROR: IoTHubDeviceClient_SetDeviceMethodCallback for the first device..........FAILED!\r\n");
}
else if (IoTHubDeviceClient_SetDeviceMethodCallback(device_handle2, DeviceMethodCallback, (void*)deviceId2) != IOTHUB_CLIENT_OK)
{
(void)printf("ERROR: IoTHubClient_SetDeviceMethodCallback for the second device..........FAILED!\r\n");
(void)printf("ERROR: IoTHubDeviceClient_SetDeviceMethodCallback for the second device..........FAILED!\r\n");
}
else
{
(void)printf("IoTHubClient_SetMessageCallback...successful.\r\n");
(void)printf("IoTHubDeviceClient_SetMessageCallback...successful.\r\n");
(void)printf("Waiting for C2D methods ...\r\n");
(void)printf("Press enter to close application\r\n");

Просмотреть файл

@ -35,7 +35,7 @@ static const char* connectionString = "[device connection string]";
static const char* proxyHost = NULL;
static int proxyPort = 0;
#define HELLO_WORLD "Hello World from IoTHubClient_LL_UploadToBlob"
#define HELLO_WORLD "Hello World from IoTHubDeviceClient_LL_UploadToBlob"
int main(void)
{
@ -48,7 +48,7 @@ int main(void)
device_ll_handle = IoTHubDeviceClient_LL_CreateFromConnectionString(connectionString, HTTP_Protocol);
if (device_ll_handle == NULL)
{
(void)printf("Failure createing Iothub device. Hint: Check you connection string.\r\n");
(void)printf("Failure creating IotHub device. Hint: Check your connection string.\r\n");
}
else
{
@ -58,7 +58,7 @@ int main(void)
#endif // !WIN32
#ifdef SET_TRUSTED_CERT_IN_SAMPLES
// Setting the Trusted Certificate. This is only necessary on system with without
// Setting the Trusted Certificate. This is only necessary on systems without
// built in certificate stores.
IoTHubDeviceClient_LL_SetOption(device_ll_handle, OPTION_TRUSTED_CERT, certificates);
#endif // SET_TRUSTED_CERT_IN_SAMPLES

Просмотреть файл

@ -94,7 +94,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>GB_MEASURE_MEMORY_FOR_THIS;GB_DEBUG_ALLOC;WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -109,7 +109,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>GB_MEASURE_MEMORY_FOR_THIS;GB_DEBUG_ALLOC;WIN32;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -126,7 +126,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -145,7 +145,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -167,6 +167,6 @@
<PropertyGroup>
<ErrorText>This project references Vcpkg package(s) that are missing on this computer. For more information, see https://github.com/Azure/azure-iot-sdk-c/tree/master/doc/setting_up_vcpkg.md. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(VcpkgRoot)include\azureiot\iothub.h')" Text="$([System.String]::Format('$(ErrorText)', '$(VcpkgRoot)include\azureiot\iothub.h'))" />
<Error Condition="!Exists('$(VcpkgCurrentInstalledDir)include\azureiot\iothub.h')" Text="$([System.String]::Format('$(ErrorText)', '$(VcpkgCurrentInstalledDir)include\azureiot\iothub.h'))" />
</Target>
</Project>

Просмотреть файл

@ -33,7 +33,8 @@ static const char* connectionString = "[device connection string]";
/*Optional string with http proxy host and integer for http proxy port (Linux only) */
static const char* proxyHost = NULL;
static int proxyPort = 0;
static const char* data_to_upload = "Hello World from IoTHubClient_LL_UploadToBlob\n";
static const char* data_to_upload_format = "Hello World from IoTHubDeviceClient_LL_UploadToBlob block: %d\n";
static char data_to_upload[128];
static int block_count = 0;
static IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_RESULT getDataCallback(IOTHUB_CLIENT_FILE_UPLOAD_RESULT result, unsigned char const ** data, size_t* size, void* context)
@ -44,9 +45,12 @@ static IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_RESULT getDataCallback(IOTHUB_CLIENT_F
if (data != NULL && size != NULL)
{
// "block_count" is used to simulate reading chunks from a larger data content, like a large file.
// Note that the IoT SDK caller does NOT free(*data), as a typical use case the buffer returned
// to the IoT layer may be part of a larger buffer that this callback is chunking up for network sends.
if (block_count < 100)
{
snprintf(data_to_upload, sizeof(data_to_upload), data_to_upload_format, block_count);
*data = (const unsigned char*)data_to_upload;
*size = strlen(data_to_upload);
block_count++;
@ -90,12 +94,12 @@ int main(void)
device_ll_handle = IoTHubDeviceClient_LL_CreateFromConnectionString(connectionString, HTTP_Protocol);
if (device_ll_handle == NULL)
{
(void)printf("Failure createing Iothub device. Hint: Check you connection string.\r\n");
(void)printf("Failure creating IotHub device. Hint: Check your connection string.\r\n");
}
else
{
#ifdef SET_TRUSTED_CERT_IN_SAMPLES
// Setting the Trusted Certificate. This is only necessary on system with without
// Setting the Trusted Certificate. This is only necessary on systems without
// built in certificate stores.
IoTHubDeviceClient_LL_SetOption(device_ll_handle, OPTION_TRUSTED_CERT, certificates);
#endif // SET_TRUSTED_CERT_IN_SAMPLES

Просмотреть файл

@ -94,7 +94,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -109,7 +109,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -126,7 +126,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -145,7 +145,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -165,6 +165,6 @@
<PropertyGroup>
<ErrorText>This project references Vcpkg package(s) that are missing on this computer. For more information, see https://github.com/Azure/azure-iot-sdk-c/tree/master/doc/setting_up_vcpkg.md. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(VcpkgRoot)include\azureiot\iothub.h')" Text="$([System.String]::Format('$(ErrorText)', '$(VcpkgRoot)include\azureiot\iothub.h'))" />
<Error Condition="!Exists('$(VcpkgCurrentInstalledDir)include\azureiot\iothub.h')" Text="$([System.String]::Format('$(ErrorText)', '$(VcpkgCurrentInstalledDir)include\azureiot\iothub.h'))" />
</Target>
</Project>

Просмотреть файл

@ -201,7 +201,7 @@ int main(void)
IOTHUB_MESSAGE_HANDLE message_handle;
float telemetry_temperature;
float telemetry_humidity;
const char* telemetry_scale = "Celcius";
const char* telemetry_scale = "Celsius";
char telemetry_msg_buffer[80];
int messagecount = 0;
@ -235,7 +235,7 @@ int main(void)
device_handle = IoTHubDeviceClient_CreateFromConnectionString(connectionString, protocol);
if (device_handle == NULL)
{
(void)printf("Failure creating Iothub device. Hint: Check you connection string.\r\n");
(void)printf("Failure creating IotHub device. Hint: Check your connection string.\r\n");
}
else
{
@ -279,7 +279,7 @@ int main(void)
(void)IoTHubDeviceClient_SetOption(device_handle, OPTION_DO_WORK_FREQUENCY_IN_MS, &ms_delay);
#ifdef SET_TRUSTED_CERT_IN_SAMPLES
// Setting the Trusted Certificate. This is only necessary on system with without
// Setting the Trusted Certificate. This is only necessary on systems without
// built in certificate stores.
(void)IoTHubDeviceClient_SetOption(device_handle, OPTION_TRUSTED_CERT, certificates);
#endif // SET_TRUSTED_CERT_IN_SAMPLES

Просмотреть файл

@ -139,7 +139,7 @@ int main(void)
device_ll_handle = IoTHubDeviceClient_LL_CreateFromConnectionString(connectionString, protocol);
if (device_ll_handle == NULL)
{
(void)printf("Failure createing Iothub device. Hint: Check you connection string.\r\n");
(void)printf("Failure creating IotHub device. Hint: Check your connection string.\r\n");
}
else
{
@ -148,7 +148,7 @@ int main(void)
//bool traceOn = true;
//IoTHubDeviceClient_LL_SetOption(device_ll_handle, OPTION_LOG_TRACE, &traceOn);
#ifdef SET_TRUSTED_CERT_IN_SAMPLES
// Setting the Trusted Certificate. This is only necessary on system with without
// Setting the Trusted Certificate. This is only necessary on systems without
// built in certificate stores.
IoTHubDeviceClient_LL_SetOption(device_ll_handle, OPTION_TRUSTED_CERT, certificates);
#endif // SET_TRUSTED_CERT_IN_SAMPLES

Просмотреть файл

@ -90,7 +90,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions);USE_AMQP;USE_MQTT;USE_HTTP</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;..\..\..\..\certs</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;..\..\..\..\certs</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -113,7 +113,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions);USE_AMQP;USE_MQTT;USE_HTTP</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;..\..\..\..\certs</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;..\..\..\..\certs</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -134,7 +134,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions);USE_AMQP;USE_MQTT;USE_HTTP</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;..\..\..\..\certs</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;..\..\..\..\certs</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -161,7 +161,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions);USE_AMQP;USE_MQTT;USE_HTTP</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;..\..\..\..\certs</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;..\..\..\..\certs</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -187,6 +187,6 @@
<PropertyGroup>
<ErrorText>This project references Vcpkg package(s) that are missing on this computer. For more information, see https://github.com/Azure/azure-iot-sdk-c/tree/master/doc/setting_up_vcpkg.md. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(VcpkgRoot)include\azureiot\iothub.h')" Text="$([System.String]::Format('$(ErrorText)', '$(VcpkgRoot)include\azureiot\iothub.h'))" />
<Error Condition="!Exists('$(VcpkgCurrentInstalledDir)include\azureiot\iothub.h')" Text="$([System.String]::Format('$(ErrorText)', '$(VcpkgCurrentInstalledDir)include\azureiot\iothub.h'))" />
</Target>
</Project>

Просмотреть файл

@ -9,7 +9,7 @@
#include "azure_c_shared_utility/threadapi.h"
#include "azure_c_shared_utility/crt_abstractions.h"
#include "azure_c_shared_utility/shared_util_options.h"
#include "iothub_client.h"
#include "iothub_device_client_ll.h"
#include "iothub_message.h"
#include "iothubtransportamqp.h"
#include "iothub_client_options.h"
@ -196,8 +196,8 @@ static int create_events(EVENT_INSTANCE* events, const char* deviceId)
void iothub_client_sample_amqp_run(void)
{
TRANSPORT_HANDLE transport_handle;
IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle1;
IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle2;
IOTHUB_DEVICE_CLIENT_LL_HANDLE iotHubClientHandle1;
IOTHUB_DEVICE_CLIENT_LL_HANDLE iotHubClientHandle2;
EVENT_INSTANCE messages_device1[MESSAGE_COUNT];
EVENT_INSTANCE messages_device2[MESSAGE_COUNT];
@ -236,22 +236,22 @@ void iothub_client_sample_amqp_run(void)
config2.protocol = AMQP_Protocol;
config2.transportHandle = IoTHubTransport_GetLLTransport(transport_handle);
if ((iotHubClientHandle1 = IoTHubClient_LL_CreateWithTransport(&config1)) == NULL)
if ((iotHubClientHandle1 = IoTHubDeviceClient_LL_CreateWithTransport(&config1)) == NULL)
{
(void)printf("ERROR: iotHubClientHandle1 is NULL!\r\n");
}
else if ((iotHubClientHandle2 = IoTHubClient_LL_CreateWithTransport(&config2)) == NULL)
else if ((iotHubClientHandle2 = IoTHubDeviceClient_LL_CreateWithTransport(&config2)) == NULL)
{
(void)printf("ERROR: iotHubClientHandle1 is NULL!\r\n");
}
else
{
bool traceOn = true;
IoTHubClient_LL_SetOption(iotHubClientHandle1, OPTION_LOG_TRACE, &traceOn);
IoTHubDeviceClient_LL_SetOption(iotHubClientHandle1, OPTION_LOG_TRACE, &traceOn);
#ifdef SET_TRUSTED_CERT_IN_SAMPLES
// For mbed add the certificate information
if (IoTHubClient_LL_SetOption(iotHubClientHandle1, OPTION_TRUSTED_CERT, certificates) != IOTHUB_CLIENT_OK)
if (IoTHubDeviceClient_LL_SetOption(iotHubClientHandle1, OPTION_TRUSTED_CERT, certificates) != IOTHUB_CLIENT_OK)
{
printf("failure to set option \"TrustedCerts\"\r\n");
}
@ -262,17 +262,17 @@ void iothub_client_sample_amqp_run(void)
(void)printf("ERROR: failed creating events for the devices..........FAILED!\r\n");
}
/* Setting Message call back, so we can receive Commands. */
else if (IoTHubClient_LL_SetMessageCallback(iotHubClientHandle1, ReceiveMessageCallback, &receiveContext1) != IOTHUB_CLIENT_OK)
else if (IoTHubDeviceClient_LL_SetMessageCallback(iotHubClientHandle1, ReceiveMessageCallback, &receiveContext1) != IOTHUB_CLIENT_OK)
{
(void)printf("ERROR: IoTHubClient_SetMessageCallback for device 1..........FAILED!\r\n");
(void)printf("ERROR: IoTHubDeviceClient_SetMessageCallback for device 1..........FAILED!\r\n");
}
else if (IoTHubClient_LL_SetMessageCallback(iotHubClientHandle2, ReceiveMessageCallback, &receiveContext2) != IOTHUB_CLIENT_OK)
else if (IoTHubDeviceClient_LL_SetMessageCallback(iotHubClientHandle2, ReceiveMessageCallback, &receiveContext2) != IOTHUB_CLIENT_OK)
{
(void)printf("ERROR: IoTHubClient_SetMessageCallback for device 2..........FAILED!\r\n");
(void)printf("ERROR: IoTHubDeviceClient_SetMessageCallback for device 2..........FAILED!\r\n");
}
else
{
(void)printf("IoTHubClient_SetMessageCallback...successful.\r\n");
(void)printf("IoTHubDeviceClient_SetMessageCallback...successful.\r\n");
/* Now that we are ready to receive commands, let's send some messages */
size_t iterator = 0;
@ -280,25 +280,25 @@ void iothub_client_sample_amqp_run(void)
{
if (iterator < MESSAGE_COUNT)
{
if (IoTHubClient_LL_SendEventAsync(iotHubClientHandle1, messages_device1[iterator].messageHandle, SendConfirmationCallback, &messages_device1[iterator]) != IOTHUB_CLIENT_OK)
if (IoTHubDeviceClient_LL_SendEventAsync(iotHubClientHandle1, messages_device1[iterator].messageHandle, SendConfirmationCallback, &messages_device1[iterator]) != IOTHUB_CLIENT_OK)
{
(void)printf("ERROR: IoTHubClient_SendEventAsync for device 1..........FAILED!\r\n");
(void)printf("ERROR: IoTHubDeviceClient_SendEventAsync for device 1..........FAILED!\r\n");
}
else if (IoTHubClient_LL_SendEventAsync(iotHubClientHandle2, messages_device2[iterator].messageHandle, SendConfirmationCallback, &messages_device2[iterator]) != IOTHUB_CLIENT_OK)
else if (IoTHubDeviceClient_LL_SendEventAsync(iotHubClientHandle2, messages_device2[iterator].messageHandle, SendConfirmationCallback, &messages_device2[iterator]) != IOTHUB_CLIENT_OK)
{
(void)printf("ERROR: IoTHubClient_SendEventAsync for device 2..........FAILED!\r\n");
(void)printf("ERROR: IoTHubDeviceClient_SendEventAsync for device 2..........FAILED!\r\n");
}
else
{
(void)printf("IoTHubClient_SendEventAsync accepted data for transmission to IoT Hub.\r\n");
(void)printf("IoTHubDeviceClient_SendEventAsync accepted data for transmission to IoT Hub.\r\n");
}
IoTHubMessage_Destroy(messages_device1[iterator].messageHandle);
IoTHubMessage_Destroy(messages_device2[iterator].messageHandle);
}
IoTHubClient_LL_DoWork(iotHubClientHandle1);
IoTHubClient_LL_DoWork(iotHubClientHandle2);
IoTHubDeviceClient_LL_DoWork(iotHubClientHandle1);
IoTHubDeviceClient_LL_DoWork(iotHubClientHandle2);
ThreadAPI_Sleep(1);
iterator++;
@ -307,12 +307,12 @@ void iothub_client_sample_amqp_run(void)
(void)printf("iothub_client_sample_mqtt has gotten quit message, call DoWork %d more time to complete final sending...\r\n", DOWORK_LOOP_NUM);
for (size_t index = 0; index < DOWORK_LOOP_NUM; index++)
{
IoTHubClient_LL_DoWork(iotHubClientHandle1);
IoTHubDeviceClient_LL_DoWork(iotHubClientHandle1);
ThreadAPI_Sleep(1);
}
}
IoTHubClient_LL_Destroy(iotHubClientHandle1);
IoTHubClient_LL_Destroy(iotHubClientHandle2);
IoTHubDeviceClient_LL_Destroy(iotHubClientHandle1);
IoTHubDeviceClient_LL_Destroy(iotHubClientHandle2);
}
IoTHubTransport_Destroy(transport_handle);
}

Просмотреть файл

@ -92,7 +92,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>GB_MEASURE_MEMORY_FOR_THIS;GB_DEBUG_ALLOC;WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -107,7 +107,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -124,7 +124,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -143,7 +143,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -164,6 +164,6 @@
<PropertyGroup>
<ErrorText>This project references Vcpkg package(s) that are missing on this computer. For more information, see https://github.com/Azure/azure-iot-sdk-c/tree/master/doc/setting_up_vcpkg.md. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(VcpkgRoot)include\azureiot\iothub.h')" Text="$([System.String]::Format('$(ErrorText)', '$(VcpkgRoot)include\azureiot\iothub.h'))" />
<Error Condition="!Exists('$(VcpkgCurrentInstalledDir)include\azureiot\iothub.h')" Text="$([System.String]::Format('$(ErrorText)', '$(VcpkgCurrentInstalledDir)include\azureiot\iothub.h'))" />
</Target>
</Project>

Просмотреть файл

@ -227,7 +227,7 @@ int main(void)
//IoTHubDeviceClient_LL_SetOption(device_ll_handle1, OPTION_LOG_TRACE, &traceOn);
//IoTHubDeviceClient_LL_SetOption(device_ll_handle2, OPTION_LOG_TRACE, &traceOn);
#ifdef SET_TRUSTED_CERT_IN_SAMPLES
// Setting the Trusted Certificate. This is only necessary on system without
// Setting the Trusted Certificate. This is only necessary on systems without
// built in certificate stores.
IoTHubDeviceClient_LL_SetOption(device_ll_handle1, OPTION_TRUSTED_CERT, certificates);
IoTHubDeviceClient_LL_SetOption(device_ll_handle2, OPTION_TRUSTED_CERT, certificates);

Просмотреть файл

@ -127,7 +127,7 @@ int main(void)
device_ll_handle = IoTHubDeviceClient_LL_CreateFromConnectionString(connectionString, protocol);
if (device_ll_handle == NULL)
{
(void)printf("Failure createing Iothub device. Hint: Check you connection string.\r\n");
(void)printf("Failure creating IotHub device. Hint: Check your connection string.\r\n");
}
else
{
@ -136,7 +136,7 @@ int main(void)
//bool traceOn = true;
//IoTHubDeviceClient_LL_SetOption(device_ll_handle, OPTION_LOG_TRACE, &traceOn);
// Setting the Trusted Certificate. This is only necessary on system with without
// Setting the Trusted Certificate. This is only necessary on systems without
// built in certificate stores.
#ifdef SET_TRUSTED_CERT_IN_SAMPLES
IoTHubDeviceClient_LL_SetOption(device_ll_handle, OPTION_TRUSTED_CERT, certificates);

Просмотреть файл

@ -112,7 +112,7 @@ int main(void)
device_ll_handle = IoTHubDeviceClient_LL_CreateFromConnectionString(connectionString, protocol);
if (device_ll_handle == NULL)
{
(void)printf("Failure createing Iothub device. Hint: Check you connection string.\r\n");
(void)printf("Failure creating IotHub device. Hint: Check your connection string.\r\n");
}
else
{
@ -126,7 +126,7 @@ int main(void)
#endif
#ifdef SET_TRUSTED_CERT_IN_SAMPLES
// Setting the Trusted Certificate. This is only necessary on system with without
// Setting the Trusted Certificate. This is only necessary on systems without
// built in certificate stores.
IoTHubDeviceClient_LL_SetOption(device_ll_handle, OPTION_TRUSTED_CERT, certificates);
#endif // SET_TRUSTED_CERT_IN_SAMPLES
@ -136,7 +136,7 @@ int main(void)
//you are URL Encoding inputs yourself.
//ONLY valid for use with MQTT
//bool urlEncodeOn = true;
//IoTHubDeviceClient_LL_SetOption(iothub_ll_handle, OPTION_AUTO_URL_ENCODE_DECODE, &urlEncodeOn);
//IoTHubDeviceClient_LL_SetOption(device_ll_handle, OPTION_AUTO_URL_ENCODE_DECODE, &urlEncodeOn);
#endif
// Setting connection status callback to get indication of connection to iothub
@ -151,10 +151,14 @@ int main(void)
//message_handle = IoTHubMessage_CreateFromByteArray((const unsigned char*)msgText, strlen(msgText)));
// Set Message property
/*(void)IoTHubMessage_SetMessageId(message_handle, "MSG_ID");
/*
(void)IoTHubMessage_SetMessageId(message_handle, "MSG_ID");
(void)IoTHubMessage_SetCorrelationId(message_handle, "CORE_ID");
(void)IoTHubMessage_SetContentTypeSystemProperty(message_handle, "application%2fjson");
(void)IoTHubMessage_SetContentEncodingSystemProperty(message_handle, "utf-8");*/
(void)IoTHubMessage_SetContentEncodingSystemProperty(message_handle, "utf-8");
(void)IoTHubMessage_SetMessageCreationTimeUtcSystemProperty(message_handle, "2020-07-01T01:00:00.346Z");
*/
// Add custom properties to message
(void)IoTHubMessage_SetProperty(message_handle, "property_key", "property_value");

Просмотреть файл

@ -90,7 +90,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions);USE_AMQP;USE_MQTT;USE_HTTP</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;..\..\..\..\certs</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;..\..\..\..\certs</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -113,7 +113,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions);USE_AMQP;USE_MQTT;USE_HTTP</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;..\..\..\..\certs</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;..\..\..\..\certs</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -134,7 +134,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions);USE_AMQP;USE_MQTT;USE_HTTP</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;..\..\..\..\certs</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;..\..\..\..\certs</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -161,7 +161,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions);USE_AMQP;USE_MQTT;USE_HTTP</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\;$(VcpkgRoot)include\azureiot;..\..\..\..\certs</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\;$(VcpkgCurrentInstalledDir)include\azureiot;..\..\..\..\certs</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -187,6 +187,6 @@
<PropertyGroup>
<ErrorText>This project references Vcpkg package(s) that are missing on this computer. For more information, see https://github.com/Azure/azure-iot-sdk-c/tree/master/doc/setting_up_vcpkg.md. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(VcpkgRoot)include\azureiot\iothub.h')" Text="$([System.String]::Format('$(ErrorText)', '$(VcpkgRoot)include\azureiot\iothub.h'))" />
<Error Condition="!Exists('$(VcpkgCurrentInstalledDir)include\azureiot\iothub.h')" Text="$([System.String]::Format('$(ErrorText)', '$(VcpkgCurrentInstalledDir)include\azureiot\iothub.h'))" />
</Target>
</Project>

Просмотреть файл

@ -0,0 +1,5 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
add_sample_directory(pnp_simple_thermostat)
add_sample_directory(pnp_temperature_controller)

Просмотреть файл

@ -0,0 +1,131 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "iothub.h"
#include "iothub_device_client_ll.h"
#include "iothub_client_options.h"
#include "iothubtransportmqtt.h"
#include "pnp_device_client_ll.h"
#ifdef USE_PROV_MODULE_FULL
// DPS functionality using symmetric keys is only available if the cmake
// flags <-Duse_prov_client=ON -Dhsm_type_symm_key=ON -Drun_e2e_tests=OFF> are enabled when building the Azure IoT C SDK.
#include "pnp_dps_ll.h"
#endif
#include "azure_c_shared_utility/strings.h"
#include "azure_c_shared_utility/threadapi.h"
#include "azure_c_shared_utility/xlogging.h"
#ifdef SET_TRUSTED_CERT_IN_SAMPLES
// For devices that do not have (or want) an OS level trusted certificate store,
// but instead bring in default trusted certificates from the Azure IoT C SDK.
#include "azure_c_shared_utility/shared_util_options.h"
#include "certs.h"
#endif // SET_TRUSTED_CERT_IN_SAMPLES
//
// AllocateDeviceClientHandle does the actual createHandle call, depending on the security type
//
static IOTHUB_DEVICE_CLIENT_LL_HANDLE AllocateDeviceClientHandle(const PNP_DEVICE_CONFIGURATION* pnpDeviceConfiguration)
{
IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceHandle = NULL;
if (pnpDeviceConfiguration->securityType == PNP_CONNECTION_SECURITY_TYPE_CONNECTION_STRING)
{
if ((deviceHandle = IoTHubDeviceClient_LL_CreateFromConnectionString(pnpDeviceConfiguration->u.connectionString, MQTT_Protocol)) == NULL)
{
LogError("Failure creating IotHub client. Hint: Check your connection string");
}
}
#ifdef USE_PROV_MODULE_FULL
else if ((deviceHandle = PnP_CreateDeviceClientLLHandle_ViaDps(pnpDeviceConfiguration)) == NULL)
{
LogError("Cannot retrieve IoT Hub connection information from DPS client");
}
#endif /* USE_PROV_MODULE_FULL */
return deviceHandle;
}
IOTHUB_DEVICE_CLIENT_LL_HANDLE PnP_CreateDeviceClientLLHandle(const PNP_DEVICE_CONFIGURATION* pnpDeviceConfiguration)
{
IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceHandle = NULL;
IOTHUB_CLIENT_RESULT iothubResult;
bool urlAutoEncodeDecode = true;
int iothubInitResult;
bool result;
// Before invoking ANY IoT Hub or DPS functionality, IoTHub_Init must be invoked.
if ((iothubInitResult = IoTHub_Init()) != 0)
{
LogError("Failure to initialize client, error=%d", iothubInitResult);
result = false;
}
else if ((deviceHandle = AllocateDeviceClientHandle(pnpDeviceConfiguration)) == NULL)
{
LogError("Unable to allocate deviceHandle");
result = false;
}
// Sets verbosity level
else if ((iothubResult = IoTHubDeviceClient_LL_SetOption(deviceHandle, OPTION_LOG_TRACE, &pnpDeviceConfiguration->enableTracing)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to set logging option, error=%d", iothubResult);
result = false;
}
// Sets the name of ModelId for this PnP device.
// This *MUST* be set before the client is connected to IoTHub. We do not automatically connect when the
// handle is created, but will implicitly connect to subscribe for device method and device twin callbacks below.
else if ((iothubResult = IoTHubDeviceClient_LL_SetOption(deviceHandle, OPTION_MODEL_ID, pnpDeviceConfiguration->modelId)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to set the ModelID, error=%d", iothubResult);
result = false;
}
// Optionally, set the callback function that processes incoming device methods, which is the channel PnP Commands are transferred over
else if ((pnpDeviceConfiguration->deviceMethodCallback != NULL) && (iothubResult = IoTHubDeviceClient_LL_SetDeviceMethodCallback(deviceHandle, pnpDeviceConfiguration->deviceMethodCallback, NULL)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to set device method callback, error=%d", iothubResult);
result = false;
}
// Optionall, set the callback function that processes device twin changes from the IoTHub, which is the channel that PnP Properties are
// transferred over. This will also automatically retrieve the full twin for the application on startup.
else if ((pnpDeviceConfiguration->deviceTwinCallback != NULL) && (iothubResult = IoTHubDeviceClient_LL_SetDeviceTwinCallback(deviceHandle, pnpDeviceConfiguration->deviceTwinCallback, (void*)deviceHandle)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to set device twin callback, error=%d", iothubResult);
result = false;
}
// Enabling auto url encode will have the underlying SDK perform URL encoding operations automatically.
else if ((iothubResult = IoTHubDeviceClient_LL_SetOption(deviceHandle, OPTION_AUTO_URL_ENCODE_DECODE, &urlAutoEncodeDecode)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to set auto Url encode option, error=%d", iothubResult);
result = false;
}
#ifdef SET_TRUSTED_CERT_IN_SAMPLES
// Setting the Trusted Certificate. This is only necessary on systems without built in certificate stores.
else if ((iothubResult = IoTHubDeviceClient_LL_SetOption(deviceHandle, OPTION_TRUSTED_CERT, certificates)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to set the trusted cert, error=%d", iothubResult);
result = false;
}
#endif // SET_TRUSTED_CERT_IN_SAMPLES
else
{
result = true;
}
if ((result == false) && (deviceHandle != NULL))
{
IoTHubDeviceClient_LL_Destroy(deviceHandle);
deviceHandle = NULL;
}
if ((result == false) && (iothubInitResult == 0))
{
IoTHub_Deinit();
}
return deviceHandle;
}

Просмотреть файл

@ -0,0 +1,67 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef PNP_DEVICE_CLIENT_LL_H
#define PNP_DEVICE_CLIENT_LL_H
#include "iothub_device_client_ll.h"
//
// Whether we're using a connection string or DPS provisioning for device credentials
//
typedef enum PNP_CONNECTION_SECURITY_TYPE_TAG
{
PNP_CONNECTION_SECURITY_TYPE_CONNECTION_STRING,
PNP_CONNECTION_SECURITY_TYPE_DPS
} PNP_CONNECTION_SECURITY_TYPE;
#ifdef USE_PROV_MODULE_FULL
//
// PNP_DPS_CONNECTION_AUTH is used to configure the DPS device client
//
typedef struct PNP_DPS_CONFIGURATION_TAG
{
const char* endpoint;
const char* idScope;
const char* deviceId;
const char* deviceKey;
} PNP_DPS_CONNECTION_AUTH;
#endif /* USE_PROV_MODULE_FULL */
//
// PNP_DEVICE_CONFIGURATION is used to setup the IOTHUB_DEVICE_CLIENT_LL_HANDLE
//
typedef struct PNP_DEVICE_CONFIGURATION_TAG
{
// Whether we're using connection string or DPS
PNP_CONNECTION_SECURITY_TYPE securityType;
// The connection string or DPS security information
union {
char* connectionString;
#ifdef USE_PROV_MODULE_FULL
PNP_DPS_CONNECTION_AUTH dpsConnectionAuth;
#endif
} u;
// ModelId of this PnP device
const char* modelId;
// Whether more verbose tracing is enabled for the IoT Hub client
bool enableTracing;
// Callback for IoT Hub device methods, which is the mechanism PnP commands use. If PnP commands
// are not used, this should be NULL to conserve memory and bandwidth.
IOTHUB_CLIENT_DEVICE_METHOD_CALLBACK_ASYNC deviceMethodCallback;
// Callback for IoT Hub device twin notifications, which is the mechanism PnP properties from service use.
// If PnP properties are not configured by the server, this should be NULL to conserve memory and bandwidth.
IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK deviceTwinCallback;
} PNP_DEVICE_CONFIGURATION;
//
// PnP_CreateDeviceClientLLHandle creates an IOTHUB_DEVICE_CLIENT_LL_HANDLE that will be ready to interact with PnP.
// Beyond basic handle creation, it also sets the handle to the appropriate ModelId, optionally sets up callback functions
// for Device Method and Device Twin callbacks (to process PnP Commands and Properties, respectively)
// as well as some other basic maintenence on the handle.
//
// NOTE: When using DPS based authentication, this function can *block* until DPS responds to the request or timeout.
//
IOTHUB_DEVICE_CLIENT_LL_HANDLE PnP_CreateDeviceClientLLHandle(const PNP_DEVICE_CONFIGURATION* pnpDeviceConfiguration);
#endif /* PNP_DEVICE_CLIENT_LL_H */

Просмотреть файл

@ -0,0 +1,179 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef USE_PROV_MODULE_FULL
#error "Missing cmake flag for DPS"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "iothub_device_client_ll.h"
#include "iothubtransportmqtt.h"
#include "pnp_device_client_ll.h"
#include "azure_c_shared_utility/strings.h"
#include "azure_c_shared_utility/threadapi.h"
#include "azure_c_shared_utility/xlogging.h"
// DPS related header files
#include "azure_prov_client/iothub_security_factory.h"
#include "azure_prov_client/prov_device_client.h"
#include "azure_prov_client/prov_transport_mqtt_client.h"
#include "azure_prov_client/prov_security_factory.h"
// Format of custom DPS payload sent when registering a PnP device.
static const char g_dps_PayloadFormatForModelId[] = "{\"modelId\":\"%s\"}";
// State of DPS registration process. We cannot proceed with PnP until we get into the state PNP_DPS_REGISTRATION_SUCCEEDED.
typedef enum PNP_DPS_REGISTRATION_STATUS_TAG
{
PNP_DPS_REGISTRATION_NOT_COMPLETE,
PNP_DPS_REGISTRATION_SUCCEEDED,
PNP_DPS_REGISTRATION_FAILED
} PNP_DPS_REGISTRATION_STATUS;
PNP_DPS_REGISTRATION_STATUS g_pnpDpsRegistrationStatus;
// Maximum amount of times we'll poll for DPS registration being ready. Note that even though DPS works off of callbacks,
// the main() loop itself blocks
static const int g_dpsRegistrationMaxPolls = 60;
// Amount to sleep between querying state from DPS registration loop
static const int g_dpsRegistrationPollSleep = 1000;
// IoT Hub for this device as determined by the DPS client runtime
static char* g_dpsIothubUri;
// DeviceId for this device as determined by the DPS client runtime
static char* g_dpsDeviceId;
//
// provisioningRegisterCallback is called back by the DPS client when the DPS server has either succeeded or failed our request.
//
static void provisioningRegisterCallback(PROV_DEVICE_RESULT registerResult, const char* iothubUri, const char* deviceId, void* userContext)
{
(void)userContext;
if (registerResult != PROV_DEVICE_RESULT_OK)
{
LogError("DPS Provisioning callback called with error state %d", registerResult);
g_pnpDpsRegistrationStatus = PNP_DPS_REGISTRATION_FAILED;
}
else
{
if ((mallocAndStrcpy_s(&g_dpsIothubUri, iothubUri) != 0) ||
(mallocAndStrcpy_s(&g_dpsDeviceId, deviceId) != 0))
{
LogError("Unable to copy provisioning information");
g_pnpDpsRegistrationStatus = PNP_DPS_REGISTRATION_FAILED;
}
else
{
LogInfo("Provisioning callback indicates success. iothubUri=%s, deviceId=%s", iothubUri, deviceId);
g_pnpDpsRegistrationStatus = PNP_DPS_REGISTRATION_SUCCEEDED;
}
}
}
IOTHUB_DEVICE_CLIENT_LL_HANDLE PnP_CreateDeviceClientLLHandle_ViaDps(const PNP_DEVICE_CONFIGURATION* pnpDeviceConfiguration)
{
IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceHandle = NULL;
bool result;
PROV_DEVICE_RESULT provDeviceResult;
PROV_DEVICE_LL_HANDLE provDeviceHandle = NULL;
STRING_HANDLE modelIdPayload = NULL;
LogInfo("Initiating DPS client to retrieve IoT Hub connection information");
g_pnpDpsRegistrationStatus = PNP_DPS_REGISTRATION_NOT_COMPLETE;
if ((modelIdPayload = STRING_construct_sprintf(g_dps_PayloadFormatForModelId, pnpDeviceConfiguration->modelId)) == NULL)
{
LogError("Cannot allocate DPS payload for modelId.");
result = false;
}
else if ((prov_dev_set_symmetric_key_info(pnpDeviceConfiguration->u.dpsConnectionAuth.deviceId, pnpDeviceConfiguration->u.dpsConnectionAuth.deviceKey) != 0))
{
LogError("prov_dev_set_symmetric_key_info failed.");
result = false;
}
else if (prov_dev_security_init(SECURE_DEVICE_TYPE_SYMMETRIC_KEY) != 0)
{
LogError("prov_dev_security_init failed");
result = false;
}
else if ((provDeviceHandle = Prov_Device_LL_Create(pnpDeviceConfiguration->u.dpsConnectionAuth.endpoint, pnpDeviceConfiguration->u.dpsConnectionAuth.idScope, Prov_Device_MQTT_Protocol)) == NULL)
{
LogError("Failed calling Prov_Device_LL_Create");
result = false;
}
else if ((provDeviceResult = Prov_Device_LL_SetOption(provDeviceHandle, PROV_OPTION_LOG_TRACE, &pnpDeviceConfiguration->enableTracing)) != PROV_DEVICE_RESULT_OK)
{
LogError("Setting provisioning tracing on failed, error=%d", provDeviceResult);
result = false;
}
// This step indicates the ModelId of the device to DPS. This allows the service to (optionally) perform custom operations,
// such as allocating a different IoT Hub to devices based on their ModelId.
else if ((provDeviceResult = Prov_Device_LL_Set_Provisioning_Payload(provDeviceHandle, STRING_c_str(modelIdPayload))) != PROV_DEVICE_RESULT_OK)
{
LogError("Failed setting provisioning data, error=%d", provDeviceResult);
result = false;
}
else if ((provDeviceResult = Prov_Device_LL_Register_Device(provDeviceHandle, provisioningRegisterCallback, NULL, NULL, NULL)) != PROV_DEVICE_RESULT_OK)
{
LogError("Prov_Device_LL_Register_Device failed, error=%d", provDeviceResult);
result = false;
}
else
{
for (int i = 0; (i < g_dpsRegistrationMaxPolls) && (g_pnpDpsRegistrationStatus == PNP_DPS_REGISTRATION_NOT_COMPLETE); i++)
{
Prov_Device_LL_DoWork(provDeviceHandle);
ThreadAPI_Sleep(g_dpsRegistrationPollSleep);
}
if (g_pnpDpsRegistrationStatus == PNP_DPS_REGISTRATION_SUCCEEDED)
{
LogInfo("DPS successfully registered. Continuing on to creation of IoTHub device client handle.");
result = true;
}
else if (g_pnpDpsRegistrationStatus == PNP_DPS_REGISTRATION_NOT_COMPLETE)
{
LogError("Timed out attempting to register DPS device");
result = false;
}
else
{
LogError("Error registering device for DPS");
result = false;
}
}
// Destroy the provisioning handle here, instead of the typical convention of doing so at the end of the function.
// We do so because this handle is no longer required and because on devices with limited amounts of memory
// cannot keep this open and have a device handle (via IoTHubDeviceClient_LL_CreateFromDeviceAuth below) at the same time.
if (provDeviceHandle != NULL)
{
Prov_Device_LL_Destroy(provDeviceHandle);
}
if (result == true)
{
if (iothub_security_init(IOTHUB_SECURITY_TYPE_SYMMETRIC_KEY) != 0)
{
LogError("iothub_security_init failed");
result = false;
}
else if ((deviceHandle = IoTHubDeviceClient_LL_CreateFromDeviceAuth(g_dpsIothubUri, g_dpsDeviceId, MQTT_Protocol)) == NULL)
{
LogError("IoTHubDeviceClient_LL_CreateFromDeviceAuth failed");
result = true;
}
}
free(g_dpsIothubUri);
free(g_dpsDeviceId);
STRING_delete(modelIdPayload);
return deviceHandle;
}

Просмотреть файл

@ -0,0 +1,22 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef PNP_DPS_LL_H
#define PNP_DPS_LL_H
#include "iothub_device_client_ll.h"
#include "pnp_device_client_ll.h"
#ifndef USE_PROV_MODULE_FULL
#error "Missing cmake flag for DPS"
#endif
//
// PnP_CreateDeviceClientLLHandle_ViaDps is used to create a IOTHUB_DEVICE_CLIENT_LL_HANDLE, invoking the DPS client
// to retrieve the needed hub information.
//
// NOTE: This function will BLOCK waiting for DPS to finish provisioning.
//
IOTHUB_DEVICE_CLIENT_LL_HANDLE PnP_CreateDeviceClientLLHandle_ViaDps(const PNP_DEVICE_CONFIGURATION* pnpDeviceConfiguration);
#endif /* PNP_DPS_LL_H */

Просмотреть файл

@ -0,0 +1,328 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// Header associated with this .c file
#include "pnp_protocol.h"
// JSON parsing library
#include "parson.h"
// IoT core utility related header files
#include "azure_c_shared_utility/xlogging.h"
#include "azure_c_shared_utility/strings.h"
// Format used when building a response for a root property that does not contain metadata
static const char g_propertyWithoutResponseSchemaWithoutComponent[] = "{\"%s\":%s}";
// Format used when building a response for a component's property that does not contain metadata
static const char g_propertyWithoutResponseSchemaWithComponent[] = "{\"""%s\":{\"__t\":\"c\",\"%s\":%s}}";
// Format used when building a response for a root property that does contain metadata
static const char g_propertyWithResponseSchemaWithoutComponent[] = "{\"%s\":{\"value\":%s,\"ac\":%d,\"ad\":\"%s\",\"av\":%d}}";
// Format used when building a response for a component's property that does contain metadata
static const char g_propertyWithResponseSchemaWithComponent[] = "{\"""%s\":{\"__t\":\"c\",\"%s\":{\"value\":%s,\"ac\":%d,\"ad\":\"%s\",\"av\":%d}}}";
// Character that separates a PnP component from the specific command on the component.
static const char g_commandSeparator = '*';
// The version of the desired twin is represented by the $version metadata.
static const char g_IoTHubTwinDesiredVersion[] = "$version";
// IoTHub adds a JSON field "__t":"c" into desired top-level JSON objects that represent components. Without this marking, the object
// is treated as a property off the root component.
static const char g_IoTHubTwinPnPComponentMarker[] = "__t";
// Name of desired JSON field when retrieving a full twin.
static const char g_IoTHubTwinDesiredObjectName[] = "desired";
// Telemetry message property used to indicate the message's component.
static const char PnP_TelemetryComponentProperty[] = "$.sub";
STRING_HANDLE PnP_CreateReportedProperty(const char* componentName, const char* propertyName, const char* propertyValue)
{
STRING_HANDLE jsonToSend;
if (componentName == NULL)
{
jsonToSend = STRING_construct_sprintf(g_propertyWithoutResponseSchemaWithoutComponent, propertyName, propertyValue);
}
else
{
jsonToSend = STRING_construct_sprintf(g_propertyWithoutResponseSchemaWithComponent, componentName, propertyName, propertyValue);
}
if (jsonToSend == NULL)
{
LogError("Unable to allocate JSON buffer");
}
return jsonToSend;
}
STRING_HANDLE PnP_CreateReportedPropertyWithStatus(const char* componentName, const char* propertyName, const char* propertyValue, int result, const char* description, int ackVersion)
{
STRING_HANDLE jsonToSend;
if (componentName == NULL)
{
jsonToSend = STRING_construct_sprintf(g_propertyWithResponseSchemaWithoutComponent, propertyName, propertyValue, result, description, ackVersion);
}
else
{
jsonToSend = STRING_construct_sprintf(g_propertyWithResponseSchemaWithComponent, componentName, propertyName, propertyValue, result, description, ackVersion);
}
if (jsonToSend == NULL)
{
LogError("Unable to allocate JSON buffer");
}
return jsonToSend;
}
void PnP_ParseCommandName(const char* deviceMethodName, unsigned const char** componentName, size_t* componentNameSize, const char** pnpCommandName)
{
const char* separator;
if ((separator = strchr(deviceMethodName, g_commandSeparator)) != NULL)
{
// If a separator character is present in the device method name, then a command on a subcomponent of
// the model is being targeted (e.g. thermostat1*getMaxMinReport).
*componentName = (unsigned const char*)deviceMethodName;
*componentNameSize = separator - deviceMethodName;
*pnpCommandName = separator + 1;
}
else
{
// The separator character is optional. If it is not present, it indicates a command of the root
// component and not a subcomponent (e.g. "reboot").
*componentName = NULL;
*componentNameSize = 0;
*pnpCommandName = deviceMethodName;
}
}
IOTHUB_MESSAGE_HANDLE PnP_CreateTelemetryMessageHandle(const char* componentName, const char* telemetryData)
{
IOTHUB_MESSAGE_HANDLE messageHandle;
IOTHUB_MESSAGE_RESULT iothubMessageResult;
bool result;
if ((messageHandle = IoTHubMessage_CreateFromString(telemetryData)) == NULL)
{
LogError("IoTHubMessage_CreateFromString failed");
result = false;
}
// If the component will be used, then specify this as a property of the message.
else if ((componentName != NULL) && (iothubMessageResult = IoTHubMessage_SetProperty(messageHandle, PnP_TelemetryComponentProperty, componentName)) != IOTHUB_MESSAGE_OK)
{
LogError("IoTHubMessage_SetProperty=%s failed, error=%d", PnP_TelemetryComponentProperty, iothubMessageResult);
result = false;
}
else
{
result = true;
}
if ((result == false) && (messageHandle != NULL))
{
IoTHubMessage_Destroy(messageHandle);
messageHandle = NULL;
}
return messageHandle;
}
//
// VisitComponentProperties visits each sub element of the the given objectName in the desired JSON. Each of these sub elements corresponds to
// a property of this component, which we'll invoke the application's pnpPropertyCallback to inform.
//
static void VisitComponentProperties(const char* objectName, JSON_Value* value, int version, PnP_PropertyCallbackFunction pnpPropertyCallback, void* userContextCallback)
{
JSON_Object* object = json_value_get_object(value);
size_t numChildren = json_object_get_count(object);
for (size_t i = 0; i < numChildren; i++)
{
const char* propertyName = json_object_get_name(object, i);
JSON_Value* propertyValue = json_object_get_value_at(object, i);
if ((propertyName == NULL) || (propertyValue == NULL))
{
// This should never happen because we are simply accessing parson tree. Do not pass NULL to application in case it does occur.
LogError("Unexpected error retrieving the property name and/or value of component=%s at element at index=%lu", objectName, (unsigned long)i);
continue;
}
// When a component is received from a full twin, it will have a "__t" as one of the child elements. This is metadata that indicates
// to solutions that the JSON object corresponds to a component and not a property of the root component. Because this is
// metadata and not part of this component's modeled properties, we ignore it when processing this loop.
if (strcmp(propertyName, g_IoTHubTwinPnPComponentMarker) == 0)
{
continue;
}
// Invoke the application's passed in callback for it to process this property.
pnpPropertyCallback(objectName, propertyName, propertyValue, version, userContextCallback);
}
}
//
// IsJsonObjectAComponentInModel checks whether the objectName, read from the top-level child of the desired device twin JSON,
// is in componentsInModel that the application passed into us.
//
static bool IsJsonObjectAComponentInModel(const char* objectName, const char** componentsInModel, size_t numComponentsInModel)
{
bool result = false;
for (size_t i = 0; i < numComponentsInModel; i++)
{
if (strcmp(objectName, componentsInModel[i]) == 0)
{
result = true;
break;
}
}
return result;
}
//
// VisitDesiredObject visits each child JSON element of the desired device twin. As we parse each property out, we invoke the application's passed in pnpPropertyCallback.
//
static bool VisitDesiredObject(JSON_Object* desiredObject, const char** componentsInModel, size_t numComponentsInModel, PnP_PropertyCallbackFunction pnpPropertyCallback, void* userContextCallback)
{
JSON_Value* versionValue = NULL;
size_t numChildren;
int version;
bool result;
if ((versionValue = json_object_get_value(desiredObject, g_IoTHubTwinDesiredVersion)) == NULL)
{
LogError("Cannot retrieve %s field for twin", g_IoTHubTwinDesiredVersion);
result = false;
}
else if (json_value_get_type(versionValue) != JSONNumber)
{
LogError("JSON field %s is not a number", g_IoTHubTwinDesiredVersion);
result = false;
}
else
{
version = (int)json_value_get_number(versionValue);
numChildren = json_object_get_count(desiredObject);
// Visit each child JSON element of the desired device twin.
for (size_t i = 0; i < numChildren; i++)
{
const char* name = json_object_get_name(desiredObject, i);
JSON_Value* value = json_object_get_value_at(desiredObject, i);
if (strcmp(name, g_IoTHubTwinDesiredVersion) == 0)
{
// The version field is metadata and should be ignored in this loop.
continue;
}
if ((json_type(value) == JSONObject) && IsJsonObjectAComponentInModel(name, componentsInModel, numComponentsInModel))
{
// If this current JSON is an element AND the name is one of the componentsInModel that the application knows about,
// then this json element represents a component.
VisitComponentProperties(name, value, version, pnpPropertyCallback, userContextCallback);
}
else
{
// If the child element is NOT an object OR its not a model the application knows about, this is a property of the model's root component.
// Invoke the application's passed in callback for it to process this property.
pnpPropertyCallback(NULL, name, value, version, userContextCallback);
}
}
result = true;
}
return result;
}
//
// GetDesiredJson retrieves JSON_Object* in the JSON tree corresponding to the desired payload.
//
static JSON_Object* GetDesiredJson(DEVICE_TWIN_UPDATE_STATE updateState, JSON_Value* rootValue)
{
JSON_Object* rootObject = NULL;
JSON_Object* desiredObject;
if ((rootObject = json_value_get_object(rootValue)) == NULL)
{
LogError("Unable to get root object of JSON");
desiredObject = NULL;
}
else
{
if (updateState == DEVICE_TWIN_UPDATE_COMPLETE)
{
// For a complete update, the JSON from IoTHub will contain both "desired" and "reported" - the full twin.
// We only care about "desired" in this sample, so just retrieve it.
desiredObject = json_object_get_object(rootObject, g_IoTHubTwinDesiredObjectName);
}
else
{
// For a patch update, IoTHub does not explicitly put a "desired:" JSON envelope. The "desired-ness" is implicit
// in this case, so here we simply need the root of the JSON itself.
desiredObject = rootObject;
}
}
return desiredObject;
}
bool PnP_ProcessTwinData(DEVICE_TWIN_UPDATE_STATE updateState, const unsigned char* payload, size_t size, const char** componentsInModel, size_t numComponentsInModel, PnP_PropertyCallbackFunction pnpPropertyCallback, void* userContextCallback)
{
char* jsonStr = NULL;
JSON_Value* rootValue = NULL;
JSON_Object* desiredObject;
bool result;
if ((jsonStr = PnP_CopyPayloadToString(payload, size)) == NULL)
{
LogError("Unable to allocate twin buffer");
result = false;
}
else if ((rootValue = json_parse_string(jsonStr)) == NULL)
{
LogError("Unable to parse device twin JSON");
result = false;
}
else if ((desiredObject = GetDesiredJson(updateState, rootValue)) == NULL)
{
LogError("Cannot retrieve desired JSON object");
result = false;
}
else
{
// Visit each sub-element in the desired portion of the twin JSON and invoke pnpPropertyCallback as appropriate.
result = VisitDesiredObject(desiredObject, componentsInModel, numComponentsInModel, pnpPropertyCallback, userContextCallback);
}
json_value_free(rootValue);
free(jsonStr);
return result;
}
char* PnP_CopyPayloadToString(const unsigned char* payload, size_t size)
{
char* jsonStr;
size_t sizeToAllocate = size + 1;
if ((jsonStr = (char*)malloc(sizeToAllocate)) == NULL)
{
LogError("Unable to allocate %lu size buffer", (unsigned long)(sizeToAllocate));
}
else
{
memcpy(jsonStr, payload, size);
jsonStr[size] = '\0';
}
return jsonStr;
}

Просмотреть файл

@ -0,0 +1,85 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
// PnP is a convention built on top of existing IoTHub device transport primitives.
// This header implements functions to aide applications in serializing and deserializing PnP data.
// Note that actually sending and receiving the data from the underlying IoTHub client is the application's responsibility.
//
#ifndef PNP_PROTOCOL_H
#define PNP_PROTOCOL_H
#include "azure_c_shared_utility/strings.h"
#include "iothub_client_core_common.h"
#include "iothub_message.h"
#include "parson.h"
//
// Status codes for PnP, closely mapping to HTTP status.
//
#define PNP_STATUS_SUCCESS 200
#define PNP_STATUS_BAD_FORMAT 400
#define PNP_STATUS_NOT_FOUND 404
#define PNP_STATUS_INTERNAL_ERROR 500
//
// The PnP convention defines the maximum length of a component
//
#define PNP_MAXIMUM_COMPONENT_LENGTH 64
//
// PnP_PropertyCallbackFunction defines the function prototype the application implements to receive a callback for each PnP property in a given Device Twin.
//
typedef void (*PnP_PropertyCallbackFunction)(const char* componentName, const char* propertyName, JSON_Value* propertyValue, int version, void* userContextCallback);
//
// PnP_CreateReportedProperty returns JSON to report a property's value from the device. This does NOT contain any metadata such as
// a result code or version. It is used when sending properties that are NOT marked as <"writable": true> in the DTDL defining
// the given property.
//
// The application itself needs to send this to Device Twin, using a function such as IoTHubDeviceClient_LL_SendReportedState.
//
STRING_HANDLE PnP_CreateReportedProperty(const char* componentName, const char* propertyName, const char* propertyValue);
//
// PnP_CreateReportedProperty returns JSON to report a property's value from the device. This contains metadata such as
// a result code or version. It is used when responding to a desired property change request from the server, and in particular
// for properties marked with <"writable": true>.
// For instance, after processing a thermostat's set point the application acknowledges that it has received the request and can indicate
// whether it will attempt to honor the requset or whether the request was unsuccessful.
//
// The application itself needs to send this to Device Twin, using a function such as IoTHubDeviceClient_LL_SendReportedState.
//
STRING_HANDLE PnP_CreateReportedPropertyWithStatus(const char* componentName, const char* propertyName, const char* propertyValue, int result, const char* description, int ackVersion);
//
// PnP_ParseCommandName is invoked by the application when an incoming device method arrives. This function
// parses the device method name into the targeted (optional) component and PnP specific command. Note that
// because we don't want to allocate separate buffers for componentName and pnpCommandName and we can't modify deviceMethodName in place,
// we return the componentName as a non-NULL terminated character array with its length in componentNameSize.
//
void PnP_ParseCommandName(const char* deviceMethodName, unsigned const char** componentName, size_t* componentNameSize, const char** pnpCommandName);
//
// PnP_CreateTelemetryMessageHandle creates an IOTHUB_MESSAGE_HANDLE that contains tho contents of the telemetryData.
// If the optional componentName parameter is specified, the created message will have this as a property.
//
// The application itself needs to send this to IoTHub, using a function such as IoTHubDeviceClient_LL_SendEventAsync.
//
IOTHUB_MESSAGE_HANDLE PnP_CreateTelemetryMessageHandle(const char* componentName, const char* telemetryData);
//
// PnP_ProcessTwinData is invoked by the application when a device twin arrives to its device twin processing callback.
// PnP_ProcessTwinData will visit the children of the desired portion of the twin and invoke the device's pnpPropertyCallback
// function for each property that it visits.
//
bool PnP_ProcessTwinData(DEVICE_TWIN_UPDATE_STATE updateState, const unsigned char* payload, size_t size, const char** componentsInModel, size_t numComponentsInModel, PnP_PropertyCallbackFunction pnpPropertyCallback, void* userContextCallback);
//
// PnP_CopyTwinPayloadToString takes the payload data, which arrives as a potentially non-NULL terminated string from the IoTHub SDK, and creates
// a new copy of the data with a NULL terminator. The JSON parser this sample uses, parson, only operates over NULL terminated strings.
//
char* PnP_CopyPayloadToString(const unsigned char* payload, size_t size);
#endif /* PNP_PROTOCOL_H */

Просмотреть файл

@ -0,0 +1,17 @@
# Common utilities for PnP Sample
This directory contains sample code that your application should be able to take with little or no modification to accelerate implementing a PnP device application.
Probably the easiest way to understand how they work is to review the [pnp_temperature_controller](../pnp_temperature_controller) sample, which uses them extensively.
For reference the files are:
* `pnp_device_client` header and .c file implement a function to help create a `IOTHUB_DEVICE_CLIENT_HANDLE`. The `IOTHUB_DEVICE_CLIENT_HANDLE` is an existing IoTHub Device SDK that can be used for device <=> IoTHub communication. (There are many samples demonstrating its non-PnP uses in the [samples parent directory](../..).)
Creating a `IOTHUB_DEVICE_CLIENT_HANDLE` that works with PnP requires a few additional steps, most importantly defining the device's PnP ModelId, which this code does.
The Azure IoTHub SDK defines additional types of handles - namely `IOTHUB_DEVICE_CLIENT_LL_HANDLE` (for a device using the \_LL\_ lower layer) and for modules the analogous `IOTHUB_MODULE_CLIENT_HANDLE` and `IOTHUB_MODULE_CLIENT_LL_HANDLE`. The code in this file can easily be modified to use a different handle flavor for your code.
* `pnp_protocol` header and .c file implement functions to help with serializing and de-serializing the PnP convention. As an example of their usefulness, PnP properties are sent between the device and IoTHub using a specific JSON convention over the device twin. Functions in this header perform some of the tedious parsing and JSON string generation that your PnP application would need to do.
The functions are agnostic to the underlying transport handle used. If you use `IOTHUB_DEVICE_CLIENT_LL_HANDLE`, `IOTHUB_MODULE_CLIENT_HANDLE` or `IOTHUB_MODULE_CLIENT_LL_HANDLE` instead of the sample's `IOTHUB_DEVICE_CLIENT_HANDLE`, the `pnp_protocol` logic does not need to change.

Просмотреть файл

@ -0,0 +1,41 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
#this is CMakeLists.txt for pnp_simple_thermostat
compileAsC99()
set(pnp_simple_thermostat_c_files
pnp_simple_thermostat.c
)
IF(WIN32)
#windows needs this define
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
ENDIF(WIN32)
if(${use_prov_client})
set(pnp_simple_thermostat_c_files ${pnp_simple_thermostat_c_files} ../common/pnp_dps_ll.c)
include_directories(../common)
endif()
#Conditionally use the SDK trusted certs in the samples
if(${use_sample_trusted_cert})
add_definitions(-DSET_TRUSTED_CERT_IN_SAMPLES)
include_directories(${PROJECT_SOURCE_DIR}/certs)
set(pnp_simple_thermostat_c_files ${pnp_simple_thermostat_c_files} ${PROJECT_SOURCE_DIR}/certs/certs.c)
endif()
include_directories(. ${PROJECT_SOURCE_DIR}/deps/parson)
add_executable(pnp_simple_thermostat ${pnp_simple_thermostat_c_files})
target_link_libraries(pnp_simple_thermostat iothub_client_mqtt_transport iothub_client_mqtt_ws_transport)
linkMqttLibrary(pnp_simple_thermostat)
add_definitions(-DUSE_MQTT)
target_link_libraries(pnp_simple_thermostat iothub_client)
if(${use_prov_client})
target_link_libraries(pnp_simple_thermostat prov_device_ll_client prov_mqtt_transport)
endif()

Просмотреть файл

@ -0,0 +1,762 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This sample implements an IoT Plug and Play based thermostat. This demonstrates a *relatively* simple PnP device
// that does only acts as a thermostat and does not have additional components.
// The DigitalTwin Definition Language document describing the component implemented in this sample
// is available at https://github.com/Azure/opendigitaltwins-dtdl/blob/master/DTDL/v2/samples/Thermostat.json.
// Standard C header files
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
// IoTHub Device Client and IoT core utility related header files
#include "iothub.h"
#include "iothub_device_client_ll.h"
#include "iothub_message.h"
#include "iothub_client_options.h"
#include "iothubtransportmqtt.h"
#include "azure_c_shared_utility/threadapi.h"
#include "azure_c_shared_utility/xlogging.h"
#ifdef SET_TRUSTED_CERT_IN_SAMPLES
#include "azure_c_shared_utility/shared_util_options.h"
#include "certs.h"
#endif // SET_TRUSTED_CERT_IN_SAMPLES
#ifdef USE_PROV_MODULE_FULL
#include "pnp_dps_ll.h"
#endif // USE_PROV_MODULE_FULL
// JSON parser library
#include "parson.h"
// Environment variable used to specify how app connects to hub and the two possible values
static const char g_securityTypeEnvironmentVariable[] = "IOTHUB_DEVICE_SECURITY_TYPE";
static const char g_securityTypeConnectionStringValue[] = "connectionString";
static const char g_securityTypeDpsValue[] = "DPS";
// Environment variable used to specify this application's connection string
static const char g_connectionStringEnvironmentVariable[] = "IOTHUB_DEVICE_CONNECTION_STRING";
#ifdef USE_PROV_MODULE_FULL
// Environment variable used to specify this application's DPS id scope
static const char g_dpsIdScopeEnvironmentVariable[] = "IOTHUB_DEVICE_DPS_ID_SCOPE";
// Environment variable used to specify this application's DPS device id
static const char g_dpsDeviceIdEnvironmentVariable[] = "IOTHUB_DEVICE_DPS_DEVICE_ID";
// Environment variable used to specify this application's DPS device key
static const char g_dpsDeviceKeyEnvironmentVariable[] = "IOTHUB_DEVICE_DPS_DEVICE_KEY";
// Environment variable used to optionally specify this application's DPS id scope
static const char g_dpsEndpointEnvironmentVariable[] = "IOTHUB_DEVICE_DPS_ENDPOINT";
// Global provisioning endpoint for DPS if one is not specified via the environment
static const char g_dps_DefaultGlobalProvUri[] = "global.azure-devices-provisioning.net";
// Values of connection / security settings read from environment variables and/or DPS runtime
PNP_DEVICE_CONFIGURATION g_pnpDeviceConfiguration;
#endif // USE_PROV_MODULE_FULL
// Connection string used to authenticate device when connection strings are used
const char* g_pnpDeviceConnectionString;
// Amount of time to sleep between polling hub, in milliseconds. Set to wake up every 100 milliseconds.
static unsigned int g_sleepBetweenPollsMs = 100;
// Every time the main loop wakes up, on the g_sendTelemetryPollInterval(th) pass will send a telemetry message.
// So we will send telemetry every (g_sendTelemetryPollInterval * g_sleepBetweenPollsMs) milliseconds; 60 seconds as currently configured.
static const int g_sendTelemetryPollInterval = 600;
// Whether verbose tracing at the IoTHub client is enabled or not.
static bool g_hubClientTraceEnabled = true;
// This device's PnP ModelId.
static const char g_ThermostatModelId[] = "dtmi:com:example:Thermostat;1";
// JSON fields from desired property to retrieve.
static const char g_IoTHubTwinDesiredVersion[] = "$version";
static const char g_JSONTargetTemperature[] = "targetTemperature";
// Name of command this component supports to get report information
static const char g_getMaxMinReport[] = "getMaxMinReport";
// Return codes for device methods and desired property responses
static int g_statusSuccess = 200;
static int g_statusBadFormat = 400;
static int g_statusNotFoundStatus = 404;
static int g_statusInternalError = 500;
// An empty JSON body for PnP command responses
static const char g_JSONEmpty[] = "{}";
static const size_t g_JSONEmptySize = sizeof(g_JSONEmpty) - 1;
// The default temperature to use before any is set.
#define DEFAULT_TEMPERATURE_VALUE 22
// Current temperature of the thermostat.
static double g_currentTemperature = DEFAULT_TEMPERATURE_VALUE;
// Minimum temperature thermostat has been at during current execution run.
static double g_minTemperature = DEFAULT_TEMPERATURE_VALUE;
// Maximum temperature thermostat has been at during current execution run.
static double g_maxTemperature = DEFAULT_TEMPERATURE_VALUE;
// Number of times temperature has been updated, counting the initial setting as 1. Used to determine average temperature.
static int g_numTemperatureUpdates = 1;
// Total of all temperature updates during current execution run. Used to determine average temperature.
static double g_allTemperatures = DEFAULT_TEMPERATURE_VALUE;
// snprintf format for building getMaxMinReport
static const char g_maxMinCommandResponseFormat[] = "{\"maxTemp\":%.2f,\"minTemp\":%.2f,\"avgTemp\":%.2f,\"startTime\":\"%s\",\"endTime\":\"%s\"}";
// Format string for sending temperature telemetry
static const char g_temperatureTelemetryBodyFormat[] = "{\"temperature\":%.02f}";
// Format string to report the property maximum temperature since reboot. This is a "read only" property from the
// service solution's perspective, which means we don't need to include any sort of status codes.
static const char g_maxTemperatureSinceRebootFormat[] = "{\"maxTempSinceLastReboot\":%.2f}";
// Format string to indicate the device received an update request for the temperature. Because this is a "writeable"
// property from the service solution's perspective, we need to return a status code (HTTP status code style) and version
// for the solution to correlate the request and its status.
static const char g_targetTemperatureResponseFormat[] = "{\"targetTemperature\":{\"value\":%.2f,\"ac\":%d,\"av\":%d,\"ad\":\"%s\"}}";
// Response description is an optional, human readable message including more information
// about the setting of the temperature. Because we accept all temperature requests, we
// always indicate a success. An actual sensor could optionally return information about
// a temperature being out of range or a mechanical issue on the device on error cases.
static const char g_temperaturePropertyResponseDescription[] = "success";
// Size of buffer to store ISO 8601 time.
#define TIME_BUFFER_SIZE 128
// Format string to create an ISO 8601 time. This corresponds to the DTDL datetime schema item.
static const char g_ISO8601Format[] = "%Y-%m-%dT%H:%M:%SZ";
// Start time of the program, stored in ISO 8601 format string for UTC.
char g_ProgramStartTime[TIME_BUFFER_SIZE];
//
// CopyTwinPayloadToString takes the twin payload data, which arrives as a potentially non-NULL terminated string, and creates
// a new copy of the data with a NULL terminator. The JSON parser this sample uses, parson, only operates over NULL terminated strings.
//
static char* CopyTwinPayloadToString(const unsigned char* payload, size_t size)
{
char* jsonStr;
if ((jsonStr = (char*)malloc(size+1)) == NULL)
{
LogError("Unable to allocate %lu size buffer", (unsigned long)(size+1));
}
else
{
memcpy(jsonStr, payload, size);
jsonStr[size] = '\0';
}
return jsonStr;
}
//
// BuildUtcTimeFromCurrentTime writes the current time, in ISO 8601 format, into the specified buffer
//
static bool BuildUtcTimeFromCurrentTime(char* utcTimeBuffer, size_t utcTimeBufferSize)
{
bool result;
time_t currentTime;
struct tm * currentTimeTm;
time(&currentTime);
currentTimeTm = gmtime(&currentTime);
if (strftime(utcTimeBuffer, utcTimeBufferSize, g_ISO8601Format, currentTimeTm) == 0)
{
LogError("snprintf on UTC time failed");
result = false;
}
else
{
result = true;
}
return result;
}
//
// BuildMaxMinCommandResponse builds the response to the command for getMaxMinReport
//
static bool BuildMaxMinCommandResponse(unsigned char** response, size_t* responseSize)
{
int responseBuilderSize = 0;
unsigned char* responseBuilder = NULL;
bool result;
char currentTime[TIME_BUFFER_SIZE];
if (BuildUtcTimeFromCurrentTime(currentTime, sizeof(currentTime)) == false)
{
LogError("Unable to output the current time");
result = false;
}
else if ((responseBuilderSize = snprintf(NULL, 0, g_maxMinCommandResponseFormat, g_maxTemperature, g_minTemperature, g_allTemperatures / g_numTemperatureUpdates, g_ProgramStartTime, currentTime)) < 0)
{
LogError("snprintf to determine string length for command response failed");
result = false;
}
// We MUST allocate the response buffer. It is returned to the IoTHub SDK in the direct method callback and the SDK in turn sends this to the server.
else if ((responseBuilder = calloc(1, responseBuilderSize + 1)) == NULL)
{
LogError("Unable to allocate %lu bytes", (unsigned long)(responseBuilderSize + 1));
result = false;
}
else if ((responseBuilderSize = snprintf((char*)responseBuilder, responseBuilderSize + 1, g_maxMinCommandResponseFormat, g_maxTemperature, g_minTemperature, g_allTemperatures / g_numTemperatureUpdates, g_ProgramStartTime, currentTime)) < 0)
{
LogError("snprintf to output buffer for command response");
result = false;
}
else
{
result = true;
}
if (result == true)
{
*response = responseBuilder;
*responseSize = (size_t)responseBuilderSize;
LogInfo("Response=<%s>", (const char*)responseBuilder);
}
else
{
free(responseBuilder);
}
return result;
}
//
// SetEmptyCommandResponse sets the response to be an empty JSON. IoT Hub needs
// legal JSON, regardless of error status, so if command implementation did not set this do so here.
//
static void SetEmptyCommandResponse(unsigned char** response, size_t* responseSize, int* result)
{
if ((*response = calloc(1, g_JSONEmptySize)) == NULL)
{
LogError("Unable to allocate empty JSON response");
*result = g_statusInternalError;
}
else
{
memcpy(*response, g_JSONEmpty, g_JSONEmptySize);
*responseSize = g_JSONEmptySize;
// We only overwrite the caller's result on error; otherwise leave as it was
}
}
//
// Thermostat_DeviceMethodCallback is invoked by IoT SDK when a device method arrives.
//
static int Thermostat_DeviceMethodCallback(const char* methodName, const unsigned char* payload, size_t size, unsigned char** response, size_t* responseSize, void* userContextCallback)
{
(void)userContextCallback;
char* jsonStr = NULL;
JSON_Value* rootValue = NULL;
const char* sinceStr;
int result;
LogInfo("Device method %s arrived", methodName);
*response = NULL;
*responseSize = 0;
if (strcmp(methodName, g_getMaxMinReport) != 0)
{
LogError("Method name %s is not supported on this component", methodName);
result = g_statusNotFoundStatus;
}
else if ((jsonStr = CopyTwinPayloadToString(payload, size)) == NULL)
{
LogError("Unable to allocate twin buffer");
result = g_statusInternalError;
}
else if ((rootValue = json_parse_string(jsonStr)) == NULL)
{
LogError("Unable to parse twin JSON");
result = g_statusBadFormat;
}
// See caveats section in ../readme.md; we don't actually respect this sinceStr to keep the sample simple,
// but want to demonstrate how to parse out in any case.
else if ((sinceStr = json_value_get_string(rootValue)) == NULL)
{
LogError("Cannot retrieve since value");
result = g_statusBadFormat;
}
else if (BuildMaxMinCommandResponse(response, responseSize) == false)
{
LogError("Unable to build response");
result = g_statusInternalError;
}
else
{
LogInfo("Returning success from command request");
result = g_statusSuccess;
}
if (*response == NULL)
{
SetEmptyCommandResponse(response, responseSize, &result);
}
json_value_free(rootValue);
free(jsonStr);
return result;
}
//
// GetDesiredJson retrieves JSON_Object* in the JSON tree corresponding to the desired payload.
//
static JSON_Object* GetDesiredJson(DEVICE_TWIN_UPDATE_STATE updateState, JSON_Value* rootValue)
{
JSON_Object* rootObject = NULL;
JSON_Object* desiredObject;
if ((rootObject = json_value_get_object(rootValue)) == NULL)
{
LogError("Unable to get root object of JSON");
desiredObject = NULL;
}
else
{
if (updateState == DEVICE_TWIN_UPDATE_COMPLETE)
{
// For a complete update, the JSON from IoTHub will contain both "desired" and "reported" - the full twin.
// We only care about "desired" in this sample, so just retrieve it.
desiredObject = json_object_get_object(rootObject, "desired");
}
else
{
// For a patch update, IoTHub only sends "desired" portion of twin and does not explicitly put a "desired:" JSON envelope.
// So here we simply need the root of the JSON itself.
desiredObject = rootObject;
}
}
return desiredObject;
}
//
// UpdateTemperatureAndStatistics updates the temperature and min/max/average values
//
static void UpdateTemperatureAndStatistics(double desiredTemp, bool* maxTempUpdated)
{
if (desiredTemp > g_maxTemperature)
{
g_maxTemperature = desiredTemp;
*maxTempUpdated = true;
}
else if (desiredTemp < g_minTemperature)
{
g_minTemperature = desiredTemp;
}
g_numTemperatureUpdates++;
g_allTemperatures += desiredTemp;
g_currentTemperature = desiredTemp;
}
//
// SendTargetTemperatureReport sends a PnP property indicating the device has received the desired targeted temperature
//
static void SendTargetTemperatureReport(IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClientLL, double desiredTemp, int responseStatus, int version, const char* description)
{
IOTHUB_CLIENT_RESULT iothubClientResult;
char targetTemperatureResponseProperty[256];
if (snprintf(targetTemperatureResponseProperty, sizeof(targetTemperatureResponseProperty), g_targetTemperatureResponseFormat, desiredTemp, responseStatus, version, description) < 0)
{
LogError("snprintf building targetTemperature response failed");
}
else if ((iothubClientResult = IoTHubDeviceClient_LL_SendReportedState(deviceClientLL, (const unsigned char*)targetTemperatureResponseProperty, strlen(targetTemperatureResponseProperty), NULL, NULL)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to send reported state for target temperature. Error=%d", iothubClientResult);
}
else
{
LogInfo("Sending maxTempSinceReboot property");
}
}
//
// SendMaxTemperatureSinceReboot reports a PnP property indicating the maximum temperature since the last reboot (simulated here by lifetime of executable)
//
static void SendMaxTemperatureSinceReboot(IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClientLL)
{
IOTHUB_CLIENT_RESULT iothubClientResult;
char maxTemperatureSinceRebootProperty[256];
if (snprintf(maxTemperatureSinceRebootProperty, sizeof(maxTemperatureSinceRebootProperty), g_maxTemperatureSinceRebootFormat, g_maxTemperature) < 0)
{
LogError("snprintf building maxTemperature failed");
}
else if ((iothubClientResult = IoTHubDeviceClient_LL_SendReportedState(deviceClientLL, (const unsigned char*)maxTemperatureSinceRebootProperty, strlen(maxTemperatureSinceRebootProperty), NULL, NULL)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to send reported state for maximum temperature. Error=%d", iothubClientResult);
}
else
{
LogInfo("Sending maxTempSinceReboot property");
}
}
//
// Thermostat_DeviceTwinCallback is invoked by the IoT SDK when a twin - either full twin or a PATCH update - arrives.
//
static void Thermostat_DeviceTwinCallback(DEVICE_TWIN_UPDATE_STATE updateState, const unsigned char* payload, size_t size, void* userContextCallback)
{
// The device handle associated with this request is passed as the context, since we will need to send reported events back.
IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClientLL = (IOTHUB_DEVICE_CLIENT_LL_HANDLE)userContextCallback;
char* jsonStr = NULL;
JSON_Value* rootValue = NULL;
JSON_Object* desiredObject;
JSON_Value* versionValue = NULL;
JSON_Value* targetTemperatureValue = NULL;
LogInfo("DeviceTwin callback invoked");
if ((jsonStr = CopyTwinPayloadToString(payload, size)) == NULL)
{
LogError("Unable to allocate twin buffer");
}
else if ((rootValue = json_parse_string(jsonStr)) == NULL)
{
LogError("Unable to parse twin JSON");
}
else if ((desiredObject = GetDesiredJson(updateState, rootValue)) == NULL)
{
LogError("Cannot retrieve desired JSON object");
}
else if ((targetTemperatureValue = json_object_get_value(desiredObject, g_JSONTargetTemperature)) == NULL)
{
LogInfo("JSON property %s not specified. This is NOT an error as the server doesn't need to set this, but there is no further action to take.", g_JSONTargetTemperature);
}
else if ((versionValue = json_object_get_value(desiredObject, g_IoTHubTwinDesiredVersion)) == NULL)
{
// The $version does need to be set in *any* legitimate twin desired document. Its absence suggests
// something is fundamentally wrong with how we've received the twin and we should not proceed.
LogError("Cannot retrieve field %s for twin. The underlying IoTHub device twin protocol (NOT the service solution directly) should have specified this.", g_IoTHubTwinDesiredVersion);
}
else if (json_value_get_type(versionValue) != JSONNumber)
{
// The $version must be a number (and in practice an int) A non-numerical value indicates
// something is fundamentally wrong with how we've received the twin and we should not proceed.
LogError("JSON field %s is not a number but must be", g_IoTHubTwinDesiredVersion);
}
else if (json_value_get_type(targetTemperatureValue) != JSONNumber)
{
LogError("JSON field %s is not a number", g_JSONTargetTemperature);
}
else
{
double targetTemperature = json_value_get_number(targetTemperatureValue);
int version = (int)json_value_get_number(versionValue);
LogInfo("Received targetTemperature = %f", targetTemperature);
bool maxTempUpdated = false;
UpdateTemperatureAndStatistics(targetTemperature, &maxTempUpdated);
// The device needs to let the service know that it has received the targetTemperature desired property.
SendTargetTemperatureReport(deviceClientLL, targetTemperature, g_statusSuccess, version, g_temperaturePropertyResponseDescription);
if (maxTempUpdated)
{
// If the Maximum temperature has been updated, we also report this as a property.
SendMaxTemperatureSinceReboot(deviceClientLL);
}
}
json_value_free(rootValue);
free(jsonStr);
}
//
// Thermostat_SendCurrentTemperature sends a PnP telemetry indicating the current temperature
//
void Thermostat_SendCurrentTemperature(IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClientLL)
{
IOTHUB_MESSAGE_HANDLE messageHandle = NULL;
IOTHUB_CLIENT_RESULT iothubResult;
char temperatureStringBuffer[32];
if (snprintf(temperatureStringBuffer, sizeof(temperatureStringBuffer), g_temperatureTelemetryBodyFormat, g_currentTemperature) < 0)
{
LogError("snprintf of current temperature telemetry failed");
}
else if ((messageHandle = IoTHubMessage_CreateFromString(temperatureStringBuffer)) == NULL)
{
LogError("IoTHubMessage_CreateFromString failed");
}
else if ((iothubResult = IoTHubDeviceClient_LL_SendEventAsync(deviceClientLL, messageHandle, NULL, NULL)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to send telemetry message, error=%d", iothubResult);
}
IoTHubMessage_Destroy(messageHandle);
}
//
// GetConnectionStringFromEnvironment retrieves the connection string based on environment variable
//
static bool GetConnectionStringFromEnvironment()
{
bool result;
if ((g_pnpDeviceConnectionString = getenv(g_connectionStringEnvironmentVariable)) == NULL)
{
LogError("Cannot read environment variable=%s", g_connectionStringEnvironmentVariable);
result = false;
}
else
{
#ifdef USE_PROV_MODULE_FULL
g_pnpDeviceConfiguration.securityType = PNP_CONNECTION_SECURITY_TYPE_CONNECTION_STRING;
#endif
result = true;
}
return result;
}
//
// GetDpsFromEnvironment retrieves DPS configuration for a symmetric key based connection
// from environment variables
//
static bool GetDpsFromEnvironment()
{
#ifndef USE_PROV_MODULE_FULL
// Explain to user misconfiguration. The "run_e2e_tests" must be set to OFF because otherwise
// the e2e's test HSM layer and symmetric key logic will conflict.
LogError("DPS based authentication was requested via environment variables, but DPS is not enabled.");
LogError("DPS is an optional component of the Azure IoT C SDK. It is enabled with symmetric keys at cmake time by");
LogError("passing <-Duse_prov_client=ON -Dhsm_type_symm_key=ON -Drun_e2e_tests=OFF> to cmake's command line");
return false;
#else
bool result;
if ((g_pnpDeviceConfiguration.u.dpsConnectionAuth.endpoint = getenv(g_dpsEndpointEnvironmentVariable)) == NULL)
{
// We will fall back to standard endpoint if one is not specified
g_pnpDeviceConfiguration.u.dpsConnectionAuth.endpoint = g_dps_DefaultGlobalProvUri;
}
if ((g_pnpDeviceConfiguration.u.dpsConnectionAuth.idScope = getenv(g_dpsIdScopeEnvironmentVariable)) == NULL)
{
LogError("Cannot read environment variable=%s", g_dpsIdScopeEnvironmentVariable);
result = false;
}
else if ((g_pnpDeviceConfiguration.u.dpsConnectionAuth.deviceId = getenv(g_dpsDeviceIdEnvironmentVariable)) == NULL)
{
LogError("Cannot read environment variable=%s", g_dpsDeviceIdEnvironmentVariable);
result = false;
}
else if ((g_pnpDeviceConfiguration.u.dpsConnectionAuth.deviceKey = getenv(g_dpsDeviceKeyEnvironmentVariable)) == NULL)
{
LogError("Cannot read environment variable=%s", g_dpsDeviceKeyEnvironmentVariable);
result = false;
}
else
{
g_pnpDeviceConfiguration.securityType = PNP_CONNECTION_SECURITY_TYPE_DPS;
result = true;
}
return result;
#endif // USE_PROV_MODULE_FULL
}
//
// GetConfigurationFromEnvironment reads how to connect to the IoT Hub (using
// either a connection string or a DPS symmetric key) from the environment.
//
static bool GetConnectionSettingsFromEnvironment()
{
const char* securityTypeString;
bool result;
if ((securityTypeString = getenv(g_securityTypeEnvironmentVariable)) == NULL)
{
LogError("Cannot read environment variable=%s", g_securityTypeEnvironmentVariable);
result = false;
}
else
{
if (strcmp(securityTypeString, g_securityTypeConnectionStringValue) == 0)
{
result = GetConnectionStringFromEnvironment();
}
else if (strcmp(securityTypeString, g_securityTypeDpsValue) == 0)
{
result = GetDpsFromEnvironment();
}
else
{
LogError("Environment variable %s must be either %s or %s", g_securityTypeEnvironmentVariable, g_securityTypeConnectionStringValue, g_securityTypeDpsValue);
result = false;
}
}
return result;
}
//
// CreateDeviceClientLLHandle performs actual handle creation (but nothing more), depending
// on whether connection strings or DPS is used.
//
static IOTHUB_DEVICE_CLIENT_LL_HANDLE CreateDeviceClientLLHandle(void)
{
#ifdef USE_PROV_MODULE_FULL
if (g_pnpDeviceConfiguration.securityType == PNP_CONNECTION_SECURITY_TYPE_DPS)
{
// Pass the modelId to DPS here AND later on to IoT Hub (see SetOption on OPTION_MODEL_ID) when
// that connection is created. We need to do both because DPS does not auto-populate the modelId
// it receives on DPS connection to the IoT Hub.
g_pnpDeviceConfiguration.modelId = g_ThermostatModelId;
g_pnpDeviceConfiguration.enableTracing = g_hubClientTraceEnabled;
return PnP_CreateDeviceClientLLHandle_ViaDps(&g_pnpDeviceConfiguration);
}
#endif
return IoTHubDeviceClient_LL_CreateFromConnectionString(g_pnpDeviceConnectionString, MQTT_Protocol);
}
//
// CreateAndConfigureDeviceClientHandleForPnP creates a IOTHUB_DEVICE_CLIENT_LL_HANDLE for this application, setting its
// ModelId along with various callbacks.
//
static IOTHUB_DEVICE_CLIENT_LL_HANDLE CreateAndConfigureDeviceClientHandleForPnP(void)
{
IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceHandle = NULL;
IOTHUB_CLIENT_RESULT iothubResult;
bool urlAutoEncodeDecode = true;
int iothubInitResult;
bool result;
// Before invoking ANY IoTHub Device SDK functionality, IoTHub_Init must be invoked.
if ((iothubInitResult = IoTHub_Init()) != 0)
{
LogError("Failure to initialize client. Error=%d", iothubInitResult);
result = false;
}
// Create the deviceHandle itself.
else if ((deviceHandle = CreateDeviceClientLLHandle()) == NULL)
{
LogError("Failure creating IotHub client. Hint: Check your connection string or DPS configuration");
result = false;
}
// Sets verbosity level
else if ((iothubResult = IoTHubDeviceClient_LL_SetOption(deviceHandle, OPTION_LOG_TRACE, &g_hubClientTraceEnabled)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to set logging option, error=%d", iothubResult);
result = false;
}
// Sets the name of ModelId for this PnP device.
// This *MUST* be set before the client is connected to IoTHub. We do not automatically connect when the
// handle is created, but will implicitly connect to subscribe for device method and device twin callbacks below.
else if ((iothubResult = IoTHubDeviceClient_LL_SetOption(deviceHandle, OPTION_MODEL_ID, g_ThermostatModelId)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to set the ModelID, error=%d", iothubResult);
result = false;
}
// Sets the callback function that processes incoming device methods, which is the channel PnP Commands are transferred over
else if ((iothubResult = IoTHubDeviceClient_LL_SetDeviceMethodCallback(deviceHandle, Thermostat_DeviceMethodCallback, NULL)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to set device method callback, error=%d", iothubResult);
result = false;
}
// Sets the callback function that processes device twin changes from the IoTHub, which is the channel that PnP Properties are
// transferred over. This will also automatically retrieve the full twin for the application.
else if ((iothubResult = IoTHubDeviceClient_LL_SetDeviceTwinCallback(deviceHandle, Thermostat_DeviceTwinCallback, (void*)deviceHandle)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to set device twin callback, error=%d", iothubResult);
result = false;
}
// Enabling auto url encode will have the underlying SDK perform URL encoding operations automatically.
else if ((iothubResult = IoTHubDeviceClient_LL_SetOption(deviceHandle, OPTION_AUTO_URL_ENCODE_DECODE, &urlAutoEncodeDecode)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to set auto Url encode option, error=%d", iothubResult);
result = false;
}
#ifdef SET_TRUSTED_CERT_IN_SAMPLES
// Setting the Trusted Certificate. This is only necessary on systems without built in certificate stores.
else if ((iothubResult = IoTHubDeviceClient_LL_SetOption(deviceHandle, OPTION_TRUSTED_CERT, certificates)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to set the trusted cert, error=%d", iothubResult);
result = false;
}
#endif // SET_TRUSTED_CERT_IN_SAMPLES
else
{
result = true;
}
if ((result == false) && (deviceHandle != NULL))
{
IoTHubDeviceClient_LL_Destroy(deviceHandle);
deviceHandle = NULL;
}
if ((result == false) && (iothubInitResult == 0))
{
IoTHub_Deinit();
}
return deviceHandle;
}
int main(void)
{
IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClientLL = NULL;
if (GetConnectionSettingsFromEnvironment() == false)
{
LogError("Cannot read required environment variable(s)");
}
else if (BuildUtcTimeFromCurrentTime(g_ProgramStartTime, sizeof(g_ProgramStartTime)) == false)
{
LogError("Unable to output the program start time");
}
else if ((deviceClientLL = CreateAndConfigureDeviceClientHandleForPnP()) == NULL)
{
LogError("Failed creating IotHub device client");
}
else
{
LogInfo("Successfully created device client handle. Hit Control-C to exit program\n");
int numberOfIterations = 0;
SendMaxTemperatureSinceReboot(deviceClientLL);
while (true)
{
// Wake up periodically to poll. Even if we do not plan on sending telemetry, we still need to poll periodically in order to process
// incoming requests from the server and to do connection keep alives.
if ((numberOfIterations % g_sendTelemetryPollInterval) == 0)
{
Thermostat_SendCurrentTemperature(deviceClientLL);
}
IoTHubDeviceClient_LL_DoWork(deviceClientLL);
ThreadAPI_Sleep(g_sleepBetweenPollsMs);
numberOfIterations++;
}
// Clean up the iothub sdk handle
IoTHubDeviceClient_LL_Destroy(deviceClientLL);
// Free all the IoT SDK subsystem
IoTHub_Deinit();
}
return 0;
}

Просмотреть файл

@ -0,0 +1,9 @@
# Azure IoT Plug and Play Simple Thermostat sample
This directory contains a sample thermostat that implements the model [dtmi:com:example:Thermostat;1](https://github.com/Azure/opendigitaltwins-dtdl/blob/master/DTDL/v2/samples/Thermostat.json).
This sample is relatively straightforward, only implementing telemetry, properties, and commands *without* using sub-components. Compare this to the more complex [pnp_temperature_controller](../pnp_temperature_controller).
## Configuring the sample
See [../readme.md](../readme.md) for how to configure this sample.

Просмотреть файл

@ -0,0 +1,45 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
#this is CMakeLists.txt for pnp_temperature_controller
compileAsC99()
set(pnp_temperature_controller_c_files
pnp_temperature_controller.c
pnp_thermostat_component.c
pnp_deviceinfo_component.c
../common/pnp_device_client_ll.c
../common/pnp_protocol.c
)
IF(WIN32)
#windows needs this define
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
ENDIF(WIN32)
if(${use_prov_client})
set(pnp_temperature_controller_c_files ${pnp_temperature_controller_c_files} ../common/pnp_dps_ll.c)
endif()
#Conditionally use the SDK trusted certs in the samples
if(${use_sample_trusted_cert})
add_definitions(-DSET_TRUSTED_CERT_IN_SAMPLES)
include_directories(${PROJECT_SOURCE_DIR}/certs)
set(pnp_temperature_controller_c_files ${pnp_temperature_controller_c_files} ${PROJECT_SOURCE_DIR}/certs/certs.c)
endif()
include_directories(. ../common ${PROJECT_SOURCE_DIR}/deps/parson)
add_executable(pnp_temperature_controller ${pnp_temperature_controller_c_files})
target_link_libraries(pnp_temperature_controller iothub_client_mqtt_transport iothub_client_mqtt_ws_transport)
linkMqttLibrary(pnp_temperature_controller)
add_definitions(-DUSE_MQTT)
target_link_libraries(pnp_temperature_controller iothub_client)
if(${use_prov_client})
target_link_libraries(pnp_temperature_controller prov_device_ll_client prov_mqtt_transport)
endif()

Просмотреть файл

@ -0,0 +1,86 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// The DTDL for this interface is defined at https://repo.azureiotrepository.com/Models/dtmi:azure:DeviceManagement:DeviceInformation;1?api-version=2020-05-01-preview
// PnP routines
#include "pnp_deviceinfo_component.h"
#include "pnp_protocol.h"
// Core IoT SDK utilities
#include "azure_c_shared_utility/xlogging.h"
// Property names along with their simulated values.
// NOTE: the property values must be legal JSON values. Strings specifically must be enclosed with an extra set of quotes to be legal json string values.
// The property names in this sample do not hard-code the extra quotes because the underlying PnP sample adds this to names automatically.
#define PNP_ENCODE_STRING_FOR_JSON(str) #str
static const char PnPDeviceInfo_SoftwareVersionPropertyName[] = "swVersion";
static const char PnPDeviceInfo_SoftwareVersionPropertyValue[] = PNP_ENCODE_STRING_FOR_JSON("1.0.0.0");
static const char PnPDeviceInfo_ManufacturerPropertyName[] = "manufacturer";
static const char PnPDeviceInfo_ManufacturerPropertyValue[] = PNP_ENCODE_STRING_FOR_JSON("Sample-Manufacturer");
static const char PnPDeviceInfo_ModelPropertyName[] = "model";
static const char PnPDeviceInfo_ModelPropertyValue[] = PNP_ENCODE_STRING_FOR_JSON("sample-Model-123");
static const char PnPDeviceInfo_OsNamePropertyName[] = "osName";
static const char PnPDeviceInfo_OsNamePropertyValue[] = PNP_ENCODE_STRING_FOR_JSON("sample-OperatingSystem-name");
static const char PnPDeviceInfo_ProcessorArchitecturePropertyName[] = "processorArchitecture";
static const char PnPDeviceInfo_ProcessorArchitecturePropertyValue[] = PNP_ENCODE_STRING_FOR_JSON("Contoso-Arch-64bit");
static const char PnPDeviceInfo_ProcessorManufacturerPropertyName[] = "processorManufacturer";
static const char PnPDeviceInfo_ProcessorManufacturerPropertyValue[] = PNP_ENCODE_STRING_FOR_JSON("Processor Manufacturer(TM)");
// The storage and memory fields below are doubles. They should NOT be escaped since they will be legal JSON values when output.
static const char PnPDeviceInfo_TotalStoragePropertyName[] = "totalStorage";
static const char PnPDeviceInfo_TotalStoragePropertyValue[] = "10000";
static const char PnPDeviceInfo_TotalMemoryPropertyName[] = "totalMemory";
static const char PnPDeviceInfo_TotalMemoryPropertyValue[] = "200";
//
// SendReportedPropertyForDeviceInformation sends a property as part of DeviceInfo component.
//
static void SendReportedPropertyForDeviceInformation(IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClientLL, const char* componentName, const char* propertyName, const char* propertyValue)
{
IOTHUB_CLIENT_RESULT iothubClientResult;
STRING_HANDLE jsonToSend = NULL;
if ((jsonToSend = PnP_CreateReportedProperty(componentName, propertyName, propertyValue)) == NULL)
{
LogError("Unable to build reported property response for propertyName=%s, propertyValue=%s", propertyName, propertyValue);
}
else
{
const char* jsonToSendStr = STRING_c_str(jsonToSend);
size_t jsonToSendStrLen = strlen(jsonToSendStr);
if ((iothubClientResult = IoTHubDeviceClient_LL_SendReportedState(deviceClientLL, (const unsigned char*)jsonToSendStr, jsonToSendStrLen, NULL, NULL)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to send reported state for property=%s, error=%d", propertyName, iothubClientResult);
}
else
{
LogInfo("Sending device information property to IoTHub. propertyName=%s, propertyValue=%s", propertyName, propertyValue);
}
}
STRING_delete(jsonToSend);
}
void PnP_DeviceInfoComponent_Report_All_Properties(const char* componentName, IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClientLL)
{
// NOTE: It is possible to put multiple property updates into a single JSON and IoTHubDeviceClient_LL_SendReportedState invocation.
// This sample does not do so for clarity, though production devices should seriously consider such property update batching to
// save bandwidth. PnP_CreateReportedProperty does not currently accept arrays.
SendReportedPropertyForDeviceInformation(deviceClientLL, componentName, PnPDeviceInfo_SoftwareVersionPropertyName, PnPDeviceInfo_SoftwareVersionPropertyValue);
SendReportedPropertyForDeviceInformation(deviceClientLL, componentName, PnPDeviceInfo_ManufacturerPropertyName, PnPDeviceInfo_ManufacturerPropertyValue);
SendReportedPropertyForDeviceInformation(deviceClientLL, componentName, PnPDeviceInfo_ModelPropertyName, PnPDeviceInfo_ModelPropertyValue);
SendReportedPropertyForDeviceInformation(deviceClientLL, componentName, PnPDeviceInfo_OsNamePropertyName, PnPDeviceInfo_OsNamePropertyValue);
SendReportedPropertyForDeviceInformation(deviceClientLL, componentName, PnPDeviceInfo_ProcessorArchitecturePropertyName, PnPDeviceInfo_ProcessorArchitecturePropertyValue);
SendReportedPropertyForDeviceInformation(deviceClientLL, componentName, PnPDeviceInfo_ProcessorManufacturerPropertyName, PnPDeviceInfo_ProcessorManufacturerPropertyValue);
SendReportedPropertyForDeviceInformation(deviceClientLL, componentName, PnPDeviceInfo_TotalStoragePropertyName, PnPDeviceInfo_TotalStoragePropertyValue);
SendReportedPropertyForDeviceInformation(deviceClientLL, componentName, PnPDeviceInfo_TotalMemoryPropertyName, PnPDeviceInfo_TotalMemoryPropertyValue);
}

Просмотреть файл

@ -0,0 +1,20 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This header implements a simulated DeviceInformation interface defined by dtmi:azure:DeviceManagement:DeviceInformation;1.
// This would (if actually tied into the appropriate Operating System APIs) return information about the amount of memory,
// the OS and its version, and other information about the device itself.
// DeviceInfo only reports properties defining the device and does not accept requested properties or commands.
#ifndef PNP_DEVICEINFO_COMPONENT_H
#define PNP_DEVICEINFO_COMPONENT_H
#include "iothub_device_client_ll.h"
//
// PnP_DeviceInfoComponent_Report_All_Properties sends properties corresponding to the DeviceInfo interface to the cloud.
//
void PnP_DeviceInfoComponent_Report_All_Properties(const char* componentName, IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClientLL);
#endif /* PNP_DEVICEINFO_COMPONENT_H */

Просмотреть файл

@ -0,0 +1,533 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This sample implements a PnP based Temperature Control model. It demonstrates a complex
// model in that the model has properties, commands, and telemetry off of the root component
// as well as subcomponents.
// The DTDL for component is https://github.com/Azure/opendigitaltwins-dtdl/blob/master/DTDL/v2/samples/TemperatureController.json
// Standard C header files
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// IoTHub Device Client and IoT core utility related header files
#include "iothub.h"
#include "iothub_device_client_ll.h"
#include "iothub_client_options.h"
#include "iothub_message.h"
#include "azure_c_shared_utility/strings.h"
#include "azure_c_shared_utility/threadapi.h"
#include "azure_c_shared_utility/xlogging.h"
// PnP utilities.
#include "pnp_device_client_ll.h"
#include "pnp_protocol.h"
// Headers that provide implementation for subcomponents (the two thermostat components and DeviceInfo)
#include "pnp_thermostat_component.h"
#include "pnp_deviceinfo_component.h"
// Environment variable used to specify how app connects to hub and the two possible values
static const char g_securityTypeEnvironmentVariable[] = "IOTHUB_DEVICE_SECURITY_TYPE";
static const char g_securityTypeConnectionStringValue[] = "connectionString";
static const char g_securityTypeDpsValue[] = "DPS";
// Environment variable used to specify this application's connection string
static const char g_connectionStringEnvironmentVariable[] = "IOTHUB_DEVICE_CONNECTION_STRING";
// Values of connection / security settings read from environment variables and/or DPS runtime
PNP_DEVICE_CONFIGURATION g_pnpDeviceConfiguration;
#ifdef USE_PROV_MODULE_FULL
// Environment variable used to specify this application's DPS id scope
static const char g_dpsIdScopeEnvironmentVariable[] = "IOTHUB_DEVICE_DPS_ID_SCOPE";
// Environment variable used to specify this application's DPS device id
static const char g_dpsDeviceIdEnvironmentVariable[] = "IOTHUB_DEVICE_DPS_DEVICE_ID";
// Environment variable used to specify this application's DPS device key
static const char g_dpsDeviceKeyEnvironmentVariable[] = "IOTHUB_DEVICE_DPS_DEVICE_KEY";
// Environment variable used to optionally specify this application's DPS id scope
static const char g_dpsEndpointEnvironmentVariable[] = "IOTHUB_DEVICE_DPS_ENDPOINT";
// Global provisioning endpoint for DPS if one is not specified via the environment
static const char g_dps_DefaultGlobalProvUri[] = "global.azure-devices-provisioning.net";
#endif
// Amount of time to sleep between polling hub, in milliseconds. Set to wake up every 100 milliseconds.
static unsigned int g_sleepBetweenPollsMs = 100;
// Every time the main loop wakes up, on the g_sendTelemetryPollInterval(th) pass will send a telemetry message.
// So we will send telemetry every (g_sendTelemetryPollInterval * g_sleepBetweenPollsMs) milliseconds; 60 seconds as currently configured.
static const int g_sendTelemetryPollInterval = 600;
// Whether tracing at the IoTHub client is enabled or not.
static bool g_hubClientTraceEnabled = true;
// DTMI indicating this device's ModelId.
static const char g_temperatureControllerModelId[] = "dtmi:com:example:TemperatureController;1";
// PNP_THERMOSTAT_COMPONENT_HANDLE represent the thermostat components that are sub-components of the temperature controller.
// Note that we do NOT have an analogous DeviceInfo component handle because there is only DeviceInfo subcomponent and its
// implementation is straightforward.
PNP_THERMOSTAT_COMPONENT_HANDLE g_thermostatHandle1;
PNP_THERMOSTAT_COMPONENT_HANDLE g_thermostatHandle2;
// Name of subcomponents that TemmperatureController implements.
static const char g_thermostatComponent1Name[] = "thermostat1";
static const size_t g_thermostatComponent1Size = sizeof(g_thermostatComponent1Name) - 1;
static const char g_thermostatComponent2Name[] = "thermostat2";
static const size_t g_thermostatComponent2Size = sizeof(g_thermostatComponent2Name) - 1;
static const char g_deviceInfoComponentName[] = "deviceInformation";
static const char* g_modeledComponents[] = {g_thermostatComponent1Name, g_thermostatComponent2Name, g_deviceInfoComponentName};
static const size_t g_numModeledComponents = sizeof(g_modeledComponents) / sizeof(g_modeledComponents[0]);
// Command implemented by the TemperatureControl component itself to implement reboot.
static const char g_rebootCommand[] = "reboot";
// An empty JSON body for PnP command responses
static const char g_JSONEmpty[] = "{}";
static const size_t g_JSONEmptySize = sizeof(g_JSONEmpty) - 1;
// Minimum value we will return for working set, + some random number
static const int g_workingSetMinimum = 1000;
// Random number for working set will range between the g_workingSetMinimum and (g_workingSetMinimum+g_workingSetRandomModulo)
static const int g_workingSetRandomModulo = 500;
// Format string for sending a telemetry message with the working set.
static const char g_workingSetTelemetryFormat[] = "{\"workingSet\":%d}";
// Name of the serial number property as defined in this component's DTML
static const char g_serialNumberPropertyName[] = "serialNumber";
// Value of the serial number. NOTE: This must be a legal JSON string which requires value to be in "..."
static const char g_serialNumberPropertyValue[] = "\"serial-no-123-abc\"";
//
// PnP_TempControlComponent_InvokeRebootCommand processes the reboot command on the root interface
//
static int PnP_TempControlComponent_InvokeRebootCommand(JSON_Value* rootValue)
{
int result;
if (json_value_get_type(rootValue) != JSONNumber)
{
LogError("Delay payload is not a number");
result = PNP_STATUS_BAD_FORMAT;
}
else
{
// See caveats section in ../readme.md; we don't actually respect the delay value to keep the sample simple.
int delayInSeconds = (int)json_value_get_number(rootValue);
LogInfo("Temperature controller 'reboot' command invoked with delay=%d seconds", delayInSeconds);
result = PNP_STATUS_SUCCESS;
}
return result;
}
//
// SetEmptyCommandResponse sets the response to be an empty JSON. IoT Hub wants
// legal JSON, regardless of error status, so if command implementation did not set this do so here.
//
static void SetEmptyCommandResponse(unsigned char** response, size_t* responseSize, int* result)
{
if ((*response = calloc(1, g_JSONEmptySize)) == NULL)
{
LogError("Unable to allocate empty JSON response");
*result = PNP_STATUS_INTERNAL_ERROR;
}
else
{
memcpy(*response, g_JSONEmpty, g_JSONEmptySize);
*responseSize = g_JSONEmptySize;
// We only overwrite the caller's result on error; otherwise leave as it was
}
}
//
// PnP_TempControlComponent_DeviceMethodCallback is invoked by IoT SDK when a device method arrives.
//
static int PnP_TempControlComponent_DeviceMethodCallback(const char* methodName, const unsigned char* payload, size_t size, unsigned char** response, size_t* responseSize, void* userContextCallback)
{
(void)userContextCallback;
char* jsonStr = NULL;
JSON_Value* rootValue = NULL;
int result;
unsigned const char *componentName;
size_t componentNameSize;
const char *pnpCommandName;
*response = NULL;
*responseSize = 0;
// Parse the methodName into its PnP (optional) componentName and pnpCommandName.
PnP_ParseCommandName(methodName, &componentName, &componentNameSize, &pnpCommandName);
// Parse the JSON of the payload request.
if ((jsonStr = PnP_CopyPayloadToString(payload, size)) == NULL)
{
LogError("Unable to allocate twin buffer");
result = PNP_STATUS_INTERNAL_ERROR;
}
else if ((rootValue = json_parse_string(jsonStr)) == NULL)
{
LogError("Unable to parse twin JSON");
result = PNP_STATUS_INTERNAL_ERROR;
}
else
{
if (componentName != NULL)
{
LogInfo("Received PnP command for component=%.*s, command=%s", (int)componentNameSize, componentName, pnpCommandName);
if (strncmp((const char*)componentName, g_thermostatComponent1Name, g_thermostatComponent1Size) == 0)
{
result = PnP_ThermostatComponent_ProcessCommand(g_thermostatHandle1, pnpCommandName, rootValue, response, responseSize);
}
else if (strncmp((const char*)componentName, g_thermostatComponent2Name, g_thermostatComponent2Size) == 0)
{
result = PnP_ThermostatComponent_ProcessCommand(g_thermostatHandle2, pnpCommandName, rootValue, response, responseSize);
}
else
{
LogError("PnP component=%.*s is not supported by TemperatureController", (int)componentNameSize, componentName);
result = PNP_STATUS_NOT_FOUND;
}
}
else
{
LogInfo("Received PnP command for TemperatureController component, command=%s", pnpCommandName);
if (strcmp(pnpCommandName, g_rebootCommand) == 0)
{
result = PnP_TempControlComponent_InvokeRebootCommand(rootValue);
}
else
{
LogError("PnP command=s%s is not supported by TemperatureController", pnpCommandName);
result = PNP_STATUS_NOT_FOUND;
}
}
}
if (*response == NULL)
{
SetEmptyCommandResponse(response, responseSize, &result);
}
json_value_free(rootValue);
free(jsonStr);
return result;
}
//
// PnP_TempControlComponent_ApplicationPropertyCallback is the callback function is invoked when PnP_ProcessTwinData() visits each property.
//
static void PnP_TempControlComponent_ApplicationPropertyCallback(const char* componentName, const char* propertyName, JSON_Value* propertyValue, int version, void* userContextCallback)
{
// This sample uses the pnp_device_client.h/.c to create the IOTHUB_DEVICE_CLIENT_LL_HANDLE as well as initialize callbacks.
// The convention used is that IOTHUB_DEVICE_CLIENT_LL_HANDLE is passed as the userContextCallback on the initial twin callback.
// The pnp_protocol.h/.c pass this userContextCallback down to this visitor function.
IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClient = (IOTHUB_DEVICE_CLIENT_LL_HANDLE)userContextCallback;
if (componentName == NULL)
{
// The PnP protocol does not define a mechanism to report errors such as this to IoTHub, so
// the best we can do here is to log for diagnostics purposes.
LogError("Property=%s arrived for TemperatureControl component itself. This does not support writeable properties on it (all properties are on subcomponents)", propertyName);
}
else if (strcmp(componentName, g_thermostatComponent1Name) == 0)
{
PnP_ThermostatComponent_ProcessPropertyUpdate(g_thermostatHandle1, deviceClient, propertyName, propertyValue, version);
}
else if (strcmp(componentName, g_thermostatComponent2Name) == 0)
{
PnP_ThermostatComponent_ProcessPropertyUpdate(g_thermostatHandle2, deviceClient, propertyName, propertyValue, version);
}
else
{
LogError("Component=%s is not implemented by the TemperatureController", componentName);
}
}
//
// PnP_TempControlComponent_DeviceTwinCallback is invoked by IoT SDK when a twin - either full twin or a PATCH update - arrives.
//
static void PnP_TempControlComponent_DeviceTwinCallback(DEVICE_TWIN_UPDATE_STATE updateState, const unsigned char* payload, size_t size, void* userContextCallback)
{
// Invoke PnP_ProcessTwinData to actualy process the data. PnP_ProcessTwinData uses a visitor pattern to parse
// the JSON and then visit each property, invoking PnP_TempControlComponent_ApplicationPropertyCallback on each element.
if (PnP_ProcessTwinData(updateState, payload, size, g_modeledComponents, g_numModeledComponents, PnP_TempControlComponent_ApplicationPropertyCallback, userContextCallback) == false)
{
// If we're unable to parse the JSON for any reason (typically because the JSON is malformed or we ran out of memory)
// there is no action we can take beyond logging.
LogError("Unable to process twin json. Ignoring any desired property update requests");
}
}
//
// PnP_TempControlComponent_SendWorkingSet sends a PnP telemetry indicating the current working set of the device, in
// the unit of kibibytes (https://en.wikipedia.org/wiki/Kibibyte).
// This is a random value between g_workingSetMinimum and (g_workingSetMinimum+g_workingSetRandomModulo).
//
void PnP_TempControlComponent_SendWorkingSet(IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClient)
{
IOTHUB_MESSAGE_HANDLE messageHandle = NULL;
IOTHUB_CLIENT_RESULT iothubResult;
char workingSetTelemetryPayload[64];
int workingSet = g_workingSetMinimum + (rand() % g_workingSetRandomModulo);
if (snprintf(workingSetTelemetryPayload, sizeof(workingSetTelemetryPayload), g_workingSetTelemetryFormat, workingSet) < 0)
{
LogError("Unable to create a workingSet telemetry payload string");
}
else if ((messageHandle = PnP_CreateTelemetryMessageHandle(NULL, workingSetTelemetryPayload)) == NULL)
{
LogError("Unable to create telemetry message");
}
else if ((iothubResult = IoTHubDeviceClient_LL_SendEventAsync(deviceClient, messageHandle, NULL, NULL)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to send telemetry message, error=%d", iothubResult);
}
IoTHubMessage_Destroy(messageHandle);
}
//
// PnP_TempControlComponent_ReportSerialNumber_Property sends the "serialNumber" property to IoTHub
//
static void PnP_TempControlComponent_ReportSerialNumber_Property(IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClient)
{
IOTHUB_CLIENT_RESULT iothubClientResult;
STRING_HANDLE jsonToSend = NULL;
if ((jsonToSend = PnP_CreateReportedProperty(NULL, g_serialNumberPropertyName, g_serialNumberPropertyValue)) == NULL)
{
LogError("Unable to build serial number property");
}
else
{
const char* jsonToSendStr = STRING_c_str(jsonToSend);
size_t jsonToSendStrLen = strlen(jsonToSendStr);
if ((iothubClientResult = IoTHubDeviceClient_LL_SendReportedState(deviceClient, (const unsigned char*)jsonToSendStr, jsonToSendStrLen, NULL, NULL)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to send reported state, error=%d", iothubClientResult);
}
else
{
LogInfo("Sending serialNumber property to IoTHub");
}
}
STRING_delete(jsonToSend);
}
//
// GetConnectionStringFromEnvironment retrieves the connection string based on environment variable
//
static bool GetConnectionStringFromEnvironment()
{
bool result;
if ((g_pnpDeviceConfiguration.u.connectionString = getenv(g_connectionStringEnvironmentVariable)) == NULL)
{
LogError("Cannot read environment variable=%s", g_connectionStringEnvironmentVariable);
result = false;
}
else
{
g_pnpDeviceConfiguration.securityType = PNP_CONNECTION_SECURITY_TYPE_CONNECTION_STRING;
result = true;
}
return result;
}
//
// GetDpsFromEnvironment retrieves DPS configuration for a symmetric key based connection
// from environment variables
//
static bool GetDpsFromEnvironment()
{
#ifndef USE_PROV_MODULE_FULL
// Explain to user misconfiguration. The "run_e2e_tests" must be set to OFF because otherwise
// the e2e's test HSM layer and symmetric key logic will conflict.
LogError("DPS based authentication was requested via environment variables, but DPS is not enabled.");
LogError("DPS is an optional component of the Azure IoT C SDK. It is enabled with symmetric keys at cmake time by");
LogError("passing <-Duse_prov_client=ON -Dhsm_type_symm_key=ON -Drun_e2e_tests=OFF> to cmake's command line");
return false;
#else
bool result;
if ((g_pnpDeviceConfiguration.u.dpsConnectionAuth.endpoint = getenv(g_dpsEndpointEnvironmentVariable)) == NULL)
{
// We will fall back to standard endpoint if one is not specified
g_pnpDeviceConfiguration.u.dpsConnectionAuth.endpoint = g_dps_DefaultGlobalProvUri;
}
if ((g_pnpDeviceConfiguration.u.dpsConnectionAuth.idScope = getenv(g_dpsIdScopeEnvironmentVariable)) == NULL)
{
LogError("Cannot read environment variable=%s", g_dpsIdScopeEnvironmentVariable);
result = false;
}
else if ((g_pnpDeviceConfiguration.u.dpsConnectionAuth.deviceId = getenv(g_dpsDeviceIdEnvironmentVariable)) == NULL)
{
LogError("Cannot read environment variable=%s", g_dpsDeviceIdEnvironmentVariable);
result = false;
}
else if ((g_pnpDeviceConfiguration.u.dpsConnectionAuth.deviceKey = getenv(g_dpsDeviceKeyEnvironmentVariable)) == NULL)
{
LogError("Cannot read environment variable=%s", g_dpsDeviceKeyEnvironmentVariable);
result = false;
}
else
{
g_pnpDeviceConfiguration.securityType = PNP_CONNECTION_SECURITY_TYPE_DPS;
result = true;
}
return result;
#endif // USE_PROV_MODULE_FULL
}
//
// GetConfigurationFromEnvironment reads how to connect to the IoT Hub (using
// either a connection string or a DPS symmetric key) from the environment.
//
static bool GetConnectionSettingsFromEnvironment()
{
const char* securityTypeString;
bool result;
if ((securityTypeString = getenv(g_securityTypeEnvironmentVariable)) == NULL)
{
LogError("Cannot read environment variable=%s", g_securityTypeEnvironmentVariable);
result = false;
}
else
{
if (strcmp(securityTypeString, g_securityTypeConnectionStringValue) == 0)
{
result = GetConnectionStringFromEnvironment();
}
else if (strcmp(securityTypeString, g_securityTypeDpsValue) == 0)
{
result = GetDpsFromEnvironment();
}
else
{
LogError("Environment variable %s must be either %s or %s", g_securityTypeEnvironmentVariable, g_securityTypeConnectionStringValue, g_securityTypeDpsValue);
result = false;
}
}
return result;
}
//
// CreateDeviceClientAndAllocateComponents allocates the IOTHUB_DEVICE_CLIENT_LL_HANDLE the application will use along with thermostat components
//
static IOTHUB_DEVICE_CLIENT_LL_HANDLE CreateDeviceClientAndAllocateComponents(void)
{
IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClient = NULL;
bool result;
g_pnpDeviceConfiguration.deviceMethodCallback = PnP_TempControlComponent_DeviceMethodCallback;
g_pnpDeviceConfiguration.deviceTwinCallback = PnP_TempControlComponent_DeviceTwinCallback;
g_pnpDeviceConfiguration.enableTracing = g_hubClientTraceEnabled;
g_pnpDeviceConfiguration.modelId = g_temperatureControllerModelId;
if (GetConnectionSettingsFromEnvironment() == false)
{
LogError("Cannot read required environment variable(s)");
result = false;
}
else if ((deviceClient = PnP_CreateDeviceClientLLHandle(&g_pnpDeviceConfiguration)) == NULL)
{
LogError("Failure creating IotHub device client");
result = false;
}
else if ((g_thermostatHandle1 = PnP_ThermostatComponent_CreateHandle(g_thermostatComponent1Name)) == NULL)
{
LogError("Unable to create component handle for %s", g_thermostatComponent1Name);
result = false;
}
else if ((g_thermostatHandle2 = PnP_ThermostatComponent_CreateHandle(g_thermostatComponent2Name)) == NULL)
{
LogError("Unable to create component handle for %s", g_thermostatComponent2Name);
result = false;
}
else
{
result = true;
}
if (result == false)
{
PnP_ThermostatComponent_Destroy(g_thermostatHandle2);
PnP_ThermostatComponent_Destroy(g_thermostatHandle1);
if (deviceClient != NULL)
{
IoTHubDeviceClient_LL_Destroy(deviceClient);
IoTHub_Deinit();
deviceClient = NULL;
}
}
return deviceClient;
}
int main(void)
{
IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClient = NULL;
if ((deviceClient = CreateDeviceClientAndAllocateComponents()) == NULL)
{
LogError("Failure creating IotHub device client");
}
else
{
LogInfo("Successfully created device client. Hit Control-C to exit program\n");
int numberOfIterations = 0;
// During startup, send the non-"writeable" properties.
PnP_TempControlComponent_ReportSerialNumber_Property(deviceClient);
PnP_DeviceInfoComponent_Report_All_Properties(g_deviceInfoComponentName, deviceClient);
PnP_TempControlComponent_Report_MaxTempSinceLastReboot_Property(g_thermostatHandle1, deviceClient);
PnP_TempControlComponent_Report_MaxTempSinceLastReboot_Property(g_thermostatHandle2, deviceClient);
while (true)
{
// Wake up periodically to poll. Even if we do not plan on sending telemetry, we still need to poll periodically in order to process
// incoming requests from the server and to do connection keep alives.
if ((numberOfIterations % g_sendTelemetryPollInterval) == 0)
{
PnP_TempControlComponent_SendWorkingSet(deviceClient);
PnP_ThermostatComponent_SendTelemetry(g_thermostatHandle1, deviceClient);
PnP_ThermostatComponent_SendTelemetry(g_thermostatHandle2, deviceClient);
}
IoTHubDeviceClient_LL_DoWork(deviceClient);
ThreadAPI_Sleep(g_sleepBetweenPollsMs);
numberOfIterations++;
}
// Free the memory allocated to track simulated thermostat.
PnP_ThermostatComponent_Destroy(g_thermostatHandle2);
PnP_ThermostatComponent_Destroy(g_thermostatHandle1);
// Clean up the iothub sdk handle
IoTHubDeviceClient_LL_Destroy(deviceClient);
// Free all the sdk subsystem
IoTHub_Deinit();
}
return 0;
}

Просмотреть файл

@ -0,0 +1,371 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// Standard C header files
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
// PnP routines
#include "pnp_protocol.h"
#include "pnp_thermostat_component.h"
// Core IoT SDK utilities
#include "azure_c_shared_utility/xlogging.h"
// The default temperature to use before any is set
#define DEFAULT_TEMPERATURE_VALUE 22
// Size of buffer to store ISO 8601 time.
#define TIME_BUFFER_SIZE 128
// Name of command this component supports to retrieve a report about the component.
static const char g_getMaxMinReport[] = "getMaxMinReport";
// Names of properties for desired/reporting
static const char g_targetTemperaturePropertyName[] = "targetTemperature";
static const char g_maxTempSinceLastRebootPropertyName[] = "maxTempSinceLastReboot";
// Format string to create an ISO 8601 time. This corresponds to the DTDL datetime schema item.
static const char g_ISO8601Format[] = "%Y-%m-%dT%H:%M:%SZ";
// Format string for sending temperature telemetry
static const char g_temperatureTelemetryBodyFormat[] = "{\"temperature\":%.02f}";
// Format string for building getMaxMinReport response
static const char g_maxMinCommandResponseFormat[] = "{\"maxTemp\":%.2f,\"minTemp\":%.2f,\"avgTemp\":%.2f,\"startTime\":\"%s\",\"endTime\":\"%s\"}";
// Format string for sending maxTempSinceLastReboot property
static const char g_maxTempSinceLastRebootPropertyFormat[] = "%.2f";
// Format of the body when responding to a targetTemperature
static const char g_targetTemperaturePropertyResponseFormat[] = "%.2f";
// Start time of the program, stored in ISO 8601 format string for UTC
char g_programStartTime[TIME_BUFFER_SIZE] = {0};
// Response description is an optional, human readable message including more information
// about the setting of the temperature. Because we accept all temperature requests, we
// always indicate a success. An actual sensor could optionally return information about
// a temperature being out of range or a mechanical issue on the device on error cases.
static const char g_temperaturePropertyResponseDescription[] = "success";
//
// PNP_THERMOSTAT_COMPONENT simulates a thermostat component
// (as in thermostat1 or thermostat2 in the TemperatureController model). We need separate data structures
// because the components can be independently controlled.
//
typedef struct PNP_THERMOSTAT_COMPONENT_TAG
{
// Name of this component
char componentName[PNP_MAXIMUM_COMPONENT_LENGTH + 1];
// Current temperature of this thermostat component
double currentTemperature;
// Minimum temperature this thermostat has been at during current execution run of this thermostat component
double minTemperature;
// Maximum temperature thermostat has been at during current execution run of this thermostat component
double maxTemperature;
// Number of times temperature has been updated, counting the initial setting as 1. Used to determine average temperature of this thermostat component
int numTemperatureUpdates;
// Total of all temperature updates during current execution run. Used to determine average temperature of this thermostat component
double allTemperatures;
}
PNP_THERMOSTAT_COMPONENT;
//
// BuildUtcTimeFromCurrentTime writes the current time, in ISO 8601 format, into the specified buffer
//
static bool BuildUtcTimeFromCurrentTime(char* utcTimeBuffer, size_t utcTimeBufferSize)
{
bool result;
time_t currentTime;
struct tm * currentTimeTm;
time(&currentTime);
currentTimeTm = gmtime(&currentTime);
if (strftime(utcTimeBuffer, utcTimeBufferSize, g_ISO8601Format, currentTimeTm) == 0)
{
LogError("snprintf on UTC time failed");
result = false;
}
else
{
result = true;
}
return result;
}
PNP_THERMOSTAT_COMPONENT_HANDLE PnP_ThermostatComponent_CreateHandle(const char* componentName)
{
PNP_THERMOSTAT_COMPONENT* thermostatComponent;
if (strlen(componentName) > PNP_MAXIMUM_COMPONENT_LENGTH)
{
LogError("componentName=%s is too long. Maximum length is=%d", componentName, PNP_MAXIMUM_COMPONENT_LENGTH);
thermostatComponent = NULL;
}
// On initial invocation, store the UTC time into g_programStartTime global.
else if ((g_programStartTime[0] == 0) && (BuildUtcTimeFromCurrentTime(g_programStartTime, sizeof(g_programStartTime)) == false))
{
LogError("Unable to store program start time");
thermostatComponent = NULL;
}
else if ((thermostatComponent = (PNP_THERMOSTAT_COMPONENT*)calloc(1, sizeof(PNP_THERMOSTAT_COMPONENT))) == NULL)
{
LogError("Unable to allocate thermostat");
}
else
{
strcpy(thermostatComponent->componentName, componentName);
thermostatComponent->currentTemperature = DEFAULT_TEMPERATURE_VALUE;
thermostatComponent->maxTemperature = DEFAULT_TEMPERATURE_VALUE;
thermostatComponent->minTemperature = DEFAULT_TEMPERATURE_VALUE;
thermostatComponent->numTemperatureUpdates = 1;
thermostatComponent->allTemperatures = DEFAULT_TEMPERATURE_VALUE;
}
return (PNP_THERMOSTAT_COMPONENT_HANDLE)thermostatComponent;
}
void PnP_ThermostatComponent_Destroy(PNP_THERMOSTAT_COMPONENT_HANDLE pnpThermostatComponentHandle)
{
if (pnpThermostatComponentHandle != NULL)
{
free(pnpThermostatComponentHandle);
}
}
//
// BuildMaxMinCommandResponse builds the response to the command for getMaxMinReport
//
static bool BuildMaxMinCommandResponse(PNP_THERMOSTAT_COMPONENT* pnpThermostatComponent, unsigned char** response, size_t* responseSize)
{
int responseBuilderSize = 0;
unsigned char* responseBuilder = NULL;
bool result;
char currentTime[TIME_BUFFER_SIZE];
if (BuildUtcTimeFromCurrentTime(currentTime, sizeof(currentTime)) == false)
{
LogError("Unable to output the current time");
result = false;
}
else if ((responseBuilderSize = snprintf(NULL, 0, g_maxMinCommandResponseFormat, pnpThermostatComponent->maxTemperature, pnpThermostatComponent->minTemperature,
pnpThermostatComponent->allTemperatures / pnpThermostatComponent->numTemperatureUpdates, g_programStartTime, currentTime)) < 0)
{
LogError("snprintf to determine string length for command response failed");
result = false;
}
// We MUST allocate the response buffer. It is returned to the IoTHub SDK in the direct method callback and the SDK in turn sends this to the server.
else if ((responseBuilder = calloc(1, responseBuilderSize + 1)) == NULL)
{
LogError("Unable to allocate %lu bytes", (unsigned long)(responseBuilderSize + 1));
result = false;
}
else if ((responseBuilderSize = snprintf((char*)responseBuilder, responseBuilderSize + 1, g_maxMinCommandResponseFormat, pnpThermostatComponent->maxTemperature, pnpThermostatComponent->minTemperature,
pnpThermostatComponent->allTemperatures / pnpThermostatComponent->numTemperatureUpdates, g_programStartTime, currentTime)) < 0)
{
LogError("snprintf to output buffer for command response");
result = false;
}
else
{
result = true;
}
if (result == true)
{
*response = responseBuilder;
*responseSize = (size_t)responseBuilderSize;
}
else
{
free(responseBuilder);
}
return result;
}
int PnP_ThermostatComponent_ProcessCommand(PNP_THERMOSTAT_COMPONENT_HANDLE pnpThermostatComponentHandle, const char *pnpCommandName, JSON_Value* commandJsonValue, unsigned char** response, size_t* responseSize)
{
PNP_THERMOSTAT_COMPONENT* pnpThermostatComponent = (PNP_THERMOSTAT_COMPONENT*)pnpThermostatComponentHandle;
const char* sinceStr;
int result;
if (strcmp(pnpCommandName, g_getMaxMinReport) != 0)
{
LogError("PnP command=%s is not supported on thermostat component", pnpCommandName);
result = PNP_STATUS_NOT_FOUND;
}
// See caveats section in ../readme.md; we don't actually respect this sinceStr to keep the sample simple,
// but want to demonstrate how to parse out in any case.
else if ((sinceStr = json_value_get_string(commandJsonValue)) == NULL)
{
LogError("Cannot retrieve JSON string for command");
result = PNP_STATUS_BAD_FORMAT;
}
else if (BuildMaxMinCommandResponse(pnpThermostatComponent, response, responseSize) == false)
{
LogError("Unable to build response for component=%s", pnpThermostatComponent->componentName);
result = PNP_STATUS_INTERNAL_ERROR;
}
else
{
LogInfo("Returning success from command request for component=%s", pnpThermostatComponent->componentName);
result = PNP_STATUS_SUCCESS;
}
return result;
}
//
// UpdateTemperatureAndStatistics updates the temperature and min/max/average values
//
static void UpdateTemperatureAndStatistics(PNP_THERMOSTAT_COMPONENT* pnpThermostatComponent, double desiredTemp, bool* maxTempUpdated)
{
if (desiredTemp > pnpThermostatComponent->maxTemperature)
{
pnpThermostatComponent->maxTemperature = desiredTemp;
*maxTempUpdated = true;
}
else
{
*maxTempUpdated = false;
if (desiredTemp < pnpThermostatComponent->minTemperature)
{
pnpThermostatComponent->minTemperature = desiredTemp;
*maxTempUpdated = false;
}
}
pnpThermostatComponent->numTemperatureUpdates++;
pnpThermostatComponent->allTemperatures += desiredTemp;
pnpThermostatComponent->currentTemperature = desiredTemp;
}
//
// SendTargetTemperatureResponse sends a PnP property indicating the device has received the desired targeted temperature
//
static void SendTargetTemperatureResponse(PNP_THERMOSTAT_COMPONENT* pnpThermostatComponent, IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClientLL, int version)
{
char targetTemperatureAsString[32];
IOTHUB_CLIENT_RESULT iothubClientResult;
STRING_HANDLE jsonToSend = NULL;
if (snprintf(targetTemperatureAsString, sizeof(targetTemperatureAsString), g_targetTemperaturePropertyResponseFormat, pnpThermostatComponent->currentTemperature) < 0)
{
LogError("Unable to create target temperature string for reporting result");
}
else if ((jsonToSend = PnP_CreateReportedPropertyWithStatus(pnpThermostatComponent->componentName, g_targetTemperaturePropertyName, targetTemperatureAsString,
PNP_STATUS_SUCCESS, g_temperaturePropertyResponseDescription, version)) == NULL)
{
LogError("Unable to build reported property response");
}
else
{
const char* jsonToSendStr = STRING_c_str(jsonToSend);
size_t jsonToSendStrLen = strlen(jsonToSendStr);
if ((iothubClientResult = IoTHubDeviceClient_LL_SendReportedState(deviceClientLL, (const unsigned char*)jsonToSendStr, jsonToSendStrLen, NULL, NULL)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to send reported state, error=%d", iothubClientResult);
}
else
{
LogInfo("Sending acknowledgement of property to IoTHub for component=%s", pnpThermostatComponent->componentName);
}
}
STRING_delete(jsonToSend);
}
void PnP_TempControlComponent_Report_MaxTempSinceLastReboot_Property(PNP_THERMOSTAT_COMPONENT_HANDLE pnpThermostatComponentHandle, IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClientLL)
{
PNP_THERMOSTAT_COMPONENT* pnpThermostatComponent = (PNP_THERMOSTAT_COMPONENT*)pnpThermostatComponentHandle;
char maximumTemperatureAsString[32];
IOTHUB_CLIENT_RESULT iothubClientResult;
STRING_HANDLE jsonToSend = NULL;
if (snprintf(maximumTemperatureAsString, sizeof(maximumTemperatureAsString), g_maxTempSinceLastRebootPropertyFormat, pnpThermostatComponent->maxTemperature) < 0)
{
LogError("Unable to create max temp since last reboot string for reporting result");
}
else if ((jsonToSend = PnP_CreateReportedProperty(pnpThermostatComponent->componentName, g_maxTempSinceLastRebootPropertyName, maximumTemperatureAsString)) == NULL)
{
LogError("Unable to build max temp since last reboot property");
}
else
{
const char* jsonToSendStr = STRING_c_str(jsonToSend);
size_t jsonToSendStrLen = strlen(jsonToSendStr);
if ((iothubClientResult = IoTHubDeviceClient_LL_SendReportedState(deviceClientLL, (const unsigned char*)jsonToSendStr, jsonToSendStrLen, NULL, NULL)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to send reported state, error=%d", iothubClientResult);
}
else
{
LogInfo("Sending maximumTemperatureSinceLastReboot property to IoTHub for component=%s", pnpThermostatComponent->componentName);
}
}
STRING_delete(jsonToSend);
}
void PnP_ThermostatComponent_ProcessPropertyUpdate(PNP_THERMOSTAT_COMPONENT_HANDLE pnpThermostatComponentHandle, IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClientLL, const char* propertyName, JSON_Value* propertyValue, int version)
{
PNP_THERMOSTAT_COMPONENT* pnpThermostatComponent = (PNP_THERMOSTAT_COMPONENT*)pnpThermostatComponentHandle;
if (strcmp(propertyName, g_targetTemperaturePropertyName) != 0)
{
LogError("Property=%s was requested to be changed but is not part of the thermostat interface definition", propertyName);
}
else if (json_value_get_type(propertyValue) != JSONNumber)
{
LogError("JSON field %s is not a number", g_targetTemperaturePropertyName);
}
else
{
double targetTemperature = json_value_get_number(propertyValue);
LogInfo("Received targetTemperature=%f for component=%s", targetTemperature, pnpThermostatComponent->componentName);
bool maxTempUpdated = false;
UpdateTemperatureAndStatistics(pnpThermostatComponent, targetTemperature, &maxTempUpdated);
// The device needs to let the service know that it has received the targetTemperature desired property.
SendTargetTemperatureResponse(pnpThermostatComponent, deviceClientLL, version);
if (maxTempUpdated)
{
// If the Maximum temperature has been updated, we also report this as a property.
PnP_TempControlComponent_Report_MaxTempSinceLastReboot_Property(pnpThermostatComponent, deviceClientLL);
}
}
}
void PnP_ThermostatComponent_SendTelemetry(PNP_THERMOSTAT_COMPONENT_HANDLE pnpThermostatComponentHandle, IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClientLL)
{
PNP_THERMOSTAT_COMPONENT* pnpThermostatComponent = (PNP_THERMOSTAT_COMPONENT*)pnpThermostatComponentHandle;
IOTHUB_MESSAGE_HANDLE messageHandle = NULL;
IOTHUB_CLIENT_RESULT iothubResult;
char temperatureStringBuffer[32];
if (snprintf(temperatureStringBuffer, sizeof(temperatureStringBuffer), g_temperatureTelemetryBodyFormat, pnpThermostatComponent->currentTemperature) < 0)
{
LogError("snprintf of current temperature telemetry failed");
}
else if ((messageHandle = PnP_CreateTelemetryMessageHandle(pnpThermostatComponent->componentName, temperatureStringBuffer)) == NULL)
{
LogError("Unable to create telemetry message");
}
else if ((iothubResult = IoTHubDeviceClient_LL_SendEventAsync(deviceClientLL, messageHandle, NULL, NULL)) != IOTHUB_CLIENT_OK)
{
LogError("Unable to send telemetry message, error=%d", iothubResult);
}
IoTHubMessage_Destroy(messageHandle);
}

Просмотреть файл

@ -0,0 +1,59 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This header implements a simulated thermostat as defined by dtmi:com:example:Thermostat;1. In particular,
// this Thermostat component is defined to be run as a subcomponent by the temperature controller interface
// defined by https://github.com/Azure/opendigitaltwins-dtdl/blob/master/DTDL/v2/samples/TemperatureController.json. The
// temperature controller defines two components that implement dtmi:com:example:Thermostat;1, named thermostat1 and
// thermostat2.
//
// The code in this header/.c file is designed to be generic so that the calling application can call PnP_ThermostatComponent_CreateHandle
// multiple times and then pass processing of a given component (thermostat1 or thermostat2) to the appropriate function.
//
#ifndef PNP_THERMOSTAT_CONTROLLER_H
#define PNP_THERMOSTAT_CONTROLLER_H
#include "parson.h"
#include "iothub_device_client_ll.h"
//
// Handle representing a thermostat component.
//
typedef void* PNP_THERMOSTAT_COMPONENT_HANDLE;
//
// PnP_ThermostatComponent_CreateHandle allocates a handle to correspond to the thermostat controller.
// This operation is only for allocation and does NOT invoke any I/O operations.
//
PNP_THERMOSTAT_COMPONENT_HANDLE PnP_ThermostatComponent_CreateHandle(const char* componentName);
//
// PnP_ThermostatComponent_Destroy frees resources associated with pnpThermostatComponentHandle.
//
void PnP_ThermostatComponent_Destroy(PNP_THERMOSTAT_COMPONENT_HANDLE pnpThermostatComponentHandle);
//
// PnP_ThermostatComponent_ProcessCommand is used to process any incoming PnP Commands, transferred via the IoTHub device method channel,
// to the given PNP_THERMOSTAT_COMPONENT_HANDLE. The function returns an HTTP style return code to indicate success or failure.
//
int PnP_ThermostatComponent_ProcessCommand(PNP_THERMOSTAT_COMPONENT_HANDLE pnpThermostatComponentHandle, const char *pnpCommandName, JSON_Value* commandJsonValue, unsigned char** response, size_t* responseSize);
//
// PnP_ThermostatComponent_ProcessPropertyUpdate processes an incoming property update and, if the property is in the thermostat's model, will
// send a reported property acknowledging receipt of the property request from IoTHub.
//
void PnP_ThermostatComponent_ProcessPropertyUpdate(PNP_THERMOSTAT_COMPONENT_HANDLE pnpThermostatComponentHandle, IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClientLL, const char* propertyName, JSON_Value* propertyValue, int version);
//
// PnP_ThermostatComponent_SendTelemetry sends telemetry indicating the current temperature of the thermostat.
//
void PnP_ThermostatComponent_SendTelemetry(PNP_THERMOSTAT_COMPONENT_HANDLE pnpThermostatComponentHandle, IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClientLL);
//
// PnP_TempControlComponent_Report_MaxTempSinceLastReboot_Property sends a property indicating maxTempSinceLastReboot. Since
// this property is not "writeable" in the DTDL, the application can invoke this at startup.
//
void PnP_TempControlComponent_Report_MaxTempSinceLastReboot_Property(PNP_THERMOSTAT_COMPONENT_HANDLE pnpThermostatComponentHandle, IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClientLL);
#endif /* PNP_THERMOSTAT_CONTROLLER_H */

Просмотреть файл

@ -0,0 +1,23 @@
# Azure IoT Plug and Play Temperature Controller sample
This directory contains a sample a temperature controller that implements the model [dtmi:com:example:TemperatureController;1](https://github.com/Azure/opendigitaltwins-dtdl/blob/master/DTDL/v2/samples/TemperatureController.json).
The model consists of:
* The `reboot` command, `serialNumber` property, and `workingSet` telemetry that the temperature controller implements on the root interface.
* Two thermostat subcomponents, `thermostat1` and `thermostat2`. (To get a sense of this sample's greater complexity compared to the simpler one, [pnp_simple_thermostat](../pnp_simple_thermostat) *only* implemented a single thermostat with no subcomponents. The sample in this directory has two such thermostats in addition to everything else.)
* A `deviceInfo` component that reports properties about the device itself.
Note that the individual components are in separate .c and .h files for easier composition.
* [pnp_thermostat_component.c](./pnp_thermostat_component.c) implements the root temperature controller component. Because this is the root component, this code also handles routing to the subcomponents. For instance, if a PnP command is intended for `thermostat1`, code in this file first needs to parse this and route to the appropriate logic.
* [pnp_deviceinfo_component.c](./pnp_deviceinfo_component.c) implements a simple, simulated DeviceInformation component whose DTDL is defined [here](https://repo.azureiotrepository.com/Models/dtmi:azure:DeviceManagement:DeviceInformation;1?api-version=2020-05-01-preview). This component only does a one-time reporting of the device state on program initiation.
* [pnp_thermostat_component.c](./pnp_thermostat_component.c) implements a thermostat component. The temperature controller can have multiple components of the same type. The components `thermostat1` and `thermostat2` both implement `dtmi:com:example:Thermostat;1` in the temperature controller model.
## Configuring the sample
See [../readme.md](../readme.md) for how to configure this sample.

Просмотреть файл

@ -0,0 +1,47 @@
# Samples to demonstrate Azure IoT Plug and Play
The samples in this directory demonstrate how to implement an Azure IoT Plug and Play device. Azure IoT Plug and Play is documented [here](aka.ms/iotpnp). The samples assume basic familiarity with PnP concepts, though not in depth knowledge of the PnP "convention". The "convention" is a set of rules for serializing and de-serialing data that uses IoTHub primitives for transport which the samples themselves implement.
## Directory structure
The directory contains the following samples:
* [pnp_simple_thermostat](./pnp_simple_thermostat) A simple thermostat that implements the model [dtmi:com:example:Thermostat;1](https://github.com/Azure/opendigitaltwins-dtdl/blob/master/DTDL/v2/samples/Thermostat.json). This sample is considered simple because it only implements one component, the thermostat itself. **You should begin with this sample.**
* [pnp_temperature_controller](./pnp_temperature_controller) A temperature controller that implements the model [dtmi:com:example:TemperatureController;1](https://github.com/Azure/opendigitaltwins-dtdl/blob/master/DTDL/v2/samples/TemperatureController.json). This is considerably more complex than the [pnp_simple_thermostat](./pnp_simple_thermostat) and demonstrates the use of subcomponents. **You should move onto this sample only after fully understanding pnp_simple_thermostat.**
* [common](./common) This directory contains functions for serializing and de-serializing data for PnP and for creating the `IOTHUB_DEVICE_CLIENT_HANDLE` that acts as the transport. `pnp_temperature_controller` makes extensive use of these functions and demonstrates their use. **The files in [common](./common) are written generically such that your PnP device application should be able to use them with little or no modification, speeding up your development.**
## Configuring the samples
Both samples use environment variables to retrieve configuration.
* If you are using a connection string to authenticate:
* set IOTHUB_DEVICE_SECURITY_TYPE="connectionString"
* set IOTHUB_DEVICE_CONNECTION_STRING="\<connection string of your device\>"
* If you are using a DPS enrollment group to authenticate:
* set IOTHUB_DEVICE_SECURITY_TYPE="DPS"
* set IOTHUB_DEVICE_DPS_ID_SCOPE="\<ID Scope of DPS instance\>"
* set IOTHUB_DEVICE_DPS_DEVICE_ID="\<Device's ID\>"
* set IOTHUB_DEVICE_DPS_DEVICE_KEY="\<Device's security key \>"
* *OPTIONAL*, if you do not wish to use the default endpoint "global.azure-devices-provisioning.net"
* set IOTHUB_DEVICE_DPS_ENDPOINT="\<DPS endpoint\>"
* If you are running on a device that does not have environment variables, hardcode the values in the .c file itself.
## Enabling Device Provisioning Service client (DPS)
To enable DPS with symmetric keys (which is what this sample uses when DPS is configured), use the cmake flags `-Duse_prov_client=ON -Dhsm_type_symm_key=ON -Drun_e2e_tests=OFF `
If you are building connection string only authentication, these extra cmake flags are not required.
## Caveats
* Azure IoT Plug and Play is only supported for MQTT and MQTT over WebSockets for the Azure IoT C Device SDK. Modifying these samples to use AMQP, AMQP over WebSockets, or HTTP protocols **will not work**.
* When the thermostat receives a desired temperature, it immediately makes that the actual temperature to keep the simulation code easier to follow. In a real thermostat there would be delay between the desired temperature being set and the room reaching that state.
* The command `getMaxMinReport` allows the application to specify statistics of the temperature since a given date. To keep the sample simple, we ignore this field and instead return statistics from the entire lifecycle of the executable.
* The temperature controller implements a command named `reboot` which takes a request payload indicating the delay in seconds. The sample will log the value requested but will not take any further action.

Просмотреть файл

@ -24,6 +24,9 @@ This folder contains simple samples showing how to use the various features of t
* Uploading blob to Azure:
* **iothub_client_sample_upload_to_blob**: Uploads a blob to Azure through IoT Hub
* IoT Plug and Play
* **pnp**: Samples demonstrating IoT Plug and Play device functionality
## How to compile and run the samples
Prior to running the samples, you will need to have an [instance of Azure IoT Hub][lnk-setup-iot-hub] available and a [device Identity created][lnk-manage-iot-hub] in the hub.

Просмотреть файл

@ -13,6 +13,10 @@
#include "azure_c_shared_utility/azure_base64.h"
#include "azure_c_shared_utility/shared_util_options.h"
static const char blockListXmlBegin[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<BlockList>";
static const char blockListXmlEnd[] = "</BlockList>";
static const char blockListUriMarker[] = "&comp=blocklist";
BLOB_RESULT Blob_UploadBlock(
HTTPAPIEX_HANDLE httpApiExHandle,
const char* relativePath,
@ -131,257 +135,258 @@ BLOB_RESULT Blob_UploadBlock(
return result;
}
// InvokeUserCallbackAndSendBlobs invokes the application's getDataCallbackEx as many time as callback requests and, for each call,
// sends the blob contents to the server.
static BLOB_RESULT InvokeUserCallbackAndSendBlobs(HTTPAPIEX_HANDLE httpApiExHandle, const char* relativePath, STRING_HANDLE blockIDList, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK_EX getDataCallbackEx, void* context, unsigned int* httpStatus, BUFFER_HANDLE httpResponse)
{
BLOB_RESULT result;
/*Codes_SRS_BLOB_02_021: [ For every block returned by `getDataCallbackEx` the following operations shall happen: ]*/
unsigned int blockID = 0; /* incremented for each new block */
unsigned int isError = 0; /* set to 1 if a block upload fails or if getDataCallbackEx returns incorrect blocks to upload */
unsigned int uploadOneMoreBlock = 1; /* set to 1 while getDataCallbackEx returns correct blocks to upload */
unsigned char const * source = NULL; /* data set by getDataCallbackEx */
size_t size = 0; /* source size set by getDataCallbackEx */
IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_RESULT getDataReturnValue;
do
{
getDataReturnValue = getDataCallbackEx(FILE_UPLOAD_OK, &source, &size, context);
if (getDataReturnValue == IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_ABORT)
{
/*Codes_SRS_BLOB_99_004: [ If `getDataCallbackEx` returns `IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_RESULT_ABORT`, then `Blob_UploadMultipleBlocksFromSasUri` shall exit the loop and return `BLOB_ABORTED`. ]*/
LogInfo("Upload to blob has been aborted by the user");
uploadOneMoreBlock = 0;
result = BLOB_ABORTED;
}
else if (source == NULL || size == 0)
{
/*Codes_SRS_BLOB_99_002: [ If the size of the block returned by `getDataCallbackEx` is 0 or if the data is NULL, then `Blob_UploadMultipleBlocksFromSasUri` shall exit the loop. ]*/
uploadOneMoreBlock = 0;
result = BLOB_OK;
}
else
{
if (size > BLOCK_SIZE)
{
/*Codes_SRS_BLOB_99_001: [ If the size of the block returned by `getDataCallbackEx` is bigger than 4MB, then `Blob_UploadMultipleBlocksFromSasUri` shall fail and return `BLOB_INVALID_ARG`. ]*/
LogError("tried to upload block of size %lu, max allowed size is %d", (unsigned long)size, BLOCK_SIZE);
result = BLOB_INVALID_ARG;
isError = 1;
}
else if (blockID >= MAX_BLOCK_COUNT)
{
/*Codes_SRS_BLOB_99_003: [ If `getDataCallbackEx` returns more than 50000 blocks, then `Blob_UploadMultipleBlocksFromSasUri` shall fail and return `BLOB_INVALID_ARG`. ]*/
LogError("unable to upload more than %lu blocks in one blob", (unsigned long)MAX_BLOCK_COUNT);
result = BLOB_INVALID_ARG;
isError = 1;
}
else
{
/*Codes_SRS_BLOB_02_023: [ Blob_UploadMultipleBlocksFromSasUri shall create a BUFFER_HANDLE from source and size parameters. ]*/
BUFFER_HANDLE requestContent = BUFFER_create(source, size);
if (requestContent == NULL)
{
/*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
LogError("unable to BUFFER_create");
result = BLOB_ERROR;
isError = 1;
}
else
{
result = Blob_UploadBlock(
httpApiExHandle,
relativePath,
requestContent,
blockID,
blockIDList,
httpStatus,
httpResponse);
BUFFER_delete(requestContent);
}
/*Codes_SRS_BLOB_02_026: [ Otherwise, if HTTP response code is >=300 then Blob_UploadMultipleBlocksFromSasUri shall succeed and return BLOB_OK. ]*/
if (result != BLOB_OK || *httpStatus >= 300)
{
LogError("unable to Blob_UploadBlock. Returned value=%d, httpStatus=%u", result, (unsigned int)*httpStatus);
isError = 1;
}
}
blockID++;
}
}
while(uploadOneMoreBlock && !isError);
return result;
}
// SendBlockIdList to send an XML of uploaded blockIds to the server after the application's payload block(s) have been transfered.
static BLOB_RESULT SendBlockIdList(HTTPAPIEX_HANDLE httpApiExHandle, const char* relativePath, STRING_HANDLE blockIDList, unsigned int* httpStatus, BUFFER_HANDLE httpResponse)
{
BLOB_RESULT result;
/*complete the XML*/
if (STRING_concat(blockIDList, blockListXmlEnd) != 0)
{
/*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
LogError("failed to STRING_concat");
result = BLOB_ERROR;
}
else
{
/*Codes_SRS_BLOB_02_029: [Blob_UploadMultipleBlocksFromSasUri shall construct a new relativePath from following string : base relativePath + "&comp=blocklist"]*/
STRING_HANDLE newRelativePath = STRING_construct(relativePath);
if (newRelativePath == NULL)
{
/*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
LogError("failed to STRING_construct");
result = BLOB_ERROR;
}
else
{
if (STRING_concat(newRelativePath, blockListUriMarker) != 0)
{
/*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
LogError("failed to STRING_concat");
result = BLOB_ERROR;
}
else
{
/*Codes_SRS_BLOB_02_030: [ Blob_UploadMultipleBlocksFromSasUri shall call HTTPAPIEX_ExecuteRequest with a PUT operation, passing the new relativePath, httpStatus and httpResponse and the XML string as content. ]*/
const char* s = STRING_c_str(blockIDList);
BUFFER_HANDLE blockIDListAsBuffer = BUFFER_create((const unsigned char*)s, strlen(s));
if (blockIDListAsBuffer == NULL)
{
/*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
LogError("failed to BUFFER_create");
result = BLOB_ERROR;
}
else
{
if (HTTPAPIEX_ExecuteRequest(
httpApiExHandle,
HTTPAPI_REQUEST_PUT,
STRING_c_str(newRelativePath),
NULL,
blockIDListAsBuffer,
httpStatus,
NULL,
httpResponse
) != HTTPAPIEX_OK)
{
/*Codes_SRS_BLOB_02_031: [ If HTTPAPIEX_ExecuteRequest fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_HTTP_ERROR. ]*/
LogError("unable to HTTPAPIEX_ExecuteRequest");
result = BLOB_HTTP_ERROR;
}
else
{
/*Codes_SRS_BLOB_02_032: [ Otherwise, Blob_UploadMultipleBlocksFromSasUri shall succeed and return BLOB_OK. ]*/
result = BLOB_OK;
}
BUFFER_delete(blockIDListAsBuffer);
}
}
STRING_delete(newRelativePath);
}
}
return result;
}
BLOB_RESULT Blob_UploadMultipleBlocksFromSasUri(const char* SASURI, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK_EX getDataCallbackEx, void* context, unsigned int* httpStatus, BUFFER_HANDLE httpResponse, const char* certificates, HTTP_PROXY_OPTIONS *proxyOptions)
{
BLOB_RESULT result;
const char* hostnameBegin;
STRING_HANDLE blockIDList = NULL;
HTTPAPIEX_HANDLE httpApiExHandle = NULL;
char* hostname = NULL;
/*Codes_SRS_BLOB_02_001: [ If SASURI is NULL then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
if (SASURI == NULL)
/*Codes_SRS_BLOB_02_002: [ If getDataCallbackEx is NULL then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
if ((SASURI == NULL) || (getDataCallbackEx == NULL))
{
LogError("parameter SASURI is NULL");
LogError("One or more required values is NULL, SASURI=%p, getDataCallbackEx=%p", SASURI, getDataCallbackEx);
result = BLOB_INVALID_ARG;
}
/*Codes_SRS_BLOB_02_017: [ Blob_UploadMultipleBlocksFromSasUri shall copy from SASURI the hostname to a new const char* ]*/
/*to find the hostname, the following logic is applied:*/
/*the hostname starts at the first character after "://"*/
/*the hostname ends at the first character before the next "/" after "://"*/
else if ((hostnameBegin = strstr(SASURI, "://")) == NULL)
{
/*Codes_SRS_BLOB_02_005: [ If the hostname cannot be determined, then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
LogError("hostname cannot be determined");
result = BLOB_INVALID_ARG;
}
else
{
/*Codes_SRS_BLOB_02_002: [ If getDataCallbackEx is NULL then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
if (getDataCallbackEx == NULL)
hostnameBegin += 3; /*have to skip 3 characters which are "://"*/
const char* relativePath = strchr(hostnameBegin, '/');
if (relativePath == NULL)
{
LogError("IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK_EX getDataCallbackEx is NULL");
/*Codes_SRS_BLOB_02_005: [ If the hostname cannot be determined, then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
LogError("hostname cannot be determined");
result = BLOB_INVALID_ARG;
}
/*the below define avoid a "condition always false" on some compilers*/
else
{
/*Codes_SRS_BLOB_02_017: [ Blob_UploadMultipleBlocksFromSasUri shall copy from SASURI the hostname to a new const char* ]*/
/*to find the hostname, the following logic is applied:*/
/*the hostname starts at the first character after "://"*/
/*the hostname ends at the first character before the next "/" after "://"*/
const char* hostnameBegin = strstr(SASURI, "://");
if (hostnameBegin == NULL)
size_t hostnameSize = relativePath - hostnameBegin;
if ((hostname = (char*)malloc(hostnameSize + 1)) == NULL)
{
/*Codes_SRS_BLOB_02_005: [ If the hostname cannot be determined, then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
LogError("hostname cannot be determined");
result = BLOB_INVALID_ARG;
/*Codes_SRS_BLOB_02_016: [ If the hostname copy cannot be made then then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
LogError("oom - out of memory");
result = BLOB_ERROR;
}
else
{
hostnameBegin += 3; /*have to skip 3 characters which are "://"*/
const char* hostnameEnd = strchr(hostnameBegin, '/');
if (hostnameEnd == NULL)
(void)memcpy(hostname, hostnameBegin, hostnameSize);
hostname[hostnameSize] = '\0';
/*Codes_SRS_BLOB_02_018: [ Blob_UploadMultipleBlocksFromSasUri shall create a new HTTPAPI_EX_HANDLE by calling HTTPAPIEX_Create passing the hostname. ]*/
httpApiExHandle = HTTPAPIEX_Create(hostname);
if (httpApiExHandle == NULL)
{
/*Codes_SRS_BLOB_02_005: [ If the hostname cannot be determined, then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
LogError("hostname cannot be determined");
result = BLOB_INVALID_ARG;
/*Codes_SRS_BLOB_02_007: [ If HTTPAPIEX_Create fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR. ]*/
LogError("unable to create a HTTPAPIEX_HANDLE");
result = BLOB_ERROR;
}
else
else if ((certificates != NULL) && (HTTPAPIEX_SetOption(httpApiExHandle, "TrustedCerts", certificates) == HTTPAPIEX_ERROR))
{
size_t hostnameSize = hostnameEnd - hostnameBegin;
char* hostname = (char*)malloc(hostnameSize + 1); /*+1 because of '\0' at the end*/
if (hostname == NULL)
{
/*Codes_SRS_BLOB_02_016: [ If the hostname copy cannot be made then then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
LogError("oom - out of memory");
result = BLOB_ERROR;
}
else
{
HTTPAPIEX_HANDLE httpApiExHandle;
(void)memcpy(hostname, hostnameBegin, hostnameSize);
hostname[hostnameSize] = '\0';
/*Codes_SRS_BLOB_02_018: [ Blob_UploadMultipleBlocksFromSasUri shall create a new HTTPAPI_EX_HANDLE by calling HTTPAPIEX_Create passing the hostname. ]*/
httpApiExHandle = HTTPAPIEX_Create(hostname);
if (httpApiExHandle == NULL)
{
/*Codes_SRS_BLOB_02_007: [ If HTTPAPIEX_Create fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR. ]*/
LogError("unable to create a HTTPAPIEX_HANDLE");
result = BLOB_ERROR;
}
else
{
if ((certificates != NULL)&& (HTTPAPIEX_SetOption(httpApiExHandle, "TrustedCerts", certificates) == HTTPAPIEX_ERROR))
{
LogError("failure in setting trusted certificates");
result = BLOB_ERROR;
}
else if ((proxyOptions != NULL && proxyOptions->host_address != NULL) && HTTPAPIEX_SetOption(httpApiExHandle, OPTION_HTTP_PROXY, proxyOptions) == HTTPAPIEX_ERROR)
{
LogError("failure in setting proxy options");
result = BLOB_ERROR;
}
else
{
/*Codes_SRS_BLOB_02_019: [ Blob_UploadMultipleBlocksFromSasUri shall compute the base relative path of the request from the SASURI parameter. ]*/
const char* relativePath = hostnameEnd; /*this is where the relative path begins in the SasUri*/
/*Codes_SRS_BLOB_02_028: [ Blob_UploadMultipleBlocksFromSasUri shall construct an XML string with the following content: ]*/
STRING_HANDLE blockIDList = STRING_construct("<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<BlockList>"); /*the XML "build as we go"*/
if (blockIDList == NULL)
{
/*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
LogError("failed to STRING_construct");
result = BLOB_HTTP_ERROR;
}
else
{
/*Codes_SRS_BLOB_02_021: [ For every block returned by `getDataCallbackEx` the following operations shall happen: ]*/
unsigned int blockID = 0; /* incremented for each new block */
unsigned int isError = 0; /* set to 1 if a block upload fails or if getDataCallbackEx returns incorrect blocks to upload */
unsigned int uploadOneMoreBlock = 1; /* set to 1 while getDataCallbackEx returns correct blocks to upload */
unsigned char const * source; /* data set by getDataCallbackEx */
size_t size; /* source size set by getDataCallbackEx */
IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_RESULT getDataReturnValue;
do
{
getDataReturnValue = getDataCallbackEx(FILE_UPLOAD_OK, &source, &size, context);
if (getDataReturnValue == IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_ABORT)
{
/*Codes_SRS_BLOB_99_004: [ If `getDataCallbackEx` returns `IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_RESULT_ABORT`, then `Blob_UploadMultipleBlocksFromSasUri` shall exit the loop and return `BLOB_ABORTED`. ]*/
LogInfo("Upload to blob has been aborted by the user");
uploadOneMoreBlock = 0;
result = BLOB_ABORTED;
}
else if (source == NULL || size == 0)
{
/*Codes_SRS_BLOB_99_002: [ If the size of the block returned by `getDataCallbackEx` is 0 or if the data is NULL, then `Blob_UploadMultipleBlocksFromSasUri` shall exit the loop. ]*/
uploadOneMoreBlock = 0;
result = BLOB_OK;
}
else
{
if (size > BLOCK_SIZE)
{
/*Codes_SRS_BLOB_99_001: [ If the size of the block returned by `getDataCallbackEx` is bigger than 4MB, then `Blob_UploadMultipleBlocksFromSasUri` shall fail and return `BLOB_INVALID_ARG`. ]*/
LogError("tried to upload block of size %lu, max allowed size is %d", (unsigned long)size, BLOCK_SIZE);
result = BLOB_INVALID_ARG;
isError = 1;
}
else if (blockID >= MAX_BLOCK_COUNT)
{
/*Codes_SRS_BLOB_99_003: [ If `getDataCallbackEx` returns more than 50000 blocks, then `Blob_UploadMultipleBlocksFromSasUri` shall fail and return `BLOB_INVALID_ARG`. ]*/
LogError("unable to upload more than %lu blocks in one blob", (unsigned long)MAX_BLOCK_COUNT);
result = BLOB_INVALID_ARG;
isError = 1;
}
else
{
/*Codes_SRS_BLOB_02_023: [ Blob_UploadMultipleBlocksFromSasUri shall create a BUFFER_HANDLE from source and size parameters. ]*/
BUFFER_HANDLE requestContent = BUFFER_create(source, size);
if (requestContent == NULL)
{
/*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
LogError("unable to BUFFER_create");
result = BLOB_ERROR;
isError = 1;
}
else
{
result = Blob_UploadBlock(
httpApiExHandle,
relativePath,
requestContent,
blockID,
blockIDList,
httpStatus,
httpResponse);
BUFFER_delete(requestContent);
}
/*Codes_SRS_BLOB_02_026: [ Otherwise, if HTTP response code is >=300 then Blob_UploadMultipleBlocksFromSasUri shall succeed and return BLOB_OK. ]*/
if (result != BLOB_OK || *httpStatus >= 300)
{
LogError("unable to Blob_UploadBlock. Returned value=%d, httpStatus=%u", result, (unsigned int)*httpStatus);
isError = 1;
}
}
blockID++;
}
}
while(uploadOneMoreBlock && !isError);
if (isError || result != BLOB_OK)
{
/*do nothing, it will be reported "as is"*/
}
else
{
/*complete the XML*/
if (STRING_concat(blockIDList, "</BlockList>") != 0)
{
/*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
LogError("failed to STRING_concat");
result = BLOB_ERROR;
}
else
{
/*Codes_SRS_BLOB_02_029: [Blob_UploadMultipleBlocksFromSasUri shall construct a new relativePath from following string : base relativePath + "&comp=blocklist"]*/
STRING_HANDLE newRelativePath = STRING_construct(relativePath);
if (newRelativePath == NULL)
{
/*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
LogError("failed to STRING_construct");
result = BLOB_ERROR;
}
else
{
if (STRING_concat(newRelativePath, "&comp=blocklist") != 0)
{
/*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
LogError("failed to STRING_concat");
result = BLOB_ERROR;
}
else
{
/*Codes_SRS_BLOB_02_030: [ Blob_UploadMultipleBlocksFromSasUri shall call HTTPAPIEX_ExecuteRequest with a PUT operation, passing the new relativePath, httpStatus and httpResponse and the XML string as content. ]*/
const char* s = STRING_c_str(blockIDList);
BUFFER_HANDLE blockIDListAsBuffer = BUFFER_create((const unsigned char*)s, strlen(s));
if (blockIDListAsBuffer == NULL)
{
/*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
LogError("failed to BUFFER_create");
result = BLOB_ERROR;
}
else
{
if (HTTPAPIEX_ExecuteRequest(
httpApiExHandle,
HTTPAPI_REQUEST_PUT,
STRING_c_str(newRelativePath),
NULL,
blockIDListAsBuffer,
httpStatus,
NULL,
httpResponse
) != HTTPAPIEX_OK)
{
/*Codes_SRS_BLOB_02_031: [ If HTTPAPIEX_ExecuteRequest fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_HTTP_ERROR. ]*/
LogError("unable to HTTPAPIEX_ExecuteRequest");
result = BLOB_HTTP_ERROR;
}
else
{
/*Codes_SRS_BLOB_02_032: [ Otherwise, Blob_UploadMultipleBlocksFromSasUri shall succeed and return BLOB_OK. ]*/
result = BLOB_OK;
}
BUFFER_delete(blockIDListAsBuffer);
}
}
STRING_delete(newRelativePath);
}
}
}
STRING_delete(blockIDList);
}
}
HTTPAPIEX_Destroy(httpApiExHandle);
}
free(hostname);
}
LogError("failure in setting trusted certificates");
result = BLOB_ERROR;
}
else if ((proxyOptions != NULL && proxyOptions->host_address != NULL) && HTTPAPIEX_SetOption(httpApiExHandle, OPTION_HTTP_PROXY, proxyOptions) == HTTPAPIEX_ERROR)
{
LogError("failure in setting proxy options");
result = BLOB_ERROR;
}
/*Codes_SRS_BLOB_02_028: [ Blob_UploadMultipleBlocksFromSasUri shall construct an XML string with the following content: ]*/
else if ((blockIDList = STRING_construct(blockListXmlBegin)) == NULL)
{
/*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
LogError("failed to STRING_construct");
result = BLOB_HTTP_ERROR;
}
else if ((result = InvokeUserCallbackAndSendBlobs(httpApiExHandle, relativePath, blockIDList, getDataCallbackEx, context, httpStatus, httpResponse)) != BLOB_OK)
{
LogError("Failed in invoking callback/sending blob step");
}
else if (*httpStatus < 300)
{
// Per SRS_BLOB_02_026, it possible for us to have a result=BLOB_OK AND a non-success HTTP status code.
// In order to maintain back-compat with existing code, we will return the BLOB_OK to the caller but NOT invoke this final step.
result = SendBlockIdList(httpApiExHandle, relativePath, blockIDList, httpStatus, httpResponse);
}
}
}
}
HTTPAPIEX_Destroy(httpApiExHandle);
STRING_delete(blockIDList);
free(hostname);
return result;
}

Просмотреть файл

@ -25,6 +25,7 @@
#define DO_WORK_FREQ_DEFAULT 1
#define DO_WORK_MAXIMUM_ALLOWED_FREQUENCY 100
struct IOTHUB_QUEUE_CONTEXT_TAG;
@ -1269,6 +1270,13 @@ void IoTHubClientCore_Destroy(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle)
queue_cb_info->iothub_callback.event_confirm_cb_info.eventConfirmationCallback(queue_cb_info->iothub_callback.event_confirm_cb_info.confirm_result, queue_cb_info->userContextCallback);
}
}
else if (queue_cb_info->type == CALLBACK_TYPE_REPORTED_STATE)
{
if (queue_cb_info->iothub_callback.reported_state_cb_info.reportedStateCallback)
{
queue_cb_info->iothub_callback.reported_state_cb_info.reportedStateCallback(queue_cb_info->iothub_callback.reported_state_cb_info.status_code, queue_cb_info->userContextCallback);
}
}
}
}
VECTOR_destroy(iotHubClientInstance->saved_user_callback_list);
@ -1714,7 +1722,7 @@ IOTHUB_CLIENT_RESULT IoTHubClientCore_SetOption(IOTHUB_CLIENT_CORE_HANDLE iotHub
if (strcmp(OPTION_DO_WORK_FREQUENCY_IN_MS, optionName) == 0)
{
/* Codes_SRS_IOTHUBCLIENT_41_003: [ The value for `OPTION_DO_WORK_FREQUENCY_IN_MS` shall be limited to 100 to follow SDK best practices by not reducing the DoWork frequency below 10 Hz ]*/
if (0 < * (unsigned int *)value && * (unsigned int *)value <= 100)
if (0 < * (unsigned int *)value && * (unsigned int *)value <= DO_WORK_MAXIMUM_ALLOWED_FREQUENCY)
{
/* Codes_SRS_IOTHUBCLIENT_41_004: [ If `currentMessageTimeout` is not greater than `do_work_freq_ms`, `IotHubClientCore_SetOption` shall return `IOTHUB_CLIENT_INVALID_ARG` ]*/
/* Codes_SRS_IOTHUBCLIENT_41_007: [** If parameter `optionName` is `OPTION_DO_WORK_FREQUENCY_IN_MS` then `value` should be of type `tickcounter_ms_t *`. **]*/
@ -1732,7 +1740,7 @@ IOTHUB_CLIENT_RESULT IoTHubClientCore_SetOption(IOTHUB_CLIENT_CORE_HANDLE iotHub
else
{
result = IOTHUB_CLIENT_INVALID_ARG;
LogError("Invalid value: OPTION_DO_WORK_FREQUENCY_IN_MS cannot exceed 100 ms. If you wish to reduce the frequency further, consider using the LL layer.");
LogError("Invalid value: OPTION_DO_WORK_FREQUENCY_IN_MS cannot exceed %d ms. If you wish to reduce the frequency further, consider using the LL layer.", DO_WORK_MAXIMUM_ALLOWED_FREQUENCY);
}
}
/* Codes_SRS_IOTHUBCLIENT_41_005: [ If parameter `optionName` is `OPTION_MESSAGE_TIMEOUT` then `IoTHubClientCore_SetOption` shall set `currentMessageTimeout` parameter of `IoTHubClientInstance` ]*/

Просмотреть файл

@ -39,6 +39,8 @@
#define LOG_ERROR_RESULT LogError("result = %s", MU_ENUM_TO_STRING(IOTHUB_CLIENT_RESULT, result));
#define INDEFINITE_TIME ((time_t)(-1))
#define ERROR_CODE_BECAUSE_DESTROY 0
MU_DEFINE_ENUM_STRINGS_WITHOUT_INVALID(IOTHUB_CLIENT_FILE_UPLOAD_RESULT, IOTHUB_CLIENT_FILE_UPLOAD_RESULT_VALUES);
MU_DEFINE_ENUM_STRINGS_WITHOUT_INVALID(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_RESULT_VALUES);
@ -128,6 +130,7 @@ typedef struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA_TAG
STRING_HANDLE product_info;
IOTHUB_DIAGNOSTIC_SETTING_DATA diagnostic_setting;
SINGLYLINKEDLIST_HANDLE event_callbacks; // List of IOTHUB_EVENT_CALLBACK's
STRING_HANDLE model_id;
}IOTHUB_CLIENT_CORE_LL_HANDLE_DATA;
static const char HOSTNAME_TOKEN[] = "HostName";
@ -141,7 +144,6 @@ static const char MODULE_ID_TOKEN[] = "ModuleId";
static const char PROVISIONING_TOKEN[] = "UseProvisioning";
static const char PROVISIONING_ACCEPTABLE_VALUE[] = "true";
#ifdef USE_EDGE_MODULES
/*The following section should be moved to iothub_module_client_ll.c during impending refactor*/
@ -615,6 +617,22 @@ static const char* IoTHubClientCore_LL_GetProductInfo(void* ctx)
return result;
}
static const char* IoTHubClientCore_LL_GetModelId(void* ctx)
{
const char* result;
if (ctx == NULL)
{
result = NULL;
LogError("invalid argument ctx %p", ctx);
}
else
{
IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* iothub_data = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)ctx;
result = STRING_c_str(iothub_data->model_id);
}
return result;
}
static bool IoTHubClientCore_LL_MessageCallbackFromInput(MESSAGE_CALLBACK_INFO* messageData, void* ctx)
{
bool result;
@ -828,6 +846,7 @@ static IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* initialize_iothub_client(const IOTHUB_
transport_cb.msg_input_cb = IoTHubClientCore_LL_MessageCallbackFromInput;
transport_cb.msg_cb = IoTHubClientCore_LL_MessageCallback;
transport_cb.method_complete_cb = IoTHubClientCore_LL_DeviceMethodComplete;
transport_cb.get_model_id_cb = IoTHubClientCore_LL_GetModelId;
if (client_config != NULL)
{
@ -1726,11 +1745,29 @@ void IoTHubClientCore_LL_Destroy(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle
while ((unsend = DList_RemoveHeadList(&(handleData->iot_msg_queue))) != &(handleData->iot_msg_queue))
{
IOTHUB_DEVICE_TWIN* temp = containingRecord(unsend, IOTHUB_DEVICE_TWIN, entry);
// The Twin reported properties status codes are based on HTTP codes and provided by the service.
// Following design already implemented in the transport layer, the status code shall be artificially
// returned as zero to indicate the report was not sent due to the client being destroyed.
if (temp->reported_state_callback != NULL)
{
temp->reported_state_callback(ERROR_CODE_BECAUSE_DESTROY, temp->context);
}
device_twin_data_destroy(temp);
}
while ((unsend = DList_RemoveHeadList(&(handleData->iot_ack_queue))) != &(handleData->iot_ack_queue))
{
IOTHUB_DEVICE_TWIN* temp = containingRecord(unsend, IOTHUB_DEVICE_TWIN, entry);
// The Twin reported properties status codes are based on HTTP codes and provided by the service.
// Following design already implemented in the transport layer, the status code shall be artificially
// returned as zero to indicate the report was not sent due to the client being destroyed.
if (temp->reported_state_callback != NULL)
{
temp->reported_state_callback(ERROR_CODE_BECAUSE_DESTROY, temp->context);
}
device_twin_data_destroy(temp);
}
@ -1747,6 +1784,7 @@ void IoTHubClientCore_LL_Destroy(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle
IoTHubClient_EdgeHandle_Destroy(handleData->methodHandle);
#endif
STRING_delete(handleData->product_info);
STRING_delete(handleData->model_id);
free(handleData);
}
}
@ -2319,6 +2357,23 @@ IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_SetOption(IOTHUB_CLIENT_CORE_LL_HANDLE
result = IOTHUB_CLIENT_OK;
}
}
else if (strcmp(optionName, OPTION_MODEL_ID) == 0)
{
if (handleData->model_id != NULL)
{
LogError("DT ModelId already specified.");
result = IOTHUB_CLIENT_ERROR;
}
else if ((handleData->model_id = STRING_construct((const char*)value)) == NULL)
{
LogError("STRING_construct failed");
result = IOTHUB_CLIENT_ERROR;
}
else
{
result = IOTHUB_CLIENT_OK;
}
}
else
{
// This section is unusual for SetOption calls because it attempts to pass unhandled options
@ -2974,6 +3029,7 @@ int IoTHubClientCore_LL_GetTransportCallbacks(TRANSPORT_CALLBACKS_INFO* transpor
transport_cb->msg_input_cb = IoTHubClientCore_LL_MessageCallbackFromInput;
transport_cb->msg_cb = IoTHubClientCore_LL_MessageCallback;
transport_cb->method_complete_cb = IoTHubClientCore_LL_DeviceMethodComplete;
transport_cb->get_model_id_cb = IoTHubClientCore_LL_GetModelId;
result = 0;
}
return result;

Просмотреть файл

@ -120,6 +120,8 @@ EXPORTS
IoTHubMessage_GetContentType
IoTHubMessage_GetContentTypeSystemProperty
IoTHubMessage_GetContentEncodingSystemProperty
IoTHubMessage_GetMessageCreationTimeUtcSystemProperty
IoTHubMessage_GetMessageUserIdSystemProperty
IoTHubMessage_GetCorrelationId
IoTHubMessage_GetDiagnosticPropertyData
IoTHubMessage_GetMessageId
@ -130,6 +132,8 @@ EXPORTS
IoTHubMessage_SetConnectionModuleId
IoTHubMessage_SetContentTypeSystemProperty
IoTHubMessage_SetContentEncodingSystemProperty
IoTHubMessage_SetMessageCreationTimeUtcSystemProperty
IoTHubMessage_SetMessageUserIdSystemProperty
IoTHubMessage_SetCorrelationId
IoTHubMessage_SetInputName
IoTHubMessage_SetMessageId

Просмотреть файл

@ -36,7 +36,7 @@
#define SASTOKEN_LIFETIME 3600
static const char* const URL_API_VERSION = "?api-version=2018-06-27";
static const char* const URL_API_VERSION = "?api-version=2020-09-30";
static const char* const RELATIVE_PATH_FMT_MODULE_METHOD = "/twins/%s/modules/%s/methods%s";
static const char* const RELATIVE_PATH_FMT_DEVICE_METHOD = "/twins/%s/methods%s";
static const char* const PAYLOAD_FMT = "{\"methodName\":\"%s\",\"timeout\":%d,\"payload\":%s}";
@ -440,7 +440,7 @@ static IOTHUB_CLIENT_RESULT sendHttpRequestMethod(IOTHUB_CLIENT_EDGE_HANDLE modu
}
else
{
if (statusCode == 200)
if (statusCode >= 200 && statusCode < 300)
{
result = IOTHUB_CLIENT_OK;
}

Просмотреть файл

@ -33,15 +33,17 @@ typedef struct IOTHUB_MESSAGE_HANDLE_DATA_TAG
char* connectionDeviceId;
IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA_HANDLE diagnosticData;
bool is_security_message;
char* creationTimeUtc;
char* userId;
}IOTHUB_MESSAGE_HANDLE_DATA;
static bool ContainsOnlyUsAscii(const char* asciiValue)
static bool ContainsValidUsAscii(const char* asciiValue)
{
bool result = true;
const char* iterator = asciiValue;
while (iterator != NULL && *iterator != '\0')
{
// Allow only printable ascii char
// Union of all allowed ASCII characters for the different protocols (HTTPS, MQTT, AMQP) is [dec 32, dec 126].
if (*iterator < ' ' || *iterator > '~')
{
result = false;
@ -49,14 +51,15 @@ static bool ContainsOnlyUsAscii(const char* asciiValue)
}
iterator++;
}
return result;
}
/* Codes_SRS_IOTHUBMESSAGE_07_008: [ValidateAsciiCharactersFilter shall loop through the mapKey and mapValue strings to ensure that they only contain valid US-Ascii characters Ascii value 32 - 126.] */
/* Codes_SRS_IOTHUBMESSAGE_07_008: [ValidateAsciiCharactersFilter shall loop through the mapKey and mapValue strings to ensure that they only contain valid US-Ascii characters.*/
static int ValidateAsciiCharactersFilter(const char* mapKey, const char* mapValue)
{
int result;
if (!ContainsOnlyUsAscii(mapKey) || !ContainsOnlyUsAscii(mapValue))
if (!ContainsValidUsAscii(mapKey) || !ContainsValidUsAscii(mapValue))
{
result = MU_FAILURE;
}
@ -100,6 +103,8 @@ static void DestroyMessageData(IOTHUB_MESSAGE_HANDLE_DATA* handleData)
free(handleData->inputName);
free(handleData->connectionModuleId);
free(handleData->connectionDeviceId);
free(handleData->creationTimeUtc);
free(handleData->userId);
free(handleData);
}
@ -127,6 +132,54 @@ static int set_content_encoding(IOTHUB_MESSAGE_HANDLE_DATA* handleData, const ch
return result;
}
static int set_message_creation_time(IOTHUB_MESSAGE_HANDLE_DATA* handleData, const char* messageCreationTimeUtc)
{
int result;
char* tmp_message_creation_time;
if (handleData->creationTimeUtc != NULL)
{
free(handleData->creationTimeUtc);
handleData->creationTimeUtc = NULL;
}
if (mallocAndStrcpy_s(&tmp_message_creation_time, messageCreationTimeUtc) != 0)
{
LogError("Failed saving a copy of messageCreationTimeUtc");
result = MU_FAILURE;
}
else
{
handleData->creationTimeUtc = tmp_message_creation_time;
result = 0;
}
return result;
}
static int set_message_user_id(IOTHUB_MESSAGE_HANDLE_DATA* handleData, const char* userId)
{
int result;
char* tmp_message_user_id;
if (handleData->userId != NULL)
{
free(handleData->userId);
handleData->userId = NULL;
}
if (mallocAndStrcpy_s(&tmp_message_user_id, userId) != 0)
{
LogError("Failed saving a copy of userId");
result = MU_FAILURE;
}
else
{
handleData->userId = tmp_message_user_id;
result = 0;
}
return result;
}
static IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA_HANDLE CloneDiagnosticPropertyData(const IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA* source)
{
IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA_HANDLE result = NULL;
@ -348,6 +401,18 @@ IOTHUB_MESSAGE_HANDLE IoTHubMessage_Clone(IOTHUB_MESSAGE_HANDLE iotHubMessageHan
DestroyMessageData(result);
result = NULL;
}
else if (source->creationTimeUtc != NULL && mallocAndStrcpy_s(&result->creationTimeUtc, source->creationTimeUtc) != 0)
{
LogError("unable to copy creationTimeUtc");
DestroyMessageData(result);
result = NULL;
}
else if (source->userId != NULL && mallocAndStrcpy_s(&result->userId, source->userId) != 0)
{
LogError("unable to copy userId");
DestroyMessageData(result);
result = NULL;
}
else if (source->connectionModuleId != NULL && mallocAndStrcpy_s(&result->connectionModuleId, source->connectionModuleId) != 0)
{
LogError("unable to copy inputName");
@ -508,7 +573,13 @@ IOTHUB_MESSAGE_RESULT IoTHubMessage_SetProperty(IOTHUB_MESSAGE_HANDLE msg_handle
}
else
{
if (Map_AddOrUpdate(msg_handle->properties, key, value) != MAP_OK)
MAP_RESULT map_result = Map_AddOrUpdate(msg_handle->properties, key, value);
if (map_result == MAP_FILTER_REJECT)
{
LogError("Failure validating property as ASCII");
result = IOTHUB_MESSAGE_INVALID_TYPE;
}
else if (map_result != MAP_OK)
{
LogError("Failure adding property to internal map");
result = IOTHUB_MESSAGE_ERROR;
@ -752,6 +823,90 @@ const char* IoTHubMessage_GetContentEncodingSystemProperty(IOTHUB_MESSAGE_HANDLE
return result;
}
IOTHUB_MESSAGE_RESULT IoTHubMessage_SetMessageCreationTimeUtcSystemProperty(IOTHUB_MESSAGE_HANDLE iotHubMessageHandle, const char* creationTimeUtc)
{
IOTHUB_MESSAGE_RESULT result;
if (iotHubMessageHandle == NULL || creationTimeUtc == NULL)
{
LogError("Invalid argument (iotHubMessageHandle=%p, creationTimeUtc=%p)", iotHubMessageHandle, creationTimeUtc);
result = IOTHUB_MESSAGE_INVALID_ARG;
}
else
{
if (set_message_creation_time(iotHubMessageHandle, creationTimeUtc) != 0)
{
LogError("Failed saving a copy of creationTimeUtc");
result = IOTHUB_MESSAGE_ERROR;
}
else
{
result = IOTHUB_MESSAGE_OK;
}
}
return result;
}
const char* IoTHubMessage_GetMessageCreationTimeUtcSystemProperty(IOTHUB_MESSAGE_HANDLE iotHubMessageHandle)
{
const char* result;
if (iotHubMessageHandle == NULL)
{
LogError("Invalid argument (iotHubMessageHandle is NULL)");
result = NULL;
}
else
{
IOTHUB_MESSAGE_HANDLE_DATA* handleData = iotHubMessageHandle;
result = (const char*)handleData->creationTimeUtc;
}
return result;
}
IOTHUB_MESSAGE_RESULT IoTHubMessage_SetMessageUserIdSystemProperty(IOTHUB_MESSAGE_HANDLE iotHubMessageHandle, const char* userId)
{
IOTHUB_MESSAGE_RESULT result;
if (iotHubMessageHandle == NULL || userId == NULL)
{
LogError("Invalid argument (iotHubMessageHandle=%p, userId=%p)", iotHubMessageHandle, userId);
result = IOTHUB_MESSAGE_INVALID_ARG;
}
else
{
if (set_message_user_id(iotHubMessageHandle, userId) != 0)
{
LogError("Failed saving a copy of userId");
result = IOTHUB_MESSAGE_ERROR;
}
else
{
result = IOTHUB_MESSAGE_OK;
}
}
return result;
}
const char* IoTHubMessage_GetMessageUserIdSystemProperty(IOTHUB_MESSAGE_HANDLE iotHubMessageHandle)
{
const char* result;
if (iotHubMessageHandle == NULL)
{
LogError("Invalid argument (iotHubMessageHandle is NULL)");
result = NULL;
}
else
{
IOTHUB_MESSAGE_HANDLE_DATA* handleData = iotHubMessageHandle;
result = (const char*)handleData->userId;
}
return result;
}
const IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA* IoTHubMessage_GetDiagnosticPropertyData(IOTHUB_MESSAGE_HANDLE iotHubMessageHandle)
{
const IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA* result;

Просмотреть файл

@ -1017,10 +1017,14 @@ static void invoke_callback(const void* item, const void* action_context, bool*
if (NULL != caller_info->on_event_send_complete_callback)
{
#if defined(_MSC_VER) /* pragma warning is only available on Microsoft C compilers */
#pragma warning(push)
#pragma warning(disable:4305) // Allow typecasting to smaller type on 64 bit systems, since we control ultimate caller.
#endif
TELEMETRY_MESSENGER_EVENT_SEND_COMPLETE_RESULT messenger_send_result = (TELEMETRY_MESSENGER_EVENT_SEND_COMPLETE_RESULT)action_context;
#if defined(_MSC_VER) /* pragma warning is only available on Microsoft C compilers */
#pragma warning(pop)
#endif
caller_info->on_event_send_complete_callback(caller_info->message, messenger_send_result, caller_info->context);
}
*continue_processing = true;

Просмотреть файл

@ -17,6 +17,7 @@
#include "internal/iothubtransport_amqp_messenger.h"
#include "internal/iothubtransport_amqp_twin_messenger.h"
#include "iothub_client_options.h"
#include "internal/iothub_internal_consts.h"
MU_DEFINE_ENUM_STRINGS_WITHOUT_INVALID(TWIN_MESSENGER_SEND_STATUS, TWIN_MESSENGER_SEND_STATUS_VALUES);
MU_DEFINE_ENUM_STRINGS_WITHOUT_INVALID(TWIN_REPORT_STATE_RESULT, TWIN_REPORT_STATE_RESULT_VALUES);
@ -44,7 +45,6 @@ MU_DEFINE_ENUM_STRINGS_WITHOUT_INVALID(TWIN_UPDATE_TYPE, TWIN_UPDATE_TYPE_VALUES
#define TWIN_CORRELATION_ID_PROPERTY_NAME "com.microsoft:channel-correlation-id"
#define TWIN_API_VERSION_PROPERTY_NAME "com.microsoft:api-version"
#define TWIN_CORRELATION_ID_PROPERTY_FORMAT "twin:%s"
#define TWIN_API_VERSION_NUMBER "2016-11-14"
#define DEFAULT_MAX_TWIN_SUBSCRIPTION_ERROR_COUNT 3
#define DEFAULT_TWIN_OPERATION_TIMEOUT_SECS 300.0
@ -687,7 +687,7 @@ static MAP_HANDLE create_link_attach_properties(TWIN_MESSENGER_INSTANCE* twin_ms
destroy_link_attach_properties(result);
result = NULL;
}
else if (Map_Add(result, TWIN_API_VERSION_PROPERTY_NAME, TWIN_API_VERSION_NUMBER) != MAP_OK)
else if (Map_Add(result, TWIN_API_VERSION_PROPERTY_NAME, IOTHUB_API_VERSION) != MAP_OK)
{
LogError("Failed adding AMQP link property 'api-version' (%s)", twin_msgr->device_id);
destroy_link_attach_properties(result);
@ -1620,7 +1620,7 @@ static void on_amqp_messenger_state_changed_callback(void* context, AMQP_MESSENG
}
// Else, it shall wait for the moment the AMQP msgr is subscribed.
}
else if (twin_msgr->state == TWIN_MESSENGER_STATE_STOPPING && new_state == TWIN_MESSENGER_STATE_STOPPED)
else if (twin_msgr->state == TWIN_MESSENGER_STATE_STOPPING && new_state == AMQP_MESSENGER_STATE_STOPPED)
{
if (!twin_msgr->amqp_msgr_is_subscribed)
{
@ -1776,7 +1776,7 @@ TWIN_MESSENGER_HANDLE twin_messenger_create(const TWIN_MESSENGER_CONFIG* messeng
// Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_013: [`amqp_msgr_config->device_id` shall be set with `twin_msgr->device_id`]
// Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_014: [`amqp_msgr_config->iothub_host_fqdn` shall be set with `twin_msgr->iothub_host_fqdn`]
// Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_015: [`amqp_msgr_config` shall have "twin/" as send link target suffix and receive link source suffix]
// Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_016: [`amqp_msgr_config` shall have send and receive link attach properties set as "com.microsoft:client-version" = `twin_msgr->client_version`, "com.microsoft:channel-correlation-id" = `twin:<UUID>`, "com.microsoft:api-version" = "2016-11-14"]
// Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_016: [`amqp_msgr_config` shall have send and receive link attach properties set as "com.microsoft:client-version" = `twin_msgr->client_version`, "com.microsoft:channel-correlation-id" = `twin:<UUID>`, "com.microsoft:api-version" = "Current API version"]
// Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_017: [`amqp_msgr_config` shall be set with `on_amqp_messenger_state_changed_callback` and `on_amqp_messenger_subscription_changed_callback` callbacks]
AMQP_MESSENGER_CONFIG amqp_msgr_config;
amqp_msgr_config.prod_info_cb = twin_msgr->prod_info_cb;

Просмотреть файл

@ -81,6 +81,8 @@ static const char* DEVICE_METHOD_RESPONSE_TOPIC = "$iothub/methods/res/%d/?$rid=
static const char* REQUEST_ID_PROPERTY = "?$rid=";
static const char* MESSAGE_ID_PROPERTY = "mid";
static const char* MESSAGE_CREATION_TIME_UTC = "ctime";
static const char* MESSAGE_USER_ID = "uid";
static const char* CORRELATION_ID_PROPERTY = "cid";
static const char* CONTENT_TYPE_PROPERTY = "ct";
static const char* CONTENT_ENCODING_PROPERTY = "ce";
@ -91,6 +93,10 @@ static const char* CONNECTION_MODULE_ID_PROPERTY = "cmid";
static const char* DIAGNOSTIC_CONTEXT_CREATION_TIME_UTC_PROPERTY = "creationtimeutc";
static const char DT_MODEL_ID_TOKEN[] = "model-id";
static const char DEFAULT_IOTHUB_PRODUCT_IDENTIFIER[] = CLIENT_DEVICE_TYPE_PREFIX "/" IOTHUB_SDK_VERSION;
#define TOLOWER(c) (((c>='A') && (c<='Z'))?c-'A'+'a':c)
#define UNSUBSCRIBE_FROM_TOPIC 0x0000
@ -236,7 +242,7 @@ typedef struct MQTTTRANSPORT_HANDLE_DATA_TAG
int http_proxy_port;
char* http_proxy_username;
char* http_proxy_password;
bool isProductInfoSet;
bool isConnectUsernameSet;
int disconnect_recv_flag;
} MQTTTRANSPORT_HANDLE_DATA, *PMQTTTRANSPORT_HANDLE_DATA;
@ -293,6 +299,7 @@ static void free_proxy_data(MQTTTRANSPORT_HANDLE_DATA* mqtt_transport_instance)
// Destroys xio transport associated with MQTT handle and resets appropriate state
static void DestroyXioTransport(PMQTTTRANSPORT_HANDLE_DATA transport_data)
{
mqtt_client_clear_xio(transport_data->mqttClient);
xio_destroy(transport_data->xioTransport);
transport_data->xioTransport = NULL;
}
@ -311,6 +318,7 @@ static void free_transport_handle_data(MQTTTRANSPORT_HANDLE_DATA* transport_data
if (transport_data->mqttClient != NULL)
{
mqtt_client_deinit(transport_data->mqttClient);
transport_data->mqttClient = NULL;
}
if (transport_data->retry_control_handle != NULL)
@ -418,6 +426,7 @@ static const char* retrieve_mqtt_return_codes(CONNECT_RETURN_CODE rtn_code)
static int retrieve_device_method_rid_info(const char* resp_topic, STRING_HANDLE method_name, STRING_HANDLE request_id)
{
int result;
STRING_TOKENIZER_HANDLE token_handle = STRING_TOKENIZER_create_from_char(resp_topic);
if (token_handle == NULL)
{
@ -474,6 +483,7 @@ static int retrieve_device_method_rid_info(const char* resp_topic, STRING_HANDLE
}
STRING_TOKENIZER_destroy(token_handle);
}
return result;
}
@ -727,6 +737,17 @@ static int addSystemPropertiesTouMqttMessage(IOTHUB_MESSAGE_HANDLE iothub_messag
index++;
}
}
if (result == 0)
{
const char* message_creation_time_utc = IoTHubMessage_GetMessageCreationTimeUtcSystemProperty(iothub_message_handle);
if (message_creation_time_utc != NULL)
{
result = addSystemPropertyToTopicString(topic_string, index, MESSAGE_CREATION_TIME_UTC, message_creation_time_utc, urlencode);
index++;
}
}
if (result == 0)
{
if (is_security_msg)
@ -1184,15 +1205,17 @@ static int subscribeToNotifyStateIfNeeded(PMQTTTRANSPORT_HANDLE_DATA transport_d
return result;
}
static bool isSystemProperty(const char* tokenData)
{
bool result = false;
size_t propCount = sizeof(sysPropList) / sizeof(sysPropList[0]);
size_t index = 0;
size_t tokenDataLength = strlen(tokenData);
for (index = 0; index < propCount; index++)
{
if (memcmp(tokenData, sysPropList[index].propName, sysPropList[index].propLength) == 0)
if (tokenDataLength >= sysPropList[index].propLength &&
memcmp(tokenData, sysPropList[index].propName, sysPropList[index].propLength) == 0)
{
result = true;
break;
@ -1259,6 +1282,19 @@ static int setMqttMessagePropertyIfPossible(IOTHUB_MESSAGE_HANDLE IoTHubMessage,
// Not finding a system property to map to isn't an error.
int result = 0;
if (nameLen > 5)
{
if (strcmp((const char*)&propName[nameLen - 5], MESSAGE_CREATION_TIME_UTC) == 0)
{
if (IoTHubMessage_SetMessageCreationTimeUtcSystemProperty(IoTHubMessage, propValue) != IOTHUB_MESSAGE_OK)
{
LogError("Failed to set IOTHUB_MESSAGE_HANDLE 'CreationTimeUtc' property.");
result = MU_FAILURE;
}
return result;
}
}
if (nameLen > 4)
{
if (strcmp((const char*)&propName[nameLen - 4], CONNECTION_DEVICE_ID) == 0)
@ -1302,6 +1338,15 @@ static int setMqttMessagePropertyIfPossible(IOTHUB_MESSAGE_HANDLE IoTHubMessage,
}
return result;
}
else if (strcmp((const char*)&propName[nameLen - 3], MESSAGE_USER_ID) == 0)
{
if (IoTHubMessage_SetMessageUserIdSystemProperty(IoTHubMessage, propValue) != IOTHUB_MESSAGE_OK)
{
LogError("Failed to set IOTHUB_MESSAGE_HANDLE 'userId' property.");
result = MU_FAILURE;
}
return result;
}
}
if (nameLen > 2)
@ -2172,6 +2217,81 @@ static STRING_HANDLE buildClientId(const char* device_id, const char* module_id)
}
}
static int buildConfigForUsernameStep2IfNeeded(PMQTTTRANSPORT_HANDLE_DATA transport_data)
{
int result;
if (!transport_data->isConnectUsernameSet)
{
STRING_HANDLE userName = NULL;
STRING_HANDLE modelIdParameter = NULL;
STRING_HANDLE urlEncodedModelId = NULL;
const char* modelId = transport_data->transport_callbacks.get_model_id_cb(transport_data->transport_ctx);
// TODO: The preview API version in SDK is only scoped to scenarios that require the modelId to be set.
// https://github.com/Azure/azure-iot-sdk-c/issues/1547 tracks removing this once non-preview API versions support modelId.
const char* apiVersion = IOTHUB_API_VERSION;
const char* appSpecifiedProductInfo = transport_data->transport_callbacks.prod_info_cb(transport_data->transport_ctx);
STRING_HANDLE productInfoEncoded = NULL;
if ((productInfoEncoded = URL_EncodeString((appSpecifiedProductInfo != NULL) ? appSpecifiedProductInfo : DEFAULT_IOTHUB_PRODUCT_IDENTIFIER)) == NULL)
{
LogError("Unable to UrlEncode productInfo");
result = MU_FAILURE;
}
else if ((userName = STRING_construct_sprintf("%s?api-version=%s&DeviceClientType=%s", STRING_c_str(transport_data->configPassedThroughUsername), apiVersion, STRING_c_str(productInfoEncoded))) == NULL)
{
LogError("Failed constructing string");
result = 0;
}
else if (modelId != NULL)
{
if ((urlEncodedModelId = URL_EncodeString(modelId)) == NULL)
{
LogError("Failed to URL encode the modelID string");
result = MU_FAILURE;
}
else if ((modelIdParameter = STRING_construct_sprintf("&%s=%s", DT_MODEL_ID_TOKEN, STRING_c_str(urlEncodedModelId))) == NULL)
{
LogError("Cannot build modelID string");
result = MU_FAILURE;
}
else if (STRING_concat_with_STRING(userName, modelIdParameter) != 0)
{
LogError("Failed to set modelID parameter in connect");
result = MU_FAILURE;
}
else
{
result = 0;
}
}
else
{
result = 0;
}
if (result == 0)
{
STRING_delete(transport_data->configPassedThroughUsername);
transport_data->configPassedThroughUsername = userName;
userName = NULL;
// setting connect string is only allowed once in the lifetime of the device client.
transport_data->isConnectUsernameSet = true;
}
STRING_delete(userName);
STRING_delete(modelIdParameter);
STRING_delete(urlEncodedModelId);
STRING_delete(productInfoEncoded);
}
else
{
result = 0;
}
return result;
}
static int SendMqttConnectMsg(PMQTTTRANSPORT_HANDLE_DATA transport_data)
{
int result;
@ -2215,47 +2335,13 @@ static int SendMqttConnectMsg(PMQTTTRANSPORT_HANDLE_DATA transport_data)
if (result == 0)
{
if (!transport_data->isProductInfoSet)
{
// This requires the iothubClientHandle, which sadly the MQTT transport only gets on DoWork, so this code still needs to remain here.
// The correct place for this would be in the Create method, but we don't get the client handle there.
// Also, when device multiplexing is used, the customer creates the transport directly and explicitly, when the client is still not created.
// This will be a major hurdle when we add device multiplexing to MQTT transport.
STRING_HANDLE clone;
const char* product_info = transport_data->transport_callbacks.prod_info_cb(transport_data->transport_ctx);
if (product_info == NULL)
{
clone = STRING_construct_sprintf("%s%%2F%s", CLIENT_DEVICE_TYPE_PREFIX, IOTHUB_SDK_VERSION);
}
else
{
clone = URL_EncodeString(product_info);
}
if (clone == NULL)
{
LogError("Failed obtaining the product info");
}
else
{
if (STRING_concat_with_STRING(transport_data->configPassedThroughUsername, clone) != 0)
{
LogError("Failed concatenating the product info");
}
else
{
transport_data->isProductInfoSet = true;
}
STRING_delete(clone);
}
}
STRING_HANDLE clientId;
clientId = buildClientId(STRING_c_str(transport_data->device_id), STRING_c_str(transport_data->module_id));
if (NULL == clientId)
if (buildConfigForUsernameStep2IfNeeded(transport_data) != 0)
{
LogError("Failed to add optional connect parameters.");
result = MU_FAILURE;
}
else if ((clientId = buildClientId(STRING_c_str(transport_data->device_id), STRING_c_str(transport_data->module_id))) == NULL)
{
LogError("Unable to allocate clientId");
result = MU_FAILURE;
@ -2301,7 +2387,6 @@ static int SendMqttConnectMsg(PMQTTTRANSPORT_HANDLE_DATA transport_data)
}
STRING_delete(clientId);
}
}
return result;
}
@ -2432,15 +2517,18 @@ static int InitializeConnection(PMQTTTRANSPORT_HANDLE_DATA transport_data)
return result;
}
static STRING_HANDLE buildConfigForUsername(const IOTHUB_CLIENT_CONFIG* upperConfig, const char* moduleId)
// At handle creation time, we don't have all the fields required for building up the user name (e.g. productID)
// We build up as much of the string as we can at this point because we do not store upperConfig after initialization.
// In buildConfigForUsernameStep2IfNeeded, only immediately before we do CONNECT itself, do we complete building up this string.
static STRING_HANDLE buildConfigForUsernameStep1(const IOTHUB_CLIENT_CONFIG* upperConfig, const char* moduleId)
{
if (moduleId == NULL)
{
return STRING_construct_sprintf("%s.%s/%s/?api-version=%s&DeviceClientType=", upperConfig->iotHubName, upperConfig->iotHubSuffix, upperConfig->deviceId, IOTHUB_API_VERSION);
return STRING_construct_sprintf("%s.%s/%s/", upperConfig->iotHubName, upperConfig->iotHubSuffix, upperConfig->deviceId);
}
else
{
return STRING_construct_sprintf("%s.%s/%s/%s/?api-version=%s&DeviceClientType=", upperConfig->iotHubName, upperConfig->iotHubSuffix, upperConfig->deviceId, moduleId, IOTHUB_API_VERSION);
return STRING_construct_sprintf("%s.%s/%s/%s/", upperConfig->iotHubName, upperConfig->iotHubSuffix, upperConfig->deviceId, moduleId);
}
}
@ -2528,7 +2616,7 @@ static PMQTTTRANSPORT_HANDLE_DATA InitializeTransportHandleData(const IOTHUB_CLI
}
else
{
/* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_008: [If the upperConfig contains a valid protocolGatewayHostName value the this shall be used for the hostname, otherwise the hostname shall be constructed using the iothubname and iothubSuffix.] */
/* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_008: [If the upperConfig contains a valid protocolGatewayHostName value this shall be used for the hostname, otherwise the hostname shall be constructed using the iothubName and iothubSuffix.] */
if (upperConfig->protocolGatewayHostName == NULL)
{
state->hostAddress = STRING_construct_sprintf("%s.%s", upperConfig->iotHubName, upperConfig->iotHubSuffix);
@ -2544,7 +2632,7 @@ static PMQTTTRANSPORT_HANDLE_DATA InitializeTransportHandleData(const IOTHUB_CLI
free_transport_handle_data(state);
state = NULL;
}
else if ((state->configPassedThroughUsername = buildConfigForUsername(upperConfig, moduleId)) == NULL)
else if ((state->configPassedThroughUsername = buildConfigForUsernameStep1(upperConfig, moduleId)) == NULL)
{
free_transport_handle_data(state);
state = NULL;
@ -2580,7 +2668,7 @@ static PMQTTTRANSPORT_HANDLE_DATA InitializeTransportHandleData(const IOTHUB_CLI
state->topic_DeviceMethods = NULL;
state->topic_InputQueue = NULL;
state->log_trace = state->raw_trace = false;
state->isProductInfoSet = false;
state->isConnectUsernameSet = false;
state->auto_url_encode_decode = false;
state->conn_attempted = false;
}
@ -3171,7 +3259,10 @@ void IoTHubTransport_MQTT_Common_DoWork(TRANSPORT_LL_HANDLE handle)
currentListEntry = savedFromCurrentListEntry.Flink;
}
sendPendingGetTwinRequests(transport_data);
if (transport_data->twin_resp_sub_recv)
{
sendPendingGetTwinRequests(transport_data);
}
}
/* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_030: [IoTHubTransport_MQTT_Common_DoWork shall call mqtt_client_dowork everytime it is called if it is connected.] */
mqtt_client_dowork(transport_data->mqttClient);

Просмотреть файл

@ -15,6 +15,7 @@
#include "azure_uamqp_c/amqp_definitions_application_properties.h"
#include "internal/iothubtransportamqp_methods.h"
#include "internal/iothub_internal_consts.h"
typedef enum SUBSCRIBE_STATE_TAG
{
@ -602,8 +603,8 @@ static int set_link_attach_properties(IOTHUBTRANSPORT_AMQP_METHODS_HANDLE iothub
}
else
{
/* Codes_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_151: [ A property value of type string that shall contain the `2016-11-14` shall be created by calling `amqpvalue_create_string`. ]*/
AMQP_VALUE api_version_property_value = amqpvalue_create_string("2016-11-14");
/* Codes_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_151: [ A property value of type string that shall contain the `Current API version` shall be created by calling `amqpvalue_create_string`. ]*/
AMQP_VALUE api_version_property_value = amqpvalue_create_string(IOTHUB_API_VERSION);
if (api_version_property_value == NULL)
{
/* Codes_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_145: [ If any call for creating or setting the link attach properties fails `iothubtransportamqp_methods_subscribe` shall fail and return a non-zero value. ]*/
@ -1091,4 +1092,4 @@ int iothubtransportamqp_methods_respond(IOTHUBTRANSPORT_AMQP_METHOD_HANDLE metho
}
return result;
}
}

Просмотреть файл

@ -31,6 +31,7 @@
#define AMQP_DIAGNOSTIC_ID_KEY "Diagnostic-Id"
#define AMQP_DIAGNOSTIC_CONTEXT_KEY "Correlation-Context"
#define AMQP_DIAGNOSTIC_CREATION_TIME_UTC_KEY "creationtimeutc"
#define AMQP_IOTHUB_CREATION_TIME_UTC "iothub-creation-time-utc"
static int encode_callback(void* context, const unsigned char* bytes, size_t length)
{
@ -90,7 +91,7 @@ static int set_message_correlation_id_if_needed(IOTHUB_MESSAGE_HANDLE messageHan
if ((uamqp_correlation_id = amqpvalue_create_string(correlationId)) == NULL)
{
LogError("Failed amqpvalue_create_string for message_id");
LogError("Failed amqpvalue_create_string for correlationId");
result = MU_FAILURE;
}
else if (properties_set_correlation_id(uamqp_message_properties, uamqp_correlation_id) != 0)
@ -309,18 +310,31 @@ static int override_fault_injection_properties_if_needed(MESSAGE_HANDLE message_
static int create_application_properties_to_encode(MESSAGE_HANDLE message_batch_container, IOTHUB_MESSAGE_HANDLE messageHandle, AMQP_VALUE *application_properties, size_t *application_properties_length)
{
MAP_HANDLE properties_map;
const char* const* property_keys;
const char* const* property_values;
const char* const* property_keys = NULL;
const char* const* property_values = NULL;
const char* message_creation_time_utc;
size_t property_count = 0;
AMQP_VALUE uamqp_properties_map = NULL;
int result;
int result = RESULT_OK;
if ((properties_map = IoTHubMessage_Properties(messageHandle)) == NULL)
{
LogError("Failed to get property map from IoTHub message.");
result = MU_FAILURE;
}
else if (Map_GetInternals(properties_map, &property_keys, &property_values, &property_count) != MAP_OK)
if (RESULT_OK == result &&
NULL != (message_creation_time_utc = IoTHubMessage_GetMessageCreationTimeUtcSystemProperty(messageHandle)))
{
if (Map_AddOrUpdate(properties_map, AMQP_IOTHUB_CREATION_TIME_UTC, message_creation_time_utc) != MAP_OK)
{
LogError("Failed to add/update application message property map.");
result = MU_FAILURE;
}
}
if (RESULT_OK == result &&
Map_GetInternals(properties_map, &property_keys, &property_values, &property_count) != MAP_OK)
{
LogError("Failed reading the incoming uAMQP message properties");
result = MU_FAILURE;
@ -389,10 +403,6 @@ static int create_application_properties_to_encode(MESSAGE_HANDLE message_batch_
}
}
}
else
{
result = RESULT_OK;
}
if (NULL != uamqp_properties_map)
{
@ -521,6 +531,7 @@ static int create_diagnostic_message_annotations(IOTHUB_MESSAGE_HANDLE messageHa
}
return result;
}
static int create_security_message_annotations(IOTHUB_MESSAGE_HANDLE messageHandle, AMQP_VALUE* message_annotations_map)
{
int result = RESULT_OK;
@ -984,6 +995,34 @@ static int readCorrelationIdFromuAQMPMessage(IOTHUB_MESSAGE_HANDLE iothub_messag
return result;
}
static int readUserIdFromuAQMPMessage(IOTHUB_MESSAGE_HANDLE iothub_message_handle, PROPERTIES_HANDLE uamqp_message_properties)
{
int result;
amqp_binary uamqp_message_property;
if (properties_get_user_id(uamqp_message_properties, &uamqp_message_property) != 0 || uamqp_message_property.length == 0)
{
result = RESULT_OK;
}
else
{
char string_buffer[MESSAGE_ID_MAX_SIZE];
memset(string_buffer, 0, MESSAGE_ID_MAX_SIZE);
strncpy(string_buffer, uamqp_message_property.bytes, uamqp_message_property.length > (MESSAGE_ID_MAX_SIZE - 1) ? MESSAGE_ID_MAX_SIZE - 1 : uamqp_message_property.length);
if (IoTHubMessage_SetMessageUserIdSystemProperty(iothub_message_handle, string_buffer) != IOTHUB_MESSAGE_OK)
{
LogError("Failed to set IOTHUB_MESSAGE_HANDLE 'user-id' property.");
result = MU_FAILURE;
}
else
{
result = RESULT_OK;
}
}
return result;
}
static int readPropertiesFromuAMQPMessage(IOTHUB_MESSAGE_HANDLE iothub_message_handle, MESSAGE_HANDLE uamqp_message)
{
int result;
@ -1007,7 +1046,12 @@ static int readPropertiesFromuAMQPMessage(IOTHUB_MESSAGE_HANDLE iothub_message_h
}
else if (readCorrelationIdFromuAQMPMessage(iothub_message_handle, uamqp_message_properties) != RESULT_OK)
{
LogError("Failed readPropertiesFromuAMQPMessage.");
LogError("Failed readCorrelationIdFromuAQMPMessage.");
result = MU_FAILURE;
}
else if (readUserIdFromuAQMPMessage(iothub_message_handle, uamqp_message_properties) != RESULT_OK)
{
LogError("Failed readUserIdFromuAQMPMessage.");
result = MU_FAILURE;
}
else

Просмотреть файл

@ -301,6 +301,16 @@ static void reset_test_data()
memset(&context, 0, sizeof(context));
}
static void set_expected_calls_for_Blob_UploadMultipleBlocksFromSasUri_cleanup()
{
STRICT_EXPECTED_CALL(HTTPAPIEX_Destroy(IGNORED_PTR_ARG)) /*this is the HTTPAPIEX handle*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG))/*this is the XML string used for Put Block List operation*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)) /*this is freeing the copy of hte hostname*/
.IgnoreArgument_ptr();
}
TEST_FUNCTION_INITIALIZE(Setup)
{
umock_c_reset_all_calls();
@ -402,12 +412,7 @@ TEST_FUNCTION(Blob_UploadMultipleBlocksFromSasUri_succeeds_when_HTTP_status_code
.IgnoreArgument_handle();
}
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG))/*this is the XML string used for Put Block List operation*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(HTTPAPIEX_Destroy(IGNORED_PTR_ARG)) /*this is the HTTPAPIEX handle*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)) /*this is freeing the copy of hte hostname*/
.IgnoreArgument_ptr();
set_expected_calls_for_Blob_UploadMultipleBlocksFromSasUri_cleanup();
///act
BLOB_RESULT result = Blob_UploadMultipleBlocksFromSasUri(TEST_VALID_SASURI_1, FileUpload_GetData_Callback, &context, &httpResponse, testValidBufferHandle, NULL, NULL);
@ -480,12 +485,7 @@ TEST_FUNCTION(Blob_UploadMultipleBlocksFromSasUri_fails_when_HTTPAPIEX_ExecuteRe
.IgnoreArgument_handle();
}
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG))/*this is the XML string used for Put Block List operation*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(HTTPAPIEX_Destroy(IGNORED_PTR_ARG)) /*this is the HTTPAPIEX handle*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)) /*this is freeing the copy of hte hostname*/
.IgnoreArgument_ptr();
set_expected_calls_for_Blob_UploadMultipleBlocksFromSasUri_cleanup();
///act
BLOB_RESULT result = Blob_UploadMultipleBlocksFromSasUri(TEST_VALID_SASURI_1, FileUpload_GetData_Callback, &context, &httpResponse, testValidBufferHandle, NULL, NULL);
@ -516,14 +516,8 @@ TEST_FUNCTION(Blob_UploadMultipleBlocksFromSasUri_fails_when_BUFFER_create_fails
STRICT_EXPECTED_CALL(BUFFER_create(&c, 1))
.SetReturn(NULL);
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG))/*this is the XML string used for Put Block List operation*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(HTTPAPIEX_Destroy(IGNORED_PTR_ARG))
.IgnoreArgument_handle();
}
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG))
.IgnoreArgument_ptr();
set_expected_calls_for_Blob_UploadMultipleBlocksFromSasUri_cleanup();
}
///act
@ -550,10 +544,10 @@ TEST_FUNCTION(Blob_UploadMultipleBlocksFromSasUri_fails_when_HTTPAPIEX_Create_fa
STRICT_EXPECTED_CALL(HTTPAPIEX_Create(TEST_HOSTNAME_1))
.SetReturn(NULL)
;
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG))
.IgnoreArgument_ptr();
}
set_expected_calls_for_Blob_UploadMultipleBlocksFromSasUri_cleanup();
///act
BLOB_RESULT result = Blob_UploadMultipleBlocksFromSasUri(TEST_VALID_SASURI_1, FileUpload_GetData_Callback, &context, &httpResponse, testValidBufferHandle, NULL, NULL);
@ -577,6 +571,8 @@ TEST_FUNCTION(Blob_UploadMultipleBlocksFromSasUri_fails_when_malloc_fails)
.SetReturn(NULL)
;
set_expected_calls_for_Blob_UploadMultipleBlocksFromSasUri_cleanup();
///act
BLOB_RESULT result = Blob_UploadMultipleBlocksFromSasUri(TEST_VALID_SASURI_1, FileUpload_GetData_Callback, &context, &httpResponse, testValidBufferHandle, NULL, NULL);
@ -596,6 +592,8 @@ TEST_FUNCTION(Blob_UploadMultipleBlocksFromSasUri_when_SasUri_is_wrong_fails_1)
context.source = &c;
context.toUpload = context.size;
set_expected_calls_for_Blob_UploadMultipleBlocksFromSasUri_cleanup();
///act
BLOB_RESULT result = Blob_UploadMultipleBlocksFromSasUri("https:/h.h/doms", FileUpload_GetData_Callback, &context, &httpResponse, testValidBufferHandle, NULL, NULL); /*wrong format for protocol, notice it is actually http:\h.h\doms (missing a \ from http)*/
@ -615,6 +613,8 @@ TEST_FUNCTION(Blob_UploadMultipleBlocksFromSasUri_when_SasUri_is_wrong_fails_2)
context.source = &c;
context.toUpload = context.size;
set_expected_calls_for_Blob_UploadMultipleBlocksFromSasUri_cleanup();
///act
BLOB_RESULT result = Blob_UploadMultipleBlocksFromSasUri("https://h.h", FileUpload_GetData_Callback, &context, &httpResponse, testValidBufferHandle, NULL, NULL); /*there's no relative path here*/
@ -750,12 +750,7 @@ static void Blob_UploadMultipleBlocksFromSasUri_various_sizes_happy_path_Impl(HT
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)) /*this is destroying the relative path for Put Block List*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG))/*this is the XML string used for Put Block List operation*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(HTTPAPIEX_Destroy(IGNORED_PTR_ARG)) /*this is the HTTPAPIEX handle*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)) /*this is freeing the copy of hte hostname*/
.IgnoreArgument_ptr();
set_expected_calls_for_Blob_UploadMultipleBlocksFromSasUri_cleanup();
///act
BLOB_RESULT result = Blob_UploadMultipleBlocksFromSasUri("https://h.h/something?a=b", FileUpload_GetData_Callback, &context, &httpResponse, testValidBufferHandle, NULL, proxyOptions);
@ -932,12 +927,7 @@ TEST_FUNCTION(Blob_UploadMultipleBlocksFromSasUri_various_sizes_with_certificate
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)) /*this is destroying the relative path for Put Block List*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG))/*this is the XML string used for Put Block List operation*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(HTTPAPIEX_Destroy(IGNORED_PTR_ARG)) /*this is the HTTPAPIEX handle*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)) /*this is freeing the copy of hte hostname*/
.IgnoreArgument_ptr();
set_expected_calls_for_Blob_UploadMultipleBlocksFromSasUri_cleanup();
///act
BLOB_RESULT result = Blob_UploadMultipleBlocksFromSasUri("https://h.h/something?a=b", FileUpload_GetData_Callback, &context, &httpResponse, testValidBufferHandle, "a", NULL);
@ -955,87 +945,8 @@ TEST_FUNCTION(Blob_UploadMultipleBlocksFromSasUri_various_sizes_with_certificate
TEST_FUNCTION(Blob_UploadMultipleBlocksFromSasUri_64MB_unhappy_paths)
{
size_t size = 64 * 1024 * 1024;
size_t calls_that_cannot_fail[] =
{
13 ,/*STRING_delete*/
26 ,/*STRING_delete*/
39 ,/*STRING_delete*/
52 ,/*STRING_delete*/
65 ,/*STRING_delete*/
78 ,/*STRING_delete*/
91 ,/*STRING_delete*/
104 ,/*STRING_delete*/
117 ,/*STRING_delete*/
130 ,/*STRING_delete*/
143 ,/*STRING_delete*/
156 ,/*STRING_delete*/
169 ,/*STRING_delete*/
182 ,/*STRING_delete*/
195 ,/*STRING_delete*/
208 ,/*STRING_delete*/
11 ,/*STRING_c_str*/
24 ,/*STRING_c_str*/
37 ,/*STRING_c_str*/
50 ,/*STRING_c_str*/
63 ,/*STRING_c_str*/
76 ,/*STRING_c_str*/
89 ,/*STRING_c_str*/
102 ,/*STRING_c_str*/
115 ,/*STRING_c_str*/
128 ,/*STRING_c_str*/
141 ,/*STRING_c_str*/
154 ,/*STRING_c_str*/
167 ,/*STRING_c_str*/
180 ,/*STRING_c_str*/
193 ,/*STRING_c_str*/
206 ,/*STRING_c_str*/
14 ,/*STRING_delete*/
27 ,/*STRING_delete*/
40 ,/*STRING_delete*/
53 ,/*STRING_delete*/
66 ,/*STRING_delete*/
79 ,/*STRING_delete*/
92 ,/*STRING_delete*/
105 ,/*STRING_delete*/
118 ,/*STRING_delete*/
131 ,/*STRING_delete*/
144 ,/*STRING_delete*/
157 ,/*STRING_delete*/
170 ,/*STRING_delete*/
183 ,/*STRING_delete*/
196 ,/*STRING_delete*/
209 ,/*STRING_delete*/
15 ,/*BUFFER_delete*/
28 ,/*BUFFER_delete*/
41 ,/*BUFFER_delete*/
54 ,/*BUFFER_delete*/
67 ,/*BUFFER_delete*/
80 ,/*BUFFER_delete*/
93 ,/*BUFFER_delete*/
106 ,/*BUFFER_delete*/
119 ,/*BUFFER_delete*/
132 ,/*BUFFER_delete*/
145 ,/*BUFFER_delete*/
158 ,/*BUFFER_delete*/
171 ,/*BUFFER_delete*/
184 ,/*BUFFER_delete*/
197 ,/*BUFFER_delete*/
210 ,/*BUFFER_delete*/
214, /*STRING_c_str*/
216, /*STRING_c_str*/
218, /*BUFFER_delete*/
219, /*STRING_delete*/
220, /*STRING_delete*/
221, /*HTTPAPIEX_Destroy*/
222, /*gballoc_free*/
};
(void)umock_c_negative_tests_init();
umock_c_reset_all_calls();
///arrange
unsigned char * content = (unsigned char*)gballoc_malloc(size);
@ -1083,7 +994,8 @@ TEST_FUNCTION(Blob_UploadMultipleBlocksFromSasUri_64MB_unhappy_paths)
.IgnoreArgument_s2();
STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)) /*this is getting the relative path as const char* */ /*11, 24, 27...*/
.IgnoreArgument_handle();
.IgnoreArgument_handle()
.CallCannotFail();
STRICT_EXPECTED_CALL(HTTPAPIEX_ExecuteRequest(IGNORED_PTR_ARG, HTTPAPI_REQUEST_PUT, IGNORED_PTR_ARG, NULL, IGNORED_PTR_ARG, &httpResponse, NULL, testValidBufferHandle))
.IgnoreArgument_handle()
@ -1109,13 +1021,15 @@ TEST_FUNCTION(Blob_UploadMultipleBlocksFromSasUri_64MB_unhappy_paths)
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)) /*this is getting the XML as const char* so it can be passed to _ExecuteRequest*/
.IgnoreArgument_handle();
.IgnoreArgument_handle()
.CallCannotFail();
STRICT_EXPECTED_CALL(BUFFER_create(IGNORED_PTR_ARG, IGNORED_NUM_ARG)) /*this is creating the XML body as BUFFER_HANDLE*/
.IgnoreAllArguments();
STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)) /*this is getting the relative path*/
.IgnoreArgument_handle();
.IgnoreArgument_handle()
.CallCannotFail();
STRICT_EXPECTED_CALL(HTTPAPIEX_ExecuteRequest(
IGNORED_PTR_ARG,
@ -1137,27 +1051,15 @@ TEST_FUNCTION(Blob_UploadMultipleBlocksFromSasUri_64MB_unhappy_paths)
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)) /*this is destroying the relative path for Put Block List*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG))/*this is the XML string used for Put Block List operation*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(HTTPAPIEX_Destroy(IGNORED_PTR_ARG)) /*this is the HTTPAPIEX handle*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)) /*this is freeing the copy of hte hostname*/
.IgnoreArgument_ptr();
set_expected_calls_for_Blob_UploadMultipleBlocksFromSasUri_cleanup();
umock_c_negative_tests_snapshot();
for (size_t i = 0; i < umock_c_negative_tests_call_count(); i++)
{
size_t j;
umock_c_negative_tests_reset();
for (j = 0;j<sizeof(calls_that_cannot_fail) / sizeof(calls_that_cannot_fail[0]);j++) /*not running the tests that cannot fail*/
{
if (calls_that_cannot_fail[j] == i)
break;
}
if (j == sizeof(calls_that_cannot_fail) / sizeof(calls_that_cannot_fail[0]))
if (umock_c_negative_tests_can_call_fail(i))
{
umock_c_negative_tests_fail_call(i);
@ -1185,83 +1087,6 @@ TEST_FUNCTION(Blob_UploadMultipleBlocksFromSasUri_64MB_with_certificate_unhappy_
{
size_t size = 64 * 1024 * 1024;
size_t calls_that_cannot_fail[] =
{
13 + 1 ,/*STRING_delete*/
26 + 1 ,/*STRING_delete*/
39 + 1 ,/*STRING_delete*/
52 + 1 ,/*STRING_delete*/
65 + 1 ,/*STRING_delete*/
78 + 1 ,/*STRING_delete*/
91 + 1 ,/*STRING_delete*/
104 + 1 ,/*STRING_delete*/
117 + 1 ,/*STRING_delete*/
130 + 1 ,/*STRING_delete*/
143 + 1 ,/*STRING_delete*/
156 + 1 ,/*STRING_delete*/
169 + 1 ,/*STRING_delete*/
182 + 1 ,/*STRING_delete*/
195 + 1 ,/*STRING_delete*/
208 + 1 ,/*STRING_delete*/
11 + 1 ,/*STRING_c_str*/
24 + 1 ,/*STRING_c_str*/
37 + 1 ,/*STRING_c_str*/
50 + 1 ,/*STRING_c_str*/
63 + 1 ,/*STRING_c_str*/
76 + 1 ,/*STRING_c_str*/
89 + 1 ,/*STRING_c_str*/
102 + 1 ,/*STRING_c_str*/
115 + 1 ,/*STRING_c_str*/
128 + 1 ,/*STRING_c_str*/
141 + 1 ,/*STRING_c_str*/
154 + 1 ,/*STRING_c_str*/
167 + 1 ,/*STRING_c_str*/
180 + 1 ,/*STRING_c_str*/
193 + 1 ,/*STRING_c_str*/
206 + 1 ,/*STRING_c_str*/
14 + 1 ,/*STRING_delete*/
27 + 1 ,/*STRING_delete*/
40 + 1 ,/*STRING_delete*/
53 + 1 ,/*STRING_delete*/
66 + 1 ,/*STRING_delete*/
79 + 1 ,/*STRING_delete*/
92 + 1 ,/*STRING_delete*/
105 + 1 ,/*STRING_delete*/
118 + 1 ,/*STRING_delete*/
131 + 1 ,/*STRING_delete*/
144 + 1 ,/*STRING_delete*/
157 + 1 ,/*STRING_delete*/
170 + 1 ,/*STRING_delete*/
183 + 1 ,/*STRING_delete*/
196 + 1 ,/*STRING_delete*/
209 + 1 ,/*STRING_delete*/
15 + 1 ,/*BUFFER_delete*/
28 + 1 ,/*BUFFER_delete*/
41 + 1 ,/*BUFFER_delete*/
54 + 1 ,/*BUFFER_delete*/
67 + 1 ,/*BUFFER_delete*/
80 + 1 ,/*BUFFER_delete*/
93 + 1 ,/*BUFFER_delete*/
106 + 1 ,/*BUFFER_delete*/
119 + 1 ,/*BUFFER_delete*/
132 + 1 ,/*BUFFER_delete*/
145 + 1 ,/*BUFFER_delete*/
158 + 1 ,/*BUFFER_delete*/
171 + 1 ,/*BUFFER_delete*/
184 + 1 ,/*BUFFER_delete*/
197 + 1 ,/*BUFFER_delete*/
210 + 1 ,/*BUFFER_delete*/
214+1, /*STRING_c_str*/
216+1, /*STRING_c_str*/
218+1, /*BUFFER_delete*/
219+1, /*STRING_delete*/
220+1, /*STRING_delete*/
221+1, /*HTTPAPIEX_Destroy*/
222+1, /*gballoc_free*/
};
(void)umock_c_negative_tests_init();
@ -1313,7 +1138,8 @@ TEST_FUNCTION(Blob_UploadMultipleBlocksFromSasUri_64MB_with_certificate_unhappy_
.IgnoreArgument_s2();
STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)) /*this is getting the relative path as const char* */ /*12, 25, 38...*/
.IgnoreArgument_handle();
.IgnoreArgument_handle()
.CallCannotFail();
STRICT_EXPECTED_CALL(HTTPAPIEX_ExecuteRequest(IGNORED_PTR_ARG, HTTPAPI_REQUEST_PUT, IGNORED_PTR_ARG, NULL, IGNORED_PTR_ARG, &httpResponse, NULL, testValidBufferHandle))
.IgnoreArgument_handle()
@ -1339,13 +1165,15 @@ TEST_FUNCTION(Blob_UploadMultipleBlocksFromSasUri_64MB_with_certificate_unhappy_
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)) /*this is getting the XML as const char* so it can be passed to _ExecuteRequest*/
.IgnoreArgument_handle();
.IgnoreArgument_handle()
.CallCannotFail();
STRICT_EXPECTED_CALL(BUFFER_create(IGNORED_PTR_ARG, IGNORED_NUM_ARG)) /*this is creating the XML body as BUFFER_HANDLE*/
.IgnoreAllArguments();
STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)) /*this is getting the relative path*/
.IgnoreArgument_handle();
.IgnoreArgument_handle()
.CallCannotFail();
STRICT_EXPECTED_CALL(HTTPAPIEX_ExecuteRequest(
IGNORED_PTR_ARG,
@ -1367,27 +1195,15 @@ TEST_FUNCTION(Blob_UploadMultipleBlocksFromSasUri_64MB_with_certificate_unhappy_
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)) /*this is destroying the relative path for Put Block List*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG))/*this is the XML string used for Put Block List operation*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(HTTPAPIEX_Destroy(IGNORED_PTR_ARG)) /*this is the HTTPAPIEX handle*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)) /*this is freeing the copy of the hostname*/ /* 223 */
.IgnoreArgument_ptr();
set_expected_calls_for_Blob_UploadMultipleBlocksFromSasUri_cleanup();
umock_c_negative_tests_snapshot();
for (size_t i = 0; i < umock_c_negative_tests_call_count(); i++)
{
size_t j;
umock_c_negative_tests_reset();
for (j = 0;j<sizeof(calls_that_cannot_fail) / sizeof(calls_that_cannot_fail[0]);j++) /*not running the tests that cannot fail*/
{
if (calls_that_cannot_fail[j] == i)
break;
}
if (j == sizeof(calls_that_cannot_fail) / sizeof(calls_that_cannot_fail[0]))
if (umock_c_negative_tests_can_call_fail(i))
{
umock_c_negative_tests_fail_call(i);
@ -1480,12 +1296,7 @@ TEST_FUNCTION(Blob_UploadFromSasUri_when_http_code_is_404_it_immediately_succeed
/*this part is Put Block list*/ /*notice: no op because it failed before with 404*/
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG))/*this is the XML string used for Put Block List operation*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(HTTPAPIEX_Destroy(IGNORED_PTR_ARG)) /*this is the HTTPAPIEX handle*/
.IgnoreArgument_handle();
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)) /*this is freeing the copy of hte hostname*/
.IgnoreArgument_ptr();
set_expected_calls_for_Blob_UploadMultipleBlocksFromSasUri_cleanup();
///act
BLOB_RESULT result = Blob_UploadMultipleBlocksFromSasUri("https://h.h/something?a=b", FileUpload_GetData_Callback, &context, &httpResponse, testValidBufferHandle, NULL, NULL);

Просмотреть файл

@ -47,12 +47,10 @@ typedef struct DEVICE_REPORTED_DATA_TAG
LOCK_HANDLE lock;
} DEVICE_REPORTED_DATA;
static IOTHUB_ACCOUNT_INFO_HANDLE g_iothubAcctInfo = NULL;
static IOTHUB_DEVICE_CLIENT_HANDLE iothub_deviceclient_handle = NULL;
static IOTHUB_MODULE_CLIENT_HANDLE iothub_moduleclient_handle = NULL;
static void reportedStateCallback(int status_code, void* userContextCallback)
{
DEVICE_REPORTED_DATA *device = (DEVICE_REPORTED_DATA *) userContextCallback;
@ -176,10 +174,10 @@ typedef struct DEVICE_DESIRED_DATA_TAG
} DEVICE_DESIRED_DATA;
static const char *REPORTED_PAYLOAD_FORMAT = "{\"integer_property\": %d, \"string_property\": \"%s\"}";
static const char *REPORTED_PAYLOAD_FORMAT = "{\"integer_property\": %d, \"string_property\": \"%s\", \"array\": [%d, \"%s\"] }";
static char *malloc_and_fill_reported_payload(const char *string, int aint)
{
size_t length = snprintf(NULL, 0, REPORTED_PAYLOAD_FORMAT, aint, string);
size_t length = snprintf(NULL, 0, REPORTED_PAYLOAD_FORMAT, aint, string, aint, string);
char *retValue = (char *) malloc(length + 1);
if (retValue == NULL)
{
@ -187,7 +185,7 @@ static char *malloc_and_fill_reported_payload(const char *string, int aint)
}
else
{
(void) sprintf(retValue, REPORTED_PAYLOAD_FORMAT, aint, string);
(void) sprintf(retValue, REPORTED_PAYLOAD_FORMAT, aint, string, aint, string);
}
return retValue;
}
@ -328,7 +326,10 @@ static void dt_e2e_update_twin(IOTHUB_SERVICE_CLIENT_DEVICE_TWIN_HANDLE serviceC
free(twinResponse);
}
static char* dt_e2e_get_twin(IOTHUB_SERVICE_CLIENT_DEVICE_TWIN_HANDLE serviceClientDeviceTwinHandle, IOTHUB_PROVISIONED_DEVICE* deviceToUse)
// Device and modules twins may be retrieved using either the device|module client SDK (the way a device would). Or they may be retrieved
// using the service SDK, simulating how a solution would interact with the twin. The twin retrieved from the service
// provides additional metadata about the device. This helper API uses the service API to retrieve the required data.
static char* dt_e2e_get_twin_from_service(IOTHUB_SERVICE_CLIENT_DEVICE_TWIN_HANDLE serviceClientDeviceTwinHandle, IOTHUB_PROVISIONED_DEVICE* deviceToUse)
{
char *twinData;
@ -350,15 +351,7 @@ static char* dt_e2e_get_twin(IOTHUB_SERVICE_CLIENT_DEVICE_TWIN_HANDLE serviceCli
void dt_e2e_send_reported_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACCOUNT_AUTH_METHOD accountAuthMethod)
{
// arrange
IOTHUB_PROVISIONED_DEVICE* deviceToUse;
if (accountAuthMethod == IOTHUB_ACCOUNT_AUTH_X509)
{
deviceToUse = IoTHubAccount_GetX509Device(g_iothubAcctInfo);
}
else
{
deviceToUse = IoTHubAccount_GetSASDevice(g_iothubAcctInfo);
}
IOTHUB_PROVISIONED_DEVICE* deviceToUse = IoTHubAccount_GetDevice(g_iothubAcctInfo, accountAuthMethod);
DEVICE_REPORTED_DATA *device = device_reported_init();
ASSERT_IS_NOT_NULL(device, "failed to create the device client data");
@ -413,7 +406,7 @@ void dt_e2e_send_reported_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB
IOTHUB_SERVICE_CLIENT_DEVICE_TWIN_HANDLE serviceClientDeviceTwinHandle = IoTHubDeviceTwin_Create(iotHubServiceClientHandle);
ASSERT_IS_NOT_NULL(serviceClientDeviceTwinHandle, "IoTHubDeviceTwin_Create failed");
char *twinData = dt_e2e_get_twin(serviceClientDeviceTwinHandle, deviceToUse);
char *twinData = dt_e2e_get_twin_from_service(serviceClientDeviceTwinHandle, deviceToUse);
JSON_Value *root_value = json_parse_string(twinData);
ASSERT_IS_NOT_NULL(root_value, "json_parse_string failed");
@ -438,10 +431,13 @@ void dt_e2e_send_reported_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB
}
}
static const char *COMPLETE_DESIRED_PAYLOAD_FORMAT = "{\"properties\":{\"desired\":{\"integer_property\": %d, \"string_property\": \"%s\"}}}";
static const char *COMPLETE_DESIRED_PAYLOAD_FORMAT = "{\"properties\":{\"desired\":{\"integer_property\": %d, \"string_property\": \"%s\", \"array\": [%d, \"%s\"]}}}";
static char *malloc_and_fill_desired_payload(const char *string, int aint)
{
size_t length = snprintf(NULL, 0, COMPLETE_DESIRED_PAYLOAD_FORMAT, aint, string);
size_t length = snprintf(NULL, 0, COMPLETE_DESIRED_PAYLOAD_FORMAT, aint, string, aint, string);
char *retValue = (char *) malloc(length + 1);
if (retValue == NULL)
{
@ -449,7 +445,7 @@ static char *malloc_and_fill_desired_payload(const char *string, int aint)
}
else
{
(void) sprintf(retValue, COMPLETE_DESIRED_PAYLOAD_FORMAT, aint, string);
(void) sprintf(retValue, COMPLETE_DESIRED_PAYLOAD_FORMAT, aint, string, aint, string);
}
return retValue;
}
@ -505,7 +501,7 @@ static void deviceTwinCallback(DEVICE_TWIN_UPDATE_STATE update_state, const unsi
}
}
static DEVICE_DESIRED_DATA *device_desired_init()
static DEVICE_DESIRED_DATA *device_desired_data_init()
{
DEVICE_DESIRED_DATA *retValue;
@ -604,7 +600,7 @@ static int dt_e2e_parse_twin_version(const char *twinData, bool jsonFromGetTwin)
static int dt_e2e_gettwin_version(IOTHUB_SERVICE_CLIENT_DEVICE_TWIN_HANDLE serviceClientDeviceTwinHandle, IOTHUB_PROVISIONED_DEVICE* deviceToUse)
{
char *twinData = dt_e2e_get_twin(serviceClientDeviceTwinHandle, deviceToUse);
char *twinData = dt_e2e_get_twin_from_service(serviceClientDeviceTwinHandle, deviceToUse);
int version = dt_e2e_parse_twin_version(twinData, true);
// cleanup
@ -615,17 +611,9 @@ static int dt_e2e_gettwin_version(IOTHUB_SERVICE_CLIENT_DEVICE_TWIN_HANDLE servi
void dt_e2e_get_complete_desired_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACCOUNT_AUTH_METHOD accountAuthMethod)
{
// arrange
IOTHUB_PROVISIONED_DEVICE* deviceToUse;
if (accountAuthMethod == IOTHUB_ACCOUNT_AUTH_X509)
{
deviceToUse = IoTHubAccount_GetX509Device(g_iothubAcctInfo);
}
else
{
deviceToUse = IoTHubAccount_GetSASDevice(g_iothubAcctInfo);
}
IOTHUB_PROVISIONED_DEVICE* deviceToUse = IoTHubAccount_GetDevice(g_iothubAcctInfo, accountAuthMethod);
DEVICE_DESIRED_DATA *device = device_desired_init();
DEVICE_DESIRED_DATA *device = device_desired_data_init();
ASSERT_IS_NOT_NULL(device, "failed to create the device client data");
dt_e2e_create_client_handle(deviceToUse, protocol);
@ -666,6 +654,9 @@ void dt_e2e_get_complete_desired_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol,
JSON_Value *root_value = NULL;
const char *string_property = NULL;
int integer_property = 0;
const char *string_property_from_array = NULL;
int integer_property_from_array = 0;
time_t beginOperation, nowTime;
beginOperation = time(NULL);
@ -699,6 +690,8 @@ void dt_e2e_get_complete_desired_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol,
if (root_value != NULL)
{
JSON_Object *root_object = json_value_get_object(root_value);
JSON_Array *array;
if (root_object != NULL)
{
switch (device->update_state)
@ -706,10 +699,19 @@ void dt_e2e_get_complete_desired_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol,
case DEVICE_TWIN_UPDATE_COMPLETE:
string_property = json_object_dotget_string(root_object, "desired.string_property");
integer_property = (int)json_object_dotget_number(root_object, "desired.integer_property");
array = json_object_dotget_array(root_object, "desired.array");
ASSERT_IS_NOT_NULL(array, "Array not specified");
integer_property_from_array = (int)json_array_get_number(array, 0);
string_property_from_array = json_array_get_string(array, 1);
break;
case DEVICE_TWIN_UPDATE_PARTIAL:
string_property = json_object_get_string(root_object, "string_property");
integer_property = (int)json_object_get_number(root_object, "integer_property");
array = json_object_get_array(root_object, "array");
ASSERT_IS_NOT_NULL(array, "Array not specified");
integer_property_from_array = (int)json_array_get_number(array, 0);
string_property_from_array = json_array_get_string(array, 1);
break;
default: // invalid update state
ASSERT_FAIL("Invalid update_state reported");
@ -744,6 +746,8 @@ void dt_e2e_get_complete_desired_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol,
ASSERT_IS_NOT_NULL(root_value, "json_parse_string failed");
ASSERT_ARE_EQUAL(char_ptr, expected_desired_string, string_property, "string data retrieved differs from expected");
ASSERT_ARE_EQUAL(int, expected_desired_integer, integer_property, "integer data retrieved differs from expected");
ASSERT_ARE_EQUAL(char_ptr, expected_desired_string, string_property_from_array, "string data (from array) retrieved differs from expected");
ASSERT_ARE_EQUAL(int, expected_desired_integer, integer_property_from_array, "integer data (from array) retrieved differs from expected");
(void)Unlock(device->lock);
@ -758,31 +762,17 @@ void dt_e2e_get_complete_desired_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol,
}
}
void dt_e2e_get_twin_async_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACCOUNT_AUTH_METHOD accountAuthMethod)
// request_full_twin_and_wait_for_response requests the full twin from the Hub (using device, NOT service sdk).
// Verifies that the server sends a response or else times out.
static void request_full_twin_and_wait_for_response(IOTHUB_PROVISIONED_DEVICE* deviceToUse, DEVICE_DESIRED_DATA *deviceDesiredData)
{
// arrange
IOTHUB_PROVISIONED_DEVICE* deviceToUse;
if (accountAuthMethod == IOTHUB_ACCOUNT_AUTH_X509)
{
deviceToUse = IoTHubAccount_GetX509Device(g_iothubAcctInfo);
}
else
{
deviceToUse = IoTHubAccount_GetSASDevice(g_iothubAcctInfo);
}
DEVICE_DESIRED_DATA *device = device_desired_init();
ASSERT_IS_NOT_NULL(device, "failed to create the device client data");
dt_e2e_create_client_handle(deviceToUse, protocol);
if (deviceToUse->moduleConnectionString != NULL)
{
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IoTHubModuleClient_GetTwinAsync(iothub_moduleclient_handle, deviceTwinCallback, device), IOTHUB_CLIENT_OK);
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IoTHubModuleClient_GetTwinAsync(iothub_moduleclient_handle, deviceTwinCallback, deviceDesiredData), IOTHUB_CLIENT_OK);
}
else
{
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IoTHubDeviceClient_GetTwinAsync(iothub_deviceclient_handle, deviceTwinCallback, device), IOTHUB_CLIENT_OK);
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IoTHubDeviceClient_GetTwinAsync(iothub_deviceclient_handle, deviceTwinCallback, deviceDesiredData), IOTHUB_CLIENT_OK);
}
bool callbackReceived = false;
@ -793,43 +783,96 @@ void dt_e2e_get_twin_async_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHU
(difftime(nowTime, beginOperation) < MAX_CLOUD_TRAVEL_TIME) // time box
)
{
if (Lock(device->lock) != LOCK_OK)
if (Lock(deviceDesiredData->lock) != LOCK_OK)
{
ASSERT_FAIL("Lock failed");
}
else
{
if (device->receivedCallBack)
if (deviceDesiredData->receivedCallBack)
{
ASSERT_IS_NOT_NULL(device->cb_payload);
ASSERT_IS_TRUE(strlen(device->cb_payload) > 0);
callbackReceived = device->receivedCallBack;
Unlock(device->lock);
ASSERT_IS_NOT_NULL(deviceDesiredData->cb_payload);
ASSERT_IS_TRUE(strlen(deviceDesiredData->cb_payload) > 0);
callbackReceived = deviceDesiredData->receivedCallBack;
Unlock(deviceDesiredData->lock);
break;
}
Unlock(device->lock);
Unlock(deviceDesiredData->lock);
}
ThreadAPI_Sleep(1000);
}
ASSERT_IS_TRUE(callbackReceived, "Did not receive the GetTwinAsync call back");
ASSERT_IS_TRUE(callbackReceived, "Did not receive the GetTwinAsync call back");
}
void dt_e2e_get_twin_async_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACCOUNT_AUTH_METHOD accountAuthMethod)
{
// arrange
IOTHUB_PROVISIONED_DEVICE* deviceToUse = IoTHubAccount_GetDevice(g_iothubAcctInfo, accountAuthMethod);
DEVICE_DESIRED_DATA *deviceDesiredData = device_desired_data_init();
ASSERT_IS_NOT_NULL(deviceDesiredData, "failed to create the device client data");
dt_e2e_create_client_handle(deviceToUse, protocol);
request_full_twin_and_wait_for_response(deviceToUse, deviceDesiredData);
// cleanup
destroy_on_device_or_module();
device_desired_deinit(device);
device_desired_deinit(deviceDesiredData);
}
// dt_e2e_send_module_id_test makes sure that when OPTION_MODEL_ID is specified at creation time, then
// the Service Twin has it specified.
void dt_e2e_send_module_id_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACCOUNT_AUTH_METHOD accountAuthMethod, const char* modelId)
{
// arrange
IOTHUB_PROVISIONED_DEVICE* deviceToUse = IoTHubAccount_GetDevice(g_iothubAcctInfo, accountAuthMethod);
DEVICE_DESIRED_DATA *deviceDesiredData = device_desired_data_init();
ASSERT_IS_NOT_NULL(deviceDesiredData, "failed to create the device client data");
dt_e2e_create_client_handle(deviceToUse, protocol);
// Set the ModelId prior to any network I/O. The caller passes the modelId because the the modelId
// is persisted on the Hub after initial set. So to truly test that the modelId is sent across on
// each test, we need to have the caller change it on each invocation of this test helper.
setoption_on_device_or_module(OPTION_MODEL_ID, modelId, "Cannot specify modelId");
// We do not use the returned device twin, which doesn't contain the device's ModelId. However this step
// is still necessary because just creating a device client handle will not initiate network I/O so we
// need some mechanism to make sure we've successfully established a connection to IoT Hub.
request_full_twin_and_wait_for_response(deviceToUse, deviceDesiredData);
const char *connectionString = IoTHubAccount_GetIoTHubConnString(g_iothubAcctInfo);
IOTHUB_SERVICE_CLIENT_AUTH_HANDLE iotHubServiceClientHandle = IoTHubServiceClientAuth_CreateFromConnectionString(connectionString);
ASSERT_IS_NOT_NULL(iotHubServiceClientHandle, "IoTHubServiceClientAuth_CreateFromConnectionString failed");
IOTHUB_SERVICE_CLIENT_DEVICE_TWIN_HANDLE serviceClientDeviceTwinHandle = IoTHubDeviceTwin_Create(iotHubServiceClientHandle);
ASSERT_IS_NOT_NULL(serviceClientDeviceTwinHandle, "IoTHubDeviceTwin_Create failed");
char *twinData = dt_e2e_get_twin_from_service(serviceClientDeviceTwinHandle, deviceToUse);
JSON_Value *rootValue = json_parse_string(twinData);
ASSERT_IS_NOT_NULL(rootValue);
JSON_Object *rootObject = json_value_get_object(rootValue);
ASSERT_IS_NOT_NULL(rootObject);
const char* modelIdOnService = json_object_dotget_string(rootObject, "modelId");
ASSERT_ARE_EQUAL(char_ptr, modelId, modelIdOnService);
// cleanup
json_value_free(rootValue);
free(twinData);
IoTHubDeviceTwin_Destroy(serviceClientDeviceTwinHandle);
IoTHubServiceClientAuth_Destroy(iotHubServiceClientHandle);
destroy_on_device_or_module();
device_desired_deinit(deviceDesiredData);
}
void dt_e2e_send_reported_test_svc_fault_ctrl_kill_Tcp(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACCOUNT_AUTH_METHOD accountAuthMethod)
{
// arrange
IOTHUB_PROVISIONED_DEVICE* deviceToUse;
if (accountAuthMethod == IOTHUB_ACCOUNT_AUTH_X509)
{
deviceToUse = IoTHubAccount_GetX509Device(g_iothubAcctInfo);
}
else
{
deviceToUse = IoTHubAccount_GetSASDevice(g_iothubAcctInfo);
}
IOTHUB_PROVISIONED_DEVICE* deviceToUse = IoTHubAccount_GetDevice(g_iothubAcctInfo, accountAuthMethod);
DEVICE_REPORTED_DATA *device = device_reported_init();
ASSERT_IS_NOT_NULL(device, "failed to create the device client data");
@ -932,17 +975,9 @@ void dt_e2e_send_reported_test_svc_fault_ctrl_kill_Tcp(IOTHUB_CLIENT_TRANSPORT_P
void dt_e2e_get_complete_desired_test_svc_fault_ctrl_kill_Tcp(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACCOUNT_AUTH_METHOD accountAuthMethod)
{
// arrange
IOTHUB_PROVISIONED_DEVICE* deviceToUse;
if (accountAuthMethod == IOTHUB_ACCOUNT_AUTH_X509)
{
deviceToUse = IoTHubAccount_GetX509Device(g_iothubAcctInfo);
}
else
{
deviceToUse = IoTHubAccount_GetSASDevice(g_iothubAcctInfo);
}
IOTHUB_PROVISIONED_DEVICE* deviceToUse = IoTHubAccount_GetDevice(g_iothubAcctInfo, accountAuthMethod);
DEVICE_DESIRED_DATA *device = device_desired_init();
DEVICE_DESIRED_DATA *device = device_desired_data_init();
ASSERT_IS_NOT_NULL(device, "failed to create the device client data");
// Create the IoT Hub Data

Просмотреть файл

@ -7,6 +7,14 @@
#include "iothub_client_ll.h"
#include "iothub_account.h"
// The ModelId is used when testing that the device client successfully sends the model
// to the IoT Hub. It is OK that there is no DTDL that implements these models since
// this is opaque data to IoT Hub in any event.
#define TEST_MODEL_ID_1 "dtmi:azure:c-sdk:e2e-test;1"
#define TEST_MODEL_ID_2 "dtmi:azure:c-sdk:e2e-test;2"
#define TEST_MODEL_ID_3 "dtmi:azure:c-sdk:e2e-test;3"
#define TEST_MODEL_ID_4 "dtmi:azure:c-sdk:e2e-test;4"
extern void dt_e2e_init(bool testing_modules);
extern void dt_e2e_deinit(void);
extern void dt_e2e_send_reported_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACCOUNT_AUTH_METHOD accountAuthMethod);
@ -14,5 +22,7 @@ extern void dt_e2e_get_complete_desired_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER pr
extern void dt_e2e_send_reported_test_svc_fault_ctrl_kill_Tcp(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACCOUNT_AUTH_METHOD accountAuthMethod);
extern void dt_e2e_get_complete_desired_test_svc_fault_ctrl_kill_Tcp(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACCOUNT_AUTH_METHOD accountAuthMethod);
extern void dt_e2e_get_twin_async_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACCOUNT_AUTH_METHOD accountAuthMethod);
extern void dt_e2e_send_module_id_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACCOUNT_AUTH_METHOD accountAuthMethod, const char* modelId);
#endif /* IOTHUBCLIENT_COMMON_DT_E2E_H */

Просмотреть файл

@ -1036,7 +1036,7 @@ void e2e_send_security_event_test_sas(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol)
// Free the message
IoTHubMessage_Destroy(send_data->msgHandle);
// Send the messages to the ASC Event hub
// Create an ASC Security Message
LogInfo("Sending ASC message to endpoint");

Просмотреть файл

@ -13,7 +13,7 @@
#include "azure_c_shared_utility/crt_abstractions.h"
#include "azure_c_shared_utility/lock.h"
#include "iothub_client_options.h"
#include "iothub_client.h"
#include "iothub_device_client.h"
#include "iothub_message.h"
#include "iothub_service_client_auth.h"
#include "iothub_messaging.h"
@ -57,7 +57,7 @@ typedef struct IOTHUB_LONGHAUL_RESOURCES_TAG
LOCK_HANDLE lock;
IOTHUB_ACCOUNT_INFO_HANDLE iotHubAccountInfo;
IOTHUB_CLIENT_STATISTICS_HANDLE iotHubClientStats;
IOTHUB_CLIENT_HANDLE iotHubClientHandle;
IOTHUB_DEVICE_CLIENT_HANDLE iotHubClientHandle;
IOTHUB_SERVICE_CLIENT_AUTH_HANDLE iotHubServiceClientHandle;
bool is_svc_cl_c2d_msgr_open;
IOTHUB_MESSAGING_CLIENT_HANDLE iotHubSvcMsgHandle;
@ -635,9 +635,9 @@ IOTHUB_ACCOUNT_INFO_HANDLE longhaul_get_account_info(IOTHUB_LONGHAUL_RESOURCES_H
return result;
}
IOTHUB_CLIENT_HANDLE longhaul_get_iothub_client_handle(IOTHUB_LONGHAUL_RESOURCES_HANDLE handle)
IOTHUB_DEVICE_CLIENT_HANDLE longhaul_get_iothub_client_handle(IOTHUB_LONGHAUL_RESOURCES_HANDLE handle)
{
IOTHUB_CLIENT_HANDLE result;
IOTHUB_DEVICE_CLIENT_HANDLE result;
if (handle == NULL)
{
@ -704,7 +704,7 @@ void longhaul_tests_deinit(IOTHUB_LONGHAUL_RESOURCES_HANDLE handle)
if (iotHubLonghaulRsrcs->iotHubClientHandle != NULL)
{
IoTHubClient_Destroy(iotHubLonghaulRsrcs->iotHubClientHandle);
IoTHubDeviceClient_Destroy(iotHubLonghaulRsrcs->iotHubClientHandle);
}
if (iotHubLonghaulRsrcs->iotHubAccountInfo != NULL)
@ -794,25 +794,25 @@ IOTHUB_LONGHAUL_RESOURCES_HANDLE longhaul_tests_init()
return result;
}
IOTHUB_CLIENT_HANDLE longhaul_initialize_device_client(IOTHUB_LONGHAUL_RESOURCES_HANDLE handle, IOTHUB_PROVISIONED_DEVICE* deviceToUse, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol)
IOTHUB_DEVICE_CLIENT_HANDLE longhaul_initialize_device_client(IOTHUB_LONGHAUL_RESOURCES_HANDLE handle, IOTHUB_PROVISIONED_DEVICE* deviceToUse, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol)
{
IOTHUB_CLIENT_HANDLE result;
IOTHUB_DEVICE_CLIENT_HANDLE result;
if (handle == NULL || deviceToUse == NULL)
{
LogError("Invalid argument (handle=%p, deviceToUse=%p)", handle, deviceToUse);
result = NULL;
}
else if ((result = IoTHubClient_CreateFromConnectionString(deviceToUse->connectionString, protocol)) == NULL)
else if ((result = IoTHubDeviceClient_CreateFromConnectionString(deviceToUse->connectionString, protocol)) == NULL)
{
LogError("Could not create IoTHubClient");
}
else if (deviceToUse->howToCreate == IOTHUB_ACCOUNT_AUTH_X509 &&
(IoTHubClient_SetOption(result, OPTION_X509_CERT, deviceToUse->certificate) != IOTHUB_CLIENT_OK ||
IoTHubClient_SetOption(result, OPTION_X509_PRIVATE_KEY, deviceToUse->primaryAuthentication) != IOTHUB_CLIENT_OK))
(IoTHubDeviceClient_SetOption(result, OPTION_X509_CERT, deviceToUse->certificate) != IOTHUB_CLIENT_OK ||
IoTHubDeviceClient_SetOption(result, OPTION_X509_PRIVATE_KEY, deviceToUse->primaryAuthentication) != IOTHUB_CLIENT_OK))
{
LogError("Could not set the device x509 certificate or privateKey");
IoTHubClient_Destroy(result);
IoTHubDeviceClient_Destroy(result);
result = NULL;
}
else
@ -823,29 +823,29 @@ IOTHUB_CLIENT_HANDLE longhaul_initialize_device_client(IOTHUB_LONGHAUL_RESOURCES
iotHubLonghaulRsrcs->iotHubClientHandle = result;
#ifdef SET_TRUSTED_CERT_IN_SAMPLES
(void)IoTHubClient_SetOption(result, OPTION_TRUSTED_CERT, certificates);
(void)IoTHubDeviceClient_SetOption(result, OPTION_TRUSTED_CERT, certificates);
#endif
(void)IoTHubClient_SetOption(result, OPTION_LOG_TRACE, &trace);
(void)IoTHubClient_SetOption(result, OPTION_PRODUCT_INFO, "C-SDK-LongHaul");
(void)IoTHubDeviceClient_SetOption(result, OPTION_LOG_TRACE, &trace);
(void)IoTHubDeviceClient_SetOption(result, OPTION_PRODUCT_INFO, "C-SDK-LongHaul");
if (IoTHubClient_SetConnectionStatusCallback(result, connection_status_callback, handle) != IOTHUB_CLIENT_OK)
if (IoTHubDeviceClient_SetConnectionStatusCallback(result, connection_status_callback, handle) != IOTHUB_CLIENT_OK)
{
LogError("Failed setting the connection status callback");
IoTHubClient_Destroy(result);
IoTHubDeviceClient_Destroy(result);
iotHubLonghaulRsrcs->iotHubClientHandle = NULL;
result = NULL;
}
else if (IoTHubClient_SetMessageCallback(result, on_c2d_message_received, handle) != IOTHUB_CLIENT_OK)
else if (IoTHubDeviceClient_SetMessageCallback(result, on_c2d_message_received, handle) != IOTHUB_CLIENT_OK)
{
LogError("Failed to set the cloud-to-device message callback");
IoTHubClient_Destroy(result);
IoTHubDeviceClient_Destroy(result);
iotHubLonghaulRsrcs->iotHubClientHandle = NULL;
result = NULL;
}
else if (IoTHubClient_SetDeviceMethodCallback(result, on_device_method_received, handle) != IOTHUB_CLIENT_OK)
else if (IoTHubDeviceClient_SetDeviceMethodCallback(result, on_device_method_received, handle) != IOTHUB_CLIENT_OK)
{
LogError("Failed to set the device method callback");
IoTHubClient_Destroy(result);
IoTHubDeviceClient_Destroy(result);
iotHubLonghaulRsrcs->iotHubClientHandle = NULL;
result = NULL;
}
@ -1200,7 +1200,7 @@ static int send_telemetry(const void* context)
message_info->message_id = message_id;
message_info->iotHubLonghaul = longhaulResources;
if (IoTHubClient_SendEventAsync(longhaulResources->iotHubClientHandle, message, send_confirmation_callback, message_info) != IOTHUB_CLIENT_OK)
if (IoTHubDeviceClient_SendEventAsync(longhaulResources->iotHubClientHandle, message, send_confirmation_callback, message_info) != IOTHUB_CLIENT_OK)
{
LogError("Failed sending telemetry message");
free(message_info);
@ -1589,7 +1589,7 @@ static int update_device_twin_reported_property(const void* context)
device_twin_info.update_id = update_id;
device_twin_info.time_queued = time(NULL);
if ((device_twin_info.update_result = IoTHubClient_SendReportedState(iotHubLonghaul->iotHubClientHandle, (const unsigned char*)message, strlen(message), on_twin_report_state_completed, send_context)) != IOTHUB_CLIENT_OK)
if ((device_twin_info.update_result = IoTHubDeviceClient_SendReportedState(iotHubLonghaul->iotHubClientHandle, (const unsigned char*)message, strlen(message), on_twin_report_state_completed, send_context)) != IOTHUB_CLIENT_OK)
{
LogError("Failed sending twin reported properties update");
free(send_context);
@ -1920,7 +1920,7 @@ int longhaul_run_twin_desired_properties_tests(IOTHUB_LONGHAUL_RESOURCES_HANDLE
LogError("IoTHubClient not initialized.");
result = MU_FAILURE;
}
else if (IoTHubClient_SetDeviceTwinCallback(iotHubLonghaul->iotHubClientHandle, on_device_twin_update_received, iotHubLonghaul) != IOTHUB_CLIENT_OK)
else if (IoTHubDeviceClient_SetDeviceTwinCallback(iotHubLonghaul->iotHubClientHandle, on_device_twin_update_received, iotHubLonghaul) != IOTHUB_CLIENT_OK)
{
LogError("Failed subscribing device client for twin desired properties updates");
result = MU_FAILURE;

Просмотреть файл

@ -6,7 +6,7 @@
#include <stdlib.h>
#include <stddef.h>
#include "iothub_client.h"
#include "iothub_device_client.h"
#include "iothub_account.h"
#include "../common_longhaul/iothub_client_statistics.h"
@ -16,10 +16,10 @@ extern IOTHUB_LONGHAUL_RESOURCES_HANDLE longhaul_tests_init();
extern void longhaul_tests_deinit(IOTHUB_LONGHAUL_RESOURCES_HANDLE handle);
extern IOTHUB_ACCOUNT_INFO_HANDLE longhaul_get_account_info(IOTHUB_LONGHAUL_RESOURCES_HANDLE handle);
extern IOTHUB_CLIENT_HANDLE longhaul_get_iothub_client_handle(IOTHUB_LONGHAUL_RESOURCES_HANDLE handle);
extern IOTHUB_DEVICE_CLIENT_HANDLE longhaul_get_iothub_client_handle(IOTHUB_LONGHAUL_RESOURCES_HANDLE handle);
extern IOTHUB_CLIENT_STATISTICS_HANDLE longhaul_get_statistics(IOTHUB_LONGHAUL_RESOURCES_HANDLE handle);
extern IOTHUB_CLIENT_HANDLE longhaul_initialize_device_client(IOTHUB_LONGHAUL_RESOURCES_HANDLE handle, IOTHUB_PROVISIONED_DEVICE* deviceToUse, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol);
extern IOTHUB_DEVICE_CLIENT_HANDLE longhaul_initialize_device_client(IOTHUB_LONGHAUL_RESOURCES_HANDLE handle, IOTHUB_PROVISIONED_DEVICE* deviceToUse, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol);
extern int longhaul_start_listening_for_telemetry_messages(IOTHUB_LONGHAUL_RESOURCES_HANDLE handle, IOTHUB_PROVISIONED_DEVICE* deviceToUse);
extern int longhaul_stop_listening_for_telemetry_messages(IOTHUB_LONGHAUL_RESOURCES_HANDLE handle);

Просмотреть файл

@ -174,6 +174,7 @@ static void my_HTTPAPIEX_Destroy(HTTPAPIEX_HANDLE handle)
real_free(handle);
}
static int my_HTTPAPIEX_ExecuteRequest_statusCode = 200;
static HTTPAPIEX_RESULT my_HTTPAPIEX_ExecuteRequest(HTTPAPIEX_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath,
HTTP_HEADERS_HANDLE requestHttpHeadersHandle, BUFFER_HANDLE requestContent, unsigned int* statusCode,
HTTP_HEADERS_HANDLE responseHttpHeadersHandle, BUFFER_HANDLE responseContent)
@ -183,7 +184,7 @@ static HTTPAPIEX_RESULT my_HTTPAPIEX_ExecuteRequest(HTTPAPIEX_HANDLE handle, HTT
(void)relativePath;
(void)requestHttpHeadersHandle;
(void)requestContent;
*statusCode = 200;
*statusCode = my_HTTPAPIEX_ExecuteRequest_statusCode;
(void)responseHttpHeadersHandle;
(void)responseContent;
@ -280,8 +281,10 @@ static void createMethodPayloadExpectedCalls()
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)); //cannot fail
}
static void sendHttpRequestMethodExpectedCalls()
static void sendHttpRequestMethodExpectedCallsWithStatusCode(int statusCode)
{
my_HTTPAPIEX_ExecuteRequest_statusCode = statusCode;
STRICT_EXPECTED_CALL(environment_get_variable(IGNORED_PTR_ARG)).CallCannotFail();
STRICT_EXPECTED_CALL(HTTPHeaders_Alloc());
STRICT_EXPECTED_CALL(HTTPHeaders_AddHeaderNameValuePair(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG));
@ -313,6 +316,11 @@ static void sendHttpRequestMethodExpectedCalls()
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); //cannot fail
}
static void sendHttpRequestMethodExpectedCalls()
{
sendHttpRequestMethodExpectedCallsWithStatusCode(200);
}
static void parseResponseJsonExpectedCalls()
{
STRICT_EXPECTED_CALL(BUFFER_u_char(IGNORED_PTR_ARG));
@ -756,6 +764,39 @@ TEST_FUNCTION(IoTHubClient_Edge_DeviceMethodInvoke_SUCCESS)
IoTHubClient_EdgeHandle_Destroy(handle);
}
TEST_FUNCTION(IoTHubClient_Edge_DeviceMethodInvoke_2xx_SUCCESS)
{
//arrange
IOTHUB_CLIENT_EDGE_HANDLE handle = create_module_client_method_handle();
int responseStatus;
unsigned char* responsePayload;
size_t responsePayloadSize;
for (int statusCode = 200; statusCode < 300; statusCode++)
{
umock_c_reset_all_calls();
createMethodPayloadExpectedCalls();
STRICT_EXPECTED_CALL(BUFFER_new());
sendHttpRequestMethodExpectedCallsWithStatusCode(statusCode);
parseResponseJsonExpectedCalls();
STRICT_EXPECTED_CALL(BUFFER_delete(IGNORED_PTR_ARG)); //cannot fail
STRICT_EXPECTED_CALL(BUFFER_delete(IGNORED_PTR_ARG)); //cannot fail
//act
IOTHUB_CLIENT_RESULT result = IoTHubClient_Edge_DeviceMethodInvoke(handle, TEST_DEVICE_ID2, TEST_METHOD_NAME, TEST_METHOD_PAYLOAD, TEST_TIMEOUT, &responseStatus, &responsePayload, &responsePayloadSize);
//assert
ASSERT_IS_TRUE(result == IOTHUB_CLIENT_OK);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
free(responsePayload);
}
//cleanup
IoTHubClient_EdgeHandle_Destroy(handle);
}
TEST_FUNCTION(IoTHubClient_Edge_DeviceMethodInvoke_FAIL)
{
//arrange

Просмотреть файл

@ -8,7 +8,7 @@
#include "testrunnerswitcher.h"
#include "iothub.h"
#include "iothub_client.h"
#include "iothub_device_client.h"
#include "iothub_client_options.h"
#include "iothub_message.h"
#include "iothubtransporthttp.h"
@ -355,7 +355,7 @@ static void EventData_Destroy(EXPECTED_SEND_DATA* data)
static void SendEvent(IOTHUB_PROVISIONED_DEVICE* deviceToUse)
{
// arrange
IOTHUB_CLIENT_HANDLE iotHubClientHandle;
IOTHUB_DEVICE_CLIENT_HANDLE iotHubClientHandle;
IOTHUB_MESSAGE_HANDLE msgHandle;
EXPECTED_SEND_DATA* sendData = EventData_Create();
@ -365,22 +365,22 @@ static void SendEvent(IOTHUB_PROVISIONED_DEVICE* deviceToUse)
{
IOTHUB_CLIENT_RESULT result;
// Create the IoT Hub Data
iotHubClientHandle = IoTHubClient_CreateFromConnectionString(deviceToUse->connectionString, HTTP_Protocol);
iotHubClientHandle = IoTHubDeviceClient_CreateFromConnectionString(deviceToUse->connectionString, HTTP_Protocol);
ASSERT_IS_NOT_NULL(iotHubClientHandle, "Failure creating IothubClient handle");
msgHandle = IoTHubMessage_CreateFromByteArray((const unsigned char*)sendData->expectedString, strlen(sendData->expectedString));
ASSERT_IS_NOT_NULL(msgHandle, "Failure to create message handle");
if (deviceToUse->howToCreate == IOTHUB_ACCOUNT_AUTH_X509) {
result = IoTHubClient_SetOption(iotHubClientHandle, OPTION_X509_CERT, deviceToUse->certificate);
result = IoTHubDeviceClient_SetOption(iotHubClientHandle, OPTION_X509_CERT, deviceToUse->certificate);
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Could not set the device x509 certificate");
result = IoTHubClient_SetOption(iotHubClientHandle, OPTION_X509_PRIVATE_KEY, deviceToUse->primaryAuthentication);
result = IoTHubDeviceClient_SetOption(iotHubClientHandle, OPTION_X509_PRIVATE_KEY, deviceToUse->primaryAuthentication);
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Could not set the device x509 privateKey");
}
// act
result = IoTHubClient_SendEventAsync(iotHubClientHandle, msgHandle, ReceiveConfirmationCallback, sendData);
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Failure calling IoTHubClient_SendEventAsync");
result = IoTHubDeviceClient_SendEventAsync(iotHubClientHandle, msgHandle, ReceiveConfirmationCallback, sendData);
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Failure calling IoTHubDeviceClient_SendEventAsync");
}
time_t beginOperation, nowTime;
@ -432,14 +432,14 @@ static void SendEvent(IOTHUB_PROVISIONED_DEVICE* deviceToUse)
// cleanup
IoTHubMessage_Destroy(msgHandle);
IoTHubClient_Destroy(iotHubClientHandle);
IoTHubDeviceClient_Destroy(iotHubClientHandle);
EventData_Destroy(sendData);
}
static void RecvMessage(IOTHUB_PROVISIONED_DEVICE* deviceToUse)
{
// arrange
IOTHUB_CLIENT_HANDLE iotHubClientHandle;
IOTHUB_DEVICE_CLIENT_HANDLE iotHubClientHandle;
IOTHUB_SERVICE_CLIENT_AUTH_HANDLE iotHubServiceClientHandle;
IOTHUB_MESSAGING_CLIENT_HANDLE iotHubMessagingHandle;
@ -487,22 +487,22 @@ static void RecvMessage(IOTHUB_PROVISIONED_DEVICE* deviceToUse)
iotHubMessagingResult = IoTHubMessaging_SendAsync(iotHubMessagingHandle, deviceToUse->deviceId, messageHandle, sendCompleteCallback, receiveUserContext);
ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessagingResult, "IoTHubMessaging_SendAsync failed, could not send C2D message to the device");
iotHubClientHandle = IoTHubClient_CreateFromConnectionString(deviceToUse->connectionString, HTTP_Protocol);
iotHubClientHandle = IoTHubDeviceClient_CreateFromConnectionString(deviceToUse->connectionString, HTTP_Protocol);
ASSERT_IS_NOT_NULL(iotHubClientHandle, "Failure creating Iothub Client");
if (deviceToUse->howToCreate == IOTHUB_ACCOUNT_AUTH_X509) {
IOTHUB_CLIENT_RESULT result;
result = IoTHubClient_SetOption(iotHubClientHandle, OPTION_X509_CERT, deviceToUse->certificate);
result = IoTHubDeviceClient_SetOption(iotHubClientHandle, OPTION_X509_CERT, deviceToUse->certificate);
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Could not set the device x509 certificate");
result = IoTHubClient_SetOption(iotHubClientHandle, OPTION_X509_PRIVATE_KEY, deviceToUse->primaryAuthentication);
result = IoTHubDeviceClient_SetOption(iotHubClientHandle, OPTION_X509_PRIVATE_KEY, deviceToUse->primaryAuthentication);
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Could not set the device x509 privateKey");
}
IOTHUB_CLIENT_RESULT result = IoTHubClient_SetMessageCallback(iotHubClientHandle, ReceiveMessageCallback, receiveUserContext);
IOTHUB_CLIENT_RESULT result = IoTHubDeviceClient_SetMessageCallback(iotHubClientHandle, ReceiveMessageCallback, receiveUserContext);
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Failure setting message callback");
unsigned int minimumPollingTime = 1; /*because it should not wait*/
if (IoTHubClient_SetOption(iotHubClientHandle, OPTION_MIN_POLLING_TIME, &minimumPollingTime) != IOTHUB_CLIENT_OK)
if (IoTHubDeviceClient_SetOption(iotHubClientHandle, OPTION_MIN_POLLING_TIME, &minimumPollingTime) != IOTHUB_CLIENT_OK)
{
printf("failure to set option \"MinimumPollingTime\"\r\n");
}
@ -541,7 +541,7 @@ static void RecvMessage(IOTHUB_PROVISIONED_DEVICE* deviceToUse)
IoTHubMessaging_Destroy(iotHubMessagingHandle);
IoTHubServiceClientAuth_Destroy(iotHubServiceClientHandle);
IoTHubClient_Destroy(iotHubClientHandle);
IoTHubDeviceClient_Destroy(iotHubClientHandle);
ReceiveUserContext_Destroy(receiveUserContext);
}
@ -595,8 +595,8 @@ TEST_FUNCTION(IoTHub_HTTP_SendEvent_Shared_e2e)
IOTHUB_CLIENT_CONFIG iotHubConfig1 = { 0 };
IOTHUB_CLIENT_CONFIG iotHubConfig2 = { 0 };
IOTHUB_CLIENT_HANDLE iotHubClientHandle1;
IOTHUB_CLIENT_HANDLE iotHubClientHandle2;
IOTHUB_DEVICE_CLIENT_HANDLE iotHubClientHandle1;
IOTHUB_DEVICE_CLIENT_HANDLE iotHubClientHandle2;
IOTHUB_MESSAGE_HANDLE msgHandle1;
IOTHUB_MESSAGE_HANDLE msgHandle2;
@ -627,30 +627,30 @@ TEST_FUNCTION(IoTHub_HTTP_SendEvent_Shared_e2e)
{
IOTHUB_CLIENT_RESULT result;
// Create the IoT Hub Data
iotHubClientHandle1 = IoTHubClient_CreateWithTransport(transportHandle, &iotHubConfig1);
iotHubClientHandle1 = IoTHubDeviceClient_CreateWithTransport(transportHandle, &iotHubConfig1);
ASSERT_IS_NOT_NULL(iotHubClientHandle1, "Failure creating IothubClient handle device 1");
msgHandle1 = IoTHubMessage_CreateFromByteArray((const unsigned char*)sendData1->expectedString, strlen(sendData1->expectedString));
ASSERT_IS_NOT_NULL(msgHandle1, "Failure to create message handle");
// act
result = IoTHubClient_SendEventAsync(iotHubClientHandle1, msgHandle1, ReceiveConfirmationCallback, sendData1);
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Failure calling IoTHubClient_SendEventAsync");
result = IoTHubDeviceClient_SendEventAsync(iotHubClientHandle1, msgHandle1, ReceiveConfirmationCallback, sendData1);
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Failure calling IoTHubDeviceClient_SendEventAsync");
}
// Send the Event device 2
{
IOTHUB_CLIENT_RESULT result;
// Create the IoT Hub Data
iotHubClientHandle2 = IoTHubClient_CreateWithTransport(transportHandle, &iotHubConfig2);
iotHubClientHandle2 = IoTHubDeviceClient_CreateWithTransport(transportHandle, &iotHubConfig2);
ASSERT_IS_NOT_NULL(iotHubClientHandle2, "Failure creating IothubClient handle device 2");
msgHandle2 = IoTHubMessage_CreateFromByteArray((const unsigned char*)sendData2->expectedString, strlen(sendData2->expectedString));
ASSERT_IS_NOT_NULL(msgHandle2, "Failure to create message handle");
// act
result = IoTHubClient_SendEventAsync(iotHubClientHandle2, msgHandle2, ReceiveConfirmationCallback, sendData2);
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Failure calling IoTHubClient_SendEventAsync");
result = IoTHubDeviceClient_SendEventAsync(iotHubClientHandle2, msgHandle2, ReceiveConfirmationCallback, sendData2);
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Failure calling IoTHubDeviceClient_SendEventAsync");
}
time_t beginOperation, nowTime;
@ -714,8 +714,8 @@ TEST_FUNCTION(IoTHub_HTTP_SendEvent_Shared_e2e)
IoTHubMessage_Destroy(msgHandle2);
IoTHubMessage_Destroy(msgHandle1);
IoTHubClient_Destroy(iotHubClientHandle2);
IoTHubClient_Destroy(iotHubClientHandle1);
IoTHubDeviceClient_Destroy(iotHubClientHandle2);
IoTHubDeviceClient_Destroy(iotHubClientHandle1);
IoTHubTransport_Destroy(transportHandle);
EventData_Destroy(sendData2);
EventData_Destroy(sendData1);
@ -741,8 +741,8 @@ TEST_FUNCTION(IoTHub_HTTP_RecvMessage_shared_E2ETest)
TRANSPORT_HANDLE transportHandle;
IOTHUB_CLIENT_CONFIG iotHubConfig1 = { 0 };
IOTHUB_CLIENT_CONFIG iotHubConfig2 = { 0 };
IOTHUB_CLIENT_HANDLE iotHubClientHandle1;
IOTHUB_CLIENT_HANDLE iotHubClientHandle2;
IOTHUB_DEVICE_CLIENT_HANDLE iotHubClientHandle1;
IOTHUB_DEVICE_CLIENT_HANDLE iotHubClientHandle2;
IOTHUB_SERVICE_CLIENT_AUTH_HANDLE iotHubServiceClientHandle1;
IOTHUB_SERVICE_CLIENT_AUTH_HANDLE iotHubServiceClientHandle2;
@ -854,22 +854,22 @@ TEST_FUNCTION(IoTHub_HTTP_RecvMessage_shared_E2ETest)
ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessagingResult, "IoTHubMessaging_SendAsync failed, could not send C2D message to the device");
// Create Device Client
iotHubClientHandle1 = IoTHubClient_CreateWithTransport(transportHandle, &iotHubConfig1);
iotHubClientHandle1 = IoTHubDeviceClient_CreateWithTransport(transportHandle, &iotHubConfig1);
ASSERT_IS_NOT_NULL(iotHubClientHandle1, "Failure creating Iothub Client, device 1");
iotHubClientHandle2 = IoTHubClient_CreateWithTransport(transportHandle, &iotHubConfig2);
iotHubClientHandle2 = IoTHubDeviceClient_CreateWithTransport(transportHandle, &iotHubConfig2);
ASSERT_IS_NOT_NULL(iotHubClientHandle2, "Failure creating Iothub Client, device 2");
IOTHUB_CLIENT_RESULT result1 = IoTHubClient_SetMessageCallback(iotHubClientHandle1, ReceiveMessageCallback, receiveUserContext1);
IOTHUB_CLIENT_RESULT result1 = IoTHubDeviceClient_SetMessageCallback(iotHubClientHandle1, ReceiveMessageCallback, receiveUserContext1);
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result1, "Failure setting message callback, device 1");
IOTHUB_CLIENT_RESULT result2 = IoTHubClient_SetMessageCallback(iotHubClientHandle2, ReceiveMessageCallback, receiveUserContext2);
IOTHUB_CLIENT_RESULT result2 = IoTHubDeviceClient_SetMessageCallback(iotHubClientHandle2, ReceiveMessageCallback, receiveUserContext2);
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result2, "Failure setting message callback device 2");
unsigned int minimumPollingTime = 1; /*because it should not wait*/
if (IoTHubClient_SetOption(iotHubClientHandle1, OPTION_MIN_POLLING_TIME, &minimumPollingTime) != IOTHUB_CLIENT_OK)
if (IoTHubDeviceClient_SetOption(iotHubClientHandle1, OPTION_MIN_POLLING_TIME, &minimumPollingTime) != IOTHUB_CLIENT_OK)
{
printf("failure to set option \"MinimumPollingTime\"\r\n");
}
if (IoTHubClient_SetOption(iotHubClientHandle2, OPTION_MIN_POLLING_TIME, &minimumPollingTime) != IOTHUB_CLIENT_OK)
if (IoTHubDeviceClient_SetOption(iotHubClientHandle2, OPTION_MIN_POLLING_TIME, &minimumPollingTime) != IOTHUB_CLIENT_OK)
{
printf("failure to set option \"MinimumPollingTime\"\r\n");
}
@ -916,8 +916,8 @@ TEST_FUNCTION(IoTHub_HTTP_RecvMessage_shared_E2ETest)
ASSERT_IS_TRUE(wasFound2, "Failure retrieving message from client 2 that was sent to IotHub.");
// cleanup
IoTHubClient_Destroy(iotHubClientHandle2);
IoTHubClient_Destroy(iotHubClientHandle1);
IoTHubDeviceClient_Destroy(iotHubClientHandle2);
IoTHubDeviceClient_Destroy(iotHubClientHandle1);
IoTHubMessage_Destroy(messageHandle2);
ReceiveUserContext_Destroy(receiveUserContext2);

Просмотреть файл

@ -69,7 +69,7 @@ MOCKABLE_FUNCTION(, JSON_Object*, json_value_get_object, const JSON_Value *, val
#define TEST_STRING_HANDLE_DEVICE_SAS ((STRING_HANDLE)0x2)
#define TEST_API_VERSION "?api-version=2016-11-14"
#define TEST_IOTHUB_SDK_VERSION "1.3.8"
#define TEST_IOTHUB_SDK_VERSION "1.3.9"
static const char* const testUploadtrustedCertificates = "some certificates";
static const char* const TEST_SAS_TOKEN = "test_sas_token";

Просмотреть файл

@ -21,6 +21,11 @@ TEST_SUITE_CLEANUP(TestClassCleanup)
//
// MQTT tests.
//
TEST_FUNCTION(IoTHub_MQTT_SendModelId_e2e_sas)
{
dt_e2e_send_module_id_test(MQTT_Protocol, IOTHUB_ACCOUNT_AUTH_CONNSTRING, TEST_MODEL_ID_1);
}
TEST_FUNCTION(IoTHub_MQTT_SendReported_e2e_sas)
{
dt_e2e_send_reported_test(MQTT_Protocol, IOTHUB_ACCOUNT_AUTH_CONNSTRING);
@ -37,6 +42,11 @@ TEST_FUNCTION(IoTHub_MQTT_GetTwinAsync_e2e_sas)
}
#ifndef __APPLE__
TEST_FUNCTION(IoTHub_MQTT_SendModelId_e2e_x509)
{
dt_e2e_send_module_id_test(MQTT_Protocol, IOTHUB_ACCOUNT_AUTH_X509, TEST_MODEL_ID_2);
}
TEST_FUNCTION(IoTHub_MQTT_SendReported_e2e_x509)
{
dt_e2e_send_reported_test(MQTT_Protocol, IOTHUB_ACCOUNT_AUTH_X509);
@ -57,6 +67,11 @@ TEST_FUNCTION(IoTHub_MQTT_GetTwinAsync_e2e_x509)
//
// MQTT_WS tests.
//
TEST_FUNCTION(IoTHub_MQTT_WS_SendModelId_e2e_sas)
{
dt_e2e_send_module_id_test(MQTT_WebSocket_Protocol, IOTHUB_ACCOUNT_AUTH_CONNSTRING, TEST_MODEL_ID_3);
}
TEST_FUNCTION(IoTHub_MQTT_WS_SendReported_e2e_sas)
{
dt_e2e_send_reported_test(MQTT_WebSocket_Protocol, IOTHUB_ACCOUNT_AUTH_CONNSTRING);
@ -71,8 +86,12 @@ TEST_FUNCTION(IoTHub_MQTT_WS_GetTwinAsync_e2e_sas)
{
dt_e2e_get_twin_async_test(MQTT_WebSocket_Protocol, IOTHUB_ACCOUNT_AUTH_CONNSTRING);
}
#ifndef __APPLE__
TEST_FUNCTION(IoTHub_MQTT_WS_SendModelId_e2e_x509)
{
dt_e2e_send_module_id_test(MQTT_WebSocket_Protocol, IOTHUB_ACCOUNT_AUTH_X509, TEST_MODEL_ID_4);
}
TEST_FUNCTION(IoTHub_MQTT_WS_GetFullDesired_e2e_x509)
{
dt_e2e_get_complete_desired_test(MQTT_WebSocket_Protocol, IOTHUB_ACCOUNT_AUTH_X509);
@ -90,5 +109,6 @@ TEST_FUNCTION(IoTHub_MQTT_WS_GetTwinAsync_e2e_x509)
#endif
#endif
END_TEST_SUITE(iothubclient_mqtt_dt_e2e)

Просмотреть файл

@ -21,6 +21,11 @@ TEST_SUITE_CLEANUP(TestClassCleanup)
//
// MQTT tests.
//
TEST_FUNCTION(IoTHub_MQTT_Module_SendModelId_e2e_sas)
{
dt_e2e_send_module_id_test(MQTT_Protocol, IOTHUB_ACCOUNT_AUTH_CONNSTRING, TEST_MODEL_ID_1);
}
TEST_FUNCTION(IoTHub_MQTT_Module_SendReported_e2e_sas)
{
dt_e2e_send_reported_test(MQTT_Protocol, IOTHUB_ACCOUNT_AUTH_CONNSTRING);
@ -32,6 +37,11 @@ TEST_FUNCTION(IoTHub_MQTT_Module_GetFullDesired_e2e_sas)
}
#ifndef __APPLE__
TEST_FUNCTION(IoTHub_MQTT_Module_SendModelId_e2e_x509)
{
dt_e2e_send_module_id_test(MQTT_Protocol, IOTHUB_ACCOUNT_AUTH_X509, TEST_MODEL_ID_2);
}
TEST_FUNCTION(IoTHub_MQTT_Module_SendReported_e2e_x509)
{
dt_e2e_send_reported_test(MQTT_Protocol, IOTHUB_ACCOUNT_AUTH_X509);
@ -47,6 +57,11 @@ TEST_FUNCTION(IoTHub_MQTT_Module_GetFullDesired_e2e_x509)
//
// MQTT_WS tests.
//
TEST_FUNCTION(IoTHub_MQTT_WS_Module_SendModelId_e2e_sas)
{
dt_e2e_send_module_id_test(MQTT_WebSocket_Protocol, IOTHUB_ACCOUNT_AUTH_CONNSTRING, TEST_MODEL_ID_3);
}
TEST_FUNCTION(IoTHub_MQTT_WS_Module_SendReported_e2e_sas)
{
dt_e2e_send_reported_test(MQTT_WebSocket_Protocol, IOTHUB_ACCOUNT_AUTH_CONNSTRING);
@ -58,6 +73,11 @@ TEST_FUNCTION(IoTHub_MQTT_WS_Module_GetFullDesired_e2e_sas)
}
#ifndef __APPLE__
TEST_FUNCTION(IoTHub_MQTT_WS_Module_SendModelId_e2e_x509)
{
dt_e2e_send_module_id_test(MQTT_WebSocket_Protocol, IOTHUB_ACCOUNT_AUTH_X509, TEST_MODEL_ID_4);
}
TEST_FUNCTION(IoTHub_MQTT_WS_Module_GetFullDesired_e2e_x509)
{
dt_e2e_get_complete_desired_test(MQTT_WebSocket_Protocol, IOTHUB_ACCOUNT_AUTH_X509);

Просмотреть файл

@ -3,6 +3,12 @@
#include "testrunnerswitcher.h"
// Note: Even though iothub_client.h is deprecated, we are using it as basis of our tests and NOT the recommended
// device_client.h. In practice for most tests there's no difference (both APIs quickly pass through to core implementation).
// However, the iothub_client.h has both an Ex and non-Ex version of IoTHubClient_UploadMultipleBlocksToBlobAsync.
// The device_client did NOT bring this Ex/non split forward.
// We must maintain back-compat with the non-Ex function, so we need to #include "iothub_client.h" as it is only way to access it.
#include "iothub_client.h"
#include "iothub_client_options.h"
#include "iothub_message.h"
@ -48,8 +54,8 @@ static int uploadBlobNumber;
static LOCK_HANDLE updateBlobTestLock;
#define IOTHUB_UPLOADTOBLOB_TIMEOUT_SEC 120
#define TEST_MAX_SIMULTANEOUS_UPLOADS 5
#define TEST_MAX_SIMULTANEOUS_UPLOADS 3
#define TEST_SLEEP_BETWEEN_UPLOAD_TO_BLOB_E2E_TESTS_MS 3000
TEST_DEFINE_ENUM_TYPE(UPLOADTOBLOB_CALLBACK_STATUS, IOTHUB_CLIENT_FILE_UPLOAD_RESULT_VALUES);
@ -191,6 +197,21 @@ static void check_upload_result(UPLOADTOBLOB_CALLBACK_STATUS uploadToBlobStatus)
}
}
static void sleep_between_upload_blob_e2e_tests(void)
{
// We need a Sleep() between each E2E test. Current (as of October, 2020) throttling
// rules limit an S1 hub to 1.67 upload initiations per second for the entire IoT Hub (not just per device).
// https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-quotas-throttling
//
// On gate runs, we have many instances of this test executable running at the same time and we cannot orchestrate
// them. Most individual testcases take <1 second to run. Without a sleep, this amount of traffic
// will end up going over throttling maximums and causing test case failures.
//
LogInfo("Invoking sleep for %d milliseconds after test case", TEST_SLEEP_BETWEEN_UPLOAD_TO_BLOB_E2E_TESTS_MS);
ThreadAPI_Sleep(TEST_SLEEP_BETWEEN_UPLOAD_TO_BLOB_E2E_TESTS_MS);
}
void e2e_uploadtoblob_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACCOUNT_AUTH_METHOD accountAuthMethod)
{
IOTHUB_CLIENT_RESULT result;
@ -228,7 +249,10 @@ void e2e_uploadtoblob_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACC
poll_for_upload_completion(&uploadToBlobStatus);
check_upload_result(uploadToBlobStatus);
ThreadAPI_Sleep(3000);
// We need to sleep in any event to avoid triggering IoT Hub upload threshold limits in our E2E tests. We need to do this
// before the client destroy - and not test runs themselves which would've been better - because of https://github.com/Azure/azure-iot-sdk-c/issues/1705.
sleep_between_upload_blob_e2e_tests();
IoTHubClient_Destroy(iotHubClientHandle);
}
@ -335,6 +359,7 @@ void e2e_uploadtoblob_multiblock_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol,
poll_for_upload_completion(&uploadToBlobStatus);
check_upload_result(uploadToBlobStatus);
sleep_between_upload_blob_e2e_tests();
IoTHubClient_Destroy(iotHubClientHandle);
}
@ -374,6 +399,7 @@ void e2e_uploadtoblob_test_multiple_simultaneous_uploads(IOTHUB_CLIENT_TRANSPORT
time_t endOperation = time(NULL);
ASSERT_ARE_EQUAL(bool, true, (difftime(endOperation, beginOperation) < IOTHUB_UPLOADTOBLOB_TIMEOUT_SEC * 2) ? true : false, "Multithreaded upload took longer than allowed");
sleep_between_upload_blob_e2e_tests();
IoTHubClient_Destroy(iotHubClientHandle);
}

Просмотреть файл

@ -45,7 +45,7 @@ void* my_gballoc_realloc(void* ptr, size_t size)
#include "azure_c_shared_utility/constbuffer.h"
#include "azure_c_shared_utility/platform.h"
#include "azure_c_shared_utility/envvariable.h"
#include "azure_c_shared_utility/urlencode.h"
#include "iothub_client_version.h"
#include "iothub_message.h"
@ -120,6 +120,7 @@ MOCKABLE_FUNCTION(, const char*, Transport_GetOption_Product_Info_Callback, void
MOCKABLE_FUNCTION(, void, Transport_Twin_ReportedStateComplete_Callback, uint32_t, item_id, int, status_code, void*, ctx);
MOCKABLE_FUNCTION(, void, Transport_Twin_RetrievePropertyComplete_Callback, DEVICE_TWIN_UPDATE_STATE, update_state, const unsigned char*, payLoad, size_t, size, void*, ctx);
MOCKABLE_FUNCTION(, int, Transport_DeviceMethod_Complete_Callback, const char*, method_name, const unsigned char*, payLoad, size_t, size, METHOD_HANDLE, response_id, void*, ctx);
MOCKABLE_FUNCTION(, const char*, Transport_GetOption_Model_Id_Callback, void*, ctx);
static int bool_Compare(bool left, bool right)
{
@ -178,6 +179,7 @@ static TEST_MUTEX_HANDLE test_serialize_mutex;
bool g_fail_string_construct_sprintf;
bool g_fail_platform_get_platform_info;
bool g_fail_string_concat_with_string;
bool g_fail_string_construct;
static const char* TEST_STRING_VALUE = "Test string value";
@ -361,7 +363,16 @@ static STRING_HANDLE my_STRING_new(void)
static STRING_HANDLE my_STRING_construct(const char* psz)
{
(void)psz;
return (STRING_HANDLE)my_gballoc_malloc(1);
STRING_HANDLE result;
if (g_fail_string_construct)
{
result = (STRING_HANDLE)NULL;
}
else
{
result = (STRING_HANDLE)my_gballoc_malloc(1);
}
return result;
}
STRING_HANDLE STRING_construct_sprintf(const char* psz, ...)
@ -958,6 +969,7 @@ TEST_FUNCTION_INITIALIZE(method_init)
g_fail_string_construct_sprintf = false;
g_fail_platform_get_platform_info = false;
g_fail_string_concat_with_string = false;
g_fail_string_construct = false;
g_transport_cb_ctx = NULL;
memset(&g_transport_cb_info, 0, sizeof(TRANSPORT_CALLBACKS_INFO));
@ -2120,6 +2132,7 @@ TEST_FUNCTION(IoTHubClientCore_LL_Destroys_the_underlying_transport_succeeds)
STRICT_EXPECTED_CALL(IoTHubClient_EdgeHandle_Destroy(IGNORED_PTR_ARG));
#endif
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
@ -2156,10 +2169,10 @@ TEST_FUNCTION(IoTHubClientCore_LL_Destroys_unregisters_but_does_not_destroy_tran
STRICT_EXPECTED_CALL(IoTHubClient_EdgeHandle_Destroy(IGNORED_PTR_ARG));
#endif
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
//act
IoTHubClientCore_LL_Destroy(handle);
@ -2273,6 +2286,7 @@ TEST_FUNCTION(IoTHubClientCore_LL_Destroy_after_sendEvent_succeeds)
STRICT_EXPECTED_CALL(IoTHubClient_EdgeHandle_Destroy(IGNORED_PTR_ARG));
#endif
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
@ -4384,6 +4398,57 @@ TEST_FUNCTION(IoTHubClientCore_LL_SendReportedState_succeeds)
IoTHubClientCore_LL_Destroy(handle);
}
TEST_FUNCTION(IoTHubClientCore_LL_Destroy_with_pending_reported_state_succeeds)
{
//arrange
IOTHUB_CLIENT_CORE_LL_HANDLE handle = IoTHubClientCore_LL_Create(&TEST_CONFIG);
umock_c_reset_all_calls();
setup_IoTHubClientCore_LL_sendreportedstate_mocks();
IOTHUB_CLIENT_RESULT result = IoTHubClientCore_LL_SendReportedState(handle, TEST_REPORTED_STATE, TEST_REPORTED_SIZE, iothub_reported_state_callback, NULL);
umock_c_reset_all_calls();
STRICT_EXPECTED_CALL(FAKE_IoTHubTransport_Unregister(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(FAKE_IoTHubTransport_Destroy(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(DList_RemoveHeadList(IGNORED_PTR_ARG)); /*because there is one item in the list*/
STRICT_EXPECTED_CALL(DList_RemoveHeadList(IGNORED_PTR_ARG)); /*because there is one item in the list*/
STRICT_EXPECTED_CALL(iothub_reported_state_callback(IGNORED_NUM_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(CONSTBUFFER_DecRef(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(DList_RemoveHeadList(IGNORED_PTR_ARG)); /*because there is one item in the list*/
STRICT_EXPECTED_CALL(DList_RemoveHeadList(IGNORED_PTR_ARG)); /*because there is one item in the list*/
STRICT_EXPECTED_CALL(IoTHubClient_Auth_Destroy(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(tickcounter_destroy(IGNORED_PTR_ARG));
#ifndef DONT_USE_UPLOADTOBLOB
STRICT_EXPECTED_CALL(IoTHubClient_LL_UploadToBlob_Destroy(IGNORED_PTR_ARG));
#endif
#ifdef USE_EDGE_MODULES
STRICT_EXPECTED_CALL(IoTHubClient_EdgeHandle_Destroy(IGNORED_PTR_ARG));
#endif
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
//act
IoTHubClientCore_LL_Destroy(handle);
//assert
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
//act
//assert
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
//cleanup
}
/* Tests_SRS_IoTHubClientCore_LL_10_012: [ IoTHubClientCore_LL_SendReportedState shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter iotHubClientHandle is NULL. ] */
TEST_FUNCTION(IoTHubClientCore_LL_SendReportedState_NULL_fails)
{
@ -5522,6 +5587,63 @@ TEST_FUNCTION(IoTHubClientCore_LL_SetOption_product_info_fails_case1)
IoTHubClientCore_LL_Destroy(h);
}
TEST_FUNCTION(IoTHubClientCore_LL_SetOption_model_id_succeeds)
{
//arrange
IOTHUB_CLIENT_CORE_LL_HANDLE h = IoTHubClientCore_LL_Create(&TEST_CONFIG);
umock_c_reset_all_calls();
STRICT_EXPECTED_CALL(STRING_construct(IGNORED_PTR_ARG));
//act
IOTHUB_CLIENT_RESULT result = IoTHubClientCore_LL_SetOption(h, OPTION_MODEL_ID, "dtmi:YOUR_COMPANY_NAME_HERE:sample_device;1");
//assert
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
//cleanup
IoTHubClientCore_LL_Destroy(h);
}
TEST_FUNCTION(IoTHubClientCore_LL_SetOption_model_id_string_construct_fails)
{
//arrange
IOTHUB_CLIENT_CORE_LL_HANDLE h = IoTHubClientCore_LL_Create(&TEST_CONFIG);
umock_c_reset_all_calls();
STRICT_EXPECTED_CALL(STRING_construct(IGNORED_PTR_ARG));
//act
g_fail_string_construct = true;
IOTHUB_CLIENT_RESULT result = IoTHubClientCore_LL_SetOption(h, OPTION_MODEL_ID, "dtmi:YOUR_COMPANY_NAME_HERE:sample_device;1");
//assert
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_ERROR, result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
//cleanup
IoTHubClientCore_LL_Destroy(h);
}
TEST_FUNCTION(IoTHubClientCore_LL_SetOption_model_id_twice_fails)
{
//arrange
IOTHUB_CLIENT_CORE_LL_HANDLE h = IoTHubClientCore_LL_Create(&TEST_CONFIG);
umock_c_reset_all_calls();
STRICT_EXPECTED_CALL(STRING_construct(IGNORED_PTR_ARG));
IOTHUB_CLIENT_RESULT result = IoTHubClientCore_LL_SetOption(h, OPTION_MODEL_ID, "dtmi:YOUR_COMPANY_NAME_HERE:sample_device;1");
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result);
//act
result = IoTHubClientCore_LL_SetOption(h, OPTION_MODEL_ID, "dtmi:YOUR_COMPANY_NAME_HERE:sample_device;2");
//assert
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_ERROR, result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
//cleanup
IoTHubClientCore_LL_Destroy(h);
}
/*Tests_SRS_IoTHubClientCore_LL_10_037: [Calling IoTHubClientCore_LL_SetOption with value between [0, 100] shall return `IOTHUB_CLIENT_OK`. ]*/
TEST_FUNCTION(IoTHubClientCore_LL_SetOption_diag_sampling_percentage_succeeds)
{

Просмотреть файл

@ -1350,6 +1350,47 @@ TEST_FUNCTION(IoTHubClientCore_Destroy_calls_IOTHUB_CLIENT_EVENT_CONFIRMATION_CA
// cleanup
}
TEST_FUNCTION(IoTHubClientCore_Destroy_calls_pending_reported_state_callback_succeed)
{
// arrange
IOTHUB_CLIENT_CORE_HANDLE iothub_handle = IoTHubClientCore_Create(TEST_CLIENT_CONFIG);
umock_c_reset_all_calls();
const unsigned char* reported_state = (const unsigned char*)0x1234;
EXPECTED_CALL(ThreadAPI_Create(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(Lock(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG));
STRICT_EXPECTED_CALL(IoTHubClientCore_LL_SendReportedState(TEST_IOTHUB_CLIENT_CORE_LL_HANDLE, reported_state, 1, IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(Unlock(IGNORED_PTR_ARG));
(void)IoTHubClientCore_SendReportedState(iothub_handle, reported_state, 1, test_report_state_callback, NULL);
umock_c_reset_all_calls();
STRICT_EXPECTED_CALL(VECTOR_push_back(IGNORED_PTR_ARG, IGNORED_PTR_ARG, 1));
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(Lock(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(Unlock(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(ThreadAPI_Join(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(Lock(IGNORED_PTR_ARG));
EXPECTED_CALL(singlylinkedlist_get_head_item(TEST_SLL_HANDLE));
STRICT_EXPECTED_CALL(singlylinkedlist_destroy(TEST_SLL_HANDLE));
STRICT_EXPECTED_CALL(IoTHubClientCore_LL_Destroy(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(Unlock(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(VECTOR_size(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(VECTOR_element(IGNORED_PTR_ARG,0));
STRICT_EXPECTED_CALL(test_report_state_callback(0, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(VECTOR_destroy(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(Lock_Deinit(IGNORED_PTR_ARG));
EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
// act
g_reportedStateCallback(0, g_userContextCallback); // Simulating a cb from LL with unsent reported state.
IoTHubClientCore_Destroy(iothub_handle);
// assert
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
}
TEST_FUNCTION(IoTHubClient_SendEventAsync_handle_NULL_fail)
{

Просмотреть файл

@ -82,6 +82,11 @@ static const char* TEST_CONNECTION_MODULE_ID = "connectionmoduleid";
static const char* TEST_CONNECTION_MODULE_ID2 = "connectionmoduleid2";
static const char* TEST_PROPERTY_KEY = "property_key";
static const char* TEST_PROPERTY_VALUE = "property_value";
static const char* TEST_NON_ASCII_PROPERTY_KEY = "\x01property_key";
static const char* TEST_NON_ASCII_PROPERTY_VALUE = "\x01property_value";
static const char* TEST_MESSAGE_CREATION_TIME_UTC = "2020-07-01T01:00:00.000Z";
static const char* TEST_MESSAGE_USER_ID = "2d4e2570-e7c2-4651-b190-4607986e3b9f";
static IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA TEST_DIAGNOSTIC_DATA = { "12345678", "1506054179"};
static IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA TEST_DIAGNOSTIC_DATA2 = { "87654321", "1506054179.100" };
@ -599,6 +604,8 @@ TEST_FUNCTION(IoTHubMessage_Destroy_destroys_a_BYTEARRAY_IoTHubMEssage)
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(gballoc_free(h));
//act
@ -628,6 +635,8 @@ TEST_FUNCTION(IoTHubMessage_Destroy_destroys_a_STRING_IoTHubMessage)
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(gballoc_free(h));
//act
@ -1727,7 +1736,7 @@ TEST_FUNCTION(IoTHubMessage_SetProperty_handle_NULL_Fail)
IOTHUB_MESSAGE_RESULT result = IoTHubMessage_SetProperty(NULL, TEST_PROPERTY_KEY, TEST_PROPERTY_VALUE);
//assert
ASSERT_ARE_NOT_EQUAL(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_OK, result);
ASSERT_ARE_EQUAL(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_INVALID_ARG, result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
//cleanup
@ -1743,7 +1752,7 @@ TEST_FUNCTION(IoTHubMessage_SetProperty_key_NULL_Fail)
IOTHUB_MESSAGE_RESULT result = IoTHubMessage_SetProperty(h, NULL, TEST_PROPERTY_VALUE);
//assert
ASSERT_ARE_NOT_EQUAL(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_OK, result);
ASSERT_ARE_EQUAL(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_INVALID_ARG, result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
//cleanup
@ -1760,7 +1769,45 @@ TEST_FUNCTION(IoTHubMessage_SetProperty_value_NULL_Fail)
IOTHUB_MESSAGE_RESULT result = IoTHubMessage_SetProperty(h, TEST_PROPERTY_KEY, NULL);
//assert
ASSERT_ARE_NOT_EQUAL(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_OK, result);
ASSERT_ARE_EQUAL(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_INVALID_ARG, result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
//cleanup
IoTHubMessage_Destroy(h);
}
TEST_FUNCTION(IoTHubMessage_SetProperty_key_Non_Ascii_Fail)
{
//arrange
IOTHUB_MESSAGE_HANDLE h = IoTHubMessage_CreateFromByteArray(c, 1);
umock_c_reset_all_calls();
STRICT_EXPECTED_CALL(Map_AddOrUpdate(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)).SetReturn(MAP_FILTER_REJECT);
//act
IOTHUB_MESSAGE_RESULT result = IoTHubMessage_SetProperty(h, TEST_NON_ASCII_PROPERTY_KEY, TEST_PROPERTY_VALUE);
//assert
ASSERT_ARE_EQUAL(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_INVALID_TYPE, result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
//cleanup
IoTHubMessage_Destroy(h);
}
TEST_FUNCTION(IoTHubMessage_SetProperty_value_Non_Ascii_Fail)
{
//arrange
IOTHUB_MESSAGE_HANDLE h = IoTHubMessage_CreateFromByteArray(c, 1);
umock_c_reset_all_calls();
STRICT_EXPECTED_CALL(Map_AddOrUpdate(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)).SetReturn(MAP_FILTER_REJECT);
//act
IOTHUB_MESSAGE_RESULT result = IoTHubMessage_SetProperty(h, TEST_PROPERTY_KEY, TEST_NON_ASCII_PROPERTY_VALUE);
//assert
ASSERT_ARE_EQUAL(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_INVALID_TYPE, result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
//cleanup
@ -1779,7 +1826,7 @@ TEST_FUNCTION(IoTHubMessage_SetProperty_Fail)
IOTHUB_MESSAGE_RESULT result = IoTHubMessage_SetProperty(h, TEST_PROPERTY_KEY, TEST_PROPERTY_VALUE);
//assert
ASSERT_ARE_NOT_EQUAL(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_OK, result);
ASSERT_ARE_EQUAL(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_ERROR, result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
//cleanup
@ -2148,6 +2195,64 @@ TEST_FUNCTION(IoTHubMessage_IsSecurityMessage_false_Succeed)
IoTHubMessage_Destroy(h);
}
// [if any of the parameters are NULL then IoTHubMessage_SetMessageCreationTimeUtcSystemProperty shall return a IOTHUB_MESSAGE_INVALID_ARG value.]
TEST_FUNCTION(IoTHubMessage_SetMessageCreationTimeUtcSystemProperty_NULL_handle_Fails)
{
set_string_NULL_handle_fails_impl(IoTHubMessage_SetMessageCreationTimeUtcSystemProperty, TEST_MESSAGE_CREATION_TIME_UTC);
}
// [if any of the parameters are NULL then IoTHubMessage_SetMessageCreationTimeUtcSystemProperty shall return a IOTHUB_MESSAGE_INVALID_ARG value.]
TEST_FUNCTION(IoTHubMessage_SetMessageCreationTimeUtcSystemProperty_NULL_CreationTimeUtc_Fails)
{
set_string_NULL_string_fails_impl(IoTHubMessage_SetMessageCreationTimeUtcSystemProperty);
}
// [If the IOTHUB_MESSAGE_HANDLE CreationTimeUtc is not NULL, then the IOTHUB_MESSAGE_HANDLE CreationTimeUtc will be deallocated.]
TEST_FUNCTION(IoTHubMessage_SetMessageCreationTimeUtcSystemProperty_CreationTimeUtc_Not_NULL_SUCCEED)
{
set_string_string_already_allocated_succeeds_impl(IoTHubMessage_SetMessageCreationTimeUtcSystemProperty, TEST_MESSAGE_CREATION_TIME_UTC);
}
// [IoTHubMessage_SetMessageCreationTimeUtcSystemProperty finishes successfully it shall return IOTHUB_MESSAGE_OK.]
TEST_FUNCTION(IoTHubMessage_SetMessageCreationTimeUtcSystemProperty_SUCCEED)
{
set_string_succeeds_impl(IoTHubMessage_SetMessageCreationTimeUtcSystemProperty, TEST_MESSAGE_CREATION_TIME_UTC);
}
// [if the iotHubMessageHandle parameter is NULL then IoTHubMessage_GetMessageCreationTimeUtcSystemProperty shall return a NULL value.]
TEST_FUNCTION(IoTHubMessage_GetMessageCreationTimeUtcSystemProperty_NULL_handle_Fails)
{
get_string_NULL_handle_fails_impl(IoTHubMessage_GetMessageCreationTimeUtcSystemProperty);
}
// [IoTHubMessage_GetMessageCreationTimeUtcSystemProperty shall return the CreationTimeUtc as a const char*.]
TEST_FUNCTION(IoTHubMessage_GetMessageCreationTimeUtcSystemProperty_ConnectionModuleId_Not_Set_Fails)
{
get_string_not_set_fails_impl(IoTHubMessage_GetMessageCreationTimeUtcSystemProperty);
}
// [IoTHubMessage_GetMessageCreationTimeUtcSystemProperty shall return the CreationTimeUtc as a const char*.]
TEST_FUNCTION(IoTHubMessage_GetMessageCreationTimeUtcSystemProperty_SUCCEED)
{
get_string_succeeds_impl(IoTHubMessage_SetMessageCreationTimeUtcSystemProperty, IoTHubMessage_GetMessageCreationTimeUtcSystemProperty, TEST_MESSAGE_CREATION_TIME_UTC);
}
// [if the iotHubMessageHandle parameter is NULL then IoTHubMessage_GetMessageUserIdSystemProperty shall return a NULL value.]
TEST_FUNCTION(IoTHubMessage_GetMessageUserIdSystemProperty_NULL_handle_Fails)
{
get_string_NULL_handle_fails_impl(IoTHubMessage_GetMessageUserIdSystemProperty);
}
// [IoTHubMessage_GetMessageUserIdSystemProperty shall return the UserId as a const char*.]
TEST_FUNCTION(IoTHubMessage_GetMessageUserIdProperty_ConnectionModuleId_Not_Set_Fails)
{
get_string_not_set_fails_impl(IoTHubMessage_GetMessageUserIdSystemProperty);
}
// [IoTHubMessage_GetMessageUserIdSystemProperty shall return the user id as a const char*.]
TEST_FUNCTION(IoTHubMessage_GetUserIdSystemProperty_SUCCEED)
{
get_string_succeeds_impl(IoTHubMessage_SetMessageUserIdSystemProperty, IoTHubMessage_GetMessageUserIdSystemProperty, TEST_MESSAGE_USER_ID);
}
END_TEST_SUITE(iothubmessage_ut)

Просмотреть файл

@ -52,6 +52,7 @@ void real_free(void* ptr)
#include "azure_uamqp_c/messaging.h"
#include "internal/iothub_client_private.h"
#include "internal/iothubtransport_amqp_messenger.h"
#include "internal/iothub_internal_consts.h"
#undef ENABLE_MOCKS
@ -128,7 +129,6 @@ static void on_umock_c_error(UMOCK_C_ERROR_CODE error_code)
#define TWIN_CORRELATION_ID_PROPERTY_NAME "com.microsoft:channel-correlation-id"
#define TWIN_API_VERSION_PROPERTY_NAME "com.microsoft:api-version"
#define TWIN_API_VERSION_NUMBER "2016-11-14"
#define TEST_ATTACH_PROPERTIES (MAP_HANDLE)0x4444
#define UNIQUE_ID_BUFFER_SIZE 37
@ -425,7 +425,7 @@ static void set_create_link_attach_properties_expected_calls(TWIN_MESSENGER_CONF
set_generate_twin_correlation_id_expected_calls();
STRICT_EXPECTED_CALL(Map_Add(TEST_ATTACH_PROPERTIES, CLIENT_VERSION_PROPERTY_NAME, TEST_CLIENT_VERSION_STR));
STRICT_EXPECTED_CALL(Map_Add(TEST_ATTACH_PROPERTIES, TWIN_CORRELATION_ID_PROPERTY_NAME, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(Map_Add(TEST_ATTACH_PROPERTIES, TWIN_API_VERSION_PROPERTY_NAME, TWIN_API_VERSION_NUMBER));
STRICT_EXPECTED_CALL(Map_Add(TEST_ATTACH_PROPERTIES, TWIN_API_VERSION_PROPERTY_NAME, IOTHUB_API_VERSION));
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
}
@ -1048,7 +1048,7 @@ TEST_FUNCTION(twin_msgr_create_NULL_device_id)
// Tests_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_013: [`amqp_msgr_config->device_id` shall be set with `twin_msgr->device_id`]
// Tests_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_014: [`amqp_msgr_config->iothub_host_fqdn` shall be set with `twin_msgr->iothub_host_fqdn`]
// Tests_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_015: [`amqp_msgr_config` shall have "twin/" as send link target suffix and receive link source suffix]
// Tests_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_016: [`amqp_msgr_config` shall have send and receive link attach properties set as "com.microsoft:client-version" = `twin_msgr->client_version`, "com.microsoft:channel-correlation-id" = `twin:<UUID>`, "com.microsoft:api-version" = "2016-11-14"]
// Tests_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_016: [`amqp_msgr_config` shall have send and receive link attach properties set as "com.microsoft:client-version" = `twin_msgr->client_version`, "com.microsoft:channel-correlation-id" = `twin:<UUID>`, "com.microsoft:api-version" = "Current API version"]
// Tests_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_017: [`amqp_msgr_config` shall be set with `on_amqp_messenger_state_changed_callback` and `on_amqp_messenger_subscription_changed_callback` callbacks]
// Tests_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_019: [`twin_msgr->amqp_msgr` shall subscribe for AMQP messages by calling amqp_messenger_subscribe_for_messages() passing `on_amqp_message_received`]
// Tests_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_021: [If no failures occurr, twin_messenger_create() shall return a handle to `twin_msgr`]

Просмотреть файл

@ -76,6 +76,7 @@ MOCKABLE_FUNCTION(, const char*, Transport_GetOption_Product_Info_Callback, void
MOCKABLE_FUNCTION(, void, Transport_Twin_ReportedStateComplete_Callback, uint32_t, item_id, int, status_code, void*, ctx);
MOCKABLE_FUNCTION(, void, Transport_Twin_RetrievePropertyComplete_Callback, DEVICE_TWIN_UPDATE_STATE, update_state, const unsigned char*, payLoad, size_t, size, void*, ctx);
MOCKABLE_FUNCTION(, int, Transport_DeviceMethod_Complete_Callback, const char*, method_name, const unsigned char*, payLoad, size_t, size, METHOD_HANDLE, response_id, void*, ctx);
MOCKABLE_FUNCTION(, const char*, Transport_GetOption_Model_Id_Callback, void*, ctx);
#undef ENABLE_MOCKS
@ -150,6 +151,12 @@ static const char* my_Transport_GetOption_Product_Info_Callback(void* ctx)
return "product_info";
}
static const char* my_Transport_GetOption_Model_Id_Callback(void* ctx)
{
(void)ctx;
return "dtmi:testDeviceCapabilityModel;1";
}
static const char* TEST_STRING_VALUE = "Test string value";
static const char* TEST_DEVICE_ID = "thisIsDeviceID";
static const char* TEST_MODULE_ID = "thisIsModuleID";
@ -185,6 +192,7 @@ static const char* TEST_CONTENT_TYPE = "application/json";
static const char* TEST_CONTENT_ENCODING = "utf8";
static const char* TEST_DIAG_ID = "1234abcd";
static const char* TEST_DIAG_CREATION_TIME_UTC = "1506054516.100";
static const char* TEST_MESSAGE_CREATION_TIME_UTC = "2010-01-01T01:00:00.000Z";
static const char* TEST_OUTPUT_NAME = "TestOutputName";
static const char* PROPERTY_SEPARATOR = "&";
@ -297,6 +305,7 @@ static IOTHUBMESSAGE_DISPOSITION_RESULT g_msg_disposition;
#define TEST_RETRY_POLICY IOTHUB_CLIENT_RETRY_EXPONENTIAL_BACKOFF_WITH_JITTER
#define TEST_RETRY_TIMEOUT_SECS 60
#define TEST_MAX_DISCONNECT_VALUE 50
//Callbacks for Testing
static ON_MQTT_MESSAGE_RECV_CALLBACK g_fnMqttMsgRecv;
@ -305,6 +314,7 @@ static ON_MQTT_ERROR_CALLBACK g_fnMqttErrorCallback;
static void* g_callbackCtx;
static void* g_errorcallbackCtx;
static bool g_nullMapVariable;
static bool g_skip_disconnect_callback;
static ON_MQTT_DISCONNECTED_CALLBACK g_disconnect_callback;
static void* g_disconnect_callback_ctx;
static TRANSPORT_CALLBACKS_INFO transport_cb_info;
@ -640,7 +650,7 @@ static void my_ThreadAPI_Sleep(unsigned int milliseconds)
{
(void)milliseconds;
// this is for disconnect callback
if (g_disconnect_callback != NULL)
if (g_disconnect_callback != NULL && !g_skip_disconnect_callback)
{
g_disconnect_callback(g_disconnect_callback_ctx);
}
@ -710,6 +720,7 @@ TEST_SUITE_INITIALIZE(suite_init)
transport_cb_info.msg_input_cb = Transport_MessageCallbackFromInput;
transport_cb_info.msg_cb = Transport_MessageCallback;
transport_cb_info.method_complete_cb = Transport_DeviceMethod_Complete_Callback;
transport_cb_info.get_model_id_cb = Transport_GetOption_Model_Id_Callback;
g_cbuff.buffer = appMessage;
g_cbuff.size = appMsgSize;
@ -788,6 +799,8 @@ TEST_SUITE_INITIALIZE(suite_init)
REGISTER_GLOBAL_MOCK_FAIL_RETURN(URL_DecodeString, NULL);
REGISTER_GLOBAL_MOCK_HOOK(Transport_GetOption_Product_Info_Callback, my_Transport_GetOption_Product_Info_Callback);
REGISTER_GLOBAL_MOCK_FAIL_RETURN(Transport_GetOption_Product_Info_Callback, NULL);
REGISTER_GLOBAL_MOCK_HOOK(Transport_GetOption_Model_Id_Callback, my_Transport_GetOption_Model_Id_Callback);
REGISTER_GLOBAL_MOCK_FAIL_RETURN(Transport_GetOption_Model_Id_Callback, NULL);
REGISTER_GLOBAL_MOCK_RETURN(IoTHub_Transport_ValidateCallbacks, 0);
REGISTER_GLOBAL_MOCK_FAIL_RETURN(IoTHub_Transport_ValidateCallbacks, __LINE__);
@ -977,6 +990,8 @@ TEST_FUNCTION_INITIALIZE(method_init)
umock_c_reset_all_calls();
g_skip_disconnect_callback = false;
get_twin_update_state = DEVICE_TWIN_UPDATE_COMPLETE;
get_twin_payLoad = NULL;
get_twin_size = 0;
@ -1160,6 +1175,7 @@ static void setup_initialize_reconnection_mocks()
.CopyOutArgumentBuffer_retry_action(&retry_action, sizeof(retry_action));
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(xio_retrieveoptions(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(mqtt_client_clear_xio(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(xio_destroy(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(IoTHubClient_Auth_Get_Credential_Type(IGNORED_PTR_ARG));
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_STRING_VALUE);
@ -1196,15 +1212,29 @@ static void setup_devicemethod_response_mocks()
}
static void setup_initialize_connection_mocks()
static void setup_initialize_connection_mocks(bool useModelId)
{
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(IoTHubClient_Auth_Get_Credential_Type(IGNORED_PTR_ARG));
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_STRING_VALUE);
STRICT_EXPECTED_CALL(IoTHubClient_Auth_Get_SasToken(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_NUM_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(Transport_GetOption_Model_Id_Callback(IGNORED_PTR_ARG)).SetReturn(useModelId ? TEST_STRING_VALUE : NULL);
STRICT_EXPECTED_CALL(Transport_GetOption_Product_Info_Callback(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(URL_EncodeString(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_concat_with_STRING(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG));
if (useModelId)
{
STRICT_EXPECTED_CALL(URL_EncodeString(IGNORED_PTR_ARG));
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_STRING_VALUE);
STRICT_EXPECTED_CALL(STRING_concat_with_STRING(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
}
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)).IgnoreArgument_handle();
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)).IgnoreArgument_handle();
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)).IgnoreArgument_handle();
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)).IgnoreArgument_handle();
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)).IgnoreArgument_handle();
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_DEVICE_ID);
@ -1267,9 +1297,9 @@ static void setup_IoTHubTransport_MQTT_Common_DoWork_emtpy_msg_mocks(void)
STRICT_EXPECTED_CALL(IoTHubMessage_GetMessageId(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(IoTHubMessage_GetContentTypeSystemProperty(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(IoTHubMessage_GetContentEncodingSystemProperty(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(IoTHubMessage_GetMessageCreationTimeUtcSystemProperty(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(IoTHubMessage_GetDiagnosticPropertyData(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(IoTHubMessage_GetOutputName(IGNORED_PTR_ARG));
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG));
EXPECTED_CALL(mqttmessage_create_in_place(IGNORED_NUM_ARG, IGNORED_PTR_ARG, DELIVER_AT_LEAST_ONCE, IGNORED_PTR_ARG, IGNORED_NUM_ARG));
@ -1297,13 +1327,14 @@ static void setup_IoTHubTransport_MQTT_Common_DoWork_resend_events_mocks(
const char* content_type,
const char* content_encoding,
const char* diag_id,
const char* creation_time_utc,
const char* diag_creation_time_utc,
const char* message_creation_time_utc,
bool auto_urlencode,
const char* output_name,
bool security_msg)
{
TEST_DIAG_DATA.diagnosticId = (char*)diag_id;
TEST_DIAG_DATA.diagnosticCreationTimeUtc = (char*)creation_time_utc;
TEST_DIAG_DATA.diagnosticCreationTimeUtc = (char*)diag_creation_time_utc;
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(IoTHubClient_Auth_Get_Credential_Type(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(IoTHubClient_Auth_Get_SasToken_Expiry(IGNORED_PTR_ARG));
@ -1383,17 +1414,24 @@ static void setup_IoTHubTransport_MQTT_Common_DoWork_resend_events_mocks(
STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG));
}
STRICT_EXPECTED_CALL(IoTHubMessage_GetMessageCreationTimeUtcSystemProperty(IGNORED_PTR_ARG)).SetReturn(message_creation_time_utc);
if (auto_urlencode && (message_creation_time_utc != NULL))
{
STRICT_EXPECTED_CALL(URL_EncodeString(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG));
}
STRICT_EXPECTED_CALL(IoTHubMessage_GetDiagnosticPropertyData(IGNORED_PTR_ARG)).SetReturn(&TEST_DIAG_DATA);
bool validMessage = true;
if (diag_id != NULL && creation_time_utc != NULL)
if (diag_id != NULL && diag_creation_time_utc != NULL)
{
STRICT_EXPECTED_CALL(URL_Encode(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG));
}
else if (diag_id != NULL || creation_time_utc != NULL)
else if (diag_id != NULL || diag_creation_time_utc != NULL)
{
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG));
validMessage = false;
@ -1440,13 +1478,14 @@ static void setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks(
const char* content_type,
const char* content_encoding,
const char* diag_id,
const char* creation_time_utc,
const char* diag_creation_time_utc,
const char* message_creation_time_utc,
bool auto_urlencode,
const char* output_name,
bool security_msg)
{
TEST_DIAG_DATA.diagnosticId = (char*)diag_id;
TEST_DIAG_DATA.diagnosticCreationTimeUtc = (char*)creation_time_utc;
TEST_DIAG_DATA.diagnosticCreationTimeUtc = (char*)diag_creation_time_utc;
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(IoTHubClient_Auth_Get_Credential_Type(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(IoTHubClient_Auth_Get_SasToken_Expiry(IGNORED_PTR_ARG));
@ -1520,6 +1559,13 @@ static void setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks(
STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG));
}
STRICT_EXPECTED_CALL(IoTHubMessage_GetMessageCreationTimeUtcSystemProperty(IGNORED_PTR_ARG)).SetReturn(message_creation_time_utc);
if (auto_urlencode && (message_creation_time_utc != NULL))
{
STRICT_EXPECTED_CALL(URL_EncodeString(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG));
}
if (security_msg)
{
STRICT_EXPECTED_CALL(URL_EncodeString(IGNORED_PTR_ARG));
@ -1529,14 +1575,14 @@ static void setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks(
STRICT_EXPECTED_CALL(IoTHubMessage_GetDiagnosticPropertyData(IGNORED_PTR_ARG)).SetReturn(&TEST_DIAG_DATA);
bool validMessage = true;
if (diag_id != NULL && creation_time_utc != NULL)
if (diag_id != NULL && diag_creation_time_utc != NULL)
{
STRICT_EXPECTED_CALL(URL_Encode(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG));
}
else if (diag_id != NULL || creation_time_utc != NULL)
else if (diag_id != NULL || diag_creation_time_utc != NULL)
{
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG));
validMessage = false;
@ -1688,7 +1734,7 @@ static void setup_message_recv_msg_callback_mocks()
static TRANSPORT_LL_HANDLE setup_iothub_mqtt_connection(IOTHUBTRANSPORT_CONFIG* config)
{
TRANSPORT_LL_HANDLE handle = IoTHubTransport_MQTT_Common_Create(config, get_IO_transport, &transport_cb_info, transport_cb_ctx);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
CONNECT_ACK connack;
connack.isSessionPresent = true;
@ -2057,8 +2103,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_Destroy_parameter_NULL_succeed)
// assert
}
/* Tests_SRS_IOTHUB_MQTT_TRANSPORT_07_013: [If the parameter subscribe is true then IoTHubTransport_MQTT_Common_Destroy shall call IoTHubTransport_MQTT_Common_Unsubscribe.] */
TEST_FUNCTION(IoTHubTransport_MQTT_Common_Destroy_Unsubscribe_succeeds)
static void IoTHubTransport_MQTT_Common_Destroy_Unsubscribe_impl(bool useModelId)
{
// arrange
IOTHUBTRANSPORT_CONFIG config ={ 0 };
@ -2068,7 +2113,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_Destroy_Unsubscribe_succeeds)
(void)IoTHubTransport_MQTT_Common_Subscribe(handle);
CONNECT_ACK connack ={ true, CONNECTION_ACCEPTED };
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(useModelId);
IoTHubTransport_MQTT_Common_DoWork(handle);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_CONNACK, &connack, g_callbackCtx);
@ -2099,8 +2144,21 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_Destroy_Unsubscribe_succeeds)
IoTHubTransport_MQTT_Common_Destroy(handle);
// assert
}
/* Tests_SRS_IOTHUB_MQTT_TRANSPORT_07_013: [If the parameter subscribe is true then IoTHubTransport_MQTT_Common_Destroy shall call IoTHubTransport_MQTT_Common_Unsubscribe.] */
TEST_FUNCTION(IoTHubTransport_MQTT_Common_Destroy_Unsubscribe_succeeds)
{
IoTHubTransport_MQTT_Common_Destroy_Unsubscribe_impl(false);
}
TEST_FUNCTION(IoTHubTransport_MQTT_Common_Destroy_Unsubscribe_with_modelID_succeeds)
{
IoTHubTransport_MQTT_Common_Destroy_Unsubscribe_impl(true);
}
static void set_expected_calls_for_free_transport_handle_data()
{
STRICT_EXPECTED_CALL(mqtt_client_deinit(TEST_MQTT_CLIENT_HANDLE)).IgnoreArgument(1);
@ -2119,6 +2177,7 @@ static void set_expected_calls_for_free_transport_handle_data()
EXPECTED_CALL(STRING_delete(NULL));
EXPECTED_CALL(STRING_delete(NULL));
STRICT_EXPECTED_CALL(mqtt_client_clear_xio(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(xio_destroy(IGNORED_PTR_ARG));
EXPECTED_CALL(gballoc_free(NULL));
@ -2145,6 +2204,54 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_Destroy_One_Message_Ack_succeeds)
STRICT_EXPECTED_CALL(mqtt_client_disconnect(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(mqtt_client_dowork(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(ThreadAPI_Sleep(IGNORED_NUM_ARG));
STRICT_EXPECTED_CALL(mqtt_client_clear_xio(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(xio_destroy(IGNORED_PTR_ARG));
EXPECTED_CALL(DList_IsListEmpty(IGNORED_PTR_ARG));
EXPECTED_CALL(DList_RemoveHeadList(IGNORED_PTR_ARG));
EXPECTED_CALL(DList_InitializeListHead(IGNORED_PTR_ARG));
EXPECTED_CALL(DList_InsertTailList(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(Transport_SendComplete_Callback(IGNORED_PTR_ARG, IOTHUB_CLIENT_CONFIRMATION_BECAUSE_DESTROY, transport_cb_ctx));
EXPECTED_CALL(gballoc_free(NULL));
EXPECTED_CALL(DList_IsListEmpty(IGNORED_PTR_ARG));
EXPECTED_CALL(DList_IsListEmpty(IGNORED_PTR_ARG));
EXPECTED_CALL(DList_IsListEmpty(IGNORED_PTR_ARG)); // pending_get_twin_queue
set_expected_calls_for_free_transport_handle_data();
// act
IoTHubTransport_MQTT_Common_Destroy(handle);
// assert
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
}
/* Tests_SRS_IOTHUB_MQTT_TRANSPORT_07_014: [IoTHubTransport_MQTT_Common_Destroy shall free all the resources currently in use even during
disconnect timeout.] */
TEST_FUNCTION(IoTHubTransport_MQTT_Common_Destroy_disconnect_timeout_succeeds)
{
// arrange
IOTHUBTRANSPORT_CONFIG config ={ 0 };
SetupIothubTransportConfig(&config, TEST_DEVICE_ID, TEST_DEVICE_KEY, TEST_IOTHUB_NAME, TEST_IOTHUB_SUFFIX, TEST_PROTOCOL_GATEWAY_HOSTNAME, NULL);
IOTHUB_MESSAGE_LIST message1;
memset(&message1, 0, sizeof(IOTHUB_MESSAGE_LIST) );
message1.messageHandle = TEST_IOTHUB_MSG_BYTEARRAY;
g_skip_disconnect_callback = true;
DList_InsertTailList(config.waitingToSend, &(message1.entry));
TRANSPORT_LL_HANDLE handle = setup_iothub_mqtt_connection(&config);
IoTHubTransport_MQTT_Common_DoWork(handle);
umock_c_reset_all_calls();
STRICT_EXPECTED_CALL(mqtt_client_disconnect(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG));
for(int i = 0; i < TEST_MAX_DISCONNECT_VALUE; ++i)
{
STRICT_EXPECTED_CALL(mqtt_client_dowork(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(ThreadAPI_Sleep(IGNORED_NUM_ARG));
}
STRICT_EXPECTED_CALL(mqtt_client_clear_xio(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(xio_destroy(IGNORED_PTR_ARG));
EXPECTED_CALL(DList_IsListEmpty(IGNORED_PTR_ARG));
EXPECTED_CALL(DList_RemoveHeadList(IGNORED_PTR_ARG));
@ -2218,7 +2325,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_Destroy_from_disconnected_state)
(void)IoTHubTransport_MQTT_Common_Subscribe(handle);
CONNECT_ACK connack ={ true, CONNECTION_ACCEPTED };
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_CONNACK, &connack, g_callbackCtx);
@ -2270,7 +2377,7 @@ static void IoTHubTransport_MQTT_Common_Subscribe_Succeed_impl(const char *modul
TRANSPORT_LL_HANDLE handle = IoTHubTransport_MQTT_Common_Create(&config, get_IO_transport, &transport_cb_info, transport_cb_ctx);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_CONNACK, &connack, g_callbackCtx);
@ -2319,7 +2426,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_Subscribe_fail)
TRANSPORT_LL_HANDLE handle = IoTHubTransport_MQTT_Common_Create(&config, get_IO_transport, &transport_cb_info, transport_cb_ctx);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_CONNACK, &connack, g_callbackCtx);
@ -2365,7 +2472,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_Subscribe_set_subscribe_type_Succeed)
TRANSPORT_LL_HANDLE handle = IoTHubTransport_MQTT_Common_Create(&config, get_IO_transport, &transport_cb_info, transport_cb_ctx);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_CONNACK, &connack, g_callbackCtx);
umock_c_reset_all_calls();
@ -2701,6 +2808,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_Destroy_return_pending_get_twin_reques
umock_c_reset_all_calls();
EXPECTED_CALL(mqtt_client_clear_xio(IGNORED_PTR_ARG));
EXPECTED_CALL(xio_destroy(NULL));
EXPECTED_CALL(DList_IsListEmpty(IGNORED_PTR_ARG));
EXPECTED_CALL(DList_IsListEmpty(IGNORED_PTR_ARG));
@ -2973,6 +3081,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_SetOption_keepAlive_previous_connectio
STRICT_EXPECTED_CALL(mqtt_client_dowork(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(ThreadAPI_Sleep(IGNORED_NUM_ARG));
}
STRICT_EXPECTED_CALL(mqtt_client_clear_xio(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(xio_destroy(IGNORED_PTR_ARG));
int keepAlive = 10;
@ -3753,6 +3862,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_Destroy_frees_the_proxy_options)
STRICT_EXPECTED_CALL(mqtt_client_deinit(IGNORED_PTR_ARG))
.IgnoreAllCalls();
STRICT_EXPECTED_CALL(mqtt_client_clear_xio(IGNORED_PTR_ARG)).IgnoreAllCalls();
STRICT_EXPECTED_CALL(xio_destroy(IGNORED_PTR_ARG))
.IgnoreAllCalls();
EXPECTED_CALL(DList_IsListEmpty(IGNORED_PTR_ARG))
@ -3902,27 +4012,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_mqtt_client_connect_fail)
TRANSPORT_LL_HANDLE handle = IoTHubTransport_MQTT_Common_Create(&config, get_IO_transport, &transport_cb_info, transport_cb_ctx);
umock_c_reset_all_calls();
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(IoTHubClient_Auth_Get_Credential_Type(IGNORED_PTR_ARG));
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_DEVICE_ID);
STRICT_EXPECTED_CALL(IoTHubClient_Auth_Get_SasToken(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_NUM_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(Transport_GetOption_Product_Info_Callback(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(URL_EncodeString(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_concat_with_STRING(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)).IgnoreArgument_handle();
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_DEVICE_ID);
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(NULL);
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_DEVICE_ID);
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_STRING_VALUE);
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_HOST_NAME);
STRICT_EXPECTED_CALL(IoTHubClient_Auth_Get_Credential_Type(IGNORED_PTR_ARG));
EXPECTED_CALL(mqtt_client_connect(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)).IgnoreArgument_handle();
setup_initialize_connection_mocks(false);
STRICT_EXPECTED_CALL(mqtt_client_dowork(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
// removeExpiredTwinRequests
@ -3948,7 +4038,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_Retry_Policy_First_connect_succ
IoTHubTransport_MQTT_Common_SetRetryPolicy(handle, TEST_RETRY_POLICY, TEST_RETRY_TIMEOUT_SECS);
umock_c_reset_all_calls();
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
STRICT_EXPECTED_CALL(mqtt_client_dowork(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
// removeExpiredTwinRequests
@ -3993,7 +4083,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_send_get_twin_succeed)
QOS_VALUE QosValue[] = { DELIVER_AT_LEAST_ONCE };
SUBSCRIBE_ACK suback;
suback.packetId = 1234;
suback.packetId = 0;
suback.qosCount = 1;
suback.qosReturn = QosValue;
@ -4138,7 +4228,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_Retry_Policy_First_connect_succ
CONNECT_ACK connack = { true, CONNECTION_ACCEPTED };
umock_c_reset_all_calls();
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
STRICT_EXPECTED_CALL(mqtt_client_dowork(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
// removeExpiredTwinRequests
@ -4163,7 +4253,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_Retry_Policy_First_Connect_Fail
TRANSPORT_LL_HANDLE handle = IoTHubTransport_MQTT_Common_Create(&config, get_IO_transport, &transport_cb_info, transport_cb_ctx);
IoTHubTransport_MQTT_Common_SetRetryPolicy(handle, TEST_RETRY_POLICY, TEST_RETRY_TIMEOUT_SECS);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
CONNECT_ACK connack;
connack.isSessionPresent = false;
@ -4254,7 +4344,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_Retry_Policy_Connection_Break_R
size_t counter;
RETRY_ACTION retry_action = RETRY_ACTION_RETRY_LATER;
// setup_initialize_connection_mocks();
// setup_initialize_connection_mocks(false);
for (counter = 0; counter < 100; counter++)
{
if (counter == 30) // This is a random number....
@ -4361,7 +4451,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_no_messages_succeed)
TRANSPORT_LL_HANDLE handle = IoTHubTransport_MQTT_Common_Create(&config, get_IO_transport, &transport_cb_info, transport_cb_ctx);
umock_c_reset_all_calls();
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
STRICT_EXPECTED_CALL(mqtt_client_dowork(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
// removeExpiredTwinRequests
@ -4391,7 +4481,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_no_messages_fail)
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_CONNACK, &connack, g_callbackCtx);
umock_c_reset_all_calls();
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
STRICT_EXPECTED_CALL(mqtt_client_dowork(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
@ -4432,26 +4522,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_SAS_token_from_user_succeed)
TRANSPORT_LL_HANDLE handle = IoTHubTransport_MQTT_Common_Create(&config, get_IO_transport, &transport_cb_info, transport_cb_ctx);
umock_c_reset_all_calls();
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(IoTHubClient_Auth_Get_Credential_Type(IGNORED_PTR_ARG)).SetReturn(IOTHUB_CREDENTIAL_TYPE_SAS_TOKEN);
STRICT_EXPECTED_CALL(IoTHubClient_Auth_Is_SasToken_Valid(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(IoTHubClient_Auth_Get_SasToken(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_NUM_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(Transport_GetOption_Product_Info_Callback(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(URL_EncodeString(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_concat_with_STRING(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)).IgnoreArgument_handle();
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_STRING_VALUE);
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_STRING_VALUE);
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_STRING_VALUE);
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_STRING_VALUE);
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_STRING_VALUE);
STRICT_EXPECTED_CALL(IoTHubClient_Auth_Get_Credential_Type(IGNORED_PTR_ARG)).SetReturn(IOTHUB_CREDENTIAL_TYPE_SAS_TOKEN);
EXPECTED_CALL(mqtt_client_connect(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)).IgnoreArgument_handle();
setup_initialize_connection_mocks(false);
STRICT_EXPECTED_CALL(mqtt_client_dowork(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
@ -4534,21 +4605,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_x509_succeed)
TRANSPORT_LL_HANDLE handle = IoTHubTransport_MQTT_Common_Create(&config, get_IO_transport, &transport_cb_info, transport_cb_ctx);
umock_c_reset_all_calls();
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(IoTHubClient_Auth_Get_Credential_Type(IGNORED_PTR_ARG)).SetReturn(IOTHUB_CREDENTIAL_TYPE_X509);
STRICT_EXPECTED_CALL(Transport_GetOption_Product_Info_Callback(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(URL_EncodeString(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_concat_with_STRING(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)).IgnoreArgument_handle();
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_STRING_VALUE);
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_STRING_VALUE);
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_STRING_VALUE);
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_STRING_VALUE);
EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)).SetReturn(TEST_STRING_VALUE);
STRICT_EXPECTED_CALL(IoTHubClient_Auth_Get_Credential_Type(IGNORED_PTR_ARG));
EXPECTED_CALL(mqtt_client_connect(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)).IgnoreArgument_handle();
setup_initialize_connection_mocks(false);
STRICT_EXPECTED_CALL(mqtt_client_dowork(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
// removeExpiredTwinRequests
@ -4589,11 +4646,11 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_with_1_event_item_succeeds)
IoTHubTransport_MQTT_Common_DoWork(handle);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_SUBSCRIBE_ACK, &suback, g_callbackCtx);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
umock_c_reset_all_calls();
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks(NULL, NULL, 0, TEST_IOTHUB_MSG_BYTEARRAY, false, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false);
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks(NULL, NULL, 0, TEST_IOTHUB_MSG_BYTEARRAY, false, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false);
// act
IoTHubTransport_MQTT_Common_DoWork(handle);
@ -4629,7 +4686,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_get_item_fails)
IoTHubTransport_MQTT_Common_DoWork(handle);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_SUBSCRIBE_ACK, &suback, g_callbackCtx);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(true);
IoTHubTransport_MQTT_Common_DoWork(handle);
umock_c_reset_all_calls();
@ -4737,7 +4794,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_with_emtpy_item_succeeds)
IoTHubTransport_MQTT_Common_DoWork(handle);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_SUBSCRIBE_ACK, &suback, g_callbackCtx);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
umock_c_reset_all_calls();
@ -4773,11 +4830,11 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_with_security_msg_succeeds)
TRANSPORT_LL_HANDLE handle = setup_iothub_mqtt_connection(&config);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_SUBSCRIBE_ACK, &suback, g_callbackCtx);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
umock_c_reset_all_calls();
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks(NULL, NULL, 0, TEST_IOTHUB_MSG_STRING, false, NULL, NULL, NULL, "json/application", NULL, NULL, false, NULL, true);
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks(NULL, NULL, 0, TEST_IOTHUB_MSG_STRING, false, NULL, NULL, NULL, "json/application", NULL, NULL, NULL, false, NULL, true);
// act
IoTHubTransport_MQTT_Common_DoWork(handle);
@ -4814,7 +4871,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_with_1_event_item_fail)
IoTHubTransport_MQTT_Common_DoWork(handle);
umock_c_reset_all_calls();
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks(NULL, NULL, 0, TEST_IOTHUB_MSG_BYTEARRAY, false, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false);
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks(NULL, NULL, 0, TEST_IOTHUB_MSG_BYTEARRAY, false, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false);
umock_c_negative_tests_snapshot();
size_t calls_cannot_fail[] = { 4 };
@ -4874,11 +4931,11 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_with_1_event_item_with_properti
IoTHubTransport_MQTT_Common_DoWork(handle);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_SUBSCRIBE_ACK, &suback, g_callbackCtx);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
umock_c_reset_all_calls();
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks((const char* const**)&keys, (const char* const**)&values, propCount, TEST_IOTHUB_MSG_BYTEARRAY, false, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false);
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks((const char* const**)&keys, (const char* const**)&values, propCount, TEST_IOTHUB_MSG_BYTEARRAY, false, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false);
// act
IoTHubTransport_MQTT_Common_DoWork(handle);
@ -4920,11 +4977,11 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_with_1_event_item_with_2_proper
IoTHubTransport_MQTT_Common_DoWork(handle);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_SUBSCRIBE_ACK, &suback, g_callbackCtx);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
umock_c_reset_all_calls();
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks((const char* const**)&keys, (const char* const**)&values, propCount, TEST_IOTHUB_MSG_BYTEARRAY, false, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false);
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks((const char* const**)&keys, (const char* const**)&values, propCount, TEST_IOTHUB_MSG_BYTEARRAY, false, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false);
// act
IoTHubTransport_MQTT_Common_DoWork(handle);
@ -4968,11 +5025,11 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_with_1_event_item_with_properti
bool urlencode = true;
IoTHubTransport_MQTT_Common_SetOption(handle, OPTION_AUTO_URL_ENCODE_DECODE, &urlencode);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_SUBSCRIBE_ACK, &suback, g_callbackCtx);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
umock_c_reset_all_calls();
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks((const char* const**)&keys, (const char* const**)&values, propCount, TEST_IOTHUB_MSG_BYTEARRAY, false, NULL, NULL, NULL, NULL, NULL, NULL, true, NULL, false);
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks((const char* const**)&keys, (const char* const**)&values, propCount, TEST_IOTHUB_MSG_BYTEARRAY, false, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true, NULL, false);
// act
IoTHubTransport_MQTT_Common_DoWork(handle);
@ -5016,11 +5073,11 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_with_1_event_item_with_2_proper
bool urlencode = true;
IoTHubTransport_MQTT_Common_SetOption(handle, OPTION_AUTO_URL_ENCODE_DECODE, &urlencode);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_SUBSCRIBE_ACK, &suback, g_callbackCtx);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
umock_c_reset_all_calls();
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks((const char* const**)&keys, (const char* const**)&values, propCount, TEST_IOTHUB_MSG_BYTEARRAY, false, NULL, NULL, NULL, NULL, NULL, NULL, true, NULL, false);
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks((const char* const**)&keys, (const char* const**)&values, propCount, TEST_IOTHUB_MSG_BYTEARRAY, false, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true, NULL, false);
// act
IoTHubTransport_MQTT_Common_DoWork(handle);
@ -5052,7 +5109,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_no_resend_message_succeeds)
DList_InsertTailList(config.waitingToSend, &(message2.entry));
TRANSPORT_LL_HANDLE handle = IoTHubTransport_MQTT_Common_Create(&config, get_IO_transport, &transport_cb_info, transport_cb_ctx);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_SUBSCRIBE_ACK, &suback, g_callbackCtx);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
IoTHubTransport_MQTT_Common_DoWork(handle);
umock_c_reset_all_calls();
@ -5093,7 +5150,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_resend_message_succeeds)
DList_InsertTailList(config.waitingToSend, &(message2.entry));
TRANSPORT_LL_HANDLE handle = IoTHubTransport_MQTT_Common_Create(&config, get_IO_transport, &transport_cb_info, transport_cb_ctx);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_CONNACK, &connack, g_callbackCtx);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_SUBSCRIBE_ACK, &suback, g_callbackCtx);
@ -5101,7 +5158,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_resend_message_succeeds)
umock_c_reset_all_calls();
g_current_ms += 5*60*1000;
setup_IoTHubTransport_MQTT_Common_DoWork_resend_events_mocks(NULL, NULL, 0, TEST_IOTHUB_MSG_STRING, false, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false);
setup_IoTHubTransport_MQTT_Common_DoWork_resend_events_mocks(NULL, NULL, 0, TEST_IOTHUB_MSG_STRING, false, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false);
// act
IoTHubTransport_MQTT_Common_DoWork(handle);
@ -5173,6 +5230,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_message_timeout_succeeds)
STRICT_EXPECTED_CALL(mqtt_client_dowork(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(ThreadAPI_Sleep(IGNORED_NUM_ARG));
}
STRICT_EXPECTED_CALL(mqtt_client_clear_xio(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(xio_destroy(IGNORED_PTR_ARG));
// removeExpiredTwinRequests
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
@ -5252,6 +5310,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_2_message_timeout_succeeds)
STRICT_EXPECTED_CALL(mqtt_client_dowork(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(ThreadAPI_Sleep(IGNORED_NUM_ARG));
}
STRICT_EXPECTED_CALL(mqtt_client_clear_xio(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(xio_destroy(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(DList_InitializeListHead(IGNORED_PTR_ARG));
@ -5289,7 +5348,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_device_twin_resend_message_succ
suback.qosReturn = QosValue;
(void)IoTHubTransport_MQTT_Common_Subscribe_DeviceTwin(handle);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_CONNACK, &connack, g_callbackCtx);
IoTHubTransport_MQTT_Common_DoWork(handle);
@ -5363,11 +5422,11 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_with_1_event_item_STRING_type_s
IoTHubTransport_MQTT_Common_DoWork(handle);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_SUBSCRIBE_ACK, &suback, g_callbackCtx);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
umock_c_reset_all_calls();
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks(NULL, NULL, 0, TEST_IOTHUB_MSG_STRING, false, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false);
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks(NULL, NULL, 0, TEST_IOTHUB_MSG_STRING, false, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false);
// act
IoTHubTransport_MQTT_Common_DoWork(handle);
@ -5408,12 +5467,12 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_with_message_system_properties_
IoTHubTransport_MQTT_Common_DoWork(handle);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_SUBSCRIBE_ACK, &suback, g_callbackCtx);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
umock_c_reset_all_calls();
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks(NULL, NULL, 0, TEST_IOTHUB_MSG_STRING, false,
"msg_id", "core_id", TEST_CONTENT_TYPE, TEST_CONTENT_ENCODING, TEST_DIAG_ID, TEST_DIAG_CREATION_TIME_UTC, false, TEST_OUTPUT_NAME, false);
"msg_id", "core_id", TEST_CONTENT_TYPE, TEST_CONTENT_ENCODING, TEST_DIAG_ID, TEST_DIAG_CREATION_TIME_UTC, TEST_MESSAGE_CREATION_TIME_UTC, false, TEST_OUTPUT_NAME, false);
// act
IoTHubTransport_MQTT_Common_DoWork(handle);
@ -5451,12 +5510,12 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_with_message_system_properties_
bool urlencode = true;
IoTHubTransport_MQTT_Common_SetOption(handle, OPTION_AUTO_URL_ENCODE_DECODE, &urlencode);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_SUBSCRIBE_ACK, &suback, g_callbackCtx);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
umock_c_reset_all_calls();
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks(NULL, NULL, 0, TEST_IOTHUB_MSG_STRING, false,
"msg_id", "core_id", TEST_CONTENT_TYPE, TEST_CONTENT_ENCODING, TEST_DIAG_ID, TEST_DIAG_CREATION_TIME_UTC, true, NULL, false);
"msg_id", "core_id", TEST_CONTENT_TYPE, TEST_CONTENT_ENCODING, TEST_DIAG_ID, TEST_DIAG_CREATION_TIME_UTC, TEST_MESSAGE_CREATION_TIME_UTC, true, NULL, false);
// act
IoTHubTransport_MQTT_Common_DoWork(handle);
@ -5493,12 +5552,12 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_with_message_incomplete_diagnos
IoTHubTransport_MQTT_Common_DoWork(handle);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_SUBSCRIBE_ACK, &suback, g_callbackCtx);
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(true);
IoTHubTransport_MQTT_Common_DoWork(handle);
umock_c_reset_all_calls();
setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks(NULL, NULL, 0, TEST_IOTHUB_MSG_STRING, false,
NULL, NULL, NULL, NULL, TEST_DIAG_ID, NULL, false, NULL, false);
NULL, NULL, NULL, NULL, TEST_DIAG_ID, NULL, NULL, false, NULL, false);
// act
IoTHubTransport_MQTT_Common_DoWork(handle);
@ -5576,7 +5635,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_connectFailCount_exceed_succeed
TRANSPORT_LL_HANDLE handle = IoTHubTransport_MQTT_Common_Create(&config, get_IO_transport, &transport_cb_info, transport_cb_ctx);
umock_c_reset_all_calls();
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
for (size_t index = 0; index < iterationCount-1; index++)
{
@ -5616,7 +5675,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_mqtt_client_connect_times_out)
TRANSPORT_LL_HANDLE handle = IoTHubTransport_MQTT_Common_Create(&config, get_IO_transport, &transport_cb_info, transport_cb_ctx);
umock_c_reset_all_calls();
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
g_fnMqttOperationCallback(TEST_MQTT_CLIENT_HANDLE, MQTT_CLIENT_ON_CONNACK, &connack, g_callbackCtx);
@ -5633,6 +5692,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_mqtt_client_connect_times_out)
STRICT_EXPECTED_CALL(mqtt_client_dowork(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(ThreadAPI_Sleep(IGNORED_NUM_ARG));
}
STRICT_EXPECTED_CALL(mqtt_client_clear_xio(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(xio_destroy(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(Transport_ConnectionStatusCallBack(IOTHUB_CLIENT_CONNECTION_UNAUTHENTICATED, IOTHUB_CLIENT_CONNECTION_EXPIRED_SAS_TOKEN, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(mqtt_client_dowork(IGNORED_PTR_ARG));
@ -5661,7 +5721,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_mqtt_client_connecting_times_ou
TRANSPORT_LL_HANDLE handle = IoTHubTransport_MQTT_Common_Create(&config, get_IO_transport, &transport_cb_info, transport_cb_ctx);
umock_c_reset_all_calls();
setup_initialize_connection_mocks();
setup_initialize_connection_mocks(false);
IoTHubTransport_MQTT_Common_DoWork(handle);
g_current_ms += (5 * 600 * 2000); // 4+ minutes have passed.
@ -5669,6 +5729,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_mqtt_client_connecting_times_ou
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(xio_retrieveoptions(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(mqtt_client_clear_xio(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(xio_destroy(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
// removeExpiredTwinRequests
@ -5827,6 +5888,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_delivered_MQTT_CLIENT_NO_PING_RESPONSE
umock_c_reset_all_calls();
STRICT_EXPECTED_CALL(Transport_ConnectionStatusCallBack(IOTHUB_CLIENT_CONNECTION_UNAUTHENTICATED, IOTHUB_CLIENT_CONNECTION_NO_PING_RESPONSE, IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(xio_retrieveoptions(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(mqtt_client_clear_xio(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(xio_destroy(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(mqtt_client_dowork(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
@ -5854,6 +5916,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_delivered_MQTT_CLIENT_MQTT_CLIENT_MEMO
umock_c_reset_all_calls();
STRICT_EXPECTED_CALL(xio_retrieveoptions(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(mqtt_client_clear_xio(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(xio_destroy(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(mqtt_client_dowork(IGNORED_PTR_ARG));
STRICT_EXPECTED_CALL(tickcounter_get_current_ms(IGNORED_PTR_ARG, IGNORED_PTR_ARG));

Просмотреть файл

@ -66,6 +66,7 @@ extern "C"
#undef ENABLE_MOCKS
#include "internal/iothubtransportamqp_methods.h"
#include "internal/iothub_internal_consts.h"
static IOTHUBTRANSPORT_AMQP_METHOD_HANDLE g_method_handle;
static int g_respond_result;
@ -450,7 +451,7 @@ static void setup_subscribe_expected_calls(bool testing_modules)
STRICT_EXPECTED_CALL(amqpvalue_set_map_value(LINK_ATTACH_PROPERTIES_MAP, CHANNEL_CORRELATION_ID_KEY, CHANNEL_CORRELATION_ID_VALUE));
STRICT_EXPECTED_CALL(amqpvalue_create_symbol("com.microsoft:api-version"))
.SetReturn(API_VERSION_KEY);
STRICT_EXPECTED_CALL(amqpvalue_create_string("2016-11-14"))
STRICT_EXPECTED_CALL(amqpvalue_create_string(IOTHUB_API_VERSION))
.SetReturn(API_VERSION_VALUE);
STRICT_EXPECTED_CALL(amqpvalue_set_map_value(LINK_ATTACH_PROPERTIES_MAP, API_VERSION_KEY, API_VERSION_VALUE));
STRICT_EXPECTED_CALL(link_set_attach_properties(TEST_SENDER_LINK, LINK_ATTACH_PROPERTIES_MAP));
@ -896,7 +897,7 @@ TEST_FUNCTION(iothubtransportamqp_methods_destroy_frees_2_tracked_handles)
/* Tests_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_142: [ A property value of type string that shall contain the device id (and "/" + module id if module is present) shall be created by calling `amqpvalue_create_string`. ]*/
/* Tests_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_143: [ The `com.microsoft:channel-correlation-id` shall be added to the link attach properties by calling `amqpvalue_set_map_value`. ]*/
/* Tests_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_150: [ A property key which shall be a symbol named `com.microsoft:api-version` shall be created by calling `amqp_create_symbol`. ]*/
/* Tests_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_151: [ A property value of type string that shall contain the `2016-11-14` shall be created by calling `amqpvalue_create_string`. ]*/
/* Tests_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_151: [ A property value of type string that shall contain the `Current API version` shall be created by calling `amqpvalue_create_string`. ]*/
/* Tests_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_152: [ The `com.microsoft:api-version` shall be added to the link attach properties by calling `amqpvalue_set_map_value`. ]*/
/* Tests_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_144: [ The link attach properties shall be set on the receiver and sender link by calling `link_set_attach_properties`. ]*/
/* Tests_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_146: [ The link attach properties and all associated values shall be freed by calling `amqpvalue_destroy` after setting the link attach properties. ]*/
@ -952,7 +953,7 @@ TEST_FUNCTION(iothubtransportamqp_methods_subscribe_creates_links_and_sender_and
/* Tests_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_142: [ A property value of type string that shall contain the device id (and "/" + module id if module is present) shall be created by calling `amqpvalue_create_string`. ]*/
/* Tests_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_143: [ The `com.microsoft:channel-correlation-id` shall be added to the link attach properties by calling `amqpvalue_set_map_value`. ]*/
/* Tests_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_150: [ A property key which shall be a symbol named `com.microsoft:api-version` shall be created by calling `amqp_create_symbol`. ]*/
/* Tests_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_151: [ A property value of type string that shall contain the `2016-11-14` shall be created by calling `amqpvalue_create_string`. ]*/
/* Tests_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_151: [ A property value of type string that shall contain the `Current API version` shall be created by calling `amqpvalue_create_string`. ]*/
/* Tests_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_152: [ The `com.microsoft:api-version` shall be added to the link attach properties by calling `amqpvalue_set_map_value`. ]*/
/* Tests_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_144: [ The link attach properties shall be set on the receiver and sender link by calling `link_set_attach_properties`. ]*/
/* Tests_SRS_IOTHUBTRANSPORT_AMQP_METHODS_01_146: [ The link attach properties and all associated values shall be freed by calling `amqpvalue_destroy` after setting the link attach properties. ]*/
@ -1289,7 +1290,7 @@ TEST_FUNCTION(when_a_failure_occurs_iothubtransportamqp_methods_subscribe_fails)
.SetFailReturn(42);
STRICT_EXPECTED_CALL(amqpvalue_create_symbol("com.microsoft:api-version"))
.SetReturn(API_VERSION_KEY).SetFailReturn(NULL);
STRICT_EXPECTED_CALL(amqpvalue_create_string("2016-11-14"))
STRICT_EXPECTED_CALL(amqpvalue_create_string(IOTHUB_API_VERSION))
.SetReturn(API_VERSION_VALUE).SetFailReturn(NULL);
STRICT_EXPECTED_CALL(amqpvalue_set_map_value(LINK_ATTACH_PROPERTIES_MAP, API_VERSION_KEY, API_VERSION_VALUE))
.SetFailReturn(42);

Просмотреть файл

@ -9,7 +9,7 @@
#include "azure_c_shared_utility/threadapi.h"
#include "azure_c_shared_utility/crt_abstractions.h"
#include "azure_c_shared_utility/shared_util_options.h"
#include "iothub_client.h"
#include "iothub_device_client.h"
#include "iothub_client_options.h"
#include "iothub_message.h"
#include "iothubtransportamqp.h"

Просмотреть файл

@ -9,7 +9,7 @@
#include "azure_c_shared_utility/threadapi.h"
#include "azure_c_shared_utility/crt_abstractions.h"
#include "azure_c_shared_utility/shared_util_options.h"
#include "iothub_client.h"
#include "iothub_device_client.h"
#include "iothub_client_options.h"
#include "iothub_message.h"
#include "iothubtransportamqp.h"

Просмотреть файл

@ -9,7 +9,7 @@
#include "azure_c_shared_utility/threadapi.h"
#include "azure_c_shared_utility/crt_abstractions.h"
#include "azure_c_shared_utility/shared_util_options.h"
#include "iothub_client.h"
#include "iothub_device_client.h"
#include "iothub_client_options.h"
#include "iothub_message.h"
#include "iothubtransportamqp.h"

Просмотреть файл

@ -9,7 +9,7 @@
#include "azure_c_shared_utility/threadapi.h"
#include "azure_c_shared_utility/crt_abstractions.h"
#include "azure_c_shared_utility/shared_util_options.h"
#include "iothub_client.h"
#include "iothub_device_client.h"
#include "iothub_client_options.h"
#include "iothub_message.h"
#include "iothubtransportamqp.h"

Просмотреть файл

@ -9,7 +9,7 @@
#include "azure_c_shared_utility/threadapi.h"
#include "azure_c_shared_utility/crt_abstractions.h"
#include "azure_c_shared_utility/shared_util_options.h"
#include "iothub_client.h"
#include "iothub_device_client.h"
#include "iothub_client_options.h"
#include "iothub_message.h"
#include "iothubtransportamqp.h"

Просмотреть файл

@ -9,7 +9,7 @@
#include "azure_c_shared_utility/threadapi.h"
#include "azure_c_shared_utility/crt_abstractions.h"
#include "azure_c_shared_utility/shared_util_options.h"
#include "iothub_client.h"
#include "iothub_device_client.h"
#include "iothub_client_options.h"
#include "iothub_message.h"
#include "iothubtransportmqtt.h"

Просмотреть файл

@ -9,7 +9,7 @@
#include "azure_c_shared_utility/threadapi.h"
#include "azure_c_shared_utility/crt_abstractions.h"
#include "azure_c_shared_utility/shared_util_options.h"
#include "iothub_client.h"
#include "iothub_device_client.h"
#include "iothub_client_options.h"
#include "iothub_message.h"
#include "iothubtransportmqtt.h"

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше