Release of version 2.0.0

This commit is contained in:
chaurah
2016-05-05 02:46:26 +00:00
parent d2ed84ce86
commit 8aa5c18efe
96 changed files with 6852 additions and 6605 deletions

View File

@@ -1,31 +1,58 @@
#Change Log
## [1.1.2](https://github.com/aws/aws-iot-device-sdk-embedded-C/releases/tag/v1.1.2) (April 22,2016)
## [2.0.0](https://github.com/aws/aws-iot-device-sdk-embedded-C/releases/tag/v2.0.0) (April 28, 2016)
New features:
- Refactored API to make it instance specific. This is a breaking change in the API from 1.x releases because a Client Instance parameter had to be added to all APIs
- Added Threading library porting layer wrapper
- Added support for multiple connections from one application
- Shadows and connections de-linked, connection needs to be set up separately, can be used independently of shadow
- Added integration tests for testing SDK functionality
Bugfixes/Improvements:
- Yield cannot be called again while waiting for application callback to return
- Fixed issue with TLS layer handles not being cleaned up properly on connection failure reported [here](https://github.com/aws/aws-iot-device-sdk-embedded-C/issues/16)
- Renamed timer_linux.h to timer_platform.h as requested [here](https://github.com/aws/aws-iot-device-sdk-embedded-C/issues/5)
- Adds support for disconnect handler to shadow. A similar pull request can be found [here](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/9)
- New SDK folder structure, cleaned and simplified code structure
- Removed Paho Wrapper, Merge MQTT into SDK code, added specific error codes
- Refactored Network and Timer layer wrappers, added specific error codes
- Refactored samples and makefiles
## [1.1.2](https://github.com/aws/aws-iot-device-sdk-embedded-C/releases/tag/v1.1.2) (April 22, 2016)
Bugfixes/Improvements:
- Signature mismatch in MQTT library file fixed
- Makefiles have a protective target on the top to prevent accidental execution
## [1.1.1](https://github.com/aws/aws-iot-device-sdk-embedded-C/releases/tag/v1.1.1) (April 1,2016)
## [1.1.1](https://github.com/aws/aws-iot-device-sdk-embedded-C/releases/tag/v1.1.1) (April 1, 2016)
Bugfixes/Improvements:
- Removing the Executable bit from all the files in the repository. Fixing [this](https://github.com/aws/aws-iot-device-sdk-embedded-C/issues/14) issue
- Refactoring MQTT client to remove declaration after statement warnings
- Fixing [this](https://forums.aws.amazon.com/thread.jspa?threadID=222467&tstart=0) bug
## [1.1.0](https://github.com/aws/aws-iot-device-sdk-embedded-C/releases/tag/v1.1.0) (February 10,2016)
## [1.1.0](https://github.com/aws/aws-iot-device-sdk-embedded-C/releases/tag/v1.1.0) (February 10, 2016)
Features:
- Auto Reconnect and Resubscribe
Bugfixes/Improvements:
- MQTT buffer handling incase of bigger message
- Large timeout values converted to seconds and milliseconds
- Dynamic loading of Shadow parameters. Client ID and Thing Name are not hard-coded
- MQTT Library refactored
## [1.0.1](https://github.com/aws/aws-iot-device-sdk-embedded-C/releases/tag/v1.0.1) (October 21,2015)
## [1.0.1](https://github.com/aws/aws-iot-device-sdk-embedded-C/releases/tag/v1.0.1) (October 21, 2015)
Bugfixes/Improvements:
- Paho name changed to Eclipse Paho
- Renamed the Makefiles in the samples directory
- Device Shadow - Delete functionality macro fixed
@@ -34,6 +61,7 @@ Bugfixes/Improvements:
## [1.0.0](https://github.com/aws/aws-iot-device-sdk-embedded-C/releases/tag/v1.0.0) (October 8, 2015)
Features:
- Release to github
- SDK tarballs made available for public download

View File

@@ -7,11 +7,10 @@ Amazon Inc (http://www.amazon.com/).
**********************
THIRD PARTY COMPONENTS
**********************
This software includes third party software subject to the following copyrights:
This software includes third party software subject to the following licensing:
- Embedded C MQTT Client - From the Eclipse Paho Project - EPL v1.0
- mbedTLS
- jsmn (JSON Parsing)
- cURL (hostname verification)
- SSL Conservatory (hostname verification)
- mbedTLS (external library, included in tarball or downloaded separately) - Apache 2.0
- jsmn (JSON Parsing) - MIT
- cURL (hostname verification) - MIT
The licenses for these third party components are included in LICENSE.txt

View File

@@ -5,66 +5,65 @@ The scope of this document is to provide instructions to modify the provided sou
##Contents of the SDK
The SDK ported for linux can be downloaded from the below links.
* [OpenSSL](https://s3.amazonaws.com/aws-iot-device-sdk-embedded-c/linux_mqtt_openssl-1.1.2.tar)
* [mbedTLS from ARM](https://s3.amazonaws.com/aws-iot-device-sdk-embedded-c/linux_mqtt_mbedtls-1.1.2.tar)
The SDK ported for linux can be downloaded from the below link:
* [mbedTLS from ARM](https://s3.amazonaws.com/aws-iot-device-sdk-embedded-c/linux_mqtt_mbedtls-2.0.0.tar)
The C-code files of this SDK are delivered via the following directory structure (see comment behind folder name for an explanation of its content).
Directory structure Current SDK Directory Layout (OpenSSL)
|--`aws_iot_src` (Source files of the AWS IoT device SDK)<br>
|--`aws_mqtt_embedded_client_lib` (MQTT library based on [Eclipse Paho](http://www.eclipse.org/paho/clients/c/embedded/) Embedded C client)<br>
|--`certs` (Private key, device certificate and Root CA) <br>
|--`docs` (Developer guide & API documentation) <br>
|--`sample_apps` (makefiles to build sample on openSSL) <br>
The C-code files of this SDK are delivered via the following directory structure (see comment behind folder name for an explanation of its content).
Current SDK Directory Layout (mbedTLS)
|--`aws_iot_src` (Source files of the AWS IoT device SDK) <br>
|--`aws_mqtt_embedded_client_lib` (MQTT library based on [Eclipse Paho](http://www.eclipse.org/paho/clients/c/embedded/) Embedded C client) <br>
|--`certs` (Private key, device certificate and Root CA) <br>
|--`docs` (Developer guide & API documentation) <br>
|--`mbedtls_lib` (mbedTLS implementation library) <br>
|--`sample_apps` (makefiles to build sample on mbedTLS) <br>
|--`external_libs` (external libraries - jsmn, mbedTLS) <br>
|--`include` (Header files of the AWS IoT device SDK) <br>
|--`src` (Source files of the AWS IoT device SDK) <br>
|--`platform` (Platform specific files) <br>
|--`samples` (Samples including makefiles for building on mbedTLS) <br>
|--`tests` (Tests for verifying SDK is functioning as expected) <br>
All makefiles in this SDK were configured using the documented folder structure above, so moving or renaming folders will require modifications to makefiles.
##Explanation of folders and their content
`aws_iot_src` : This directory contains the SDK source code including wrappers around the MQTT library, device shadow code and utilities.
`aws_mqtt_embedded_client_lib` : The source code for the Embedded C MQTT client. This client is a modified version of the [Eclipse Paho](http://www.eclipse.org/paho/clients/c/embedded/) Embedded C client. The modifications include improved keep alive handling (callback on disconnect), a fix for unsubscribe functionality, buffer protection against too large MQTT messages and additional callback context to allow for a better layered architecture of the AWS IoT SDK.
* `certs` : This directory is initially empty and will need to contain the private key, the client certificate and the root CA. The client certificate and private key can be downloaded from the AWS IoT console or be created using the AWS CLI commands. The root CA can be downloaded from [Symantec](https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem).
`certs` : This directory is initially empty and will need to contain the private key, the client certificate and the root CA. The client certificate and private key can be downloaded from the AWS IoT console or be created using the AWS CLI commands. The root CA can be downloaded from [Symantec](https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem).
* `docs` : SDK API and file documentation.
`docs` : SDK API and file documentation.
* `external_libs` : The mbedTLS and jsmn source files. The jsmn source files are always present. The mbedTLS source files are only included when downloading the tarball version of the SDK.
`mbedtls_lib` : The mbedTLS source files. This directory is included when downloading the mbedTLS version of the SDK. It contains the mbedTLS source files to be built into the device application.
* `include` : This directory contains the header files that an application using the SDK needs to include.
`sample_apps` : This directory contains sample applications as well as their makefiles. These makefiles include the relevant source files in the above two directories. The samples include a simple MQTT example which publishes and subscribes to the AWS IoT service as well as a device shadow example that shows example usage of the device shadow functionality.
* `src` : This directory contains the SDK source code including the MQTT library, device shadow code and utilities.
* `platform` : Platform specific files for timer, TLS and threading layers. Includes a reference implementation for the linux using mbedTLS and pthread.
* `samples` : This directory contains sample applications as well as their makefiles. The samples include a simple MQTT example which publishes and subscribes to the AWS IoT service as well as a device shadow example that shows example usage of the device shadow functionality.
* `tests` : Contains tests for verifying SDK functionality. For further details please check the readme file included with the tests [here](https://github.com/aws/aws-iot-device-sdk-embedded-C/blob/master/tests/README.md/).
##Integrating the SDK into your environment
This section explains the API calls that need to be implemented in order for the Device SDK to run on your platform. The SDK interfaces follow the driver model where only prototypes are defined by the Device SDK itself while the implementation is delegated to the user of the SDK to adjust it to the platform in use. The following sections list the needed functionality for the device SDK to run successfully on any given platform.
###Timer Functions
A timer implementation is necessary to handle request timeouts (sending MQTT connect, subscribe, etc. commands) as well as connection maintenance (MQTT keep-alive pings). Timers need millisecond resolution and are polled for expiration so these can be implemented using a "milliseconds since startup" free-running counter if desired. In the synchronous sample provided with this SDK only one command will be "in flight" at one point in time plus the client's ping timer.
Define the `Timer` Struct as in `timer_linux.h`
Define the `Timer` Struct as in `timer_platform.h`
`void InitTimer(Timer*);`
InitTimer - A timer structure is initialized to a clean state.
`void init_timer(Timer *);`
init_timer - A timer structure is initialized to a clean state.
`char expired(Timer*);`
expired - a poling function to determine if the timer has expired.
`bool has_timer_expired(Timer *);`
has_timer_expired - a polling function to determine if the timer has expired.
`void countdown_ms(Timer*, unsigned int);`
`void countdown_ms(Timer *, uint32_t);`
countdown_ms - set the timer to expire in x milliseconds and start the timer.
`void countdown(Timer*, unsigned int);`
countdown - set the timer to expire in x seconds and start the timer.
`void countdown_sec(Timer *, uint32_t);`
countdown_sec - set the timer to expire in x seconds and start the timer.
`int left_ms(Timer*);`
`uint32_t left_ms(Timer *);`
left_ms - query time in milliseconds left on the timer.
@@ -74,69 +73,78 @@ In order for the MQTT client stack to be able to communicate via the TCP/IP netw
For additional details about API parameters refer to the [API documentation](http://aws-iot-device-sdk-embedded-c-docs.s3-website-us-east-1.amazonaws.com/index.html).
Define the `TLSDataParams` Struct as in `network_platform.h`
This is used for data specific to the TLS library being used.
`int iot_tls_init(Network *pNetwork);`
`IoT_Error_t iot_tls_init(Network *pNetwork, char *pRootCALocation, char *pDeviceCertLocation,
char *pDevicePrivateKeyLocation, char *pDestinationURL,
uint16_t DestinationPort, uint32_t timeout_ms, bool ServerVerificationFlag);`
Initialize the network client / structure.
`int iot_tls_connect(Network *pNetwork, TLSConnectParams TLSParams);`
`IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *TLSParams);`
Create a TLS TCP socket to the configure address using the credentials provided via the NewNetwork API call. This will include setting up certificate locations / arrays.
`int iot_tls_read(Network*, unsigned char*, int, int);`
Read from the TLS network buffer.
`int iot_tls_write(Network*, unsigned char*, int, int);`
`IoT_Error_t iot_tls_write(Network*, unsigned char*, size_t, Timer *, size_t *);`
Write to the TLS network buffer.
`void iot_tls_disconnect(Network *pNetwork);`
`IoT_Error_t iot_tls_read(Network*, unsigned char*, size_t, Timer *, size_t *);`
Read from the TLS network buffer.
`IoT_Error_t iot_tls_disconnect(Network *pNetwork);`
Disconnect API
`int iot_tls_destroy(Network *pNetwork);`
`IoT_Error_t iot_tls_destroy(Network *pNetwork);`
Clean up the connection
`IoT_Error_t iot_tls_is_connected(Network *pNetwork);`
Check if the TLS layer is still connected
The TLS library generally provides the API for the underlying TCP socket.
###Threading Functions
The MQTT client uses a state machine to control operations in multi-threaded situations. However it requires a mutex implementation to guarantee thread safety. This is not required in situations where thread safety is not important and it is disabled by default. The _ENABLE_THREAD_SUPPORT_ macro needs to be defined in aws_iot_config.h to enable this layer. You will also need to add the -lpthread linker flag for the compiler if you are using the provided reference implementation.
For additional details about API parameters refer to the [API documentation](http://aws-iot-device-sdk-embedded-c-docs.s3-website-us-east-1.amazonaws.com/index.html).
Define the `IoT_Mutex_t` Struct as in `threads_platform.h`
This is used for data specific to the TLS library being used.
`IoT_Error_t aws_iot_thread_mutex_init(IoT_Mutex_t *);`
Initialize the mutex provided as argument.
`IoT_Error_t aws_iot_thread_mutex_lock(IoT_Mutex_t *);`
Lock the mutex provided as argument
`IoT_Error_t aws_iot_thread_mutex_unlock(IoT_Mutex_t *);`
Unlock the mutex provided as argument.
`IoT_Error_t aws_iot_thread_mutex_destroy(IoT_Mutex_t *);`
Destroy the mutex provided as argument.
The threading layer provides the implementation of mutexes used for thread-safe operations.
###Sample Porting:
Marvell has ported the SDK to its IoT Starter kit. [These](https://github.com/marvell-iot/aws_starter_sdk/tree/master/wmsdk/external/aws_iot/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_wmsdk) files are example implementations of the above mentioned functions.
Marvell has ported an older version of the SDK to its IoT Starter kit. [These](https://github.com/marvell-iot/aws_starter_sdk/tree/master/wmsdk/external/aws_iot/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_wmsdk) files are example implementations of the above mentioned functions.
This provides a port of the timer and network layer. The threading layer is not a part of this port.
##Time source for certificate validation
As part of the TLS handshake the device (client) needs to validate the server certificate which includes validation of the certificate lifetime requiring that the device is aware of the actual time. Devices should be equipped with a real time clock or should be able to obtain the current time via NTP. Bypassing validation of the lifetime of a certificate is not recommended as it exposes the device to a security vulnerability, as it will still accept server certificates even when they have already expired.
As part of the TLS handshake the device (client) needs to validate the server certificate which includes validation of the certificate lifetime requiring that the device is aware of the actual time. Devices should be equipped with a real time clock or should be able to obtain the current time via NTP. Bypassing validation of the lifetime of a certificate is not recommended as it exposes the device to a security vulnerability, as it will still accept server certificates even when they have already has_timer_expired.
##Integration into operating system
###Single-Threaded implementation
The single threaded implementation implies that the sample application code (SDK + MQTT client) is called periodically by the firmware application running on the main thread. This is done by calling the function `aws_iot_mqtt_yield` (in the simple pub-sub example) and by calling `aws_iot_shadow_yield()` (in the device shadow example). In both cases the keep-alive time is set to 10 seconds. This means that the yield functions need to be called at a minimum frequency of once every 10 seconds. Note however that the `iot_mqtt_yield()` function takes care of reading incoming MQTT messages from the IoT service as well and hence should be called more frequently depending on the timing requirements of an application. All incoming messages can only be processed at the frequency at which `yield` is called.
###Multi-Threaded implementation
In the simple multithreaded case the `yield` function can be moved to a background thread. Ensure this task runs at the frequency described above. In this case, depending on the OS mechanism, a message queue or mailbox could be used to proxy incoming MQTT messages from the callback to the worker task responsible for responding to or dispatching messages. A similar mechanism could be employed to queue publish messages from threads into a publish queue that are processed by a publishing task. Ensure a synchronization primitive like mutex is used, as the library is not thread safe.
In the simple multi-threaded case the `yield` function can be moved to a background thread. Ensure this task runs at the frequency described above. In this case, depending on the OS mechanism, a message queue or mailbox could be used to proxy incoming MQTT messages from the callback to the worker task responsible for responding to or dispatching messages. A similar mechanism could be employed to queue publish messages from threads into a publish queue that are processed by a publishing task. Ensure the threading layer is enabled as the library is not thread safe otherwise.
There is a validation test for the multi-threaded implementation that can be found with the integration tests. You can find further details in the Readme for the integration tests [here](https://github.com/aws/aws-iot-device-sdk-embedded-C/blob/master/tests/integration/README.md). We have run the validation test with 10 threads sending 500 messages each and verified to be working fine. It can be used as a reference testing application to validate whether your use case will work with multi-threading enabled.
##Sample applications
The sample apps in this SDK provide a working implementation for either openSSL or mbedTLS, meaning that the function calls explained above are already implemented for these TLS libraries for linux.
###Memory Requirements
These numbers do not include TLS and TCP/IP code. This is just the AWS IoT SDK.
####Marvell Example
The following sizes are of AWS IoT sample compiled for [Marvell AWS IoT](https://github.com/marvell-iot/aws_starter_sdk) platform.
#####Size of Certificates
- Private key - 1733 bytes
- Signed Certificate from AWS IoT - 1225 bytes
- Root CA - 1680 bytes
#####Size of SDK with MQTT subscribe publish sample
All sizes are in bytes
| Name | Text | RO Data | Data | BSS | Common | Total|
|---|---|---|---|---|---|---|
|MQTT Buffer: 512 bytes | 4436 | 304 | 1 | 1200 | 0 | 5941 |
|MQTT Buffer: 256 bytes | 4436 | 304 | 1 | 688 | 0 | 5429 |
#####Size of SDK with Shadow sample
All sizes are in bytes
| Name | Text | RO Data | Data | BSS | Common | Total|
|---|---|---|---|---|---|---|
|Shadow Sample with default `aws_iot_config.h` values | 9016 | 618 | 2 | 7792 | 0 | 17428 |
| Shadow Sample with reduced JSON keys and less number of message handling at any given time | 9020 | 618 | 2 | 5322 | 0 | 14962 |
The sample apps in this SDK provide a working implementation for mbedTLS. They use a reference implementation for linux provided with the SDK. Threading layer is enabled in the subscribe publish sample.

View File

@@ -1,8 +1,3 @@
##Note: Upgrade
Makefiles in the samples folder had the executable bit set and could potentially delete all files of the host machine if executed as a bash script.
More details could be found [here](https://github.com/aws/aws-iot-device-sdk-embedded-C/issues/14). Please upgrade to the latest version of the SDK.
##Overview
The AWS IoT device SDK for embedded C is a collection of C source files which can be used in embedded applications to securely connect to the [AWS IoT platform](http://docs.aws.amazon.com/iot/latest/developerguide/what-is-aws-iot.html). It includes transport clients **MQTT**, **TLS** implementations and examples for their use. It also supports AWS IoT specific features such as **Thing Shadow**. It is distributed in source form and intended to be built into customer firmware along with application code, other libraries and RTOS. For additional information about porting the Device SDK for embedded C onto additional platforms please refer to the [PortingGuide](https://github.com/aws/aws-iot-device-sdk-embedded-c/blob/master/PortingGuide.md/).
@@ -20,20 +15,19 @@ The Device SDK implements the specific protocol for Thing Shadows to retrieve, u
The embedded C SDK was specifically designed for resource constrained devices (running on micro-controllers and RTOS).
Primary aspects are:
* Flexibility in picking and choosing functionalities (reduce memory footprint)
* Flexibility in picking and choosing functionality (reduce memory footprint)
* Static memory only (no mallocs)
* Configurable resource usage(JSON tokens, MQTT subscription handlers, etc…)
* Portability across RTOS due to use of wrapper functionality
* Can be ported to a different RTOS, uses wrappers for OS specific functions
For more information on the Architecture of the SDK refer [here](http://aws-iot-device-sdk-embedded-c-docs.s3-website-us-east-1.amazonaws.com/index.html)
##How to get started ?
Ensure you understand the AWS IoT platform and create the necessary certificates and policies. For more information on the AWS IoT platform please visit the [AWS IoT developer guide](http://docs.aws.amazon.com/iot/latest/developerguide/iot-security-identity.html).
In order to quickly get started with the AWS IoT platform, we have ported the SDK for POSIX type Operating Systems like Ubuntu, OS X and RHEL. The porting of the SDK happens at the TLS layer, and for the MQTT protocol. The SDK is configured for two TLS libraries and can be built out of the box with *GCC* using *make utility*. The tarballs can be downloaded from the below links.
In order to quickly get started with the AWS IoT platform, we have ported the SDK for POSIX type Operating Systems like Ubuntu, OS X and RHEL. The SDK is configured for the mbedTLS library and can be built out of the box with *GCC* using *make utility*. The tarball can be downloaded from the below link:
* [OpenSSL](https://s3.amazonaws.com/aws-iot-device-sdk-embedded-c/linux_mqtt_openssl-1.1.2.tar)
* [mbedTLS from ARM](https://s3.amazonaws.com/aws-iot-device-sdk-embedded-c/linux_mqtt_mbedtls-1.1.2.tar)
* [mbedTLS from ARM](https://s3.amazonaws.com/aws-iot-device-sdk-embedded-c/linux_mqtt_mbedtls-2.0.0.tar)
##Installation
This section explains the individual steps to retrieve the necessary files and be able to build your first application using the AWS IoT device SDK for embedded C.
@@ -43,64 +37,74 @@ Steps:
* Create a directory to hold your application e.g. (/home/<user>/aws_iot/my_app)
* Change directory to this new directory
* Download the SDK to device and place in the newly created directory
* Expand the tarball (tar -xf <tarball.tar>). This will create 4 directories:
* `aws_iot_src` - the AWS IoT SDK source files
* `sample_apps` - the sample applications
* `aws_mqtt_embedded_client_lib` - the aws MQTT client derived from [Eclipse Paho](http://www.eclipse.org/paho/clients/c/embedded/) Embedded C client
* `certs` - TLS certificates directory
* Change directory to sample_apps. The following sample applications are included:
* `subscribe_publish_sample` - a simple pub/sub MQTT example
* `shadow_sample` - a simple device shadow example using a connected window example
* `shadow_sample_console_echo` - a sample to work with the AWS IoT Console interactive guide
* For each sample:
* Explore the example. It connects to AWS IoT platform using MQTT and demonstrates few actions that can be performed by the SDK
* Build the example using make. (''make'')
* Place device identity cert and private key in locations referenced in the example (certs/). Alternatively, you can run the sample application with the ''-c'' flag to point to a specific certificate directory.
* Download certificate authority CA file from [Symantec](https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem) and place in location referenced in the example (certs/). Ensure the names of the cert files are the same as in the `aws_iot_config.h` file
* Run sample application (./subscribe_publish_sample or ./shadow_sample). The sample will print status messages to stdout.
* More information on the examples could be found in the sample source file
* Expand the tarball (tar -xf <tarball.tar>). This will create the below directories:
* `certs` - TLS certificates directory
* `docs` - SDK API and file documentation
* `external_libs` - The mbedTLS and jsmn source files
* `include` - The AWS IoT SDK header files
* `platform` - Platform specific files for timer, TLS and threading layers
* `samples` - The sample applications
* `src` - The AWS IoT SDK source files
* `tests` - Contains tests for verifying that the SDK is functioning as expected. More information can be found [here](https://github.com/aws/aws-iot-device-sdk-embedded-c/blob/master/tests/README.md)
* View further information on how to use the SDK in the Readme file for samples that can be found [here](https://github.com/aws/aws-iot-device-sdk-embedded-c/blob/master/samples/README.md)
Also, for a guided example on getting started with the Thing Shadow, visit the AWS IoT Console's [Interactive Guide](https://console.aws.amazon.com/iot).
##Porting to different platforms
As Embedded devices run on different Real Time Operating Systems and TCP/IP stacks, it is one of the important design goals for the Device SDK to keep it portable. Please refer to the [porting guide](https://github.com/aws/aws-iot-device-sdk-embedded-C/blob/master/PortingGuide.md/) to get more information on how to make this SDK run on your devices (i.e. micro-controllers).
## Porting to different platforms
As Embedded devices run on different Real Time Operating Systems and TCP/IP stacks, it is one of the important design goals for the Device SDK to keep it portable. Please refer to the [porting guide](https://github.com/aws/aws-iot-device-sdk-embedded-C/blob/master/PortingGuide.md) to get more information on how to make this SDK run on your devices (i.e. micro-controllers).
##Resources
## Migrating from 1.x to 2.x
The 2.x branch makes several changes to the SDK. This section provides information on what changes will be required in the client application for migrating from v1.x to 2.x.
* The first change is in the folder structure. Client applications using the SDK now need to keep only the certs, external_libs, include, src and platform folder in their application. The folder descriptions can be found above
* All the SDK headers are in the `include` folder. These need to be added to the makefile as include directories
* The source files are in the `src` folder. These need to be added to the makefile as one of the source directories
* Similar to 1.x, the platform folder contains the platform specific headers and source files. These need to be added to the makefile as well
* The `platform/threading` folder only needs to be added if multi-threading is required, and the `_ENABLE_THREAD_SUPPORT_` macro is defined in config
* The list below provides a mapping for migrating from the major APIs used in 1.x to the new APIs:
| Description | 1.x | 2.x |
| :---------- | :-- | :-- |
| Initializing the client | ```void aws_iot_mqtt_init(MQTTClient_t *pClient);``` | ```IoT_Error_t aws_iot_mqtt_init(AWS_IoT_Client *pClient, IoT_Client_Init_Params *pInitParams);``` |
| Connect | ```IoT_Error_t aws_iot_mqtt_connect(MQTTConnectParams *pParams);``` | ```IoT_Error_t aws_iot_mqtt_connect(AWS_IoT_Client *pClient, IoT_Client_Connect_Params *pConnectParams);``` |
| Subscribe | ```IoT_Error_t aws_iot_mqtt_subscribe(MQTTSubscribeParams *pParams);``` | ```IoT_Error_t aws_iot_mqtt_subscribe(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen, QoS qos, pApplicationHandler_t pApplicationHandler, void *pApplicationHandlerData);``` |
| Unsubscribe | ```IoT_Error_t aws_iot_mqtt_unsubscribe(char *pTopic);``` | ```IoT_Error_t aws_iot_mqtt_unsubscribe(AWS_IoT_Client *pClient, const char *pTopicFilter, uint16_t topicFilterLen);``` |
| Yield | ```IoT_Error_t aws_iot_mqtt_yield(int timeout);``` | ```IoT_Error_t aws_iot_mqtt_yield(AWS_IoT_Client *pClient, uint32_t timeout_ms);``` |
| Publish | ```IoT_Error_t aws_iot_mqtt_publish(MQTTPublishParams *pParams);``` | ```IoT_Error_t aws_iot_mqtt_publish(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen, IoT_Publish_Message_Params *pParams);``` |
| Disconnect | ```IoT_Error_t aws_iot_mqtt_disconnect(void);``` | ```IoT_Error_t aws_iot_mqtt_disconnect(AWS_IoT_Client *pClient);``` |
You can find more information on how to use the new APIs in the Readme file for samples that can be found [here](https://github.com/aws/aws-iot-device-sdk-embedded-c/blob/master/samples/README.md)
## Resources
[API Documentation](http://aws-iot-device-sdk-embedded-c-docs.s3-website-us-east-1.amazonaws.com/index.html)
[MQTT 3.1.1 Spec](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/csprd02/mqtt-v3.1.1-csprd02.html)
##Support
## Support
If you have any technical questions about AWS IoT Device SDK, use the [AWS IoT forum](https://forums.aws.amazon.com/forum.jspa?forumID=210).
For any other questions on AWS IoT, contact [AWS Support](https://aws.amazon.com/contact-us/).
##Sample APIs
## Sample APIs
Connecting to the AWS IoT MQTT platform
```
rc = aws_iot_mqtt_connect( &connectParams ) ;
AWS_IoT_Client client;
rc = aws_iot_mqtt_init(&client, &iotInitParams);
rc = aws_iot_mqtt_connect(&client, &iotConnectParams);
```
Subscribe to a topic
```
MQTTSubscribeParams subParams = MQTTSubscribeParamsDefault;
subParams.mHandler = MQTTcallbackHandler;
subParams.qos = QOS_0;
subParams.pTopic = "sdkTest/sub";
rc = aws_iot_mqtt_subscribe( &subParams ) ;
AWS_IoT_Client client;
rc = aws_iot_mqtt_subscribe(&client, "sdkTest/sub", 11, QOS0, iot_subscribe_callback_handler, NULL);
```
Update Thing Shadow from a device
```
rc = aws_iot_shadow_update(&mqttClient,
AWS_IOT_MY_THING_NAME,
pJsonDocumentBuffer,
ShadowUpdateStatusCallback,
pCallbackContext,
TIMEOUT_4SEC,
persistenSubscription);
```
rc = aws_iot_shadow_update(&mqttClient, AWS_IOT_MY_THING_NAME, pJsonDocumentBuffer, ShadowUpdateStatusCallback,
pCallbackContext, TIMEOUT_4SEC, persistenSubscription);
```

View File

@@ -1,302 +0,0 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#include "timer_interface.h"
#include "aws_iot_mqtt_interface.h"
#include "MQTTClient.h"
#include "aws_iot_config.h"
static Client c;
static iot_disconnect_handler clientDisconnectHandler;
static unsigned char writebuf[AWS_IOT_MQTT_TX_BUF_LEN];
static unsigned char readbuf[AWS_IOT_MQTT_RX_BUF_LEN];
const MQTTConnectParams MQTTConnectParamsDefault = {
.enableAutoReconnect = 0,
.pHostURL = AWS_IOT_MQTT_HOST,
.port = AWS_IOT_MQTT_PORT,
.pRootCALocation = NULL,
.pDeviceCertLocation = NULL,
.pDevicePrivateKeyLocation = NULL,
.pClientID = NULL,
.pUserName = NULL,
.pPassword = NULL,
.MQTTVersion = MQTT_3_1_1,
.KeepAliveInterval_sec = 10,
.isCleansession = true,
.isWillMsgPresent = false,
.will={.pTopicName = NULL, .pMessage = NULL, .isRetained = false, .qos = QOS_0},
.mqttCommandTimeout_ms = 1000,
.tlsHandshakeTimeout_ms = 2000,
.isSSLHostnameVerify = true,
.disconnectHandler = NULL
};
const MQTTPublishParams MQTTPublishParamsDefault={
.pTopic = NULL,
.MessageParams = {.qos = QOS_0, .isRetained=false, .isDuplicate = false, .id = 0, .pPayload = NULL, .PayloadLen = 0}
};
const MQTTSubscribeParams MQTTSubscribeParamsDefault={
.pTopic = NULL,
.qos = QOS_0,
.mHandler = NULL
};
const MQTTCallbackParams MQTTCallbackParamsDefault={
.pTopicName = NULL,
.TopicNameLen = 0,
.MessageParams = {.qos = QOS_0, .isRetained=false, .isDuplicate = false, .id = 0, .pPayload = NULL, .PayloadLen = 0}
};
const MQTTMessageParams MQTTMessageParamsDefault={
.qos = QOS_0,
.isRetained=false,
.isDuplicate = false,
.id = 0,
.pPayload = NULL,
.PayloadLen = 0
};
const MQTTwillOptions MQTTwillOptionsDefault={
.pTopicName = NULL,
.pMessage = NULL,
.isRetained = false,
.qos = QOS_0
};
#define GETLOWER4BYTES 0x0FFFFFFFF
void pahoMessageCallback(MessageData* md) {
MQTTMessage* message = md->message;
MQTTCallbackParams params;
// early exit if we do not have a valid callback pointer
if (md->applicationHandler == NULL) {
return;
}
if (NULL != md->topicName->lenstring.data) {
params.pTopicName = md->topicName->lenstring.data;
params.TopicNameLen = (uint16_t)(md->topicName->lenstring.len);
}
if (NULL != message) {
params.MessageParams.PayloadLen = message->payloadlen & GETLOWER4BYTES;
params.MessageParams.pPayload = (char*) message->payload;
params.MessageParams.isDuplicate = message->dup;
params.MessageParams.qos = (QoSLevel)message->qos;
params.MessageParams.isRetained = message->retained;
params.MessageParams.id = message->id;
}
((iot_message_handler)(md->applicationHandler))(params);
}
void pahoDisconnectHandler(void) {
if(NULL != clientDisconnectHandler) {
clientDisconnectHandler();
}
}
static bool isPowerCycle = true;
IoT_Error_t aws_iot_mqtt_connect(MQTTConnectParams *pParams) {
IoT_Error_t rc = NONE_ERROR;
MQTTReturnCode pahoRc = SUCCESS;
if(NULL == pParams || NULL == pParams->pClientID || NULL == pParams->pHostURL) {
return NULL_VALUE_ERROR;
}
TLSConnectParams TLSParams;
TLSParams.DestinationPort = pParams->port;
TLSParams.pDestinationURL = pParams->pHostURL;
TLSParams.pDeviceCertLocation = pParams->pDeviceCertLocation;
TLSParams.pDevicePrivateKeyLocation = pParams->pDevicePrivateKeyLocation;
TLSParams.pRootCALocation = pParams->pRootCALocation;
TLSParams.timeout_ms = pParams->tlsHandshakeTimeout_ms;
TLSParams.ServerVerificationFlag = pParams->isSSLHostnameVerify;
// This implementation assumes you are not going to switch between cleansession 1 to 0
// As we don't have a default subscription handler support in the MQTT client every time a device power cycles it has to re-subscribe to let the MQTT client to pass the message up to the application callback.
// The default message handler will be implemented in the future revisions.
if(pParams->isCleansession || isPowerCycle){
pahoRc = MQTTClient(&c, (unsigned int)(pParams->mqttCommandTimeout_ms), writebuf,
AWS_IOT_MQTT_TX_BUF_LEN, readbuf, AWS_IOT_MQTT_RX_BUF_LEN,
pParams->enableAutoReconnect, iot_tls_init, &TLSParams);
if(SUCCESS != pahoRc) {
return CONNECTION_ERROR;
}
isPowerCycle = false;
}
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
data.willFlag = pParams->isWillMsgPresent;
// compatible type for MQTT_Ver_t
switch (pParams->MQTTVersion) {
case MQTT_3_1:
data.MQTTVersion = (unsigned char) (3);
break;
case MQTT_3_1_1:
data.MQTTVersion = (unsigned char) (4);
break;
default:
data.MQTTVersion = (unsigned char) (4); // default MQTT version = 3.1.1
}
// register our disconnect handler, save customer's handler
setDisconnectHandler(&c, pahoDisconnectHandler);
clientDisconnectHandler = pParams->disconnectHandler;
data.clientID.cstring = pParams->pClientID;
data.username.cstring = pParams->pUserName;
data.password.cstring = pParams->pPassword;
data.will.topicName.cstring = (char*)pParams->will.pTopicName;
data.will.message.cstring = (char*)pParams->will.pMessage;
data.will.qos = (enum QoS)pParams->will.qos;
data.will.retained = pParams->will.isRetained;
data.keepAliveInterval = pParams->KeepAliveInterval_sec;
data.cleansession = pParams->isCleansession;
pahoRc = MQTTConnect(&c, &data);
if(MQTT_NETWORK_ALREADY_CONNECTED_ERROR == pahoRc) {
rc = NETWORK_ALREADY_CONNECTED;
} else if(SUCCESS != pahoRc) {
rc = CONNECTION_ERROR;
}
return rc;
}
IoT_Error_t aws_iot_mqtt_subscribe(MQTTSubscribeParams *pParams) {
IoT_Error_t rc = NONE_ERROR;
if (0 != MQTTSubscribe(&c, pParams->pTopic, (enum QoS)pParams->qos, pahoMessageCallback, (void (*)(void))(pParams->mHandler))) {
rc = SUBSCRIBE_ERROR;
}
return rc;
}
IoT_Error_t aws_iot_mqtt_publish(MQTTPublishParams *pParams) {
IoT_Error_t rc = NONE_ERROR;
MQTTMessage Message;
Message.dup = pParams->MessageParams.isDuplicate;
Message.id = pParams->MessageParams.id;
Message.payload = pParams->MessageParams.pPayload;
Message.payloadlen = pParams->MessageParams.PayloadLen;
Message.qos = (enum QoS)pParams->MessageParams.qos;
Message.retained = pParams->MessageParams.isRetained;
if(0 != MQTTPublish(&c, pParams->pTopic, &Message)){
rc = PUBLISH_ERROR;
}
return rc;
}
IoT_Error_t aws_iot_mqtt_unsubscribe(char *pTopic) {
IoT_Error_t rc = NONE_ERROR;
if(0 != MQTTUnsubscribe(&c, pTopic)){
rc = UNSUBSCRIBE_ERROR;
}
return rc;
}
IoT_Error_t aws_iot_mqtt_disconnect() {
IoT_Error_t rc = NONE_ERROR;
if(0 != MQTTDisconnect(&c)){
rc = DISCONNECT_ERROR;
}
return rc;
}
IoT_Error_t aws_iot_mqtt_yield(int timeout) {
MQTTReturnCode pahoRc = MQTTYield(&c, timeout);
IoT_Error_t rc = NONE_ERROR;
if(MQTT_NETWORK_RECONNECTED == pahoRc){
rc = RECONNECT_SUCCESSFUL;
} else if(SUCCESS == pahoRc){
rc = NONE_ERROR;
} else if(MQTT_NULL_VALUE_ERROR == pahoRc) {
rc = NULL_VALUE_ERROR;
} else if(MQTT_NETWORK_DISCONNECTED_ERROR == pahoRc) {
rc = NETWORK_DISCONNECTED;
} else if(MQTT_RECONNECT_TIMED_OUT == pahoRc) {
rc = NETWORK_RECONNECT_TIMED_OUT;
} else if(MQTT_ATTEMPTING_RECONNECT == pahoRc) {
rc = NETWORK_ATTEMPTING_RECONNECT;
} else if(MQTT_BUFFER_RX_MESSAGE_INVALID == pahoRc){
rc = RX_MESSAGE_INVALID;
} else if(MQTTPACKET_BUFFER_TOO_SHORT == pahoRc){
rc = RX_MESSAGE_BIGGER_THAN_MQTT_RX_BUF;
} else {
rc = YIELD_ERROR;
}
return rc;
}
IoT_Error_t aws_iot_mqtt_attempt_reconnect() {
MQTTReturnCode pahoRc = MQTTAttemptReconnect(&c);
IoT_Error_t rc = RECONNECT_SUCCESSFUL;
if(MQTT_NETWORK_RECONNECTED == pahoRc){
rc = RECONNECT_SUCCESSFUL;
} else if(MQTT_NULL_VALUE_ERROR == pahoRc) {
rc = NULL_VALUE_ERROR;
} else if(MQTT_NETWORK_DISCONNECTED_ERROR == pahoRc) {
rc = NETWORK_DISCONNECTED;
} else if(MQTT_RECONNECT_TIMED_OUT == pahoRc) {
rc = NETWORK_RECONNECT_TIMED_OUT;
} else if(MQTT_NETWORK_ALREADY_CONNECTED_ERROR == pahoRc) {
rc = NETWORK_ALREADY_CONNECTED;
} else {
rc = GENERIC_ERROR;
}
return rc;
}
IoT_Error_t aws_iot_mqtt_autoreconnect_set_status(bool value) {
MQTTReturnCode rc = setAutoReconnectEnabled(&c, (uint8_t) value);
if(MQTT_NULL_VALUE_ERROR == rc) {
return NULL_VALUE_ERROR;
}
return NONE_ERROR;
}
bool aws_iot_is_mqtt_connected(void) {
return MQTTIsConnected(&c);
}
bool aws_iot_is_autoreconnect_enabled(void) {
return MQTTIsAutoReconnectEnabled(&c);
}
void aws_iot_mqtt_init(MQTTClient_t *pClient){
pClient->connect = aws_iot_mqtt_connect;
pClient->disconnect = aws_iot_mqtt_disconnect;
pClient->isConnected = aws_iot_is_mqtt_connected;
pClient->reconnect = aws_iot_mqtt_attempt_reconnect;
pClient->publish = aws_iot_mqtt_publish;
pClient->subscribe = aws_iot_mqtt_subscribe;
pClient->unsubscribe = aws_iot_mqtt_unsubscribe;
pClient->yield = aws_iot_mqtt_yield;
pClient->isAutoReconnectEnabled = aws_iot_is_autoreconnect_enabled;
pClient->setAutoReconnectStatus = aws_iot_mqtt_autoreconnect_set_status;
}

View File

@@ -1,137 +0,0 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/**
* @file network_interface.h
* @brief Network interface definition for MQTT client.
*
* Defines an interface to the TLS layer to be used by the MQTT client.
* Starting point for porting the SDK to the networking layer of a new platform.
*/
#ifndef __NETWORK_INTERFACE_H_
#define __NETWORK_INTERFACE_H_
/**
* @brief Network Type
*
* Defines a type for the network struct. See structure definition below.
*/
typedef struct Network Network;
/**
* @brief TLS Connection Parameters
*
* Defines a type containing TLS specific parameters to be passed down to the
* TLS networking layer to create a TLS secured socket.
*/
typedef struct{
char* pRootCALocation; ///< Pointer to string containing the filename (including path) of the root CA file.
char* pDeviceCertLocation; ///< Pointer to string containing the filename (including path) of the device certificate.
char* pDevicePrivateKeyLocation; ///< Pointer to string containing the filename (including path) of the device private key file.
char* pDestinationURL; ///< Pointer to string containing the endpoint of the MQTT service.
int DestinationPort; ///< Integer defining the connection port of the MQTT service.
unsigned int timeout_ms; ///< Unsigned integer defining the TLS handshake timeout value in milliseconds.
unsigned char ServerVerificationFlag; ///< Boolean. True = perform server certificate hostname validation. False = skip validation \b NOT recommended.
}TLSConnectParams;
/**
* @brief Network Structure
*
* Structure for defining a network connection.
*/
struct Network{
int my_socket; ///< Integer holding the socket file descriptor
int (*connect) (Network *, TLSConnectParams);
int (*mqttread) (Network*, unsigned char*, int, int); ///< Function pointer pointing to the network function to read from the network
int (*mqttwrite) (Network*, unsigned char*, int, int); ///< Function pointer pointing to the network function to write to the network
void (*disconnect) (Network*); ///< Function pointer pointing to the network function to disconnect from the network
int (*isConnected) (Network*); ///< Function pointer pointing to the network function to check if physical layer is connected
int (*destroy) (Network*); ///< Function pointer pointing to the network function to destroy the network object
};
/**
* @brief Initialize the TLS implementation
*
* Perform any initialization required by the TLS layer.
* Connects the interface to implementation by setting up
* the network layer function pointers to platform implementations.
*
* @param pNetwork - Pointer to a Network struct defining the network interface.
* @return integer defining successful initialization or TLS error
*/
int iot_tls_init(Network *pNetwork);
/**
* @brief Create a TLS socket and open the connection
*
* Creates an open socket connection including TLS handshake.
*
* @param pNetwork - Pointer to a Network struct defining the network interface.
* @param TLSParams - TLSConnectParams defines the properties of the TLS connection.
* @return integer - successful connection or TLS error
*/
int iot_tls_connect(Network *pNetwork, TLSConnectParams TLSParams);
/**
* @brief Write bytes to the network socket
*
* @param Network - Pointer to a Network struct defining the network interface.
* @param unsigned char pointer - buffer to write to socket
* @param integer - number of bytes to write
* @param integer - write timeout value in milliseconds
* @return integer - number of bytes written or TLS error
*/
int iot_tls_write(Network*, unsigned char*, int, int);
/**
* @brief Read bytes from the network socket
*
* @param Network - Pointer to a Network struct defining the network interface.
* @param unsigned char pointer - pointer to buffer where read bytes should be copied
* @param integer - number of bytes to read
* @param integer - read timeout value in milliseconds
* @return integer - number of bytes read or TLS error
*/
int iot_tls_read(Network*, unsigned char*, int, int);
/**
* @brief Disconnect from network socket
*
* @param Network - Pointer to a Network struct defining the network interface.
*/
void iot_tls_disconnect(Network *pNetwork);
/**
* @brief Perform any tear-down or cleanup of TLS layer
*
* Called to cleanup any resources required for the TLS layer.
*
* @param Network - Pointer to a Network struct defining the network interface.
* @return integer - successful cleanup or TLS error
*/
int iot_tls_destroy(Network *pNetwork);
/**
* @brief Check if TLS layer is still connected
*
* Called to check if the TLS layer is still connected or not.
*
* @param Network - Pointer to a Network struct defining the network interface.
* @return int - integer indicating status of network physical layer connection
*/
int iot_tls_is_connected(Network *pNetwork);
#endif //__NETWORK_INTERFACE_H_

View File

@@ -1,281 +0,0 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#include <stdbool.h>
#include <string.h>
#include "aws_iot_error.h"
#include "aws_iot_log.h"
#include "network_interface.h"
#include "mbedtls/config.h"
#include "mbedtls/net.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/certs.h"
#include "mbedtls/x509.h"
#include "mbedtls/error.h"
#include "mbedtls/debug.h"
#include "mbedtls/timing.h"
/*
* This is a function to do further verification if needed on the cert received
*/
static int myCertVerify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) {
char buf[1024];
((void) data);
DEBUG("\nVerify requested for (Depth %d):\n", depth);
mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt);
DEBUG("%s", buf);
if ((*flags) == 0) {
DEBUG(" This certificate has no flags\n");
} else {
DEBUG(buf, sizeof(buf), " ! ", *flags); DEBUG("%s\n", buf);
}
return (0);
}
static int ret = 0, i;
static mbedtls_entropy_context entropy;
static mbedtls_ctr_drbg_context ctr_drbg;
static mbedtls_ssl_context ssl;
static mbedtls_ssl_config conf;
static uint32_t flags;
static mbedtls_x509_crt cacert;
static mbedtls_x509_crt clicert;
static mbedtls_pk_context pkey;
static mbedtls_net_context server_fd;
int iot_tls_init(Network *pNetwork) {
IoT_Error_t ret_val = NONE_ERROR;
const char *pers = "aws_iot_tls_wrapper";
unsigned char buf[MBEDTLS_SSL_MAX_CONTENT_LEN + 1];
mbedtls_net_init(&server_fd);
mbedtls_ssl_init(&ssl);
mbedtls_ssl_config_init(&conf);
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_x509_crt_init(&cacert);
mbedtls_x509_crt_init(&clicert);
mbedtls_pk_init(&pkey);
DEBUG("\n . Seeding the random number generator...");
mbedtls_entropy_init(&entropy);
if ((ret_val = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) pers,
strlen(pers))) != 0) {
ERROR(" failed\n ! mbedtls_ctr_drbg_seed returned -0x%x\n", -ret);
return ret_val;
} DEBUG("ok\n");
pNetwork->my_socket = 0;
pNetwork->connect = iot_tls_connect;
pNetwork->mqttread = iot_tls_read;
pNetwork->mqttwrite = iot_tls_write;
pNetwork->disconnect = iot_tls_disconnect;
pNetwork->isConnected = iot_tls_is_connected;
pNetwork->destroy = iot_tls_destroy;
return ret_val;
}
int iot_tls_is_connected(Network *pNetwork) {
/* Use this to add implementation which can check for physical layer disconnect */
return 1;
}
int iot_tls_connect(Network *pNetwork, TLSConnectParams params) {
const char *pers = "aws_iot_tls_wrapper";
unsigned char buf[MBEDTLS_SSL_MAX_CONTENT_LEN + 1];
DEBUG(" . Loading the CA root certificate ...");
ret = mbedtls_x509_crt_parse_file(&cacert, params.pRootCALocation);
if (ret < 0) {
ERROR(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
return ret;
} DEBUG(" ok (%d skipped)\n", ret);
DEBUG(" . Loading the client cert. and key...");
ret = mbedtls_x509_crt_parse_file(&clicert, params.pDeviceCertLocation);
if (ret != 0) {
ERROR(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
return ret;
}
ret = mbedtls_pk_parse_keyfile(&pkey, params.pDevicePrivateKeyLocation, "");
if (ret != 0) {
ERROR(" failed\n ! mbedtls_pk_parse_key returned -0x%x\n\n", -ret);
return ret;
} DEBUG(" ok\n");
char portBuffer[6];
sprintf(portBuffer, "%d", params.DestinationPort); DEBUG(" . Connecting to %s/%s...", params.pDestinationURL, portBuffer);
if ((ret = mbedtls_net_connect(&server_fd, params.pDestinationURL, portBuffer, MBEDTLS_NET_PROTO_TCP)) != 0) {
ERROR(" failed\n ! mbedtls_net_connect returned -0x%x\n\n", -ret);
return ret;
}
ret = mbedtls_net_set_block(&server_fd);
if (ret != 0) {
ERROR(" failed\n ! net_set_(non)block() returned -0x%x\n\n", -ret);
return ret;
} DEBUG(" ok\n");
DEBUG(" . Setting up the SSL/TLS structure...");
if ((ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
ERROR(" failed\n ! mbedtls_ssl_config_defaults returned -0x%x\n\n", -ret);
return ret;
}
mbedtls_ssl_conf_verify(&conf, myCertVerify, NULL);
if (params.ServerVerificationFlag == true) {
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
} else {
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
}
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
if ((ret = mbedtls_ssl_conf_own_cert(&conf, &clicert, &pkey)) != 0) {
ERROR(" failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret);
return ret;
}
mbedtls_ssl_conf_read_timeout(&conf, params.timeout_ms);
if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
ERROR(" failed\n ! mbedtls_ssl_setup returned -0x%x\n\n", -ret);
return ret;
}
if ((ret = mbedtls_ssl_set_hostname(&ssl, params.pDestinationURL)) != 0) {
ERROR(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
return ret;
}
mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, NULL, mbedtls_net_recv_timeout);
DEBUG(" ok\n");
DEBUG(" . Performing the SSL/TLS handshake...");
while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
ERROR(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n", -ret);
if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
ERROR(" Unable to verify the server's certificate. "
"Either it is invalid,\n"
" or you didn't set ca_file or ca_path "
"to an appropriate value.\n"
" Alternatively, you may want to use "
"auth_mode=optional for testing purposes.\n");
}
return ret;
}
}
DEBUG(" ok\n [ Protocol is %s ]\n [ Ciphersuite is %s ]\n", mbedtls_ssl_get_version(&ssl), mbedtls_ssl_get_ciphersuite(&ssl));
if ((ret = mbedtls_ssl_get_record_expansion(&ssl)) >= 0) {
DEBUG(" [ Record expansion is %d ]\n", ret);
} else {
DEBUG(" [ Record expansion is unknown (compression) ]\n");
}
DEBUG(" . Verifying peer X.509 certificate...");
if (params.ServerVerificationFlag == true) {
if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) {
char vrfy_buf[512];
ERROR(" failed\n");
mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags);
ERROR("%s\n", vrfy_buf);
} else {
DEBUG(" ok\n");
ret = NONE_ERROR;
}
} else {
DEBUG(" Server Verification skipped\n");
ret = NONE_ERROR;
}
if (mbedtls_ssl_get_peer_cert(&ssl) != NULL) {
DEBUG(" . Peer certificate information ...\n");
mbedtls_x509_crt_info((char *) buf, sizeof(buf) - 1, " ", mbedtls_ssl_get_peer_cert(&ssl));
DEBUG("%s\n", buf);
}
mbedtls_ssl_conf_read_timeout(&conf, 10);
return ret;
}
int iot_tls_write(Network *pNetwork, unsigned char *pMsg, int len, int timeout_ms) {
int written;
int frags;
for (written = 0, frags = 0; written < len; written += ret, frags++) {
while ((ret = mbedtls_ssl_write(&ssl, pMsg + written, len - written)) <= 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
ERROR(" failed\n ! mbedtls_ssl_write returned -0x%x\n\n", -ret);
return ret;
}
}
}
return written;
}
int iot_tls_read(Network *pNetwork, unsigned char *pMsg, int len, int timeout_ms) {
int rxLen = 0;
bool isErrorFlag = false;
bool isCompleteFlag = false;
// mbedtls_ssl_conf_read_timeout(&conf, timeout_ms);
do {
ret = mbedtls_ssl_read(&ssl, pMsg, len);
if (ret > 0) {
rxLen += ret;
} else if (ret != MBEDTLS_ERR_SSL_WANT_READ) {
isErrorFlag = true;
}
if (rxLen >= len) {
isCompleteFlag = true;
}
} while (!isErrorFlag && !isCompleteFlag);
return ret;
}
void iot_tls_disconnect(Network *pNetwork) {
do {
ret = mbedtls_ssl_close_notify(&ssl);
} while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
}
int iot_tls_destroy(Network *pNetwork) {
mbedtls_net_free(&server_fd);
mbedtls_x509_crt_free(&clicert);
mbedtls_x509_crt_free(&cacert);
mbedtls_pk_free(&pkey);
mbedtls_ssl_free(&ssl);
mbedtls_ssl_config_free(&conf);
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
return 0;
}

View File

@@ -1,73 +0,0 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#include "hostname_compare.h"
#include <string.h>
#include "rawstr.h"
// https://github.com/bagder/curl/blob/master/lib/hostcheck.c
int hostmatch(const char *hostname, const char *pattern) {
const char *pattern_label_end, *pattern_wildcard, *hostname_label_end;
int wildcard_enabled;
size_t prefixlen, suffixlen;
/* normalize pattern and hostname by stripping off trailing dots */
// size_t len = strlen(hostname);
// if (hostname[len - 1] == '.')
// hostname[len - 1] = 0;
// len = strlen(pattern);
// if (pattern[len - 1] == '.')
// pattern[len - 1] = 0;
pattern_wildcard = strchr(pattern, '*');
if (pattern_wildcard == NULL)
return Curl_raw_equal(pattern, hostname) ?
CURL_HOST_MATCH : CURL_HOST_NOMATCH;
/* We require at least 2 dots in pattern to avoid too wide wildcard
match. */
wildcard_enabled = 1;
pattern_label_end = strchr(pattern, '.');
if (pattern_label_end == NULL || strchr(pattern_label_end + 1, '.') == NULL
|| pattern_wildcard > pattern_label_end
|| Curl_raw_nequal(pattern, "xn--", 4)) {
wildcard_enabled = 0;
}
if (!wildcard_enabled)
return Curl_raw_equal(pattern, hostname) ?
CURL_HOST_MATCH :
CURL_HOST_NOMATCH;
hostname_label_end = strchr(hostname, '.');
if (hostname_label_end == NULL
|| !Curl_raw_equal(pattern_label_end, hostname_label_end))
return CURL_HOST_NOMATCH;
/* The wildcard must match at least one character, so the left-most
label of the hostname is at least as large as the left-most label
of the pattern. */
if (hostname_label_end - hostname < pattern_label_end - pattern)
return CURL_HOST_NOMATCH;
prefixlen = pattern_wildcard - pattern;
suffixlen = pattern_label_end - (pattern_wildcard + 1);
return Curl_raw_nequal(pattern, hostname, prefixlen)
&& Curl_raw_nequal(pattern_wildcard + 1,
hostname_label_end - suffixlen, suffixlen) ?
CURL_HOST_MATCH : CURL_HOST_NOMATCH;
}

View File

@@ -1,406 +0,0 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include "aws_iot_error.h"
#include "aws_iot_log.h"
#include "network_interface.h"
#include "openssl_hostname_validation.h"
static SSL_CTX *pSSLContext;
static SSL *pSSLHandle;
static int server_TCPSocket;
static char* pDestinationURL;
static int Create_TCPSocket(void);
static IoT_Error_t Connect_TCPSocket(int socket_fd, char *pURLString, int port);
static IoT_Error_t setSocketToNonBlocking(int server_fd);
static IoT_Error_t ConnectOrTimeoutOrExitOnError(SSL *pSSL, int timeout_ms);
static IoT_Error_t ReadOrTimeoutOrExitOnError(SSL *pSSL, unsigned char *msg, int totalLen, int timeout_ms);
int iot_tls_init(Network *pNetwork) {
IoT_Error_t ret_val = NONE_ERROR;
const SSL_METHOD *method;
OpenSSL_add_all_algorithms();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
SSL_load_error_strings();
if (SSL_library_init() < 0) {
ret_val = SSL_INIT_ERROR;
}
method = TLSv1_2_method();
if ((pSSLContext = SSL_CTX_new(method)) == NULL) {
ERROR(" SSL INIT Failed - Unable to create SSL Context");
ret_val = SSL_INIT_ERROR;
}
pNetwork->my_socket = 0;
pNetwork->connect = iot_tls_connect;
pNetwork->mqttread = iot_tls_read;
pNetwork->mqttwrite = iot_tls_write;
pNetwork->disconnect = iot_tls_disconnect;
pNetwork->isConnected = iot_tls_is_connected;
pNetwork->destroy = iot_tls_destroy;
return ret_val;
}
int iot_tls_is_connected(Network *pNetwork) {
/* Use this to add implementation which can check for physical layer disconnect */
return 1;
}
int tls_server_certificate_verify(int preverify_ok, X509_STORE_CTX *pX509CTX){
// preverify_ok
// 0 ==> Fail
// 1 ==> Pass
int verification_return = 0;
//last certificate(depth = 0) is the one provided by the Server
if((X509_STORE_CTX_get_error_depth(pX509CTX) == 0) && (preverify_ok == 1)){
X509 *pX509Cert;
HostnameValidationResult result;
pX509Cert = X509_STORE_CTX_get_current_cert(pX509CTX);
result = validate_hostname(pDestinationURL, pX509Cert);
if(MatchFound == result){
verification_return = 1;
}
}
else{
verification_return = preverify_ok;
}
return verification_return;
}
int iot_tls_connect(Network *pNetwork, TLSConnectParams params) {
IoT_Error_t ret_val = NONE_ERROR;
int connect_status = 0;
server_TCPSocket = Create_TCPSocket();
if(-1 == server_TCPSocket){
ret_val = TCP_SETUP_ERROR;
return ret_val;
}
if (!SSL_CTX_load_verify_locations(pSSLContext, params.pRootCALocation, NULL)) {
ERROR(" Root CA Loading error");
ret_val = SSL_CERT_ERROR;
}
if (!SSL_CTX_use_certificate_file(pSSLContext, params.pDeviceCertLocation, SSL_FILETYPE_PEM)) {
ERROR(" Device Certificate Loading error");
ret_val = SSL_CERT_ERROR;
}
if(1 != SSL_CTX_use_PrivateKey_file(pSSLContext, params.pDevicePrivateKeyLocation, SSL_FILETYPE_PEM)){
ERROR(" Device Private Key Loading error");
ret_val = SSL_CERT_ERROR;
}
if(params.ServerVerificationFlag){
SSL_CTX_set_verify(pSSLContext, SSL_VERIFY_PEER, tls_server_certificate_verify);
}
else{
SSL_CTX_set_verify(pSSLContext, SSL_VERIFY_PEER, NULL);
}
pSSLHandle = SSL_new(pSSLContext);
pDestinationURL = params.pDestinationURL;
ret_val = Connect_TCPSocket(server_TCPSocket, params.pDestinationURL, params.DestinationPort);
if(NONE_ERROR != ret_val){
ERROR(" TCP Connection error");
return ret_val;
}
SSL_set_fd(pSSLHandle, server_TCPSocket);
if(ret_val == NONE_ERROR){
ret_val = setSocketToNonBlocking(server_TCPSocket);
if(ret_val != NONE_ERROR){
ERROR(" Unable to set the socket to Non-Blocking");
}
}
if(NONE_ERROR == ret_val){
ret_val = ConnectOrTimeoutOrExitOnError(pSSLHandle, params.timeout_ms);
if(X509_V_OK != SSL_get_verify_result(pSSLHandle)){
ERROR(" Server Certificate Verification failed");
ret_val = SSL_CONNECT_ERROR;
}
else{
// ensure you have a valid certificate returned, otherwise no certificate exchange happened
if(NULL == SSL_get_peer_certificate(pSSLHandle)){
ERROR(" No certificate exchange happened");
ret_val = SSL_CONNECT_ERROR;
}
}
}
return ret_val;
}
int iot_tls_write(Network *pNetwork, unsigned char *pMsg, int len, int timeout_ms){
return WriteOrTimeoutOrExitOnError(pSSLHandle, pMsg, len, timeout_ms);
}
int iot_tls_read(Network *pNetwork, unsigned char *pMsg, int len, int timeout_ms) {
return ReadOrTimeoutOrExitOnError(pSSLHandle, pMsg, len, timeout_ms);
}
void iot_tls_disconnect(Network *pNetwork){
SSL_shutdown(pSSLHandle);
close(server_TCPSocket);
}
int iot_tls_destroy(Network *pNetwork) {
SSL_free(pSSLHandle);
SSL_CTX_free(pSSLContext);
return 0;
}
int Create_TCPSocket(void) {
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
return sockfd;
}
IoT_Error_t Connect_TCPSocket(int socket_fd, char *pURLString, int port) {
IoT_Error_t ret_val = TCP_CONNECT_ERROR;
int connect_status = -1;
struct hostent *host;
struct sockaddr_in dest_addr;
host = gethostbyname(pURLString);
if (NULL != host) {
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port);
dest_addr.sin_addr.s_addr = *(long*) (host->h_addr);
memset(&(dest_addr.sin_zero), '\0', 8);
connect_status = connect(socket_fd, (struct sockaddr *) &dest_addr,
sizeof(struct sockaddr));
if (-1 != connect_status) {
ret_val = NONE_ERROR;
}
}
return ret_val;
}
IoT_Error_t setSocketToNonBlocking( server_fd) {
int flags, status;
IoT_Error_t ret_val = NONE_ERROR;
flags = fcntl(server_TCPSocket, F_GETFL, 0);
// set underlying socket to non blocking
if (flags < 0) {
ret_val = TCP_CONNECT_ERROR;
}
status = fcntl(server_TCPSocket, F_SETFL, flags | O_NONBLOCK);
if (status < 0) {
ERROR("fcntl - %s", strerror(errno));
ret_val = TCP_CONNECT_ERROR;
}
return ret_val;
}
IoT_Error_t ConnectOrTimeoutOrExitOnError(SSL *pSSL, int timeout_ms){
enum{
SSL_CONNECTED = 1,
SELECT_TIMEOUT = 0,
SELECT_ERROR = -1
};
IoT_Error_t ret_val = NONE_ERROR;
int rc = 0;
fd_set readFds;
fd_set writeFds;
struct timeval timeout = { timeout_ms / 1000, (timeout_ms % 1000) * 1000 };
int errorCode = 0;
int select_retCode = SELECT_TIMEOUT;
do{
rc = SSL_connect(pSSL);
if(SSL_CONNECTED == rc){
ret_val = NONE_ERROR;
break;
}
errorCode = SSL_get_error(pSSL, rc);
if(errorCode == SSL_ERROR_WANT_READ){
FD_ZERO(&readFds);
FD_SET(server_TCPSocket, &readFds);
select_retCode = select(server_TCPSocket + 1, (void *) &readFds, NULL, NULL, &timeout);
if (SELECT_TIMEOUT == select_retCode) {
ERROR(" SSL Connect time out while waiting for read");
ret_val = SSL_CONNECT_TIMEOUT_ERROR;
} else if (SELECT_ERROR == select_retCode) {
ERROR(" SSL Connect Select error for read %d", select_retCode);
ret_val = SSL_CONNECT_ERROR;
}
}
else if(errorCode == SSL_ERROR_WANT_WRITE){
FD_ZERO(&writeFds);
FD_SET(server_TCPSocket, &writeFds);
select_retCode = select(server_TCPSocket + 1, NULL, (void *) &writeFds, NULL, &timeout);
if (SELECT_TIMEOUT == select_retCode) {
ERROR(" SSL Connect time out while waiting for write");
ret_val = SSL_CONNECT_TIMEOUT_ERROR;
} else if (SELECT_ERROR == select_retCode) {
ERROR(" SSL Connect Select error for write %d", select_retCode);
ret_val = SSL_CONNECT_ERROR;
}
}
else{
ret_val = SSL_CONNECT_ERROR;
}
}while(SSL_CONNECT_ERROR != ret_val && SSL_CONNECT_TIMEOUT_ERROR != ret_val);
return ret_val;
}
IoT_Error_t WriteOrTimeoutOrExitOnError(SSL *pSSL, unsigned char *msg, int totalLen, int timeout_ms){
IoT_Error_t errorStatus = NONE_ERROR;
fd_set writeFds;
enum{
SELECT_TIMEOUT = 0,
SELECT_ERROR = -1
};
int errorCode = 0;
int select_retCode;
int writtenLength = 0;
int rc = 0;
int returnCode = 0;
struct timeval timeout = { timeout_ms / 1000, (timeout_ms % 1000) * 1000 };
do{
rc = SSL_write(pSSL, msg, totalLen);
errorCode = SSL_get_error(pSSL, rc);
if(0 < rc){
writtenLength += rc;
}
else if (errorCode == SSL_ERROR_WANT_WRITE) {
FD_ZERO(&writeFds);
FD_SET(server_TCPSocket, &writeFds);
select_retCode = select(server_TCPSocket + 1, NULL, (void *) &writeFds, NULL, &timeout);
if (SELECT_TIMEOUT == select_retCode) {
errorStatus = SSL_WRITE_TIMEOUT_ERROR;
} else if (SELECT_ERROR == select_retCode) {
errorStatus = SSL_WRITE_ERROR;
}
}
else{
errorStatus = SSL_WRITE_ERROR;
}
}while(SSL_WRITE_ERROR != errorStatus && SSL_WRITE_TIMEOUT_ERROR != errorStatus && writtenLength < totalLen);
if(NONE_ERROR == errorStatus){
returnCode = writtenLength;
}
else{
returnCode = errorStatus;
}
return returnCode;
}
IoT_Error_t ReadOrTimeoutOrExitOnError(SSL *pSSL, unsigned char *msg, int totalLen, int timeout_ms){
IoT_Error_t errorStatus = NONE_ERROR;
fd_set readFds;
enum{
SELECT_TIMEOUT = 0,
SELECT_ERROR = -1
};
int errorCode = 0;
int select_retCode;
int readLength = 0;
int rc = 0;
int returnCode = 0;
struct timeval timeout = { timeout_ms / 1000, (timeout_ms % 1000) * 1000 };
do{
rc = SSL_read(pSSL, msg, totalLen);
errorCode = SSL_get_error(pSSL, rc);
if(0 < rc){
readLength += rc;
}
else if (errorCode == SSL_ERROR_WANT_READ) {
FD_ZERO(&readFds);
FD_SET(server_TCPSocket, &readFds);
select_retCode = select(server_TCPSocket + 1, (void *) &readFds, NULL, NULL, &timeout);
if (SELECT_TIMEOUT == select_retCode) {
errorStatus = SSL_READ_TIMEOUT_ERROR;
} else if (SELECT_ERROR == select_retCode) {
errorStatus = SSL_READ_ERROR;
}
}
else{
errorStatus = SSL_READ_ERROR;
}
}while(SSL_READ_ERROR != errorStatus && SSL_READ_TIMEOUT_ERROR != errorStatus && readLength < totalLen);
if(NONE_ERROR == errorStatus){
returnCode = readLength;
}
else{
returnCode = errorStatus;
}
return returnCode;
}

View File

@@ -1,154 +0,0 @@
/*Copyright (C) 2012, iSEC Partners.
*
*Permission is hereby granted, free of charge, to any person obtaining a copy of
*this software and associated documentation files (the "Software"), to deal in
*the Software without restriction, including without limitation the rights to
*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
*of the Software, and to permit persons to whom the Software is furnished to do
*so, subject to the following conditions:
*
*The above copyright notice and this permission notice shall be included in all
*copies or substantial portions of the Software.
*
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*SOFTWARE.
*
*/
#include "openssl_hostname_validation.h"
#include <strings.h>
#include "hostname_compare.h"
#define HOSTNAME_MAX_SIZE 255
/**
* Tries to find a match for hostname in the certificate's Common Name field.
*
* Returns MatchFound if a match was found.
* Returns MatchNotFound if no matches were found.
* Returns MalformedCertificate if the Common Name had a NUL character embedded in it.
* Returns Error if the Common Name could not be extracted.
*/
static HostnameValidationResult matches_common_name(const char *hostname,
const X509 *server_cert) {
int common_name_loc = -1;
X509_NAME_ENTRY *common_name_entry = NULL;
ASN1_STRING *common_name_asn1 = NULL;
char *common_name_str = NULL;
// Find the position of the CN field in the Subject field of the certificate
common_name_loc = X509_NAME_get_index_by_NID(
X509_get_subject_name((X509 *) server_cert), NID_commonName, -1);
if (common_name_loc < 0) {
return Error;
}
// Extract the CN field
common_name_entry = X509_NAME_get_entry(
X509_get_subject_name((X509 *) server_cert), common_name_loc);
if (common_name_entry == NULL) {
return Error;
}
// Convert the CN field to a C string
common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
if (common_name_asn1 == NULL) {
return Error;
}
common_name_str = (char *) ASN1_STRING_data(common_name_asn1);
// Make sure there isn't an embedded NUL character in the CN
if (ASN1_STRING_length(common_name_asn1) != strlen(common_name_str)) {
return MalformedCertificate;
}
// Compare expected hostname with the CN
if (hostmatch(hostname, common_name_str) == CURL_HOST_MATCH) {
return MatchFound;
} else {
return MatchNotFound;
}
}
/**
* Tries to find a match for hostname in the certificate's Subject Alternative Name extension.
*
* Returns MatchFound if a match was found.
* Returns MatchNotFound if no matches were found.
* Returns MalformedCertificate if any of the hostnames had a NUL character embedded in it.
* Returns NoSANPresent if the SAN extension was not present in the certificate.
*/
static HostnameValidationResult matches_subject_alternative_name(
const char *hostname, const X509 *server_cert) {
HostnameValidationResult result = MatchNotFound;
int i;
int san_names_nb = -1;
STACK_OF(GENERAL_NAME) *san_names = NULL;
// Try to extract the names within the SAN extension from the certificate
san_names = X509_get_ext_d2i((X509 *) server_cert, NID_subject_alt_name,
NULL, NULL);
if (san_names == NULL) {
return NoSANPresent;
}
san_names_nb = sk_GENERAL_NAME_num(san_names);
// Check each name within the extension
for (i = 0; i < san_names_nb; i++) {
const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(san_names, i);
if (current_name->type == GEN_DNS) {
// Current name is a DNS name, let's check it
char *dns_name = (char *) ASN1_STRING_data(current_name->d.dNSName);
// Make sure there isn't an embedded NUL character in the DNS name
if (ASN1_STRING_length(current_name->d.dNSName)
!= strlen(dns_name)) {
result = MalformedCertificate;
break;
} else { // Compare expected hostname with the DNS name
if (hostmatch(hostname, dns_name) == CURL_HOST_MATCH) {
result = MatchFound;
break;
}
}
}
}
sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
return result;
}
/**
* Validates the server's identity by looking for the expected hostname in the
* server's certificate. As described in RFC 6125, it first tries to find a match
* in the Subject Alternative Name extension. If the extension is not present in
* the certificate, it checks the Common Name instead.
*
* Returns MatchFound if a match was found.
* Returns MatchNotFound if no matches were found.
* Returns MalformedCertificate if any of the hostnames had a NUL character embedded in it.
* Returns Error if there was an error.
*/
HostnameValidationResult validate_hostname(const char *hostname, const X509 *server_cert) {
HostnameValidationResult result;
if ((hostname == NULL) || (server_cert == NULL))
return Error;
// First try the Subject Alternative Names extension
result = matches_subject_alternative_name(hostname, server_cert);
if (result == NoSANPresent) {
// Extension was not found: try the Common Name
result = matches_common_name(hostname, server_cert);
}
return result;
}

View File

@@ -1,45 +0,0 @@
/*Copyright (C) 2012, iSEC Partners.
*
*Permission is hereby granted, free of charge, to any person obtaining a copy of
*this software and associated documentation files (the "Software"), to deal in
*the Software without restriction, including without limitation the rights to
*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
*of the Software, and to permit persons to whom the Software is furnished to do
*so, subject to the following conditions:
*
*The above copyright notice and this permission notice shall be included in all
*copies or substantial portions of the Software.
*
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*SOFTWARE.
*
*/
#include <openssl/x509v3.h>
#include <openssl/ssl.h>
typedef enum {
MatchFound,
MatchNotFound,
NoSANPresent,
MalformedCertificate,
Error
} HostnameValidationResult;
/**
* Validates the server's identity by looking for the expected hostname in the
* server's certificate. As described in RFC 6125, it first tries to find a match
* in the Subject Alternative Name extension. If the extension is not present in
* the certificate, it checks the Common Name instead.
*
* Returns MatchFound if a match was found.
* Returns MatchNotFound if no matches were found.
* Returns MalformedCertificate if any of the hostnames had a NUL character embedded in it.
* Returns Error if there was an error.
*/
HostnameValidationResult validate_hostname(const char *hostname, const X509 *server_cert);

View File

@@ -1,139 +0,0 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
***************************************************************************/
#include "rawstr.h"
/* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because
its behavior is altered by the current locale. */
char Curl_raw_toupper(char in)
{
switch (in) {
case 'a':
return 'A';
case 'b':
return 'B';
case 'c':
return 'C';
case 'd':
return 'D';
case 'e':
return 'E';
case 'f':
return 'F';
case 'g':
return 'G';
case 'h':
return 'H';
case 'i':
return 'I';
case 'j':
return 'J';
case 'k':
return 'K';
case 'l':
return 'L';
case 'm':
return 'M';
case 'n':
return 'N';
case 'o':
return 'O';
case 'p':
return 'P';
case 'q':
return 'Q';
case 'r':
return 'R';
case 's':
return 'S';
case 't':
return 'T';
case 'u':
return 'U';
case 'v':
return 'V';
case 'w':
return 'W';
case 'x':
return 'X';
case 'y':
return 'Y';
case 'z':
return 'Z';
}
return in;
}
/*
* Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant
* to be locale independent and only compare strings we know are safe for
* this. See http://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
* some further explanation to why this function is necessary.
*
* The function is capable of comparing a-z case insensitively even for
* non-ascii.
*/
int Curl_raw_equal(const char *first, const char *second)
{
while(*first && *second) {
if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
/* get out of the loop as soon as they don't match */
break;
first++;
second++;
}
/* we do the comparison here (possibly again), just to make sure that if the
loop above is skipped because one of the strings reached zero, we must not
return this as a successful match */
return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second));
}
int Curl_raw_nequal(const char *first, const char *second, size_t max)
{
while(*first && *second && max) {
if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) {
break;
}
max--;
first++;
second++;
}
if(0 == max)
return 1; /* they are equal this far */
return Curl_raw_toupper(*first) == Curl_raw_toupper(*second);
}
/* Copy an upper case version of the string from src to dest. The
* strings may overlap. No more than n characters of the string are copied
* (including any NUL) and the destination string will NOT be
* NUL-terminated if that limit is reached.
*/
void Curl_strntoupper(char *dest, const char *src, size_t n)
{
if(n < 1)
return;
do {
*dest++ = Curl_raw_toupper(*src);
} while(*src++ && --n);
}

View File

@@ -1,46 +0,0 @@
#ifndef HEADER_CURL_RAWSTR_H
#define HEADER_CURL_RAWSTR_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
***************************************************************************/
#include "stddef.h"
/*
* Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant
* to be locale independent and only compare strings we know are safe for
* this.
*
* The function is capable of comparing a-z case insensitively even for
* non-ascii.
*/
int Curl_raw_equal(const char *first, const char *second);
int Curl_raw_nequal(const char *first, const char *second, size_t max);
char Curl_raw_toupper(char in);
/* checkprefix() is a shorter version of the above, used when the first
argument is zero-byte terminated */
#define checkprefix(a,b) Curl_raw_nequal(a,b,strlen(a))
void Curl_strntoupper(char *dest, const char *src, size_t n);
#endif /* HEADER_CURL_RAWSTR_H */

View File

@@ -1,326 +0,0 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/**
* @file aws_iot_mqtt_interface.h
* @brief Interface definition for MQTT client.
*/
#ifndef AWS_IOT_SDK_SRC_IOT_MQTT_INTERFACE_H_
#define AWS_IOT_SDK_SRC_IOT_MQTT_INTERFACE_H_
#include "stddef.h"
#include "stdbool.h"
#include "stdint.h"
#include "aws_iot_error.h"
/**
* @brief MQTT Version Type
*
* Defining an MQTT version type.
*
*/
typedef enum {
MQTT_3_1 = 3, ///< MQTT 3.1 (protocol message byte = 3)
MQTT_3_1_1 = 4 ///< MQTT 3.1.1 (protocol message byte = 4)
} MQTT_Ver_t;
/**
* @brief Quality of Service Type
*
* Defining a QoS type.
* @note QoS 2 is \b NOT supported by the AWS IoT Service at the time of this SDK release.
*
*/
typedef enum {
QOS_0, ///< QoS 0 = at most once delivery
QOS_1, ///< QoS 1 = at least once delivery
QOS_2 ///< QoS 2 is NOT supported
} QoSLevel;
/**
* @brief Last Will and Testament Definition
*
* Defining a type for LWT parameters.
* @note Retained messages are \b NOT supported by the AWS IoT Service at the time of this SDK release.
*
*/
typedef struct {
const char *pTopicName; ///< LWT Topic
const char *pMessage; ///< Message to be delivered as LWT
bool isRetained; ///< NOT supported
QoSLevel qos; ///< QoS of LWT message
} MQTTwillOptions;
extern const MQTTwillOptions MQTTwillOptionsDefault;
/**
* @brief Disconnect Callback Handler Type
*
* Defining a TYPE for definition of disconnect callback function pointers.
*
*/
typedef void (*iot_disconnect_handler)(void);
/**
* @brief MQTT Connection Parameters
*
* Defining a type for MQTT connection parameters. Passed into client when establishing a connection.
*
*/
typedef struct {
uint8_t enableAutoReconnect; ///< Set to true to enable auto reconnect
char *pHostURL; ///< Pointer to a string defining the endpoint for the MQTT service
uint16_t port; ///< MQTT service listening port
char *pRootCALocation; ///< Pointer to a string defining the Root CA file (full file, not path)
char *pDeviceCertLocation; ///< Pointer to a string defining the device identity certificate file (full file, not path)
char *pDevicePrivateKeyLocation; ///< Pointer to a string defining the device private key file (full file, not path)
char *pClientID; ///< Pointer to a string defining the MQTT client ID (this needs to be unique \b per \b device across your AWS account)
char *pUserName; ///< Not used in the AWS IoT Service
char *pPassword; ///< Not used in the AWS IoT Service
MQTT_Ver_t MQTTVersion; ///< Desired MQTT version used during connection
uint16_t KeepAliveInterval_sec; ///< MQTT keep alive interval in seconds. Defines inactivity time allowed before determining the connection has been lost.
bool isCleansession; ///< MQTT clean session. True = this session is to be treated as clean. Previous server state is cleared and no stated is retained from this connection.
bool isWillMsgPresent; ///< Is there a LWT associated with this connection?
MQTTwillOptions will; ///< MQTT LWT parameters.
uint32_t mqttCommandTimeout_ms; ///< Timeout for MQTT blocking calls. In milliseconds.
uint32_t tlsHandshakeTimeout_ms; ///< TLS handshake timeout. In milliseconds.
bool isSSLHostnameVerify; ///< Client should perform server certificate hostname validation.
iot_disconnect_handler disconnectHandler; ///< Callback to be invoked upon connection loss.
} MQTTConnectParams;
extern const MQTTConnectParams MQTTConnectParamsDefault;
/**
* @brief MQTT Message Parameters
*
* Defines a type for properties of MQTT messages including topic, payload an QoS.
*
*/
typedef struct {
QoSLevel qos; ///< Message Quality of Service
bool isRetained; ///< Retained messages are \b NOT supported by the AWS IoT Service at the time of this SDK release.
bool isDuplicate; ///< Is this message a duplicate QoS > 0 message? Handled automatically by the MQTT client.
uint16_t id; ///< Message sequence identifier. Handled automatically by the MQTT client.
void *pPayload; ///< Pointer to MQTT message payload (bytes).
uint32_t PayloadLen; ///< Length of MQTT payload.
} MQTTMessageParams;
extern const MQTTMessageParams MQTTMessageParamsDefault;
/**
* @brief MQTT Callback Function Parameters
*
* Defines a type for parameters returned to the user upon receipt of a publish message on a subscribed topic.
*
*/
typedef struct {
char *pTopicName; ///< Pointer to the topic string on which the message was delivered. In the case of a wildcard subscription this is the actual topic, not the wildcard filter.
uint16_t TopicNameLen; ///< Length of the topic string.
MQTTMessageParams MessageParams; ///< Message parameters structure.
} MQTTCallbackParams;
extern const MQTTCallbackParams MQTTCallbackParamsDefault;
/**
* @brief MQTT Callback Function
*
* Defines a type for the function pointer which stores the message callback function.
* A pointer to the desired callback function to be invoked upon receipt of a message on a subscribed toipc.
* Supplied upon subscribing to a topic.
*
*/
typedef int32_t (*iot_message_handler)(MQTTCallbackParams params);
/**
* @brief MQTT Subscription Parameters
*
* Defines the parameters needed when subscribing to an MQTT topic.
*
*/
typedef struct {
char *pTopic; ///< Pointer to the string defining the desired subscription topic.
QoSLevel qos; ///< Quality of service of the subscription.
iot_message_handler mHandler; ///< Callback to be invoked upon receipt of a message on the subscribed topic.
} MQTTSubscribeParams;
extern const MQTTSubscribeParams MQTTSubscribeParamsDefault;
/**
* @brief MQTT Publish Parameters
*
* Defines a type for parameters supplied when publishing an MQTT message.
*
*/
typedef struct {
char *pTopic; ///< Pointer to the string defining the desired publishing topic.
MQTTMessageParams MessageParams; ///< Parameters defining the message to be published.
} MQTTPublishParams;
extern const MQTTPublishParams MQTTPublishParamsDefault;
/**
* @brief MQTT Connection Function
*
* Called to establish an MQTT connection with the AWS IoT Service
*
* @param pParams Pointer to MQTT connection parameters
* @return An IoT Error Type defining successful/failed connection
*/
IoT_Error_t aws_iot_mqtt_connect(MQTTConnectParams *pParams);
/**
* @brief Publish an MQTT message on a topic
*
* Called to publish an MQTT message on a topic.
* @note Call is blocking. In the case of a QoS 0 message the function returns
* after the message was successfully passed to the TLS layer. In the case of QoS 1
* the function returns after the receipt of the PUBACK control packet.
*
* @param pParams Pointer to MQTT publish parameters
* @return An IoT Error Type defining successful/failed publish
*/
IoT_Error_t aws_iot_mqtt_publish(MQTTPublishParams *pParams);
/**
* @brief Subscribe to an MQTT topic.
*
* Called to send a subscribe message to the broker requesting a subscription
* to an MQTT topic.
* @note Call is blocking. The call returns after the receipt of the SUBACK control packet.
*
* @param pParams Pointer to MQTT subscribe parameters
* @return An IoT Error Type defining successful/failed subscription
*/
IoT_Error_t aws_iot_mqtt_subscribe(MQTTSubscribeParams *pParams);
/**
* @brief Unsubscribe to an MQTT topic.
*
* Called to send an usubscribe message to the broker requesting removal of a subscription
* to an MQTT topic.
* @note Call is blocking. The call returns after the receipt of the UNSUBACK control packet.
*
* @param pTopic Pointer to the requested topic string. Ensure the string is null terminated
* @return An IoT Error Type defining successful/failed unsubscription
*/
IoT_Error_t aws_iot_mqtt_unsubscribe(char *pTopic);
/**
* @brief MQTT Manual Re-Connection Function
*
* Called to establish an MQTT connection with the AWS IoT Service
* using parameters from the last time a connection was attempted
* Use after disconnect to start the reconnect process manually
* Makes only one reconnect attempt
*
* @return An IoT Error Type defining successful/failed connection
*/
IoT_Error_t aws_iot_mqtt_attempt_reconnect(void);
/**
* @brief Disconnect an MQTT Connection
*
* Called to send a disconnect message to the broker.
*
* @return An IoT Error Type defining successful/failed send of the disconnect control packet.
*/
IoT_Error_t aws_iot_mqtt_disconnect(void);
/**
* @brief Yield to the MQTT client
*
* Called to yield the current thread to the underlying MQTT client. This time is used by
* the MQTT client to manage PING requests to monitor the health of the TCP connection as
* well as periodically check the socket receive buffer for subscribe messages. Yield()
* must be called at a rate faster than the keepalive interval. It must also be called
* at a rate faster than the incoming message rate as this is the only way the client receives
* processing time to manage incoming messages.
*
* @param timeout Maximum number of milliseconds to pass thread execution to the client.
* @return An IoT Error Type defining successful/failed client processing.
* If this call results in an error it is likely the MQTT connection has dropped.
* iot_is_mqtt_connected can be called to confirm.
*/
IoT_Error_t aws_iot_mqtt_yield(int timeout);
/**
* @brief Is the MQTT client currently connected?
*
* Called to determine if the MQTT client is currently connected. Used to support logic
* in the device application around reconnecting and managing offline state.
*
* @return true = connected, false = not currently connected
*/
bool aws_iot_is_mqtt_connected(void);
/**
* @brief Is the MQTT client set to reconnect automatically?
*
* Called to determine if the MQTT client is set to reconnect automatically.
* Used to support logic in the device application around reconnecting
*
* @return true = enabled, false = disabled
*/
bool aws_iot_is_autoreconnect_enabled(void);
/**
* @brief Enable or Disable AutoReconnect on Network Disconnect
*
* Called to enable or disabled the auto reconnect features provided with the SDK
*
* @param value set to true for enabling and false for disabling
*
* @return IoT_Error_t Type defining successful/failed API call
*/
IoT_Error_t aws_iot_mqtt_autoreconnect_set_status(bool value);
typedef IoT_Error_t (*pConnectFunc_t)(MQTTConnectParams *pParams);
typedef IoT_Error_t (*pPublishFunc_t)(MQTTPublishParams *pParams);
typedef IoT_Error_t (*pSubscribeFunc_t)(MQTTSubscribeParams *pParams);
typedef IoT_Error_t (*pUnsubscribeFunc_t)(char *pTopic);
typedef IoT_Error_t (*pDisconnectFunc_t)(void);
typedef IoT_Error_t (*pYieldFunc_t)(int timeout);
typedef bool (*pIsConnectedFunc_t)(void);
typedef bool (*pIsAutoReconnectEnabledFunc_t)(void);
typedef IoT_Error_t (*pReconnectFunc_t)();
typedef IoT_Error_t (*pSetAutoReconnectStatusFunc_t)(bool);
/**
* @brief MQTT Client Type Definition
*
* Defines a structure of function pointers, each implementing a corresponding iot_mqtt_*
* function. In this way any MQTT client which implements the iot_mqtt_* interface
* can be swapped in under the MQTT/Shadow layer.
*
*/
typedef struct{
pConnectFunc_t connect; ///< function implementing the iot_mqtt_connect function
pPublishFunc_t publish; ///< function implementing the iot_mqtt_publish function
pSubscribeFunc_t subscribe; ///< function implementing the iot_mqtt_subscribe function
pUnsubscribeFunc_t unsubscribe; ///< function implementing the iot_mqtt_unsubscribe function
pDisconnectFunc_t disconnect; ///< function implementing the iot_mqtt_disconnect function
pYieldFunc_t yield; ///< function implementing the iot_mqtt_yield function
pIsConnectedFunc_t isConnected; ///< function implementing the iot_is_mqtt_connected function
pReconnectFunc_t reconnect; ///< function implementing the iot_mqtt_reconnect function
pIsAutoReconnectEnabledFunc_t isAutoReconnectEnabled; ///< function implementing the iot_is_autoreconnect_enabled function
pSetAutoReconnectStatusFunc_t setAutoReconnectStatus; ///< function implementing the iot_mqtt_autoreconnect_set_status function
}MQTTClient_t;
/**
* @brief Set the MQTT client
*
* This function provides a way to pass in an MQTT client implementation to the
* AWS IoT MQTT wrapper layer. This is done through function pointers to the
* interface functions.
*
*/
void aws_iot_mqtt_init(MQTTClient_t *pClient);
#endif /* AWS_IOT_SDK_SRC_IOT_MQTT_INTERFACE_H_ */

View File

@@ -1,175 +0,0 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#include "aws_iot_error.h"
#include "aws_iot_log.h"
#include "aws_iot_shadow_actions.h"
#include "aws_iot_shadow_json.h"
#include "aws_iot_shadow_key.h"
#include "aws_iot_shadow_records.h"
const ShadowParameters_t ShadowParametersDefault = {
.pMyThingName = AWS_IOT_MY_THING_NAME,
.pMqttClientId = AWS_IOT_MQTT_CLIENT_ID,
.pHost = AWS_IOT_MQTT_HOST,
.port = AWS_IOT_MQTT_PORT,
.pRootCA = NULL,
.pClientCRT = NULL,
.pClientKey = NULL
};
void aws_iot_shadow_reset_last_received_version(void) {
shadowJsonVersionNum = 0;
}
uint32_t aws_iot_shadow_get_last_received_version(void) {
return shadowJsonVersionNum;
}
void aws_iot_shadow_enable_discard_old_delta_msgs(void) {
shadowDiscardOldDeltaFlag = true;
}
void aws_iot_shadow_disable_discard_old_delta_msgs(void) {
shadowDiscardOldDeltaFlag = false;
}
IoT_Error_t aws_iot_shadow_init(MQTTClient_t *pClient) {
IoT_Error_t rc = NONE_ERROR;
if (pClient == NULL) {
return NULL_VALUE_ERROR;
}
resetClientTokenSequenceNum();
aws_iot_shadow_reset_last_received_version();
initDeltaTokens();
return NONE_ERROR;
}
IoT_Error_t aws_iot_shadow_connect(MQTTClient_t *pClient, ShadowParameters_t *pParams) {
IoT_Error_t rc = NONE_ERROR;
MQTTConnectParams ConnectParams = MQTTConnectParamsDefault;
if (pClient == NULL) {
return NULL_VALUE_ERROR;
}
if (pClient->connect == NULL) {
return NULL_VALUE_ERROR;
}
snprintf(myThingName, MAX_SIZE_OF_THING_NAME, "%s", pParams->pMyThingName );
snprintf(mqttClientID, MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES, "%s", pParams->pMqttClientId );
DEBUG("Thing Name %s", myThingName);
DEBUG("MQTT Client ID %s", mqttClientID);
ConnectParams.KeepAliveInterval_sec = 10;
ConnectParams.MQTTVersion = MQTT_3_1_1;
ConnectParams.mqttCommandTimeout_ms = 2000;
ConnectParams.tlsHandshakeTimeout_ms = 10000;
ConnectParams.isCleansession = true;
ConnectParams.isSSLHostnameVerify = true;
ConnectParams.isWillMsgPresent = false;
ConnectParams.pClientID = pParams->pMqttClientId;
ConnectParams.pDeviceCertLocation = pParams->pClientCRT;
ConnectParams.pDevicePrivateKeyLocation = pParams->pClientKey;
ConnectParams.pRootCALocation = pParams->pRootCA;
ConnectParams.pPassword = NULL;
ConnectParams.pUserName = NULL;
ConnectParams.pHostURL = pParams->pHost;
ConnectParams.port = pParams->port;
ConnectParams.disconnectHandler = NULL;
rc = pClient->connect(&ConnectParams);
if(rc == NONE_ERROR){
initializeRecords(pClient);
}
return rc;
}
IoT_Error_t aws_iot_shadow_register_delta(MQTTClient_t *pClient, jsonStruct_t *pStruct) {
IoT_Error_t rc = NONE_ERROR;
if (!(pClient->isConnected())) {
return CONNECTION_ERROR;
}
rc = registerJsonTokenOnDelta(pStruct);
return rc;
}
IoT_Error_t aws_iot_shadow_yield(MQTTClient_t *pClient, int timeout) {
HandleExpiredResponseCallbacks();
return pClient->yield(timeout);
}
IoT_Error_t aws_iot_shadow_disconnect(MQTTClient_t *pClient) {
return pClient->disconnect();
}
IoT_Error_t aws_iot_shadow_update(MQTTClient_t *pClient, const char *pThingName, char *pJsonString,
fpActionCallback_t callback, void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscribe) {
IoT_Error_t ret_val = NONE_ERROR;
if (!(pClient->isConnected())) {
return CONNECTION_ERROR;
}
ret_val = iot_shadow_action(pClient, pThingName, SHADOW_UPDATE, pJsonString, callback, pContextData,
timeout_seconds, isPersistentSubscribe);
return ret_val;
}
IoT_Error_t aws_iot_shadow_delete(MQTTClient_t *pClient, const char *pThingName, fpActionCallback_t callback,
void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscribe) {
IoT_Error_t ret_val = NONE_ERROR;
if (!(pClient->isConnected())) {
return CONNECTION_ERROR;
}
char deleteRequestJsonBuf[MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE];
iot_shadow_delete_request_json(deleteRequestJsonBuf);
ret_val = iot_shadow_action(pClient, pThingName, SHADOW_DELETE, deleteRequestJsonBuf, callback, pContextData,
timeout_seconds, isPersistentSubscribe);
return ret_val;
}
IoT_Error_t aws_iot_shadow_get(MQTTClient_t *pClient, const char *pThingName, fpActionCallback_t callback,
void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscribe) {
IoT_Error_t ret_val = NONE_ERROR;
if (!(pClient->isConnected())) {
return CONNECTION_ERROR;
}
char getRequestJsonBuf[MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE];
iot_shadow_get_request_json(getRequestJsonBuf);
ret_val = iot_shadow_action(pClient, pThingName, SHADOW_GET, getRequestJsonBuf, callback, pContextData,
timeout_seconds, isPersistentSubscribe);
return ret_val;
}

View File

@@ -1,93 +0,0 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/**
* @file aws_iot_error.h
* @brief Definition of error types for the SDK.
*/
#ifndef AWS_IOT_SDK_SRC_IOT_ERROR_H_
#define AWS_IOT_SDK_SRC_IOT_ERROR_H_
/*! \public
* @brief IoT Error enum
*
* Enumeration of return values from the IoT_* functions within the SDK.
*/
typedef enum {
/** Return value of yield function to indicate auto-reconnect was successful */
RECONNECT_SUCCESSFUL = 1,
/** Success return value - no error occurred. */
NONE_ERROR = 0,
/** A generic error. A placeholder for a more specific error. */
GENERIC_ERROR = -1,
/** A required parameter was passed as null. */
NULL_VALUE_ERROR = -2,
/** A connection could not be established. */
CONNECTION_ERROR = -3,
/** The subscribe failed. A SUBACK was not returned from the service. */
SUBSCRIBE_ERROR = -4,
/** The publish failed. In the case of a QoS 1 message a PUBACK was not received. */
PUBLISH_ERROR = -5,
/** The disconnect failed. The disconnect control packet could not be sent. */
DISCONNECT_ERROR = -6,
/** An error occurred when yielding to the IoT MQTT client. A possible cause is an unexpected TCP socket disconnect. */
YIELD_ERROR = -7,
/** The TCP socket could not be established. */
TCP_CONNECT_ERROR = -8,
/** The TLS handshake failed. */
SSL_CONNECT_ERROR = -9,
/** Error associated with setting up the parameters of a Socket */
TCP_SETUP_ERROR =-10,
/** A timeout occurred while waiting for the TLS handshake to complete. */
SSL_CONNECT_TIMEOUT_ERROR = -11,
/** A Generic write error based on the platform used */
SSL_WRITE_ERROR = -12,
/** SSL initialization error at the TLS layer */
SSL_INIT_ERROR = -13,
/** An error occurred when loading the certificates. The certificates could not be located or are incorrectly formatted. */
SSL_CERT_ERROR= -14,
/** The unsubscribe failed. The unsubscribe control packet could not be sent. */
UNSUBSCRIBE_ERROR = -15,
/** An error occurred while parsing the JSON string. Usually malformed JSON. */
JSON_PARSE_ERROR = -16,
/** Shadow: The response Ack table is currently full waiting for previously published updates */
WAIT_FOR_PUBLISH = -17,
/** SSL Write times out */
SSL_WRITE_TIMEOUT_ERROR = -18,
/** SSL Read times out */
SSL_READ_TIMEOUT_ERROR = -19,
/** A Generic error based on the platform used */
SSL_READ_ERROR = -20,
/** Any time an snprintf writes more than size value, this error will be returned */
SHADOW_JSON_BUFFER_TRUNCATED = -21,
/** Any time an snprintf encounters an encoding error or not enough space in the given buffer */
SHADOW_JSON_ERROR = -22,
/** Returned when the Network is disconnected and reconnect is either disabled or physical layer is disconnected */
NETWORK_DISCONNECTED = -23,
/** Returned when the Network is disconnected and the reconnect attempt has timed out */
NETWORK_RECONNECT_TIMED_OUT = -24,
/** Returned when the Network is disconnected and the reconnect attempt is in progress */
NETWORK_ATTEMPTING_RECONNECT = -25,
/** Returned when the Network is already connected and a connection attempt is made */
NETWORK_ALREADY_CONNECTED = -26,
/** The MQTT RX buffer received corrupt message */
RX_MESSAGE_INVALID = -27,
/** The MQTT RX buffer received a bigger message. The message will be dropped */
RX_MESSAGE_BIGGER_THAN_MQTT_RX_BUF = -28
}IoT_Error_t;
#endif /* AWS_IOT_SDK_SRC_IOT_ERROR_H_ */

View File

@@ -1,47 +0,0 @@
Contributing to Paho
====================
Thanks for your interest in this project.
Project description:
--------------------
The Paho project has been created to provide scalable open-source implementations of open and standard messaging protocols aimed at new, existing, and emerging applications for Machine-to-Machine (M2M) and Internet of Things (IoT).
Paho reflects the inherent physical and cost constraints of device connectivity. Its objectives include effective levels of decoupling between devices and applications, designed to keep markets open and encourage the rapid growth of scalable Web and Enterprise middleware and applications. Paho is being kicked off with MQTT publish/subscribe client implementations for use on embedded platforms, along with corresponding server support as determined by the community.
- https://projects.eclipse.org/projects/technology.paho
Developer resources:
--------------------
Information regarding source code management, builds, coding standards, and more.
- https://projects.eclipse.org/projects/technology.paho/developer
Contributor License Agreement:
------------------------------
Before your contribution can be accepted by the project, you need to create and electronically sign the Eclipse Foundation Contributor License Agreement (CLA).
- http://www.eclipse.org/legal/CLA.php
Contact:
--------
Contact the project developers via the project's "dev" list.
- https://dev.eclipse.org/mailman/listinfo/paho-dev
Search for bugs:
----------------
This project uses Bugzilla to track ongoing development and issues.
- https://bugs.eclipse.org/bugs/buglist.cgi?product=Paho
Create a new bug:
-----------------
Be sure to search for existing bugs before you create another one. Remember that contributions are always welcome!
- https://bugs.eclipse.org/bugs/enter_bug.cgi?product=Paho

File diff suppressed because it is too large Load Diff

View File

@@ -1,123 +0,0 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#ifndef __MQTT_CLIENT_C_
#define __MQTT_CLIENT_C_
/* Library Header files */
#include "stdio.h"
#include "stdint.h"
#include "stddef.h"
/* MQTT Specific header files */
#include "MQTTReturnCodes.h"
#include "MQTTMessage.h"
#include "MQTTPacket.h"
/* AWS Specific header files */
#include "aws_iot_config.h"
/* Platform specific implementation header files */
#include "network_interface.h"
#include "timer_interface.h"
#define MAX_PACKET_ID 65535
#define MAX_MESSAGE_HANDLERS AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS
#define MIN_RECONNECT_WAIT_INTERVAL AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL
#define MAX_RECONNECT_WAIT_INTERVAL AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL
void NewTimer(Timer *);
typedef struct Client Client;
typedef struct MessageData MessageData;
typedef void (*messageHandler)(MessageData *);
typedef void (*pApplicationHandler_t)(void);
typedef void (*disconnectHandler_t)(void);
typedef int (*networkInitHandler_t)(Network *);
struct MessageData {
MQTTMessage *message;
MQTTString *topicName;
pApplicationHandler_t applicationHandler;
};
MQTTReturnCode MQTTConnect(Client *c, MQTTPacket_connectData *options);
MQTTReturnCode MQTTPublish (Client *, const char *, MQTTMessage *);
MQTTReturnCode MQTTSubscribe(Client *c, const char *topicFilter, QoS qos,
messageHandler messageHandler, pApplicationHandler_t applicationHandler);
MQTTReturnCode MQTTResubscribe(Client *c);
MQTTReturnCode MQTTUnsubscribe(Client *c, const char *topicFilter);
MQTTReturnCode MQTTDisconnect (Client *);
MQTTReturnCode MQTTYield (Client *, uint32_t);
MQTTReturnCode MQTTAttemptReconnect(Client *c);
uint8_t MQTTIsConnected(Client *);
uint8_t MQTTIsAutoReconnectEnabled(Client *c);
void setDefaultMessageHandler(Client *, messageHandler);
MQTTReturnCode setDisconnectHandler(Client *c, disconnectHandler_t disconnectHandler);
MQTTReturnCode setAutoReconnectEnabled(Client *c, uint8_t value);
MQTTReturnCode MQTTClient(Client *, uint32_t, unsigned char *, size_t, unsigned char *,
size_t, uint8_t, networkInitHandler_t, TLSConnectParams *);
uint32_t MQTTGetNetworkDisconnectedCount(Client *c);
void MQTTResetNetworkDisconnectedCount(Client *c);
struct Client {
uint8_t isConnected;
uint8_t wasManuallyDisconnected;
uint8_t isPingOutstanding;
uint8_t isAutoReconnectEnabled;
uint16_t nextPacketId;
uint32_t commandTimeoutMs;
uint32_t keepAliveInterval;
uint32_t currentReconnectWaitInterval;
uint32_t counterNetworkDisconnected;
size_t bufSize;
size_t readBufSize;
unsigned char *buf;
unsigned char *readbuf;
TLSConnectParams tlsConnectParams;
MQTTPacket_connectData options;
Network networkStack;
Timer pingTimer;
Timer reconnectDelayTimer;
struct MessageHandlers {
const char *topicFilter;
void (*fp) (MessageData *);
pApplicationHandler_t applicationHandler;
QoS qos;
} messageHandlers[MAX_MESSAGE_HANDLERS]; /* Message handlers are indexed by subscription topic */
void (* defaultMessageHandler) (MessageData *);
disconnectHandler_t disconnectHandler;
networkInitHandler_t networkInitHandler;
};
#define DefaultClient {0, 0, 0, 0, NULL, NULL, 0, 0, 0}
#endif

View File

@@ -1,146 +0,0 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
#ifndef MQTTCONNECT_H_
#define MQTTCONNECT_H_
#if !defined(DLLImport)
#define DLLImport
#endif
#if !defined(DLLExport)
#define DLLExport
#endif
typedef union {
uint8_t all; /**< all connect flags */
#if defined(REVERSED)
struct
{
unsigned int username : 1; /**< 3.1 user name */
unsigned int password : 1; /**< 3.1 password */
unsigned int willRetain : 1; /**< will retain setting */
unsigned int willQoS : 2; /**< will QoS value */
unsigned int will : 1; /**< will flag */
unsigned int cleansession : 1; /**< clean session flag */
unsigned int : 1; /**< unused */
} bits;
#else
struct
{
unsigned int : 1; /**< unused */
unsigned int cleansession : 1; /**< cleansession flag */
unsigned int will : 1; /**< will flag */
unsigned int willQoS : 2; /**< will QoS value */
unsigned int willRetain : 1; /**< will retain setting */
unsigned int password : 1; /**< 3.1 password */
unsigned int username : 1; /**< 3.1 user name */
} bits;
#endif
} MQTTConnectFlags; /**< connect flags byte */
/**
* Defines the MQTT "Last Will and Testament" (LWT) settings for
* the connect packet.
*/
typedef struct {
/** The eyecatcher for this structure. must be MQTW. */
char struct_id[4];
/** The version number of this structure. Must be 0 */
uint8_t struct_version;
/** The LWT topic to which the LWT message will be published. */
MQTTString topicName;
/** The LWT payload. */
MQTTString message;
/**
* The retained flag for the LWT message (see MQTTAsync_message.retained).
*/
uint8_t retained;
/**
* The quality of service setting for the LWT message (see
* MQTTAsync_message.qos and @ref qos).
*/
QoS qos;
} MQTTPacket_willOptions;
#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, 0 }
typedef struct {
/** The eyecatcher for this structure. must be MQTC. */
char struct_id[4];
/** The version number of this structure. Must be 0 */
uint8_t struct_version;
/** Version of MQTT to be used. 3 = 3.1 4 = 3.1.1
*/
uint8_t MQTTVersion;
MQTTString clientID;
uint16_t keepAliveInterval;
uint8_t cleansession;
uint8_t willFlag;
MQTTPacket_willOptions will;
MQTTString username;
MQTTString password;
} MQTTPacket_connectData;
typedef union
{
uint8_t all; /**< all connack flags */
#if defined(REVERSED)
struct
{
unsigned int sessionpresent : 1; /**< session present flag */
unsigned int : 7; /**< unused */
} bits;
#else
struct
{
unsigned int : 7; /**< unused */
unsigned int sessionpresent : 1; /**< session present flag */
} bits;
#endif
} MQTTConnackFlags; /**< connack flags byte */
typedef enum {
CONNACK_CONNECTION_ACCEPTED = 0,
CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR = 1,
CONNACK_IDENTIFIER_REJECTED_ERROR = 2,
CONNACK_SERVER_UNAVAILABLE_ERROR = 3,
CONNACK_BAD_USERDATA_ERROR = 4,
CONNACK_NOT_AUTHORIZED_ERROR = 5
}MQTTConnackReturnCodes;
#define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'C'}, 0, 4, {NULL, {0, NULL}}, 60, 1, 0, \
MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} }
DLLExport MQTTReturnCode MQTTSerialize_connect(unsigned char *buf, size_t buflen,
MQTTPacket_connectData *options,
uint32_t *serialized_len);
DLLExport MQTTReturnCode MQTTDeserialize_connack(unsigned char *sessionPresent,
MQTTReturnCode *connack_rc,
unsigned char *buf, size_t buflen);
DLLExport MQTTReturnCode MQTTSerialize_disconnect(unsigned char *buf, size_t buflen,
uint32_t *serialized_length);
DLLExport MQTTReturnCode MQTTSerialize_pingreq(unsigned char *buf, size_t buflen,
uint32_t *serialized_length);
#endif /* MQTTCONNECT_H_ */

View File

@@ -1,293 +0,0 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Determines the length of the MQTT connect packet that would be produced using the supplied connect options.
* @param options the options to be used to build the connect packet
* @param the length of buffer needed to contain the serialized version of the packet
* @return MQTTReturnCode indicating function execution status
*/
size_t MQTTSerialize_GetConnectLength(MQTTPacket_connectData *options) {
size_t len = 0;
FUNC_ENTRY;
/* variable depending on MQTT or MQIsdp */
if(3 == options->MQTTVersion) {
len = 12;
} else if(4 == options->MQTTVersion) {
len = 10;
}
len += MQTTstrlen(options->clientID) + 2;
if(options->willFlag) {
len += MQTTstrlen(options->will.topicName) + 2 + MQTTstrlen(options->will.message) + 2;
}
if(options->username.cstring || options->username.lenstring.data) {
len += MQTTstrlen(options->username) + 2;
}
if(options->password.cstring || options->password.lenstring.data) {
len += MQTTstrlen(options->password) + 2;
}
FUNC_EXIT_RC(len);
return len;
}
/**
* Serializes the connect options into the buffer.
* @param buf the buffer into which the packet will be serialized
* @param len the length in bytes of the supplied buffer
* @param options the options to be used to build the connect packet
* @param serialized length
* @return MQTTReturnCode indicating function execution status
*/
MQTTReturnCode MQTTSerialize_connect(unsigned char *buf, size_t buflen,
MQTTPacket_connectData *options,
uint32_t *serialized_len) {
unsigned char *ptr = buf;
MQTTHeader header = {0};
MQTTConnectFlags flags = {0};
size_t len = 0;
MQTTReturnCode rc = MQTTPacket_InitHeader(&header, CONNECT, QOS0, 0, 0);
FUNC_ENTRY;
if(NULL == buf || NULL == options || NULL == serialized_len) {
FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
return MQTT_NULL_VALUE_ERROR;
}
len = MQTTSerialize_GetConnectLength(options);
if(MQTTPacket_len(len) > buflen) {
FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
return MQTTPACKET_BUFFER_TOO_SHORT;
}
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
return rc;
}
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, len); /* write remaining length */
if(4 == options->MQTTVersion) {
writeCString(&ptr, "MQTT");
writeChar(&ptr, (char) 4);
} else {
writeCString(&ptr, "MQIsdp");
writeChar(&ptr, (char) 3);
}
flags.all = 0;
flags.bits.cleansession = (options->cleansession) ? 1 : 0;
flags.bits.will = (options->willFlag) ? 1 : 0;
if(flags.bits.will) {
flags.bits.willQoS = options->will.qos;
flags.bits.willRetain = (options->will.retained) ? 1 : 0;
}
if(options->username.cstring || options->username.lenstring.data) {
flags.bits.username = 1;
}
if(options->password.cstring || options->password.lenstring.data) {
flags.bits.password = 1;
}
writeChar(&ptr, flags.all);
writeInt(&ptr, options->keepAliveInterval);
writeMQTTString(&ptr, options->clientID);
if(options->willFlag) {
writeMQTTString(&ptr, options->will.topicName);
writeMQTTString(&ptr, options->will.message);
}
if(flags.bits.username) {
writeMQTTString(&ptr, options->username);
}
if(flags.bits.password) {
writeMQTTString(&ptr, options->password);
}
*serialized_len = (uint32_t)(ptr - buf);
FUNC_EXIT_RC(SUCCESS);
return SUCCESS;
}
/**
* Deserializes the supplied (wire) buffer into connack data - return code
* @param sessionPresent the session present flag returned (only for MQTT 3.1.1)
* @param connack_rc returned integer value of the connack return code
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return MQTTReturnCode indicating function execution status
*/
MQTTReturnCode MQTTDeserialize_connack(unsigned char *sessionPresent,
MQTTReturnCode *connack_rc,
unsigned char *buf, size_t buflen) {
MQTTHeader header = {0};
unsigned char *curdata = buf;
unsigned char *enddata = NULL;
MQTTReturnCode rc = FAILURE;
uint32_t decodedLen = 0;
uint32_t readBytesLen = 0;
MQTTConnackFlags flags = {0};
unsigned char connack_rc_char;
FUNC_ENTRY;
if(NULL == sessionPresent || NULL == connack_rc || NULL == buf) {
FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
return MQTT_NULL_VALUE_ERROR;
}
/* CONNACK header size is fixed at two bytes for fixed and 2 bytes for variable,
* using that as minimum size
* MQTT v3.1.1 Specification 3.2.1 */
if(4 > buflen) {
FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
return MQTTPACKET_BUFFER_TOO_SHORT;
}
header.byte = readChar(&curdata);
if(CONNACK != header.bits.type) {
FUNC_EXIT_RC(FAILURE);
return FAILURE;
}
/* read remaining length */
rc = MQTTPacket_decodeBuf(curdata, &decodedLen, &readBytesLen);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
return rc;
}
curdata += (readBytesLen);
enddata = curdata + decodedLen;
if(enddata - curdata < 2) {
FUNC_EXIT_RC(FAILURE);
return FAILURE;
}
flags.all = readChar(&curdata);
*sessionPresent = flags.bits.sessionpresent;
connack_rc_char = readChar(&curdata);
switch(connack_rc_char) {
case CONNACK_CONNECTION_ACCEPTED:
*connack_rc = MQTT_CONNACK_CONNECTION_ACCEPTED;
break;
case CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR:
*connack_rc = MQTT_CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR;
break;
case CONNACK_IDENTIFIER_REJECTED_ERROR:
*connack_rc = MQTT_CONNACK_IDENTIFIER_REJECTED_ERROR;
break;
case CONNACK_SERVER_UNAVAILABLE_ERROR:
*connack_rc = MQTT_CONNACK_SERVER_UNAVAILABLE_ERROR;
break;
case CONNACK_BAD_USERDATA_ERROR:
*connack_rc = MQTT_CONNACK_BAD_USERDATA_ERROR;
break;
case CONNACK_NOT_AUTHORIZED_ERROR:
*connack_rc = MQTT_CONNACK_NOT_AUTHORIZED_ERROR;
break;
default:
*connack_rc = MQTT_CONNACK_UNKNOWN_ERROR;
break;
}
FUNC_EXIT_RC(SUCCESS);
return SUCCESS;
}
/**
* Serializes a 0-length packet into the supplied buffer, ready for writing to a socket
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer, to avoid overruns
* @param packettype the message type
* @param serialized length
* @return MQTTReturnCode indicating function execution status
*/
MQTTReturnCode MQTTSerialize_zero(unsigned char *buf, size_t buflen,
unsigned char packetType,
uint32_t *serialized_length) {
MQTTHeader header = {0};
unsigned char *ptr = buf;
MQTTReturnCode rc = MQTTPacket_InitHeader(&header, packetType, QOS0, 0, 0);
FUNC_ENTRY;
if(NULL == buf || NULL == serialized_length) {
FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
return MQTT_NULL_VALUE_ERROR;
}
/* Buffer should have at least 2 bytes for the header */
if(4 > buflen) {
FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
return MQTTPACKET_BUFFER_TOO_SHORT;
}
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
return rc;
}
/* write header */
writeChar(&ptr, header.byte);
/* write remaining length */
ptr += MQTTPacket_encode(ptr, 0);
*serialized_length = (uint32_t)(ptr - buf);
FUNC_EXIT_RC(SUCCESS);
return SUCCESS;
}
/**
* Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer, to avoid overruns
* @param serialized length
* @return MQTTReturnCode indicating function execution status
*/
MQTTReturnCode MQTTSerialize_disconnect(unsigned char *buf, size_t buflen,
uint32_t *serialized_length) {
return MQTTSerialize_zero(buf, buflen, DISCONNECT, serialized_length);
}
/**
* Serializes a pingreq packet into the supplied buffer, ready for writing to a socket
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer, to avoid overruns
* @param serialized length
* @return MQTTReturnCode indicating function execution status
*/
MQTTReturnCode MQTTSerialize_pingreq(unsigned char *buf, size_t buflen,
uint32_t *serialized_length) {
return MQTTSerialize_zero(buf, buflen, PINGREQ, serialized_length);
}

View File

@@ -1,151 +0,0 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "StackTrace.h"
#include "MQTTPacket.h"
#include <string.h>
/**
* Deserializes the supplied (wire) buffer into publish data
* @param dup returned integer - the MQTT dup flag
* @param qos returned integer - the MQTT QoS value
* @param retained returned integer - the MQTT retained flag
* @param packetid returned integer - the MQTT packet identifier
* @param topicName returned MQTTString - the MQTT topic in the publish
* @param payload returned byte buffer - the MQTT publish payload
* @param payloadlen returned integer - the length of the MQTT payload
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return error code. 1 is success
*/
MQTTReturnCode MQTTDeserialize_publish(unsigned char *dup, QoS *qos,
unsigned char *retained, uint16_t *packetid,
MQTTString* topicName, unsigned char **payload,
uint32_t *payloadlen, unsigned char *buf, size_t buflen) {
MQTTHeader header = {0};
unsigned char *curdata = buf;
unsigned char *enddata = NULL;
MQTTReturnCode rc = FAILURE;
uint32_t decodedLen = 0;
uint32_t readBytesLen = 0;
FUNC_ENTRY;
if(NULL == dup || NULL == qos || NULL == retained || NULL == packetid) {
FUNC_EXIT_RC(FAILURE);
return FAILURE;
}
/* Publish header size is at least four bytes.
* Fixed header is two bytes.
* Variable header size depends on QoS And Topic Name.
* QoS level 0 doesn't have a message identifier (0 - 2 bytes)
* Topic Name length fields decide size of topic name field (at least 2 bytes)
* MQTT v3.1.1 Specification 3.3.1 */
if(4 > buflen) {
FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
return MQTTPACKET_BUFFER_TOO_SHORT;
}
header.byte = readChar(&curdata);
if(PUBLISH != header.bits.type) {
FUNC_EXIT_RC(FAILURE);
return FAILURE;
}
*dup = header.bits.dup;
*qos = (QoS)header.bits.qos;
*retained = header.bits.retain;
/* read remaining length */
rc = MQTTPacket_decodeBuf(curdata, &decodedLen, &readBytesLen);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
return rc;
}
curdata += (readBytesLen);
enddata = curdata + decodedLen;
/* do we have enough data to read the protocol version byte? */
if(SUCCESS != readMQTTLenString(topicName, &curdata, enddata) || (0 > (enddata - curdata))) {
FUNC_EXIT_RC(FAILURE);
return FAILURE;
}
if(QOS0 != *qos) {
*packetid = readPacketId(&curdata);
}
*payloadlen = (uint32_t)(enddata - curdata);
*payload = curdata;
FUNC_EXIT_RC(SUCCESS);
return SUCCESS;
}
/**
* Deserializes the supplied (wire) buffer into an ack
* @param packettype returned integer - the MQTT packet type
* @param dup returned integer - the MQTT dup flag
* @param packetid returned integer - the MQTT packet identifier
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return error code. 1 is success, 0 is failure
*/
MQTTReturnCode MQTTDeserialize_ack(unsigned char *packettype, unsigned char *dup,
uint16_t *packetid, unsigned char *buf,
size_t buflen) {
MQTTReturnCode rc = FAILURE;
MQTTHeader header = {0};
unsigned char *curdata = buf;
unsigned char *enddata = NULL;
uint32_t decodedLen = 0;
uint32_t readBytesLen = 0;
FUNC_ENTRY;
if(NULL == packettype || NULL == dup || NULL == packetid || NULL == buf) {
FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
return MQTT_NULL_VALUE_ERROR;
}
/* PUBACK fixed header size is two bytes, variable header is 2 bytes, MQTT v3.1.1 Specification 3.4.1 */
if(4 > buflen) {
FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
return MQTTPACKET_BUFFER_TOO_SHORT;
}
header.byte = readChar(&curdata);
*dup = header.bits.dup;
*packettype = header.bits.type;
/* read remaining length */
rc = MQTTPacket_decodeBuf(curdata, &decodedLen, &readBytesLen);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
return rc;
}
curdata += (readBytesLen);
enddata = curdata + decodedLen;
if(enddata - curdata < 2) {
FUNC_EXIT_RC(FAILURE);
return FAILURE;
}
*packetid = readPacketId(&curdata);
FUNC_EXIT_RC(SUCCESS);
return SUCCESS;
}

View File

@@ -1,58 +0,0 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/**
* @file MQTTMessage.h
* @brief Definition of Messages for the MQTT Client
*/
#ifndef __MQTT_MESSAGE_H
#define __MQTT_MESSAGE_H
/* Enum order should match the packet ids array defined in MQTTFormat.c */
typedef enum msgTypes {
UNKNOWN = -1,
CONNECT = 1,
CONNACK = 2,
PUBLISH = 3,
PUBACK = 4,
PUBREC = 5,
PUBREL = 6,
PUBCOMP = 7,
SUBSCRIBE = 8,
SUBACK = 9,
UNSUBSCRIBE = 10,
UNSUBACK = 11,
PINGREQ = 12,
PINGRESP = 13,
DISCONNECT = 14
}MessageTypes;
typedef enum QoS {
QOS0 = 0,
QOS1 = 1,
QOS2 = 2
}QoS;
typedef struct {
QoS qos;
uint8_t retained;
uint8_t dup;
uint16_t id;
void *payload;
size_t payloadlen;
}MQTTMessage;
#endif //__MQTT_MESSAGE_H

View File

@@ -1,389 +0,0 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Sergio R. Caprile - non-blocking packet read functions for stream transport
*******************************************************************************/
#include "StackTrace.h"
#include "MQTTPacket.h"
#include <string.h>
/**
* Encodes the message length according to the MQTT algorithm
* @param buf the buffer into which the encoded data is written
* @param length the length to be encoded
* @return the number of bytes written to buffer
*/
uint32_t MQTTPacket_encode(unsigned char *buf, size_t length) {
uint32_t outLen = 0;
FUNC_ENTRY;
do {
int16_t d = length % 128;
length /= 128;
/* if there are more digits to encode, set the top bit of this digit */
if(length > 0) {
d |= 0x80;
}
buf[outLen++] = (unsigned char)d;
}while(length > 0);
FUNC_EXIT_RC(outLen);
return outLen;
}
/**
* Decodes the message length according to the MQTT algorithm
* @param getcharfn pointer to function to read the next character from the data source
* @param value the decoded length returned
* @return the number of bytes read from the socket
*/
MQTTReturnCode MQTTPacket_decode(uint32_t (*getcharfn)(unsigned char *, uint32_t), uint32_t *value, uint32_t *readBytesLen) {
unsigned char c;
uint32_t multiplier = 1;
uint32_t len = 0;
uint32_t getLen = 0;
#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4
FUNC_ENTRY;
*value = 0;
do {
if(++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) {
/* bad data */
FUNC_EXIT_RC(MQTTPACKET_READ_ERROR);
return MQTTPACKET_READ_ERROR;
}
getLen = (*getcharfn)(&c, 1);
if(1 != getLen) {
FUNC_EXIT_RC(FAILURE);
return FAILURE;
}
*value += (c & 127) * multiplier;
multiplier *= 128;
}while((c & 128) != 0);
*readBytesLen = len;
FUNC_EXIT_RC(SUCCESS);
return SUCCESS;
}
size_t MQTTPacket_len(size_t rem_len) {
rem_len += 1; /* header byte */
/* now remaining_length field */
if(rem_len < 128) {
rem_len += 1;
} else if (rem_len < 16384) {
rem_len += 2;
} else if (rem_len < 2097151) {
rem_len += 3;
} else {
rem_len += 4;
}
return rem_len;
}
static unsigned char *bufptr;
uint32_t bufchar(unsigned char *c, uint32_t count) {
uint32_t i;
for(i = 0; i < count; ++i) {
*c = *bufptr++;
}
return count;
}
MQTTReturnCode MQTTPacket_decodeBuf(unsigned char *buf, uint32_t *value, uint32_t *readBytesLen) {
bufptr = buf;
return MQTTPacket_decode(bufchar, value, readBytesLen);
}
/**
* Calculates an integer from two bytes read from the input buffer
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
* @return the integer value calculated
*/
int32_t readInt(unsigned char **pptr) {
unsigned char *ptr = *pptr;
int32_t len = 256*(*ptr) + (*(ptr+1));
*pptr += 2;
return len;
}
/**
* Calculates an integer from two bytes read from the input buffer
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
* @return the integer value calculated
*/
size_t readSizeT(unsigned char **pptr) {
unsigned char *ptr = *pptr;
size_t firstByte = (size_t)(*ptr);
size_t secondByte = (size_t)(*(ptr+1));
size_t size = 256 * firstByte + secondByte;
*pptr += 2;
return size;
}
/**
* Calculates uint16 packet id from two bytes read from the input buffer
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
* @return the value calculated
*/
uint16_t readPacketId(unsigned char **pptr) {
unsigned char *ptr = *pptr;
uint8_t firstByte = (uint8_t)(*ptr);
uint8_t secondByte = (uint8_t)(*(ptr + 1));
uint16_t len = (uint16_t)(secondByte + (256 * firstByte));
*pptr += 2;
return len;
}
/**
* Reads one character from the input buffer.
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
* @return the character read
*/
unsigned char readChar(unsigned char **pptr) {
unsigned char c = **pptr;
(*pptr)++;
return c;
}
/**
* Writes one character to an output buffer.
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param c the character to write
*/
void writeChar(unsigned char **pptr, unsigned char c) {
**pptr = c;
(*pptr)++;
}
/**
* Writes an integer as 2 bytes to an output buffer.
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param anInt the integer to write
*/
void writePacketId(unsigned char** pptr, uint16_t anInt) {
**pptr = (unsigned char)(anInt / 256);
(*pptr)++;
**pptr = (unsigned char)(anInt % 256);
(*pptr)++;
}
/**
* Writes an integer as 2 bytes to an output buffer.
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param anInt the integer to write
*/
void writeInt(unsigned char **pptr, int32_t anInt) {
**pptr = (unsigned char)(anInt / 256);
(*pptr)++;
**pptr = (unsigned char)(anInt % 256);
(*pptr)++;
}
/**
* Writes size as 2 bytes to an output buffer.
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param anInt the integer to write
*/
void writeSizeT(unsigned char **pptr, size_t size) {
**pptr = (unsigned char)(size / 256);
(*pptr)++;
**pptr = (unsigned char)(size % 256);
(*pptr)++;
}
/**
* Writes a "UTF" string to an output buffer. Converts C string to length-delimited.
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param string the C string to write
*/
void writeCString(unsigned char **pptr, const char *string) {
size_t len = strlen(string);
writeSizeT(pptr, len);
memcpy(*pptr, string, len);
*pptr += len;
}
void writeMQTTString(unsigned char **pptr, MQTTString mqttstring) {
if(mqttstring.lenstring.len > 0) {
writeSizeT(pptr, mqttstring.lenstring.len);
memcpy(*pptr, mqttstring.lenstring.data, mqttstring.lenstring.len);
*pptr += mqttstring.lenstring.len;
} else if (mqttstring.cstring) {
writeCString(pptr, mqttstring.cstring);
} else {
writeInt(pptr, 0);
}
}
/**
* @param mqttstring the MQTTString structure into which the data is to be read
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param enddata pointer to the end of the data: do not read beyond
* @return SUCCESS if successful, FAILURE if not
*/
MQTTReturnCode readMQTTLenString(MQTTString *mqttstring, unsigned char **pptr, unsigned char *enddata) {
MQTTReturnCode rc = FAILURE;
FUNC_ENTRY;
/* the first two bytes are the length of the string */
/* enough length to read the integer? */
if(enddata - (*pptr) > 1) {
mqttstring->lenstring.len = readSizeT(pptr); /* increments pptr to point past length */
if(&(*pptr)[mqttstring->lenstring.len] <= enddata) {
mqttstring->lenstring.data = (char*)*pptr;
*pptr += mqttstring->lenstring.len;
rc = SUCCESS;
}
}
mqttstring->cstring = NULL;
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Return the length of the MQTTstring - C string if there is one, otherwise the length delimited string
* @param mqttstring the string to return the length of
* @return the length of the string
*/
size_t MQTTstrlen(MQTTString mqttstring) {
size_t len = 0;
if(mqttstring.cstring) {
len = strlen(mqttstring.cstring);
} else {
len = mqttstring.lenstring.len;
}
return len;
}
/**
* Compares an MQTTString to a C string
* @param a the MQTTString to compare
* @param bptr the C string to compare
* @return boolean - equal or not
*/
uint8_t MQTTPacket_equals(MQTTString *a, char *bptr) {
size_t alen = 0;
size_t blen = 0;
char *aptr;
if(a->cstring) {
aptr = a->cstring;
alen = strlen(a->cstring);
} else {
aptr = a->lenstring.data;
alen = a->lenstring.len;
}
blen = strlen(bptr);
return (alen == blen) && (strncmp(aptr, bptr, alen) == 0);
}
/**
* Initialize the MQTTHeader structure. Used to ensure that Header bits are
* always initialized using the proper mappings. No Endianness issues here since
* the individual fields are all less than a byte. Also generates no warnings since
* all fields are initialized using hex constants
*/
MQTTReturnCode MQTTPacket_InitHeader(MQTTHeader *header, MessageTypes message_type,
QoS qos, uint8_t dup, uint8_t retained) {
if(NULL == header) {
return MQTT_NULL_VALUE_ERROR;
}
/* Set all bits to zero */
header->byte = 0;
switch(message_type) {
case UNKNOWN:
/* Should never happen */
return MQTT_UNKNOWN_ERROR;
case CONNECT:
header->bits.type = 0x01;
break;
case CONNACK:
header->bits.type = 0x02;
break;
case PUBLISH:
header->bits.type = 0x03;
break;
case PUBACK:
header->bits.type = 0x04;
break;
case PUBREC:
header->bits.type = 0x05;
break;
case PUBREL:
header->bits.type = 0x06;
break;
case PUBCOMP:
header->bits.type = 0x07;
break;
case SUBSCRIBE:
header->bits.type = 0x08;
break;
case SUBACK:
header->bits.type = 0x09;
break;
case UNSUBSCRIBE:
header->bits.type = 0x0A;
break;
case UNSUBACK:
header->bits.type = 0x0B;
break;
case PINGREQ:
header->bits.type = 0x0C;
break;
case PINGRESP:
header->bits.type = 0x0D;
break;
case DISCONNECT:
header->bits.type = 0x0E;
break;
default:
/* Should never happen */
return MQTT_UNKNOWN_ERROR;
}
header->bits.dup = (1 == dup) ? 0x01 : 0x00;
switch(qos) {
case QOS0:
header->bits.qos = 0x00;
break;
case QOS1:
header->bits.qos = 0x01;
break;
case QOS2:
header->bits.qos = 0x02;
break;
default:
/* Using QOS0 as default */
header->bits.qos = 0x00;
break;
}
header->bits.retain = (1 == retained) ? 0x01 : 0x00;
return SUCCESS;
}

View File

@@ -1,116 +0,0 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
#ifndef MQTTPACKET_H_
#define MQTTPACKET_H_
#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
extern "C" {
#endif
#if defined(WIN32_DLL) || defined(WIN64_DLL)
#define DLLImport __declspec(dllimport)
#define DLLExport __declspec(dllexport)
#elif defined(LINUX_SO)
#define DLLImport extern
#define DLLExport __attribute__ ((visibility ("default")))
#else
#define DLLImport
#define DLLExport
#endif
#include "stdint.h"
#include "stddef.h"
#include "MQTTReturnCodes.h"
#include "MQTTMessage.h"
/**
* Bitfields for the MQTT header byte.
*/
typedef union {
unsigned char byte; /**< the whole byte */
#if defined(REVERSED)
struct {
unsigned int type : 4; /**< message type nibble */
unsigned int dup : 1; /**< DUP flag bit */
unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
unsigned int retain : 1; /**< retained flag bit */
} bits;
#else
struct {
unsigned int retain : 1; /**< retained flag bit */
unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
unsigned int dup : 1; /**< DUP flag bit */
unsigned int type : 4; /**< message type nibble */
} bits;
#endif
} MQTTHeader;
typedef struct {
size_t len;
char *data;
} MQTTLenString;
typedef struct {
char *cstring;
MQTTLenString lenstring;
} MQTTString;
#define MQTTString_initializer {NULL, {0, NULL}}
MQTTReturnCode MQTTPacket_InitHeader(MQTTHeader *header, MessageTypes message_type,
QoS qos, uint8_t dup, uint8_t retained);
size_t MQTTstrlen(MQTTString mqttstring);
#include "MQTTConnect.h"
#include "MQTTPublish.h"
#include "MQTTSubscribe.h"
#include "MQTTUnsubscribe.h"
MQTTReturnCode MQTTSerialize_ack(unsigned char *buf, size_t buflen,
unsigned char type, unsigned char dup, uint16_t packetid,
uint32_t *serialized_len);
MQTTReturnCode MQTTDeserialize_ack(unsigned char *packettype, unsigned char *dup,
uint16_t *packetid, unsigned char *buf,
size_t buflen);
size_t MQTTPacket_len(size_t rem_len);
uint8_t MQTTPacket_equals(MQTTString *a, char *bptr);
uint32_t MQTTPacket_encode(unsigned char *buf, size_t length);
MQTTReturnCode MQTTPacket_decode(uint32_t (*getcharfn)(unsigned char *, uint32_t), uint32_t *value, uint32_t *readBytesLen);
MQTTReturnCode MQTTPacket_decodeBuf(unsigned char *buf, uint32_t *value, uint32_t *readBytesLen);
uint16_t readPacketId(unsigned char **pptr);
void writePacketId(unsigned char** pptr, uint16_t anInt);
int32_t readInt(unsigned char **pptr);
size_t readSizeT(unsigned char **pptr);
unsigned char readChar(unsigned char **pptr);
void writeChar(unsigned char **pptr, unsigned char c);
void writeInt(unsigned char **pptr, int32_t anInt);
void writeSizeT(unsigned char **pptr, size_t size);
MQTTReturnCode readMQTTLenString(MQTTString *mqttstring, unsigned char **pptr, unsigned char *enddata);
void writeCString(unsigned char **pptr, const char *string);
void writeMQTTString(unsigned char **pptr, MQTTString mqttstring);
#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
}
#endif
#endif /* MQTTPACKET_H_ */

View File

@@ -1,48 +0,0 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
#ifndef MQTTPUBLISH_H_
#define MQTTPUBLISH_H_
#if !defined(DLLImport)
#define DLLImport
#endif
#if !defined(DLLExport)
#define DLLExport
#endif
#include "MQTTMessage.h"
DLLExport MQTTReturnCode MQTTSerialize_publish(unsigned char *buf, size_t buflen, uint8_t dup,
QoS qos, uint8_t retained, uint16_t packetid,
MQTTString topicName, unsigned char *payload, size_t payloadlen,
uint32_t *serialized_len);
DLLExport MQTTReturnCode MQTTDeserialize_publish(unsigned char *dup, QoS *qos,
unsigned char *retained, uint16_t *packetid,
MQTTString* topicName, unsigned char **payload,
uint32_t *payloadlen, unsigned char *buf, size_t buflen);
DLLExport MQTTReturnCode MQTTSerialize_puback(unsigned char* buf, size_t buflen,
uint16_t packetid, uint32_t *serialized_len);
DLLExport MQTTReturnCode MQTTSerialize_pubrel(unsigned char *buf, size_t buflen,
unsigned char dup, uint16_t packetid,
uint32_t *serialized_len);
DLLExport MQTTReturnCode MQTTSerialize_pubcomp(unsigned char *buf, size_t buflen,
uint16_t packetid, uint32_t *serialized_len);
#endif /* MQTTPUBLISH_H_ */

View File

@@ -1,52 +0,0 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/**
* @file MQTTErrorCodes.h
* @brief Definition of error types for the MQTT Client
*/
#ifndef __MQTT_ERRORCODES_H
#define __MQTT_ERRORCODES_H
/* all failure return codes must be negative */
typedef enum {
MQTT_NETWORK_MANUALLY_DISCONNECTED = 5,
MQTT_CONNACK_CONNECTION_ACCEPTED = 4,
MQTT_ATTEMPTING_RECONNECT = 3,
MQTT_NOTHING_TO_READ = 2,
MQTT_NETWORK_RECONNECTED = 1,
SUCCESS = 0,
FAILURE = -1,
BUFFER_OVERFLOW = -2,
MQTT_UNKNOWN_ERROR = -3,
MQTT_NETWORK_DISCONNECTED_ERROR = -4,
MQTT_NETWORK_ALREADY_CONNECTED_ERROR = -5,
MQTT_NULL_VALUE_ERROR = -6,
MQTT_MAX_SUBSCRIPTIONS_REACHED_ERROR = -7,
MQTT_RECONNECT_TIMED_OUT = -8,
MQTTPACKET_BUFFER_TOO_SHORT = -9,
MQTTPACKET_READ_ERROR = -10,
MQTTPACKET_READ_COMPLETE = -11,
MQTT_CONNACK_UNKNOWN_ERROR = -12,
MQTT_CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR = -13,
MQTT_CONNACK_IDENTIFIER_REJECTED_ERROR = -14,
MQTT_CONNACK_SERVER_UNAVAILABLE_ERROR = -15,
MQTT_CONNACK_BAD_USERDATA_ERROR = -16,
MQTT_CONNACK_NOT_AUTHORIZED_ERROR = -17,
MQTT_BUFFER_RX_MESSAGE_INVALID = -18
}MQTTReturnCode;
#endif //__MQTT_ERRORCODES_H

View File

@@ -1,184 +0,0 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Ian Craggs - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=453144
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Determines the length of the MQTT publish packet that would be produced using the supplied parameters
* @param qos the MQTT QoS of the publish (packetid is omitted for QoS 0)
* @param topicName the topic name to be used in the publish
* @param payloadlen the length of the payload to be sent
* @return the length of buffer needed to contain the serialized version of the packet
*/
size_t MQTTSerialize_GetPublishLength(uint8_t qos, MQTTString topicName, size_t payloadlen) {
size_t len = 0;
len += 2 + MQTTstrlen(topicName) + payloadlen;
if(qos > 0) {
len += 2; /* packetid */
}
return len;
}
/**
* Serializes the supplied publish data into the supplied buffer, ready for sending
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param dup integer - the MQTT dup flag
* @param qos integer - the MQTT QoS value
* @param retained integer - the MQTT retained flag
* @param packetid integer - the MQTT packet identifier
* @param topicName MQTTString - the MQTT topic in the publish
* @param payload byte buffer - the MQTT publish payload
* @param payloadlen integer - the length of the MQTT payload
* @return the length of the serialized data. <= 0 indicates error
*/
MQTTReturnCode MQTTSerialize_publish(unsigned char *buf, size_t buflen, uint8_t dup,
QoS qos, uint8_t retained, uint16_t packetid,
MQTTString topicName, unsigned char *payload, size_t payloadlen,
uint32_t *serialized_len) {
unsigned char *ptr = buf;
MQTTHeader header = {0};
size_t rem_len = 0;
MQTTReturnCode rc = MQTTPacket_InitHeader(&header, PUBLISH, qos, dup, retained);
FUNC_ENTRY;
if(NULL == buf || NULL == payload || NULL == serialized_len) {
FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
return MQTT_NULL_VALUE_ERROR;
}
rem_len = MQTTSerialize_GetPublishLength(qos, topicName, payloadlen);
if(MQTTPacket_len(rem_len) > buflen) {
FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
return MQTTPACKET_BUFFER_TOO_SHORT;
}
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
return rc;
}
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
writeMQTTString(&ptr, topicName);
if(qos > 0) {
writeInt(&ptr, packetid);
}
memcpy(ptr, payload, payloadlen);
ptr += payloadlen;
*serialized_len = (uint32_t)(ptr - buf);
FUNC_EXIT_RC(SUCCESS);
return SUCCESS;
}
/**
* Serializes the ack packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param type the MQTT packet type
* @param dup the MQTT dup flag
* @param packetid the MQTT packet identifier
* @return serialized length, or error if 0
*/
MQTTReturnCode MQTTSerialize_ack(unsigned char *buf, size_t buflen,
unsigned char type, uint8_t dup, uint16_t packetid,
uint32_t *serialized_len) {
MQTTHeader header = {0};
unsigned char *ptr = buf;
QoS requestQoS = (PUBREL == type) ? QOS1 : QOS0;
MQTTReturnCode rc = MQTTPacket_InitHeader(&header, type, requestQoS, dup, 0);
FUNC_ENTRY;
if(NULL == buf || serialized_len == NULL) {
FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
return MQTT_NULL_VALUE_ERROR;
}
/* Minimum byte length required by ACK headers is
* 2 for fixed and 2 for variable part */
if(4 > buflen) {
FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
return MQTTPACKET_BUFFER_TOO_SHORT;
}
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
return rc;
}
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
writePacketId(&ptr, packetid);
*serialized_len = (uint32_t)(ptr - buf);
FUNC_EXIT_RC(SUCCESS);
return SUCCESS;
}
/**
* Serializes a puback packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param packetid integer - the MQTT packet identifier
* @return serialized length, or error if 0
*/
MQTTReturnCode MQTTSerialize_puback(unsigned char* buf, size_t buflen,
uint16_t packetid, uint32_t *serialized_len) {
return MQTTSerialize_ack(buf, buflen, PUBACK, 0, packetid, serialized_len);
}
/**
* Serializes a pubrel packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param dup integer - the MQTT dup flag
* @param packetid integer - the MQTT packet identifier
* @return serialized length, or error if 0
*/
MQTTReturnCode MQTTSerialize_pubrel(unsigned char *buf, size_t buflen,
unsigned char dup, uint16_t packetid,
uint32_t *serialized_len) {
return MQTTSerialize_ack(buf, buflen, PUBREL, dup, packetid, serialized_len);
}
/**
* Serializes a pubrel packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param packetid integer - the MQTT packet identifier
* @return serialized length, or error if 0
*/
MQTTReturnCode MQTTSerialize_pubcomp(unsigned char *buf, size_t buflen,
uint16_t packetid, uint32_t *serialized_len) {
return MQTTSerialize_ack(buf, buflen, PUBCOMP, 0, packetid, serialized_len);
}

View File

@@ -1,38 +0,0 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
#ifndef MQTTSUBSCRIBE_H_
#define MQTTSUBSCRIBE_H_
#if !defined(DLLImport)
#define DLLImport
#endif
#if !defined(DLLExport)
#define DLLExport
#endif
DLLExport MQTTReturnCode MQTTSerialize_subscribe(unsigned char *buf, size_t buflen,
unsigned char dup, uint16_t packetid, uint32_t count,
MQTTString topicFilters[], QoS requestedQoSs[],
uint32_t *serialized_len);
DLLExport MQTTReturnCode MQTTDeserialize_suback(uint16_t *packetid, uint32_t maxcount,
uint32_t *count, QoS grantedQoSs[],
unsigned char* buf, size_t buflen);
#endif /* MQTTSUBSCRIBE_H_ */

View File

@@ -1,159 +0,0 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Determines the length of the MQTT subscribe packet that would be produced using the supplied parameters
* @param count the number of topic filter strings in topicFilters
* @param topicFilters the array of topic filter strings to be used in the publish
* @return the length of buffer needed to contain the serialized version of the packet
*/
size_t MQTTSerialize_GetSubscribePacketLength(uint32_t count, MQTTString topicFilters[]) {
size_t i;
size_t len = 2; /* packetid */
for(i = 0; i < count; ++i) {
len += 2 + MQTTstrlen(topicFilters[i]) + 1; /* length + topic + req_qos */
}
return len;
}
/**
* Serializes the supplied subscribe data into the supplied buffer, ready for sending
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied bufferr
* @param dup integer - the MQTT dup flag
* @param packetid integer - the MQTT packet identifier
* @param count - number of members in the topicFilters and reqQos arrays
* @param topicFilters - array of topic filter names
* @param requestedQoSs - array of requested QoS
* @return the length of the serialized data. <= 0 indicates error
*/
MQTTReturnCode MQTTSerialize_subscribe(unsigned char *buf, size_t buflen,
unsigned char dup, uint16_t packetid, uint32_t count,
MQTTString topicFilters[], QoS requestedQoSs[],
uint32_t *serialized_len) {
unsigned char *ptr = buf;
MQTTHeader header = {0};
size_t rem_len = 0;
uint32_t i = 0;
MQTTReturnCode rc = MQTTPacket_InitHeader(&header, SUBSCRIBE, 1, dup, 0);
FUNC_ENTRY;
if(NULL == buf || NULL == serialized_len) {
FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
return MQTT_NULL_VALUE_ERROR;
}
if(MQTTPacket_len(rem_len = MQTTSerialize_GetSubscribePacketLength(count, topicFilters)) > buflen) {
FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
return MQTTPACKET_BUFFER_TOO_SHORT;
}
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
return rc;
}
/* write header */
writeChar(&ptr, header.byte);
/* write remaining length */
ptr += MQTTPacket_encode(ptr, rem_len);
writePacketId(&ptr, packetid);
for(i = 0; i < count; ++i) {
writeMQTTString(&ptr, topicFilters[i]);
writeChar(&ptr, (unsigned char)requestedQoSs[i]);
}
*serialized_len = (uint32_t)(ptr - buf);
FUNC_EXIT_RC(SUCCESS);
return SUCCESS;
}
/**
* Deserializes the supplied (wire) buffer into suback data
* @param packetid returned integer - the MQTT packet identifier
* @param maxcount - the maximum number of members allowed in the grantedQoSs array
* @param count returned integer - number of members in the grantedQoSs array
* @param grantedQoSs returned array of integers - the granted qualities of service
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return error code. 1 is success, 0 is failure
*/
MQTTReturnCode MQTTDeserialize_suback(uint16_t *packetid, uint32_t maxcount,
uint32_t *count, QoS grantedQoSs[],
unsigned char *buf, size_t buflen) {
MQTTHeader header = {0};
unsigned char *curdata = buf;
unsigned char *enddata = NULL;
MQTTReturnCode decodeRc = FAILURE;
uint32_t decodedLen = 0;
uint32_t readBytesLen = 0;
FUNC_ENTRY;
if(NULL == packetid || NULL == count || NULL == grantedQoSs) {
FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
return MQTT_NULL_VALUE_ERROR;
}
/* SUBACK header size is 4 bytes for header and at least one byte for QoS payload
* Need at least a 5 bytes buffer. MQTT3.1.1 specification 3.9
*/
if(5 > buflen) {
FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
return MQTTPACKET_BUFFER_TOO_SHORT;
}
header.byte = readChar(&curdata);
if (header.bits.type != SUBACK) {
FUNC_EXIT_RC(FAILURE);
return FAILURE;
}
/* read remaining length */
decodeRc = MQTTPacket_decodeBuf(curdata, &decodedLen, &readBytesLen);
if(decodeRc != SUCCESS) {
return decodeRc;
}
curdata += (readBytesLen);
enddata = curdata + decodedLen;
if (enddata - curdata < 2) {
FUNC_EXIT_RC(FAILURE);
return FAILURE;
}
*packetid = readPacketId(&curdata);
*count = 0;
while(curdata < enddata) {
if(*count > maxcount) {
FUNC_EXIT_RC(FAILURE);
return FAILURE;
}
grantedQoSs[(*count)++] = (QoS)readChar(&curdata);
}
FUNC_EXIT_RC(SUCCESS);
return SUCCESS;
}

View File

@@ -1,35 +0,0 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
#ifndef MQTTUNSUBSCRIBE_H_
#define MQTTUNSUBSCRIBE_H_
#if !defined(DLLImport)
#define DLLImport
#endif
#if !defined(DLLExport)
#define DLLExport
#endif
DLLExport MQTTReturnCode MQTTSerialize_unsubscribe(unsigned char* buf, size_t buflen,
uint8_t dup, uint16_t packetid,
uint32_t count, MQTTString topicFilters[],
uint32_t *serialized_len);
DLLExport MQTTReturnCode MQTTDeserialize_unsuback(uint16_t *packetid, unsigned char *buf, size_t buflen);
#endif /* MQTTUNSUBSCRIBE_H_ */

View File

@@ -1,118 +0,0 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Determines the length of the MQTT unsubscribe packet that would be produced using the supplied parameters
* @param count the number of topic filter strings in topicFilters
* @param topicFilters the array of topic filter strings to be used in the publish
* @return the length of buffer needed to contain the serialized version of the packet
*/
size_t MQTTSerialize_GetUnsubscribePacketLength(uint32_t count, MQTTString topicFilters[]) {
size_t i;
size_t len = 2; /* packetid */
for(i = 0; i < count; ++i) {
len += 2 + MQTTstrlen(topicFilters[i]); /* length + topic*/
}
return len;
}
/**
* Serializes the supplied unsubscribe data into the supplied buffer, ready for sending
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @param dup integer - the MQTT dup flag
* @param packetid integer - the MQTT packet identifier
* @param count - number of members in the topicFilters array
* @param topicFilters - array of topic filter names
* @param serialized_len - the length of the serialized data
* @return MQTTReturnCode indicating function execution status
*/
MQTTReturnCode MQTTSerialize_unsubscribe(unsigned char* buf, size_t buflen,
uint8_t dup, uint16_t packetid,
uint32_t count, MQTTString topicFilters[],
uint32_t *serialized_len) {
unsigned char *ptr = buf;
MQTTHeader header = {0};
size_t rem_len = 0;
uint32_t i = 0;
MQTTReturnCode rc = MQTTPacket_InitHeader(&header, UNSUBSCRIBE, 1, dup, 0);
FUNC_ENTRY;
if(NULL == buf || NULL == serialized_len) {
FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
return MQTT_NULL_VALUE_ERROR;
}
rem_len = MQTTSerialize_GetUnsubscribePacketLength(count, topicFilters);
if(MQTTPacket_len(rem_len) > buflen) {
FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
return MQTTPACKET_BUFFER_TOO_SHORT;
}
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
return rc;
}
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */
writePacketId(&ptr, packetid);
for(i = 0; i < count; ++i) {
writeMQTTString(&ptr, topicFilters[i]);
}
*serialized_len = (uint32_t)(ptr - buf);
FUNC_EXIT_RC(SUCCESS);
return SUCCESS;
}
/**
* Deserializes the supplied (wire) buffer into unsuback data
* @param packetid returned integer - the MQTT packet identifier
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return MQTTReturnCode indicating function execution status
*/
MQTTReturnCode MQTTDeserialize_unsuback(uint16_t *packetid, unsigned char *buf, size_t buflen) {
unsigned char type = 0;
unsigned char dup = 0;
MQTTReturnCode rc = FAILURE;
FUNC_ENTRY;
if(NULL == packetid || NULL == buf) {
FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
return MQTT_NULL_VALUE_ERROR;
}
rc = MQTTDeserialize_ack(&type, &dup, packetid, buf, buflen);
if(SUCCESS == rc && UNSUBACK != type) {
rc = FAILURE;
}
FUNC_EXIT_RC(rc);
return rc;
}

View File

@@ -1,78 +0,0 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Ian Craggs - fix for bug #434081
*******************************************************************************/
#ifndef STACKTRACE_H_
#define STACKTRACE_H_
#include <stdio.h>
#define NOSTACKTRACE 1
#if defined(NOSTACKTRACE)
#define FUNC_ENTRY
#define FUNC_ENTRY_NOLOG
#define FUNC_ENTRY_MED
#define FUNC_ENTRY_MAX
#define FUNC_EXIT
#define FUNC_EXIT_NOLOG
#define FUNC_EXIT_MED
#define FUNC_EXIT_MAX
#define FUNC_EXIT_RC(x)
#define FUNC_EXIT_MED_RC(x)
#define FUNC_EXIT_MAX_RC(x)
#else
#if defined(WIN32)
#define inline __inline
#define FUNC_ENTRY StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MINIMUM)
#define FUNC_ENTRY_NOLOG StackTrace_entry(__FUNCTION__, __LINE__, -1)
#define FUNC_ENTRY_MED StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MEDIUM)
#define FUNC_ENTRY_MAX StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MAXIMUM)
#define FUNC_EXIT StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MINIMUM)
#define FUNC_EXIT_NOLOG StackTrace_exit(__FUNCTION__, __LINE__, -1)
#define FUNC_EXIT_MED StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MEDIUM)
#define FUNC_EXIT_MAX StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MAXIMUM)
#define FUNC_EXIT_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MINIMUM)
#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MEDIUM)
#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MAXIMUM)
#else
#define FUNC_ENTRY StackTrace_entry(__func__, __LINE__, TRACE_MINIMUM)
#define FUNC_ENTRY_NOLOG StackTrace_entry(__func__, __LINE__, -1)
#define FUNC_ENTRY_MED StackTrace_entry(__func__, __LINE__, TRACE_MEDIUM)
#define FUNC_ENTRY_MAX StackTrace_entry(__func__, __LINE__, TRACE_MAXIMUM)
#define FUNC_EXIT StackTrace_exit(__func__, __LINE__, NULL, TRACE_MINIMUM)
#define FUNC_EXIT_NOLOG StackTrace_exit(__func__, __LINE__, NULL, -1)
#define FUNC_EXIT_MED StackTrace_exit(__func__, __LINE__, NULL, TRACE_MEDIUM)
#define FUNC_EXIT_MAX StackTrace_exit(__func__, __LINE__, NULL, TRACE_MAXIMUM)
#define FUNC_EXIT_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MINIMUM)
#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MEDIUM)
#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MAXIMUM)
void StackTrace_entry(const char* name, int line, int trace);
void StackTrace_exit(const char* name, int line, void* return_value, int trace);
void StackTrace_printStack(FILE* dest);
char* StackTrace_get(unsigned long);
#endif
#endif
#endif /* STACKTRACE_H_ */

View File

@@ -1,37 +0,0 @@
# Eclipse Paho MQTT C/C++ client for Embedded platforms
This repository contains the source code for the [Eclipse Paho](http://eclipse.org/paho) MQTT C/C++ client library for Embedded platorms.
It is dual licensed under the EPL and EDL (see about.html and notice.html for more details). You can choose which of these licenses you want to use the code under. The EDL allows you to embed the code into your application, and distribute your application in binary or source form without contributing any of your code, or any changes you make back to Paho. See the EDL for the exact conditions.
The MQTTPacket directory contains the lowest level C library with the smallest requirements. This supplies simple serialization
and deserialization routines. It is mainly up to you to write and read to and from the network.
The MQTTClient directory contains the next level C++ library. This still avoids most networking code so that you can plugin the
network of your choice.
## Build requirements / compilation
There are helper scripts (build...) in various directories. The client library is a set of building blocks which you pick and choose from, so that the smallest MQTT application can be built.
## Usage and API
See the samples directory for examples of intended use.
## Runtime tracing
As yet, there is no tracing. For the smallest client, should we have tracing?
## Reporting bugs
Please report bugs under the "MQTT-Embedded-C" Component in [Eclipse Bugzilla](http://bugs.eclipse.org/bugs/) for the Paho Technology project.
## More information
Discussion of the Paho clients takes place on the [Eclipse paho-dev mailing list](https://dev.eclipse.org/mailman/listinfo/paho-dev).
General questions about the MQTT protocol are discussed in the [MQTT Google Group](https://groups.google.com/forum/?hl=en-US&fromgroups#!forum/mqtt).
There is much more information available via the [MQTT community site](http://mqtt.org).

View File

@@ -1,28 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>About</title>
</head>
<body lang="EN-US">
<h2>About This Content</h2>
<p><em>December 9, 2013</em></p>
<h3>License</h3>
<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
indicated below, the Content is provided to you under the terms and conditions of the
Eclipse Public License Version 1.0 ("EPL") and Eclipse Distribution License Version 1.0 ("EDL").
A copy of the EPL is available at
<a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>
and a copy of the EDL is available at
<a href="http://www.eclipse.org/org/documents/edl-v10.php">http://www.eclipse.org/org/documents/edl-v10.php</a>.
For purposes of the EPL, "Program" will mean the Content.</p>
<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
being redistributed by another party ("Redistributor") and different terms and conditions may
apply to your use of any object code in the Content. Check the Redistributor's license that was
provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
indicated below, the terms and conditions of the EPL still apply to any source code in the Content
and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
</body></html>

View File

@@ -1,15 +0,0 @@
Eclipse Distribution License - v 1.0
Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of the Eclipse Foundation, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,70 +0,0 @@
Eclipse Public License - v 1.0
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
1. DEFINITIONS
"Contribution" means:
a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
b) in the case of each subsequent Contributor:
i) changes to the Program, and
ii) additions to the Program;
where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.
"Contributor" means any person or entity that distributes the Program.
"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.
"Program" means the Contributions distributed in accordance with this Agreement.
"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.
2. GRANT OF RIGHTS
a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.
b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
3. REQUIREMENTS
A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
a) it complies with the terms and conditions of this Agreement; and
b) its license agreement:
i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.
When the Program is made available in source code form:
a) it must be made available under this Agreement; and
b) a copy of this Agreement must be included with each copy of the Program.
Contributors may not remove or alter any copyright notices contained within the Program.
Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.
4. COMMERCIAL DISTRIBUTION
Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.
For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.
5. NO WARRANTY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.
6. DISCLAIMER OF LIABILITY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. GENERAL
If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.
All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.
Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.
This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.

View File

@@ -1,108 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Eclipse Foundation Software User Agreement</title>
</head>
<body lang="EN-US">
<h2>Eclipse Foundation Software User Agreement</h2>
<p>February 1, 2011</p>
<h3>Usage Of Content</h3>
<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
(COLLECTIVELY &quot;CONTENT&quot;). USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE
OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
<h3>Applicable Licenses</h3>
<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
(&quot;EPL&quot;). A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
repository (&quot;Repository&quot;) in software modules (&quot;Modules&quot;) and made available as downloadable archives (&quot;Downloads&quot;).</p>
<ul>
<li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical modules may include plug-ins (&quot;Plug-ins&quot;), plug-in fragments (&quot;Fragments&quot;), and features (&quot;Features&quot;).</li>
<li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java&trade; ARchive) in a directory named &quot;plugins&quot;.</li>
<li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material. Each Feature may be packaged as a sub-directory in a directory named &quot;features&quot;. Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of the Plug-ins
and/or Fragments associated with that Feature.</li>
<li>Features may also include other Features (&quot;Included Features&quot;). Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of Included Features.</li>
</ul>
<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named &quot;about.html&quot; (&quot;Abouts&quot;). The terms and conditions governing Features and
Included Features should be contained in files named &quot;license.html&quot; (&quot;Feature Licenses&quot;). Abouts and Feature Licenses may be located in any directory of a Download or Module
including, but not limited to the following locations:</p>
<ul>
<li>The top-level (root) directory</li>
<li>Plug-in and Fragment directories</li>
<li>Inside Plug-ins and Fragments packaged as JARs</li>
<li>Sub-directories of the directory named &quot;src&quot; of certain Plug-ins</li>
<li>Feature directories</li>
</ul>
<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license (&quot;Feature Update License&quot;) during the
installation process. If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
inform you where you can locate them. Feature Update Licenses may be found in the &quot;license&quot; property of files named &quot;feature.properties&quot; found within a Feature.
Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
that directory.</p>
<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE
OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
<ul>
<li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
<li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
<li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
<li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
<li>Metro Link Public License 1.00 (available at <a href="http://www.opengroup.org/openmotif/supporters/metrolink/license.html">http://www.opengroup.org/openmotif/supporters/metrolink/license.html</a>)</li>
<li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
</ul>
<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please
contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p>
<h3>Use of Provisioning Technology</h3>
<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
Update Manager (&quot;Provisioning Technology&quot;) for the purpose of allowing users to install software, documentation, information and/or
other materials (collectively &quot;Installable Software&quot;). This capability is provided with the intent of allowing such users to
install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a
href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
(&quot;Specification&quot;).</p>
<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p>
<ol>
<li>A series of actions may occur (&quot;Provisioning Process&quot;) in which a user may execute the Provisioning Technology
on a machine (&quot;Target Machine&quot;) with the intent of installing, extending or updating the functionality of an Eclipse-based
product.</li>
<li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
accessed and copied to the Target Machine.</li>
<li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
Software (&quot;Installable Software Agreement&quot;) and such Installable Software Agreement shall be accessed from the Target
Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li>
</ol>
<h3>Cryptography</h3>
<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
possession, or use, and re-export of encryption software, to see if this is permitted.</p>
<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
</body>
</html>

View File

@@ -0,0 +1 @@
# Copy source code for mbedTLS into this directory

152
include/aws_iot_error.h Normal file
View File

@@ -0,0 +1,152 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/**
* @file aws_iot_error.h
* @brief Definition of error types for the SDK.
*/
#ifndef AWS_IOT_SDK_SRC_IOT_ERROR_H_
#define AWS_IOT_SDK_SRC_IOT_ERROR_H_
/* Used to avoid warnings in case of unused parameters in function pointers */
#define IOT_UNUSED(x) (void)(x)
/*! \public
* @brief IoT Error enum
*
* Enumeration of return values from the IoT_* functions within the SDK.
* Values less than -1 are specific error codes
* Value of -1 is a generic failure response
* Value of 0 is a generic success response
* Values greater than 0 are specific non-error return codes
*/
typedef enum {
/** Returned when the Network physical layer is connected */
NETWORK_PHYSICAL_LAYER_CONNECTED = 6,
/** Returned when the Network is manually disconnected */
NETWORK_MANUALLY_DISCONNECTED = 5,
/** Returned when the Network is disconnected and the reconnect attempt is in progress */
NETWORK_ATTEMPTING_RECONNECT = 4,
/** Return value of yield function to indicate auto-reconnect was successful */
NETWORK_RECONNECTED = 3,
/** Returned when a read attempt is made on the TLS buffer and it is empty */
MQTT_NOTHING_TO_READ = 2,
/** Returned when a connection request is successful and packet response is connection accepted */
MQTT_CONNACK_CONNECTION_ACCEPTED = 1,
/** Success return value - no error occurred */
SUCCESS = 0,
/** A generic error. Not enough information for a specific error code */
FAILURE = -1,
/** A required parameter was passed as null */
NULL_VALUE_ERROR = -2,
/** The TCP socket could not be established */
TCP_CONNECTION_ERROR = -3,
/** The TLS handshake failed */
SSL_CONNECTION_ERROR = -4,
/** Error associated with setting up the parameters of a Socket */
TCP_SETUP_ERROR =-5,
/** A timeout occurred while waiting for the TLS handshake to complete. */
NETWORK_SSL_CONNECT_TIMEOUT_ERROR = -6,
/** A Generic write error based on the platform used */
NETWORK_SSL_WRITE_ERROR = -7,
/** SSL initialization error at the TLS layer */
NETWORK_SSL_INIT_ERROR = -8,
/** An error occurred when loading the certificates. The certificates could not be located or are incorrectly formatted. */
NETWORK_SSL_CERT_ERROR= -9,
/** SSL Write times out */
NETWORK_SSL_WRITE_TIMEOUT_ERROR = -10,
/** SSL Read times out */
NETWORK_SSL_READ_TIMEOUT_ERROR = -11,
/** A Generic error based on the platform used */
NETWORK_SSL_READ_ERROR = -12,
/** Returned when the Network is disconnected and reconnect is either disabled or physical layer is disconnected */
NETWORK_DISCONNECTED_ERROR = -13,
/** Returned when the Network is disconnected and the reconnect attempt has timed out */
NETWORK_RECONNECT_TIMED_OUT_ERROR = -14,
/** Returned when the Network is already connected and a connection attempt is made */
NETWORK_ALREADY_CONNECTED_ERROR = -15,
/** Network layer Error Codes */
/** Network layer Random number generator seeding failed */
NETWORK_MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED = -16,
/** A generic error code for Network layer errors */
NETWORK_SSL_UNKNOWN_ERROR = -17,
/** Returned when the physical layer is disconnected */
NETWORK_PHYSICAL_LAYER_DISCONNECTED = -18,
/** Returned when the root certificate is invalid */
NETWORK_X509_ROOT_CRT_PARSE_ERROR = -19,
/** Returned when the device certificate is invalid */
NETWORK_X509_DEVICE_CRT_PARSE_ERROR = -20,
/** Returned when the private key failed to parse */
NETWORK_PK_PRIVATE_KEY_PARSE_ERROR = -21,
/** Returned when the network layer failed to open a socket */
NETWORK_ERR_NET_SOCKET_FAILED = -22,
/** Returned when the server is unknown */
NETWORK_ERR_NET_UNKNOWN_HOST = -23,
/** Returned when connect request failed */
NETWORK_ERR_NET_CONNECT_FAILED = -24,
/** Returned when there is nothing to read in the TLS read buffer */
NETWORK_SSL_NOTHING_TO_READ = -25,
/** A connection could not be established. */
MQTT_CONNECTION_ERROR = -26,
/** A timeout occurred while waiting for the TLS handshake to complete */
MQTT_CONNECT_TIMEOUT_ERROR = -27,
/** A timeout occurred while waiting for the TLS request complete */
MQTT_REQUEST_TIMEOUT_ERROR = -28,
/** The current client state does not match the expected value */
MQTT_UNEXPECTED_CLIENT_STATE_ERROR = -29,
/** The client state is not idle when request is being made */
MQTT_CLIENT_NOT_IDLE_ERROR = -30,
/** The MQTT RX buffer received corrupt or unexpected message */
MQTT_RX_MESSAGE_PACKET_TYPE_INVALID_ERROR = -31,
/** The MQTT RX buffer received a bigger message. The message will be dropped */
MQTT_RX_BUFFER_TOO_SHORT_ERROR = -32,
/** The MQTT TX buffer is too short for the outgoing message. Request will fail */
MQTT_TX_BUFFER_TOO_SHORT_ERROR = -33,
/** The client is subscribed to the maximum possible number of subscriptions */
MQTT_MAX_SUBSCRIPTIONS_REACHED_ERROR = -34,
/** Failed to decode the remaining packet length on incoming packet */
MQTT_DECODE_REMAINING_LENGTH_ERROR = -35,
/** Connect request failed with the server returning an unknown error */
MQTT_CONNACK_UNKNOWN_ERROR = -36,
/** Connect request failed with the server returning an unacceptable protocol version error */
MQTT_CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR = -37,
/** Connect request failed with the server returning an identifier rejected error */
MQTT_CONNACK_IDENTIFIER_REJECTED_ERROR = -38,
/** Connect request failed with the server returning an unavailable error */
MQTT_CONNACK_SERVER_UNAVAILABLE_ERROR = -39,
/** Connect request failed with the server returning a bad userdata error */
MQTT_CONNACK_BAD_USERDATA_ERROR = -40,
/** Connect request failed with the server failing to authenticate the request */
MQTT_CONNACK_NOT_AUTHORIZED_ERROR = -41,
/** An error occurred while parsing the JSON string. Usually malformed JSON. */
JSON_PARSE_ERROR = -42,
/** Shadow: The response Ack table is currently full waiting for previously published updates */
SHADOW_WAIT_FOR_PUBLISH = -43,
/** Any time an snprintf writes more than size value, this error will be returned */
SHADOW_JSON_BUFFER_TRUNCATED = -44,
/** Any time an snprintf encounters an encoding error or not enough space in the given buffer */
SHADOW_JSON_ERROR = -45,
/** Mutex initialization failed */
MUTEX_INIT_ERROR = -46,
/** Mutex lock request failed */
MUTEX_LOCK_ERROR = -47,
/** Mutex unlock request failed */
MUTEX_UNLOCK_ERROR = -48,
/** Mutex destroy failed */
MUTEX_DESTROY_ERROR = -49,
}IoT_Error_t;
#endif /* AWS_IOT_SDK_SRC_IOT_ERROR_H_ */

View File

@@ -55,7 +55,7 @@ int8_t jsoneq(const char *json, jsmntok_t *tok, const char *s);
* @param tok json token - pointer to JSON node
* @param i address of int32_t to be updated
*
* @return NONE_ERROR - success
* @return SUCCESS - success
* @return JSON_PARSE_ERROR - error parsing value
*/
IoT_Error_t parseInteger32Value(int32_t *i, const char *jsonString, jsmntok_t *token);
@@ -69,7 +69,7 @@ IoT_Error_t parseInteger32Value(int32_t *i, const char *jsonString, jsmntok_t *t
* @param tok json token - pointer to JSON node
* @param i address of int16_t to be updated
*
* @return NONE_ERROR - success
* @return SUCCESS - success
* @return JSON_PARSE_ERROR - error parsing value
*/
IoT_Error_t parseInteger16Value(int16_t *i, const char *jsonString, jsmntok_t *token);
@@ -83,7 +83,7 @@ IoT_Error_t parseInteger16Value(int16_t *i, const char *jsonString, jsmntok_t *t
* @param tok json token - pointer to JSON node
* @param i address of int8_t to be updated
*
* @return NONE_ERROR - success
* @return SUCCESS - success
* @return JSON_PARSE_ERROR - error parsing value
*/
IoT_Error_t parseInteger8Value(int8_t *i, const char *jsonString, jsmntok_t *token);
@@ -97,7 +97,7 @@ IoT_Error_t parseInteger8Value(int8_t *i, const char *jsonString, jsmntok_t *tok
* @param tok json token - pointer to JSON node
* @param i address of uint32_t to be updated
*
* @return NONE_ERROR - success
* @return SUCCESS - success
* @return JSON_PARSE_ERROR - error parsing value
*/
IoT_Error_t parseUnsignedInteger32Value(uint32_t *i, const char *jsonString, jsmntok_t *token);
@@ -111,7 +111,7 @@ IoT_Error_t parseUnsignedInteger32Value(uint32_t *i, const char *jsonString, jsm
* @param tok json token - pointer to JSON node
* @param i address of uint16_t to be updated
*
* @return NONE_ERROR - success
* @return SUCCESS - success
* @return JSON_PARSE_ERROR - error parsing value
*/
IoT_Error_t parseUnsignedInteger16Value(uint16_t *i, const char *jsonString, jsmntok_t *token);
@@ -125,7 +125,7 @@ IoT_Error_t parseUnsignedInteger16Value(uint16_t *i, const char *jsonString, jsm
* @param tok json token - pointer to JSON node
* @param i address of uint8_t to be updated
*
* @return NONE_ERROR - success
* @return SUCCESS - success
* @return JSON_PARSE_ERROR - error parsing value
*/
IoT_Error_t parseUnsignedInteger8Value(uint8_t *i, const char *jsonString, jsmntok_t *token);
@@ -139,7 +139,7 @@ IoT_Error_t parseUnsignedInteger8Value(uint8_t *i, const char *jsonString, jsmnt
* @param tok json token - pointer to JSON node
* @param f address of float to be updated
*
* @return NONE_ERROR - success
* @return SUCCESS - success
* @return JSON_PARSE_ERROR - error parsing value
*/
IoT_Error_t parseFloatValue(float *f, const char *jsonString, jsmntok_t *token);
@@ -153,7 +153,7 @@ IoT_Error_t parseFloatValue(float *f, const char *jsonString, jsmntok_t *token);
* @param tok json token - pointer to JSON node
* @param d address of double to be updated
*
* @return NONE_ERROR - success
* @return SUCCESS - success
* @return JSON_PARSE_ERROR - error parsing value
*/
IoT_Error_t parseDoubleValue(double *d, const char *jsonString, jsmntok_t *token);
@@ -167,7 +167,7 @@ IoT_Error_t parseDoubleValue(double *d, const char *jsonString, jsmntok_t *token
* @param tok json token - pointer to JSON node
* @param b address of boolean to be updated
*
* @return NONE_ERROR - success
* @return SUCCESS - success
* @return JSON_PARSE_ERROR - error parsing value
*/
IoT_Error_t parseBooleanValue(bool *b, const char *jsonString, jsmntok_t *token);
@@ -181,7 +181,7 @@ IoT_Error_t parseBooleanValue(bool *b, const char *jsonString, jsmntok_t *token)
* @param tok json token - pointer to JSON node
* @param s address of string to be updated
*
* @return NONE_ERROR - success
* @return SUCCESS - success
* @return JSON_PARSE_ERROR - error parsing value
*/
IoT_Error_t parseStringValue(char *buf, const char *jsonString, jsmntok_t *token);

View File

@@ -47,6 +47,31 @@
#define DEBUG(...)
#endif
/**
* @brief Debug level trace logging macro.
*
* Macro to print message function entry and exit
*/
#ifdef IOT_TRACE
#define FUNC_ENTRY \
{\
printf("FUNC_ENTRY: %s L#%d \n", __PRETTY_FUNCTION__, __LINE__); \
}
#define FUNC_EXIT \
{\
printf("FUNC_EXIT: %s L#%d \n", __PRETTY_FUNCTION__, __LINE__); \
}
#define FUNC_EXIT_RC(x) \
{\
printf("FUNC_EXIT: %s L#%d Return Code : %d \n", __PRETTY_FUNCTION__, __LINE__, x); \
return x; \
}
#else
#define FUNC_ENTRY
#define FUNC_EXIT
#define FUNC_EXIT_RC(x) { return x; }
#endif
/**
* @brief Info level logging macro.
*
@@ -94,4 +119,6 @@
#define ERROR(...)
#endif
#endif // _IOT_LOG_H

View File

@@ -0,0 +1,402 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
// Based on Eclipse Paho.
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
/**
* @file aws_iot_mqtt_client.h
* @brief Client definition for MQTT
*/
#ifndef AWS_IOT_SDK_SRC_IOT_MQTT_CLIENT_H
#define AWS_IOT_SDK_SRC_IOT_MQTT_CLIENT_H
/* Library Header files */
#include "stdio.h"
#include "stdbool.h"
#include "stdint.h"
#include "stddef.h"
/* AWS Specific header files */
#include "aws_iot_error.h"
#include "aws_iot_config.h"
/* Platform specific implementation header files */
#include "network_interface.h"
#include "timer_interface.h"
#ifdef _ENABLE_THREAD_SUPPORT_
#include "threads_interface.h"
#endif
#define MAX_PACKET_ID 65535
typedef struct _Client AWS_IoT_Client;
/**
* @brief Quality of Service Type
*
* Defining a QoS type.
* @note QoS 2 is \b NOT supported by the AWS IoT Service at the time of this SDK release.
*
*/
typedef enum QoS {
QOS0 = 0,
QOS1 = 1
} QoS;
/**
* @brief Publish Message Parameters Type
*
* Defines a type for MQTT Publish messages. Used for both incoming and out going messages
*
*/
typedef struct {
QoS qos; ///< Message Quality of Service
uint8_t isRetained; ///< Retained messages are \b NOT supported by the AWS IoT Service at the time of this SDK release.
uint8_t isDup; ///< Is this message a duplicate QoS > 0 message? Handled automatically by the MQTT client.
uint16_t id; ///< Message sequence identifier. Handled automatically by the MQTT client.
void *payload; ///< Pointer to MQTT message payload (bytes).
size_t payloadLen; ///< Length of MQTT payload.
} IoT_Publish_Message_Params;
/**
* @brief MQTT Version Type
*
* Defining an MQTT version type. Only 3.1.1 is supported at this time
*
*/
typedef enum {
MQTT_3_1_1 = 4 ///< MQTT 3.1.1 (protocol message byte = 4)
} MQTT_Ver_t;
/**
* @brief Last Will and Testament Definition
*
* Defining a type for the MQTT "Last Will and Testament" (LWT) parameters.
* @note Retained messages are \b NOT supported by the AWS IoT Service at the time of this SDK release.
*
*/
typedef struct {
char struct_id[4]; ///< The eyecatcher for this structure. must be MQTW
char *pTopicName; ///< The LWT topic to which the LWT message will be published
uint16_t topicNameLen; ///< The length of the LWT topic, 16 bit unsinged integer
char *pMessage; ///< Message to be delivered as LWT
uint16_t msgLen; ///< The length of the Message, 16 bit unsinged integer
bool isRetained; ///< NOT supported. The retained flag for the LWT message (see MQTTAsync_message.retained)
QoS qos; ///< QoS of LWT message
} IoT_MQTT_Will_Options;
extern const IoT_MQTT_Will_Options iotMqttWillOptionsDefault;
#define IoT_MQTT_Will_Options_Initializer { {'M', 'Q', 'T', 'W'}, NULL, 0, NULL, 0, false, QOS0 }
/**
* @brief MQTT Connection Parameters
*
* Defining a type for MQTT connection parameters. Passed into client when establishing a connection.
*
*/
typedef struct {
char struct_id[4]; ///< The eyecatcher for this structure. must be MQTC
MQTT_Ver_t MQTTVersion; ///< Desired MQTT version used during connection
char *pClientID; ///< Pointer to a string defining the MQTT client ID (this needs to be unique \b per \b device across your AWS account)
uint16_t clientIDLen; ///< Client Id Length. 16 bit unsigned integer
uint16_t keepAliveIntervalInSec; ///< MQTT keep alive interval in seconds. Defines inactivity time allowed before determining the connection has been lost.
bool isCleanSession; ///< MQTT clean session. True = this session is to be treated as clean. Previous server state is cleared and no stated is retained from this connection.
bool isWillMsgPresent; ///< Is there a LWT associated with this connection?
IoT_MQTT_Will_Options will; ///< MQTT LWT parameters.
char *pUsername; ///< Not used in the AWS IoT Service, will need to be cstring if used
uint16_t usernameLen; ///< Username Length. 16 bit unsigned integer
char *pPassword; ///< Not used in the AWS IoT Service, will need to be cstring if used
uint16_t passwordLen; ///< Password Length. 16 bit unsigned integer
} IoT_Client_Connect_Params;
extern const IoT_Client_Connect_Params iotClientConnectParamsDefault;
#define IoT_Client_Connect_Params_initializer { {'M', 'Q', 'T', 'C'}, MQTT_3_1_1, NULL, 0, 60, true, false, \
IoT_MQTT_Will_Options_Initializer, NULL, 0, NULL, 0 }
/**
* @brief Disconnect Callback Handler Type
*
* Defining a TYPE for definition of disconnect callback function pointers.
*
*/
typedef void (*iot_disconnect_handler)(AWS_IoT_Client *, void *);
/**
* @brief MQTT Initialization Parameters
*
* Defining a type for MQTT initialization parameters.
* Passed into client when to initialize the client
*
*/
typedef struct {
bool enableAutoReconnect; ///< Set to true to enable auto reconnect
char *pHostURL; ///< Pointer to a string defining the endpoint for the MQTT service
uint16_t port; ///< MQTT service listening port
char *pRootCALocation; ///< Pointer to a string defining the Root CA file (full file, not path)
char *pDeviceCertLocation; ///< Pointer to a string defining the device identity certificate file (full file, not path)
char *pDevicePrivateKeyLocation; ///< Pointer to a string defining the device private key file (full file, not path)
uint32_t mqttCommandTimeout_ms; ///< Timeout for MQTT blocking calls. In milliseconds
#ifdef _ENABLE_THREAD_SUPPORT_
bool isBlockOnThreadLockEnabled; ///< Timeout for Thread blocking calls. Set to 0 to block until lock is obtained. In milliseconds
#endif
uint32_t tlsHandshakeTimeout_ms; ///< TLS handshake timeout. In milliseconds
bool isSSLHostnameVerify; ///< Client should perform server certificate hostname validation
iot_disconnect_handler disconnectHandler; ///< Callback to be invoked upon connection loss
void *disconnectHandlerData; ///< Data to pass as argument when disconnect handler is called
} IoT_Client_Init_Params;
extern const IoT_Client_Init_Params iotClientInitParamsDefault;
/**
* @brief MQTT Client State Type
*
* Defining a type for MQTT Client State
*
*/
typedef enum _ClientState {
CLIENT_STATE_INVALID = 0,
CLIENT_STATE_INITIALIZED = 1,
CLIENT_STATE_CONNECTING = 2,
CLIENT_STATE_CONNECTED_IDLE = 3,
CLIENT_STATE_CONNECTED_YIELD_IN_PROGRESS = 4,
CLIENT_STATE_CONNECTED_PUBLISH_IN_PROGRESS = 5,
CLIENT_STATE_CONNECTED_SUBSCRIBE_IN_PROGRESS = 6,
CLIENT_STATE_CONNECTED_UNSUBSCRIBE_IN_PROGRESS = 7,
CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS = 8,
CLIENT_STATE_CONNECTED_WAIT_FOR_CB_RETURN = 9,
CLIENT_STATE_DISCONNECTING = 10,
CLIENT_STATE_DISCONNECTED_ERROR = 11,
CLIENT_STATE_DISCONNECTED_MANUALLY = 12,
CLIENT_STATE_PENDING_RECONNECT = 13
} ClientState;
/**
* @brief Application Callback Handler Type
*
* Defining a TYPE for definition of application callback function pointers.
* Used to send incoming data to the application
*
*/
typedef void (*pApplicationHandler_t)(AWS_IoT_Client *pClient, char *pTopicName, uint16_t topicNameLen,
IoT_Publish_Message_Params *pParams, void *pClientData);
/**
* @brief MQTT Message Handler
*
* Defining a type for MQTT Message Handlers.
* Used to pass incoming data back to the application
*
*/
typedef struct _MessageHandlers {
const char *topicName;
uint16_t topicNameLen;
QoS qos;
pApplicationHandler_t pApplicationHandler;
void *pApplicationHandlerData;
} MessageHandlers; /* Message handlers are indexed by subscription topic */
/**
* @brief MQTT Client Status
*
* Defining a type for MQTT Client Status
* Contains information about the state of the MQTT Client
*
*/
typedef struct _ClientStatus {
ClientState clientState;
bool isPingOutstanding;
bool isAutoReconnectEnabled;
} ClientStatus;
/**
* @brief MQTT Client Data
*
* Defining a type for MQTT Client Data
* Contains data used by the MQTT Client
*
*/
typedef struct _ClientData {
uint16_t nextPacketId;
uint32_t commandTimeoutMs;
uint16_t keepAliveInterval;
uint32_t currentReconnectWaitInterval;
uint32_t counterNetworkDisconnected;
/* The below values are initialized with the
* lengths of the TX/RX buffers and never modified
* afterwards */
size_t writeBufSize;
size_t readBufSize;
unsigned char writeBuf[AWS_IOT_MQTT_TX_BUF_LEN];
unsigned char readBuf[AWS_IOT_MQTT_RX_BUF_LEN];
#ifdef _ENABLE_THREAD_SUPPORT_
bool isBlockOnThreadLockEnabled;
IoT_Mutex_t state_change_mutex;
IoT_Mutex_t tls_read_mutex;
IoT_Mutex_t tls_write_mutex;
#endif
IoT_Client_Connect_Params options;
MessageHandlers messageHandlers[AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS];
iot_disconnect_handler disconnectHandler;
void *disconnectHandlerData;
} ClientData;
/**
* @brief MQTT Client
*
* Defining a type for MQTT Client
*
*/
struct _Client {
Timer pingTimer;
Timer reconnectDelayTimer;
ClientStatus clientStatus;
ClientData clientData;
Network networkStack;
};
/**
* @brief What is the next available packet Id
*
* Called to retrieve the next packet id to be used for outgoing packets.
* Automatically increments the last sent packet id variable
*
* @param pClient Reference to the IoT Client
*
* @return next packet id as a 16 bit unsigned integer
*/
uint16_t aws_iot_mqtt_get_next_packet_id(AWS_IoT_Client *pClient);
/**
* @brief Set the connection parameters for the IoT Client
*
* Called to set the connection parameters for the IoT Client.
* Used to update the connection parameters provided before the last connect.
* Won't take effect until the next time connect is called
*
* @param pClient Reference to the IoT Client
* @param pNewConnectParams Reference to the new Connection Parameters structure
*
* @return IoT_Error_t Type defining successful/failed API call
*/
IoT_Error_t aws_iot_mqtt_set_connect_params(AWS_IoT_Client *pClient, IoT_Client_Connect_Params *pNewConnectParams);
/**
* @brief Is the MQTT client currently connected?
*
* Called to determine if the MQTT client is currently connected. Used to support logic
* in the device application around reconnecting and managing offline state.
*
* @param pClient Reference to the IoT Client
*
* @return true = connected, false = not currently connected
*/
bool aws_iot_mqtt_is_client_connected(AWS_IoT_Client *pClient);
/**
* @brief Get the current state of the client
*
* Called to get the current state of the client
*
* @param pClient Reference to the IoT Client
*
* @return ClientState value equal to the current state of the client
*/
ClientState aws_iot_mqtt_get_client_state(AWS_IoT_Client *pClient);
/**
* @brief Is the MQTT client set to reconnect automatically?
*
* Called to determine if the MQTT client is set to reconnect automatically.
* Used to support logic in the device application around reconnecting
*
* @param pClient Reference to the IoT Client
*
* @return true = enabled, false = disabled
*/
bool aws_iot_is_autoreconnect_enabled(AWS_IoT_Client *pClient);
/**
* @brief Set the IoT Client disconnect handler
*
* Called to set the IoT Client disconnect handler
* The disconnect handler is called whenever the client disconnects with error
*
* @param pClient Reference to the IoT Client
* @param pConnectHandler Reference to the new Disconnect Handler
* @param pDisconnectHandlerData Reference to the data to be passed as argument when disconnect handler is called
*
* @return IoT_Error_t Type defining successful/failed API call
*/
IoT_Error_t aws_iot_mqtt_set_disconnect_handler(AWS_IoT_Client *pClient, iot_disconnect_handler pDisconnectHandler,
void *pDisconnectHandlerData);
/**
* @brief Enable or Disable AutoReconnect on Network Disconnect
*
* Called to enable or disabled the auto reconnect features provided with the SDK
*
* @param pClient Reference to the IoT Client
* @param newStatus set to true for enabling and false for disabling
*
* @return IoT_Error_t Type defining successful/failed API call
*/
IoT_Error_t aws_iot_mqtt_autoreconnect_set_status(AWS_IoT_Client *pClient, bool newStatus);
/**
* @brief Get count of Network Disconnects
*
* Called to get the number of times a network disconnect occurred due to errors
*
* @param pClient Reference to the IoT Client
*
* @return uint32_t the disconnect count
*/
uint32_t aws_iot_mqtt_get_network_disconnected_count(AWS_IoT_Client *pClient);
/**
* @brief Reset Network Disconnect conter
*
* Called to reset the Network Disconnect counter to zero
*
* @param pClient Reference to the IoT Client
*/
void aws_iot_mqtt_reset_network_disconnected_count(AWS_IoT_Client *pClient);
#endif

View File

@@ -0,0 +1,134 @@
/*
* Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
// Based on Eclipse Paho.
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
/**
* @file aws_iot_mqtt_client_common_internal.h
* @brief Internal MQTT functions not exposed to application
*/
#ifndef AWS_IOT_SDK_SRC_IOT_COMMON_INTERNAL_H
#define AWS_IOT_SDK_SRC_IOT_COMMON_INTERNAL_H
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "aws_iot_log.h"
#include "aws_iot_mqtt_client_interface.h"
/* Enum order should match the packet ids array defined in MQTTFormat.c */
typedef enum msgTypes {
UNKNOWN = -1,
CONNECT = 1,
CONNACK = 2,
PUBLISH = 3,
PUBACK = 4,
PUBREC = 5,
PUBREL = 6,
PUBCOMP = 7,
SUBSCRIBE = 8,
SUBACK = 9,
UNSUBSCRIBE = 10,
UNSUBACK = 11,
PINGREQ = 12,
PINGRESP = 13,
DISCONNECT = 14
}MessageTypes;
/**
* Bitfields for the MQTT header byte.
*/
typedef union {
unsigned char byte; /**< the whole byte */
#if defined(REVERSED)
struct {
unsigned int type : 4; /**< message type nibble */
unsigned int dup : 1; /**< DUP flag bit */
unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
unsigned int retain : 1; /**< retained flag bit */
} bits;
#else
struct {
unsigned int retain : 1; /**< retained flag bit */
unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
unsigned int dup : 1; /**< DUP flag bit */
unsigned int type : 4; /**< message type nibble */
} bits;
#endif
} MQTTHeader;
IoT_Error_t aws_iot_mqtt_internal_init_header(MQTTHeader *pHeader, MessageTypes message_type,
QoS qos, uint8_t dup, uint8_t retained);
IoT_Error_t aws_iot_mqtt_internal_serialize_ack(unsigned char *pTxBuf, size_t txBufLen,
MessageTypes msgType, uint8_t dup, uint16_t packetId,
uint32_t *pSerializedLen);
IoT_Error_t aws_iot_mqtt_internal_deserialize_ack(unsigned char *, unsigned char *,
uint16_t *, unsigned char *, size_t);
uint32_t aws_iot_mqtt_internal_get_final_packet_length_from_remaining_length(uint32_t rem_len);
size_t aws_iot_mqtt_internal_write_len_to_buffer(unsigned char *buf, uint32_t length);
IoT_Error_t aws_iot_mqtt_internal_decode_remaining_length_from_buffer(unsigned char *buf, uint32_t *decodedLen,
uint32_t *readBytesLen);
uint16_t aws_iot_mqtt_internal_read_uint16_t(unsigned char **pptr);
void aws_iot_mqtt_internal_write_uint_16(unsigned char **pptr, uint16_t anInt);
unsigned char aws_iot_mqtt_internal_read_char(unsigned char **pptr);
void aws_iot_mqtt_internal_write_char(unsigned char **pptr, unsigned char c);
void aws_iot_mqtt_internal_write_utf8_string(unsigned char **pptr, const char *string, uint16_t stringLen);
IoT_Error_t aws_iot_mqtt_internal_send_packet(AWS_IoT_Client *pClient, size_t length, Timer *pTimer);
IoT_Error_t aws_iot_mqtt_internal_cycle_read(AWS_IoT_Client *pClient, Timer *pTimer, uint8_t *pPacketType);
IoT_Error_t aws_iot_mqtt_internal_wait_for_read(AWS_IoT_Client *pClient, uint8_t packetType, Timer *pTimer);
IoT_Error_t aws_iot_mqtt_internal_serialize_zero(unsigned char *pTxBuf, size_t txBufLen,
MessageTypes packetType, size_t *pSerializedLength);
IoT_Error_t aws_iot_mqtt_internal_deserialize_publish(uint8_t *dup, QoS *qos,
uint8_t *retained, uint16_t *pPacketId,
char **pTopicName, uint16_t *topicNameLen,
unsigned char **payload, size_t *payloadLen,
unsigned char *pRxBuf, size_t rxBufLen);
IoT_Error_t aws_iot_mqtt_set_client_state(AWS_IoT_Client *pClient, ClientState expectedCurrentState,
ClientState newState);
#ifdef _ENABLE_THREAD_SUPPORT_
IoT_Error_t aws_iot_mqtt_client_lock_mutex(AWS_IoT_Client *pClient, IoT_Mutex_t *pMutex);
IoT_Error_t aws_iot_mqtt_client_unlock_mutex(AWS_IoT_Client *pClient, IoT_Mutex_t *pMutex);
#endif
#endif /* AWS_IOT_SDK_SRC_IOT_COMMON_INTERNAL_H */

View File

@@ -0,0 +1,191 @@
/*
* Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
// Based on Eclipse Paho.
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
/**
* @file aws_iot_mqtt_interface.h
* @brief Interface definition for MQTT client.
*/
#ifndef AWS_IOT_SDK_SRC_IOT_MQTT_INTERFACE_H
#define AWS_IOT_SDK_SRC_IOT_MQTT_INTERFACE_H
/* Library Header files */
#include "stdio.h"
#include "stdbool.h"
#include "stdint.h"
#include "stddef.h"
/* AWS Specific header files */
#include "aws_iot_error.h"
#include "aws_iot_config.h"
#include "aws_iot_mqtt_client.h"
/* Platform specific implementation header files */
#include "network_interface.h"
#include "timer_interface.h"
/**
* @brief MQTT Client Initialization Function
*
* Called to initialize the MQTT Client
*
* @param pClient Reference to the IoT Client
* @param pInitParams Pointer to MQTT connection parameters
*
* @return IoT_Error_t Type defining successful/failed API call
*/
IoT_Error_t aws_iot_mqtt_init(AWS_IoT_Client *pClient, IoT_Client_Init_Params *pInitParams);
/**
* @brief MQTT Connection Function
*
* Called to establish an MQTT connection with the AWS IoT Service
*
* @param pClient Reference to the IoT Client
* @param pConnectParams Pointer to MQTT connection parameters
*
* @return An IoT Error Type defining successful/failed connection
*/
IoT_Error_t aws_iot_mqtt_connect(AWS_IoT_Client *pClient, IoT_Client_Connect_Params *pConnectParams);
/**
* @brief Publish an MQTT message on a topic
*
* Called to publish an MQTT message on a topic.
* @note Call is blocking. In the case of a QoS 0 message the function returns
* after the message was successfully passed to the TLS layer. In the case of QoS 1
* the function returns after the receipt of the PUBACK control packet.
*
* @param pClient Reference to the IoT Client
* @param pTopicName Topic Name to publish to
* @param topicNameLen Length of the topic name
* @param pParams Pointer to Publish Message parameters
*
* @return An IoT Error Type defining successful/failed publish
*/
IoT_Error_t aws_iot_mqtt_publish(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen,
IoT_Publish_Message_Params *pParams);
/**
* @brief Subscribe to an MQTT topic.
*
* Called to send a subscribe message to the broker requesting a subscription
* to an MQTT topic.
* @note Call is blocking. The call returns after the receipt of the SUBACK control packet.
*
* @param pClient Reference to the IoT Client
* @param pTopicName Topic Name to publish to
* @param topicNameLen Length of the topic name
* @param pApplicationHandler_t Reference to the handler function for this subscription
* @param pApplicationHandlerData Data to be passed as argument to the application handler callback
*
* @return An IoT Error Type defining successful/failed subscription
*/
IoT_Error_t aws_iot_mqtt_subscribe(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen,
QoS qos, pApplicationHandler_t pApplicationHandler, void *pApplicationHandlerData);
/**
* @brief Subscribe to an MQTT topic.
*
* Called to resubscribe to the topics that the client has active subscriptions on.
* Internally called when autoreconnect is enabled
*
* @note Call is blocking. The call returns after the receipt of the SUBACK control packet.
*
* @param pClient Reference to the IoT Client
*
* @return An IoT Error Type defining successful/failed subscription
*/
IoT_Error_t aws_iot_mqtt_resubscribe(AWS_IoT_Client *pClient);
/**
* @brief Unsubscribe to an MQTT topic.
*
* Called to send an unsubscribe message to the broker requesting removal of a subscription
* to an MQTT topic.
* @note Call is blocking. The call returns after the receipt of the UNSUBACK control packet.
*
* @param pClient Reference to the IoT Client
* @param pTopicName Topic Name to publish to
* @param topicNameLen Length of the topic name
*
* @return An IoT Error Type defining successful/failed unsubscribe call
*/
IoT_Error_t aws_iot_mqtt_unsubscribe(AWS_IoT_Client *pClient, const char *pTopicFilter, uint16_t topicFilterLen);
/**
* @brief Disconnect an MQTT Connection
*
* Called to send a disconnect message to the broker.
*
* @param pClient Reference to the IoT Client
*
* @return An IoT Error Type defining successful/failed send of the disconnect control packet.
*/
IoT_Error_t aws_iot_mqtt_disconnect(AWS_IoT_Client *pClient);
/**
* @brief Yield to the MQTT client
*
* Called to yield the current thread to the underlying MQTT client. This time is used by
* the MQTT client to manage PING requests to monitor the health of the TCP connection as
* well as periodically check the socket receive buffer for subscribe messages. Yield()
* must be called at a rate faster than the keepalive interval. It must also be called
* at a rate faster than the incoming message rate as this is the only way the client receives
* processing time to manage incoming messages.
*
* @param pClient Reference to the IoT Client
* @param timeout_ms Maximum number of milliseconds to pass thread execution to the client.
*
* @return An IoT Error Type defining successful/failed client processing.
* If this call results in an error it is likely the MQTT connection has dropped.
* iot_is_mqtt_connected can be called to confirm.
*/
IoT_Error_t aws_iot_mqtt_yield(AWS_IoT_Client *pClient, uint32_t timeout_ms);
/**
* @brief MQTT Manual Re-Connection Function
*
* Called to establish an MQTT connection with the AWS IoT Service
* using parameters from the last time a connection was attempted
* Use after disconnect to start the reconnect process manually
* Makes only one reconnect attempt Sets the client state to
* pending reconnect in case of failure
*
* @param pClient Reference to the IoT Client
*
* @return An IoT Error Type defining successful/failed connection
*/
IoT_Error_t aws_iot_mqtt_attempt_reconnect(AWS_IoT_Client *pClient);
#endif

View File

@@ -18,7 +18,7 @@
#include "aws_iot_shadow_interface.h"
IoT_Error_t iot_shadow_action(MQTTClient_t *pClient, const char *pThingName, ShadowActions_t action,
IoT_Error_t iot_shadow_action(const char *pThingName, ShadowActions_t action,
const char *pJsonDocumentToBeSent, fpActionCallback_t callback, void *pCallbackContext,
uint32_t timeout_seconds, bool isSticky);

View File

@@ -33,35 +33,56 @@
*
*
*/
#include "aws_iot_mqtt_interface.h"
#include "aws_iot_mqtt_client_interface.h"
#include "aws_iot_shadow_json_data.h"
/*!
* @brief Shadow Connect parameters
* @brief Shadow Initialization parameters
*
* As the Shadow SDK uses MQTT underneath, it could be connected and disconnected on events to save some battery.
* @note Always use the \c ShadowParametersDefault to initialize this struct
* @note Always use the \c ShadowIniTParametersDefault to initialize this struct
*
*
*
*/
typedef struct {
char *pMyThingName; ///< Every device has a Thing Shadow and this is the placeholder for name
char *pMqttClientId; ///< Currently the Shadow uses MQTT to connect and it is important to ensure we have unique client id
char *pHost; ///< This will be unique to a customer and can be retrieved from the console
int port; ///< By default the port is 8883
uint16_t port; ///< By default the port is 8883
char *pRootCA; ///< Location with the Filename of the Root CA
char *pClientCRT; ///< Location of Device certs signed by AWS IoT service
char *pClientKey; ///< Location of Device private key
} ShadowParameters_t;
bool enableAutoReconnect; ///< Set to true to enable auto reconnect
iot_disconnect_handler disconnectHandler; ///< Callback to be invoked upon connection loss.
} ShadowInitParameters_t;
/*!
* @brief Shadow Connect parameters
*
* As the Shadow SDK uses MQTT underneath, it could be connected and disconnected on events to save some battery.
* @note Always use the \c ShadowConnectParametersDefault to initialize this struct
*
*d
*
*/
typedef struct {
char *pMyThingName; ///< Every device has a Thing Shadow and this is the placeholder for name
char *pMqttClientId; ///< Currently the Shadow uses MQTT to connect and it is important to ensure we have unique client id
} ShadowConnectParameters_t;
/*!
* @brief This is set to defaults from the configuration file
* The certs are set to NULL because they need the path to the file. shadow_sample.c file demonstrates on how to get the relative path
*
* \relates ShadowParameters_t
* \relates ShadowInitParameters_t
*/
extern const ShadowParameters_t ShadowParametersDefault;
extern const ShadowInitParameters_t ShadowInitParametersDefault;
/*!
* @brief This is set to defaults from the configuration file
*
* \relates ShadowConnectParameters_t
*/
extern const ShadowConnectParameters_t ShadowConnectParametersDefault;
/**
@@ -72,7 +93,7 @@ extern const ShadowParameters_t ShadowParametersDefault;
* @param pClient MQTT Client used as the protocol layer
* @return An IoT Error Type defining successful/failed Initialization
*/
IoT_Error_t aws_iot_shadow_init(MQTTClient_t *pClient);
IoT_Error_t aws_iot_shadow_init(AWS_IoT_Client *pClient, ShadowInitParameters_t *pParams);
/**
* @brief Connect to the AWS IoT Thing Shadow service over MQTT
*
@@ -82,7 +103,7 @@ IoT_Error_t aws_iot_shadow_init(MQTTClient_t *pClient);
* @param pParams Shadow Conenction parameters like TLS cert location
* @return An IoT Error Type defining successful/failed Connection
*/
IoT_Error_t aws_iot_shadow_connect(MQTTClient_t *pClient, ShadowParameters_t *pParams);
IoT_Error_t aws_iot_shadow_connect(AWS_IoT_Client *pClient, ShadowConnectParameters_t *pParams);
/**
* @brief Yield function to let the background tasks of MQTT and Shadow
*
@@ -94,7 +115,7 @@ IoT_Error_t aws_iot_shadow_connect(MQTTClient_t *pClient, ShadowParameters_t *pP
* @param timeout in milliseconds, This is the maximum time the yield function will wait for a message and/or read the messages from the TLS buffer
* @return An IoT Error Type defining successful/failed Yield
*/
IoT_Error_t aws_iot_shadow_yield(MQTTClient_t *pClient, int timeout);
IoT_Error_t aws_iot_shadow_yield(AWS_IoT_Client *pClient, uint32_t timeout);
/**
* @brief Disconnect from the AWS IoT Thing Shadow service over MQTT
*
@@ -103,7 +124,7 @@ IoT_Error_t aws_iot_shadow_yield(MQTTClient_t *pClient, int timeout);
* @param pClient MQTT Client used as the protocol layer
* @return An IoT Error Type defining successful/failed disconnect status
*/
IoT_Error_t aws_iot_shadow_disconnect(MQTTClient_t *pClient);
IoT_Error_t aws_iot_shadow_disconnect(AWS_IoT_Client *pClient);
/**
* @brief Thing Shadow Acknowledgment enum
@@ -157,14 +178,14 @@ typedef void (*fpActionCallback_t)(const char *pThingName, ShadowActions_t actio
*
* @param pClient MQTT Client used as the protocol layer
* @param pThingName Thing Name of the shadow that needs to be Updated
* @param pJsonString The update action expects a JSON document to send. The JSO String should be a null terminated string. This JSON document should adhere to the AWS IoT Thing Shadow specification. To help in the process of creating this document- SDK provides apis in \c aws_iot_shadow_json_data.h
* @param pJsonString The update action expects a JSON document to send. The JSON String should be a null terminated string. This JSON document should adhere to the AWS IoT Thing Shadow specification. To help in the process of creating this document- SDK provides apis in \c aws_iot_shadow_json_data.h
* @param callback This is the callback that will be used to inform the caller of the response from the AWS IoT Shadow service.Callback could be set to NULL if response is not important
* @param pContextData This is an extra parameter that could be passed along with the callback. It should be set to NULL if not used
* @param timeout_seconds It is the time the SDK will wait for the response on either accepted/rejected before declaring timeout on the action
* @param isPersistentSubscribe As mentioned above, every time if a device updates the same shadow then this should be set to true to avoid repeated subscription and unsubscription. If the Thing Name is one off update then this should be set to false
* @return An IoT Error Type defining successful/failed update action
*/
IoT_Error_t aws_iot_shadow_update(MQTTClient_t *pClient, const char *pThingName, char *pJsonString,
IoT_Error_t aws_iot_shadow_update(AWS_IoT_Client *pClient, const char *pThingName, char *pJsonString,
fpActionCallback_t callback, void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscribe);
/**
@@ -181,7 +202,7 @@ IoT_Error_t aws_iot_shadow_update(MQTTClient_t *pClient, const char *pThingName,
* @param isPersistentSubscribe As mentioned above, every time if a device gets the same Sahdow (JSON document) then this should be set to true to avoid repeated subscription and un-subscription. If the Thing Name is one off get then this should be set to false
* @return An IoT Error Type defining successful/failed get action
*/
IoT_Error_t aws_iot_shadow_get(MQTTClient_t *pClient, const char *pThingName, fpActionCallback_t callback,
IoT_Error_t aws_iot_shadow_get(AWS_IoT_Client *pClient, const char *pThingName, fpActionCallback_t callback,
void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscribe);
/**
* @brief This function is the one used to perform an Delete action to a Thing Name's Shadow.
@@ -194,10 +215,10 @@ IoT_Error_t aws_iot_shadow_get(MQTTClient_t *pClient, const char *pThingName, fp
* @param callback This is the callback that will be used to inform the caller of the response from the AWS IoT Shadow service.Callback could be set to NULL if response is not important
* @param pContextData This is an extra parameter that could be passed along with the callback. It should be set to NULL if not used
* @param timeout_seconds It is the time the SDK will wait for the response on either accepted/rejected before declaring timeout on the action
* @param isPersistentSubscribe As mentioned above, every time if a device deletes the same Sahdow (JSON document) then this should be set to true to avoid repeated subscription and un-subscription. If the Thing Name is one off delete then this should be set to false
* @param isPersistentSubscribe As mentioned above, every time if a device deletes the same Shadow (JSON document) then this should be set to true to avoid repeated subscription and un-subscription. If the Thing Name is one off delete then this should be set to false
* @return An IoT Error Type defining successful/failed delete action
*/
IoT_Error_t aws_iot_shadow_delete(MQTTClient_t *pClient, const char *pThingName, fpActionCallback_t callback,
IoT_Error_t aws_iot_shadow_delete(AWS_IoT_Client *pClient, const char *pThingName, fpActionCallback_t callback,
void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscriptions);
/**
@@ -209,7 +230,7 @@ IoT_Error_t aws_iot_shadow_delete(MQTTClient_t *pClient, const char *pThingName,
* @param pStruct The struct used to parse JSON value
* @return An IoT Error Type defining successful/failed delta registering
*/
IoT_Error_t aws_iot_shadow_register_delta(MQTTClient_t *pClient, jsonStruct_t *pStruct);
IoT_Error_t aws_iot_shadow_register_delta(AWS_IoT_Client *pClient, jsonStruct_t *pStruct);
/**
* @brief Reset the last received version number to zero.
@@ -218,6 +239,7 @@ IoT_Error_t aws_iot_shadow_register_delta(MQTTClient_t *pClient, jsonStruct_t *p
*
*/
void aws_iot_shadow_reset_last_received_version(void);
/**
* @brief Version of a document is received with every accepted/rejected and the SDK keeps track of the last received version of the JSON document of #AWS_IOT_MY_THING_NAME shadow
*
@@ -228,15 +250,29 @@ void aws_iot_shadow_reset_last_received_version(void);
*
*/
uint32_t aws_iot_shadow_get_last_received_version(void);
/**
* @brief Enable the ignoring of delta messages with old version number
*
* As we use MQTT underneath, there could be more than 1 of the same message if we use QoS 0. To avoid getting called for the same message, this functionality should be enabled. All the old message will be ignored
*/
void aws_iot_shadow_enable_discard_old_delta_msgs(void);
/**
* @brief Disable the ignoring of delta messages with old version number
*/
void aws_iot_shadow_disable_discard_old_delta_msgs(void);
/**
* @brief This function is used to enable or disable autoreconnect
*
* Any time a disconnect happens the underlying MQTT client attempts to reconnect if this is set to true
*
* @param pClient MQTT Client used as the protocol layer
* @param newStatus The new status to set the autoreconnect option to
*
* @return An IoT Error Type defining successful/failed operation
*/
IoT_Error_t aws_iot_shadow_set_autoreconnect_status(AWS_IoT_Client *pClient, bool newStatus);
#endif //AWS_IOT_SDK_SRC_IOT_SHADOW_H_

View File

@@ -28,7 +28,7 @@ extern bool shadowDiscardOldDeltaFlag;
extern char myThingName[MAX_SIZE_OF_THING_NAME];
extern char mqttClientID[MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES];
void initializeRecords(MQTTClient_t *pClient);
void initializeRecords(AWS_IoT_Client *pClient);
bool isSubscriptionPresent(const char *pThingName, ShadowActions_t action);
IoT_Error_t subscribeToShadowActionAcks(const char *pThingName, ShadowActions_t action, bool isSticky);
void incrementSubscriptionCnt(const char *pThingName, ShadowActions_t action, bool isSticky);

View File

@@ -31,15 +31,15 @@
/**
* @brief MAJOR version, incremented when incompatible API changes are made.
*/
#define VERSION_MAJOR 1
#define VERSION_MAJOR 2
/**
* @brief MINOR version when functionality is added in a backwards-compatible manner.
*/
#define VERSION_MINOR 1
#define VERSION_MINOR 0
/**
* @brief PATCH version when backwards-compatible bug fixes are made.
*/
#define VERSION_PATCH 2
#define VERSION_PATCH 0
/**
* @brief TAG is an (optional) tag appended to the version if a more descriptive verion is needed.
*/

158
include/network_interface.h Normal file
View File

@@ -0,0 +1,158 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/**
* @file network_interface.h
* @brief Network interface definition for MQTT client.
*
* Defines an interface to the TLS layer to be used by the MQTT client.
* Starting point for porting the SDK to the networking layer of a new platform.
*/
#ifndef __NETWORK_INTERFACE_H_
#define __NETWORK_INTERFACE_H_
#include <stdint.h>
#include <stdbool.h>
#include <aws_iot_error.h>
#include "timer_interface.h"
#include "network_platform.h"
/**
* @brief Network Type
*
* Defines a type for the network struct. See structure definition below.
*/
typedef struct Network Network;
/**
* @brief TLS Connection Parameters
*
* Defines a type containing TLS specific parameters to be passed down to the
* TLS networking layer to create a TLS secured socket.
*/
typedef struct {
char *pRootCALocation; ///< Pointer to string containing the filename (including path) of the root CA file.
char *pDeviceCertLocation; ///< Pointer to string containing the filename (including path) of the device certificate.
char *pDevicePrivateKeyLocation; ///< Pointer to string containing the filename (including path) of the device private key file.
char *pDestinationURL; ///< Pointer to string containing the endpoint of the MQTT service.
uint16_t DestinationPort; ///< Integer defining the connection port of the MQTT service.
uint32_t timeout_ms; ///< Unsigned integer defining the TLS handshake timeout value in milliseconds.
bool ServerVerificationFlag; ///< Boolean. True = perform server certificate hostname validation. False = skip validation \b NOT recommended.
}TLSConnectParams;
/**
* @brief Network Structure
*
* Structure for defining a network connection.
*/
struct Network{
IoT_Error_t (*connect) (Network *, TLSConnectParams *);
IoT_Error_t (*read) (Network *, unsigned char *, size_t, Timer *, size_t *); ///< Function pointer pointing to the network function to read from the network
IoT_Error_t (*write) (Network *, unsigned char *, size_t, Timer *, size_t *); ///< Function pointer pointing to the network function to write to the network
IoT_Error_t (*disconnect) (Network *); ///< Function pointer pointing to the network function to disconnect from the network
IoT_Error_t (*isConnected) (Network *); ///< Function pointer pointing to the network function to check if physical layer is connected
IoT_Error_t (*destroy) (Network *); ///< Function pointer pointing to the network function to destroy the network object
TLSConnectParams tlsConnectParams; ///< TLSConnect params structure containing the common connection parameters
TLSDataParams tlsDataParams; ///< TLSData params structure containing the connection data parameters that are specific to the library being used
};
/**
* @brief Initialize the TLS implementation
*
* Perform any initialization required by the TLS layer.
* Connects the interface to implementation by setting up
* the network layer function pointers to platform implementations.
*
* @param pNetwork - Pointer to a Network struct defining the network interface.
* @param pRootCALocation - Path of the location of the Root CA
* @param pDeviceCertLocation - Path to the location of the Device Cert
* @param pDevicyPrivateKeyLocation - Path to the location of the device private key file
* @param pDestinationURL - The target endpoint to connect to
* @param DestinationPort - The port on the target to connect to
* @param timeout_ms - The value to use for timeout of operation
* @param ServerVerificationFlag - used to decide whether server verification is needed or not
*
* @return IoT_Error_t - successful initialization or TLS error
*/
IoT_Error_t iot_tls_init(Network *pNetwork, char *pRootCALocation, char *pDeviceCertLocation,
char *pDevicePrivateKeyLocation, char *pDestinationURL,
uint16_t DestinationPort, uint32_t timeout_ms, bool ServerVerificationFlag);
/**
* @brief Create a TLS socket and open the connection
*
* Creates an open socket connection including TLS handshake.
*
* @param pNetwork - Pointer to a Network struct defining the network interface.
* @param TLSParams - TLSConnectParams defines the properties of the TLS connection.
* @return IoT_Error_t - successful connection or TLS error
*/
IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *TLSParams);
/**
* @brief Write bytes to the network socket
*
* @param Network - Pointer to a Network struct defining the network interface.
* @param unsigned char pointer - buffer to write to socket
* @param integer - number of bytes to write
* @param Timer * - operation timer
* @return integer - number of bytes written or TLS error
* @return IoT_Error_t - successful write or TLS error code
*/
IoT_Error_t iot_tls_write(Network*, unsigned char*, size_t, Timer *, size_t *);
/**
* @brief Read bytes from the network socket
*
* @param Network - Pointer to a Network struct defining the network interface.
* @param unsigned char pointer - pointer to buffer where read bytes should be copied
* @param size_t - number of bytes to read
* @param Timer * - operation timer
* @param size_t - pointer to store number of bytes read
* @return IoT_Error_t - successful read or TLS error code
*/
IoT_Error_t iot_tls_read(Network*, unsigned char*, size_t, Timer *, size_t *);
/**
* @brief Disconnect from network socket
*
* @param Network - Pointer to a Network struct defining the network interface.
* @return IoT_Error_t - successful read or TLS error code
*/
IoT_Error_t iot_tls_disconnect(Network *pNetwork);
/**
* @brief Perform any tear-down or cleanup of TLS layer
*
* Called to cleanup any resources required for the TLS layer.
*
* @param Network - Pointer to a Network struct defining the network interface
* @return IoT_Error_t - successful cleanup or TLS error code
*/
IoT_Error_t iot_tls_destroy(Network *pNetwork);
/**
* @brief Check if TLS layer is still connected
*
* Called to check if the TLS layer is still connected or not.
*
* @param Network - Pointer to a Network struct defining the network interface
* @return IoT_Error_t - TLS error code indicating status of network physical layer connection
*/
IoT_Error_t iot_tls_is_connected(Network *pNetwork);
#endif //__NETWORK_INTERFACE_H_

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/**
* @file threads_interface.h
* @brief Thread interface definition for MQTT client.
*
* Defines an interface that can be used by system components for multithreaded situations.
* Starting point for porting the SDK to the threading hardware layer of a new platform.
*/
#include "aws_iot_config.h"
#ifdef _ENABLE_THREAD_SUPPORT_
#ifndef __THREADS_INTERFACE_H_
#define __THREADS_INTERFACE_H_
/**
* The platform specific timer header that defines the Timer struct
*/
#include "threads_platform.h"
#include <aws_iot_error.h>
/**
* @brief Mutex Type
*
* Forward declaration of a mutex struct. The definition of this struct is
* platform dependent. When porting to a new platform add this definition
* in "threads_platform.h".
*
*/
typedef struct _IoT_Mutex_t IoT_Mutex_t;
/**
* @brief Initialize the provided mutex
*
* Call this function to initialize the mutex
*
* @param IoT_Mutex_t - pointer to the mutex to be initialized
* @return IoT_Error_t - error code indicating result of operation
*/
IoT_Error_t aws_iot_thread_mutex_init(IoT_Mutex_t *);
/**
* @brief Lock the provided mutex
*
* Call this function to lock the mutex before performing a state change
* This is a blocking call.
*
* @param IoT_Mutex_t - pointer to the mutex to be locked
* @return IoT_Error_t - error code indicating result of operation
*/
IoT_Error_t aws_iot_thread_mutex_lock(IoT_Mutex_t *);
/**
* @brief Lock the provided mutex
*
* Call this function to lock the mutex before performing a state change.
* This is not a blocking call.
*
* @param IoT_Mutex_t - pointer to the mutex to be locked
* @return IoT_Error_t - error code indicating result of operation
*/
IoT_Error_t aws_iot_thread_mutex_trylock(IoT_Mutex_t *);
/**
* @brief Unlock the provided mutex
*
* Call this function to unlock the mutex before performing a state change
*
* @param IoT_Mutex_t - pointer to the mutex to be unlocked
* @return IoT_Error_t - error code indicating result of operation
*/
IoT_Error_t aws_iot_thread_mutex_unlock(IoT_Mutex_t *);
/**
* @brief Destroy the provided mutex
*
* Call this function to destroy the mutex
*
* @param IoT_Mutex_t - pointer to the mutex to be destroyed
* @return IoT_Error_t - error code indicating result of operation
*/
IoT_Error_t aws_iot_thread_mutex_destroy(IoT_Mutex_t *);
#endif /*__THREADS_INTERFACE_H_*/
#endif /*_ENABLE_THREAD_SUPPORT_*/

View File

@@ -27,8 +27,13 @@
#ifndef __TIMER_INTERFACE_H_
#define __TIMER_INTERFACE_H_
// Add the platform specific timer includes to define the Timer struct
#include "timer_linux.h"
/**
* The platform specific timer header that defines the Timer struct
*/
#include "timer_platform.h"
#include <stdint.h>
#include <stdbool.h>
/**
* @brief Timer Type
@@ -46,9 +51,9 @@ typedef struct Timer Timer;
* Call this function passing in a timer to check if that timer has expired.
*
* @param Timer - pointer to the timer to be checked for expiration
* @return character - 1 = timer expired, 0 = timer not expired
* @return bool - true = timer expired, false = timer not expired
*/
char expired(Timer*);
bool has_timer_expired(Timer *);
/**
* @brief Create a timer (milliseconds)
@@ -56,9 +61,9 @@ char expired(Timer*);
* Sets the timer to expire in a specified number of milliseconds.
*
* @param Timer - pointer to the timer to be set to expire in milliseconds
* @param unsigned int - set the timer to expire in this number of milliseconds
* @param uint32_t - set the timer to expire in this number of milliseconds
*/
void countdown_ms(Timer*, unsigned int);
void countdown_ms(Timer *, uint32_t);
/**
* @brief Create a timer (seconds)
@@ -66,19 +71,19 @@ void countdown_ms(Timer*, unsigned int);
* Sets the timer to expire in a specified number of seconds.
*
* @param Timer - pointer to the timer to be set to expire in seconds
* @param unsigned int - set the timer to expire in this number of seconds
* @param uint32_t - set the timer to expire in this number of seconds
*/
void countdown(Timer*, unsigned int);
void countdown_sec(Timer *, uint32_t);
/**
* @brief Check the time remaining on a give timer
* @brief Check the time remaining on a given timer
*
* Checks the input timer and returns the number of milliseconds remaining on the timer.
*
* @param Timer - pointer to the timer to be set to checked
* @return int - milliseconds left on the countdown timer
*/
int left_ms(Timer*);
uint32_t left_ms(Timer *);
/**
* @brief Initialize a timer
@@ -87,6 +92,6 @@ int left_ms(Timer*);
*
* @param Timer - pointer to the timer to be initialized
*/
void InitTimer(Timer*);
void init_timer(Timer *);
#endif //__TIMER_INTERFACE_H_

View File

@@ -20,37 +20,43 @@
#include <stddef.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include "timer_linux.h"
#include "timer_platform.h"
char expired(Timer* timer) {
bool has_timer_expired(Timer *timer) {
struct timeval now, res;
gettimeofday(&now, NULL);
timersub(&timer->end_time, &now, &res);
return res.tv_sec < 0 || (res.tv_sec == 0 && res.tv_usec <= 0);
}
void countdown_ms(Timer* timer, unsigned int timeout) {
void countdown_ms(Timer* timer, uint32_t timeout) {
struct timeval now;
gettimeofday(&now, NULL);
struct timeval interval = { timeout / 1000, (timeout % 1000) * 1000 };
timeradd(&now, &interval, &timer->end_time);
}
void countdown(Timer* timer, unsigned int timeout) {
uint32_t left_ms(Timer* timer) {
struct timeval now, res;
gettimeofday(&now, NULL);
timersub(&timer->end_time, &now, &res);
uint32_t result_ms = 0;
if(res.tv_sec >= 0) {
result_ms = (uint32_t)(res.tv_sec * 1000 + res.tv_usec / 1000);
}
return result_ms;
}
void countdown_sec(Timer *timer, uint32_t timeout) {
struct timeval now;
gettimeofday(&now, NULL);
struct timeval interval = { timeout, 0 };
timeradd(&now, &interval, &timer->end_time);
}
int left_ms(Timer* timer) {
struct timeval now, res;
gettimeofday(&now, NULL);
timersub(&timer->end_time, &now, &res);
return (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000;
}
void InitTimer(Timer* timer) {
timer->end_time = (struct timeval ) { 0, 0 };
void init_timer(Timer *timer) {
timer->end_time = (struct timeval) { 0, 0 };
}

View File

@@ -13,11 +13,11 @@
* permissions and limitations under the License.
*/
#ifndef SRC_PROTOCOL_MQTT_AWS_IOT_EMBEDDED_CLIENT_WRAPPER_PLATFORM_LINUX_COMMON_TIMER_LINUX_H_
#define SRC_PROTOCOL_MQTT_AWS_IOT_EMBEDDED_CLIENT_WRAPPER_PLATFORM_LINUX_COMMON_TIMER_LINUX_H_
#ifndef SRC_PROTOCOL_MQTT_AWS_IOT_EMBEDDED_CLIENT_WRAPPER_PLATFORM_LINUX_COMMON_TIMER_PLATFORM_H_
#define SRC_PROTOCOL_MQTT_AWS_IOT_EMBEDDED_CLIENT_WRAPPER_PLATFORM_LINUX_COMMON_TIMER_PLATFORM_H_
/**
* @file timer_linux.h
* @file timer_platform.h
*/
#include <sys/time.h>
#include <sys/select.h>
@@ -26,9 +26,9 @@
/**
* definition of the Timer struct. Platform specific
*/
struct Timer{
struct Timer {
struct timeval end_time;
};
#endif /* SRC_PROTOCOL_MQTT_AWS_IOT_EMBEDDED_CLIENT_WRAPPER_PLATFORM_LINUX_COMMON_TIMER_LINUX_H_ */
#endif /* SRC_PROTOCOL_MQTT_AWS_IOT_EMBEDDED_CLIENT_WRAPPER_PLATFORM_LINUX_COMMON_TIMER_PLATFORM_H_ */

View File

@@ -0,0 +1,346 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#include <stdbool.h>
#include <string.h>
#include <timer_platform.h>
#include <network_interface.h>
#include "aws_iot_error.h"
#include "aws_iot_log.h"
#include "network_interface.h"
#include "network_platform.h"
/* This is the value used for ssl read timeout */
#define IOT_SSL_READ_TIMEOUT 10
/*
* This is a function to do further verification if needed on the cert received
*/
static IoT_Error_t _iot_tls_verify_cert(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) {
char buf[1024];
((void) data);
DEBUG("\nVerify requested for (Depth %d):\n", depth);
mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt);
DEBUG("%s", buf);
if ((*flags) == 0) {
DEBUG(" This certificate has no flags\n");
} else {
DEBUG(buf, sizeof(buf), " ! ", *flags); DEBUG("%s\n", buf);
}
return SUCCESS;
}
void _iot_tls_set_connect_params(Network *pNetwork, char *pRootCALocation, char *pDeviceCertLocation,
char *pDevicePrivateKeyLocation, char *pDestinationURL,
uint16_t destinationPort, uint32_t timeout_ms, bool ServerVerificationFlag) {
pNetwork->tlsConnectParams.DestinationPort = destinationPort;
pNetwork->tlsConnectParams.pDestinationURL = pDestinationURL;
pNetwork->tlsConnectParams.pDeviceCertLocation = pDeviceCertLocation;
pNetwork->tlsConnectParams.pDevicePrivateKeyLocation = pDevicePrivateKeyLocation;
pNetwork->tlsConnectParams.pRootCALocation = pRootCALocation;
pNetwork->tlsConnectParams.timeout_ms = timeout_ms;
pNetwork->tlsConnectParams.ServerVerificationFlag = ServerVerificationFlag;
}
IoT_Error_t iot_tls_init(Network *pNetwork, char *pRootCALocation, char *pDeviceCertLocation,
char *pDevicePrivateKeyLocation, char *pDestinationURL,
uint16_t destinationPort, uint32_t timeout_ms, bool ServerVerificationFlag) {
_iot_tls_set_connect_params(pNetwork, pRootCALocation, pDeviceCertLocation, pDevicePrivateKeyLocation,
pDestinationURL, destinationPort, timeout_ms, ServerVerificationFlag);
pNetwork->connect = iot_tls_connect;
pNetwork->read = iot_tls_read;
pNetwork->write = iot_tls_write;
pNetwork->disconnect = iot_tls_disconnect;
pNetwork->isConnected = iot_tls_is_connected;
pNetwork->destroy = iot_tls_destroy;
return SUCCESS;
}
IoT_Error_t iot_tls_is_connected(Network *pNetwork) {
/* Use this to add implementation which can check for physical layer disconnect */
return NETWORK_PHYSICAL_LAYER_CONNECTED;
}
IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *params) {
if(NULL == pNetwork) {
return NULL_VALUE_ERROR;
}
if(NULL != params) {
_iot_tls_set_connect_params(pNetwork, params->pRootCALocation, params->pDeviceCertLocation,
params->pDevicePrivateKeyLocation, params->pDestinationURL,
params->DestinationPort, params->timeout_ms, params->ServerVerificationFlag);
}
int ret = 0;
const char *pers = "aws_iot_tls_wrapper";
#ifdef IOT_DEBUG
unsigned char buf[MBEDTLS_SSL_MAX_CONTENT_LEN + 1];
#endif
TLSDataParams *tlsDataParams = &(pNetwork->tlsDataParams);
mbedtls_net_init(&(tlsDataParams->server_fd));
mbedtls_ssl_init(&(tlsDataParams->ssl));
mbedtls_ssl_config_init(&(tlsDataParams->conf));
mbedtls_ctr_drbg_init(&(tlsDataParams->ctr_drbg));
mbedtls_x509_crt_init(&(tlsDataParams->cacert));
mbedtls_x509_crt_init(&(tlsDataParams->clicert));
mbedtls_pk_init(&(tlsDataParams->pkey));
DEBUG("\n . Seeding the random number generator...");
mbedtls_entropy_init(&(tlsDataParams->entropy));
if ((ret = mbedtls_ctr_drbg_seed(&(tlsDataParams->ctr_drbg), mbedtls_entropy_func, &(tlsDataParams->entropy),
(const unsigned char *) pers, strlen(pers))) != 0) {
ERROR(" failed\n ! mbedtls_ctr_drbg_seed returned -0x%x\n", -ret);
return NETWORK_MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED;
}
DEBUG(" . Loading the CA root certificate ...");
ret = mbedtls_x509_crt_parse_file(&(tlsDataParams->cacert), pNetwork->tlsConnectParams.pRootCALocation);
if (ret < 0) {
ERROR(" failed\n ! mbedtls_x509_crt_parse returned -0x%x while parsing root cert\n\n", -ret);
return NETWORK_X509_ROOT_CRT_PARSE_ERROR;
} DEBUG(" ok (%d skipped)\n", ret);
DEBUG(" . Loading the client cert. and key...");
ret = mbedtls_x509_crt_parse_file(&(tlsDataParams->clicert), pNetwork->tlsConnectParams.pDeviceCertLocation);
if (ret != 0) {
ERROR(" failed\n ! mbedtls_x509_crt_parse returned -0x%x while parsing device cert\n\n", -ret);
return NETWORK_X509_DEVICE_CRT_PARSE_ERROR;
}
ret = mbedtls_pk_parse_keyfile(&(tlsDataParams->pkey), pNetwork->tlsConnectParams.pDevicePrivateKeyLocation, "");
if (ret != 0) {
ERROR(" failed\n ! mbedtls_pk_parse_key returned -0x%x while parsing private key\n\n", -ret);
DEBUG(" path : %s ", pNetwork->tlsConnectParams.pDevicePrivateKeyLocation);
return NETWORK_PK_PRIVATE_KEY_PARSE_ERROR;
} DEBUG(" ok\n");
char portBuffer[6];
snprintf(portBuffer, 6, "%d", pNetwork->tlsConnectParams.DestinationPort);
DEBUG(" . Connecting to %s/%s...", pNetwork->tlsConnectParams.pDestinationURL, portBuffer);
if ((ret = mbedtls_net_connect(&(tlsDataParams->server_fd), pNetwork->tlsConnectParams.pDestinationURL,
portBuffer, MBEDTLS_NET_PROTO_TCP)) != 0) {
ERROR(" failed\n ! mbedtls_net_connect returned -0x%x\n\n", -ret);
switch(ret) {
case MBEDTLS_ERR_NET_SOCKET_FAILED:
return NETWORK_ERR_NET_SOCKET_FAILED;
case MBEDTLS_ERR_NET_UNKNOWN_HOST:
return NETWORK_ERR_NET_UNKNOWN_HOST;
case MBEDTLS_ERR_NET_CONNECT_FAILED:
default:
return NETWORK_ERR_NET_CONNECT_FAILED;
};
}
ret = mbedtls_net_set_block(&(tlsDataParams->server_fd));
if (ret != 0) {
ERROR(" failed\n ! net_set_(non)block() returned -0x%x\n\n", -ret);
return SSL_CONNECTION_ERROR;
} DEBUG(" ok\n");
DEBUG(" . Setting up the SSL/TLS structure...");
if ((ret = mbedtls_ssl_config_defaults(&(tlsDataParams->conf), MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
ERROR(" failed\n ! mbedtls_ssl_config_defaults returned -0x%x\n\n", -ret);
return SSL_CONNECTION_ERROR;
}
mbedtls_ssl_conf_verify(&(tlsDataParams->conf), _iot_tls_verify_cert, NULL);
if (pNetwork->tlsConnectParams.ServerVerificationFlag == true) {
mbedtls_ssl_conf_authmode(&(tlsDataParams->conf), MBEDTLS_SSL_VERIFY_REQUIRED);
} else {
mbedtls_ssl_conf_authmode(&(tlsDataParams->conf), MBEDTLS_SSL_VERIFY_OPTIONAL);
}
mbedtls_ssl_conf_rng(&(tlsDataParams->conf), mbedtls_ctr_drbg_random, &(tlsDataParams->ctr_drbg));
mbedtls_ssl_conf_ca_chain(&(tlsDataParams->conf), &(tlsDataParams->cacert), NULL);
if ((ret = mbedtls_ssl_conf_own_cert(&(tlsDataParams->conf), &(tlsDataParams->clicert), &(tlsDataParams->pkey))) != 0) {
ERROR(" failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret);
return SSL_CONNECTION_ERROR;
}
mbedtls_ssl_conf_read_timeout(&(tlsDataParams->conf), pNetwork->tlsConnectParams.timeout_ms);
if ((ret = mbedtls_ssl_setup(&(tlsDataParams->ssl), &(tlsDataParams->conf))) != 0) {
ERROR(" failed\n ! mbedtls_ssl_setup returned -0x%x\n\n", -ret);
return SSL_CONNECTION_ERROR;
}
if ((ret = mbedtls_ssl_set_hostname(&(tlsDataParams->ssl), pNetwork->tlsConnectParams.pDestinationURL)) != 0) {
ERROR(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
return SSL_CONNECTION_ERROR;
}
DEBUG("\n\nSSL state connect : %d ", tlsDataParams->ssl.state);
mbedtls_ssl_set_bio(&(tlsDataParams->ssl), &(tlsDataParams->server_fd), mbedtls_net_send, NULL, mbedtls_net_recv_timeout);
DEBUG(" ok\n");
DEBUG("\n\nSSL state connect : %d ", tlsDataParams->ssl.state);
DEBUG(" . Performing the SSL/TLS handshake...");
while ((ret = mbedtls_ssl_handshake(&(tlsDataParams->ssl))) != 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
ERROR(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n", -ret);
if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
ERROR(" Unable to verify the server's certificate. "
"Either it is invalid,\n"
" or you didn't set ca_file or ca_path "
"to an appropriate value.\n"
" Alternatively, you may want to use "
"auth_mode=optional for testing purposes.\n");
}
return SSL_CONNECTION_ERROR;
}
}
DEBUG(" ok\n [ Protocol is %s ]\n [ Ciphersuite is %s ]\n", mbedtls_ssl_get_version(&(tlsDataParams->ssl)), mbedtls_ssl_get_ciphersuite(&(tlsDataParams->ssl)));
if ((ret = mbedtls_ssl_get_record_expansion(&(tlsDataParams->ssl))) >= 0) {
DEBUG(" [ Record expansion is %d ]\n", ret);
} else {
DEBUG(" [ Record expansion is unknown (compression) ]\n");
}
DEBUG(" . Verifying peer X.509 certificate...");
if(pNetwork->tlsConnectParams.ServerVerificationFlag == true) {
if((tlsDataParams->flags = mbedtls_ssl_get_verify_result(&(tlsDataParams->ssl))) != 0) {
char vrfy_buf[512];
ERROR(" failed\n");
mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", tlsDataParams->flags);
ERROR("%s\n", vrfy_buf);
ret = SSL_CONNECTION_ERROR;
} else {
DEBUG(" ok\n");
ret = SUCCESS;
}
} else {
DEBUG(" Server Verification skipped\n");
ret = SUCCESS;
}
#ifdef IOT_DEBUG
if (mbedtls_ssl_get_peer_cert(&(tlsDataParams->ssl)) != NULL) {
DEBUG(" . Peer certificate information ...\n");
mbedtls_x509_crt_info((char *) buf, sizeof(buf) - 1, " ", mbedtls_ssl_get_peer_cert(&(tlsDataParams->ssl)));
DEBUG("%s\n", buf);
}
#endif
mbedtls_ssl_conf_read_timeout(&(tlsDataParams->conf), IOT_SSL_READ_TIMEOUT);
return ret;
}
IoT_Error_t iot_tls_write(Network *pNetwork, unsigned char *pMsg, size_t len, Timer *timer, size_t *written_len) {
size_t written_so_far;
bool isErrorFlag = false;
int frags, ret;
TLSDataParams *tlsDataParams = &(pNetwork->tlsDataParams);
for(written_so_far = 0, frags = 0; written_so_far < len && !has_timer_expired(timer); written_so_far += ret, frags++) {
while(!has_timer_expired(timer) && (ret = mbedtls_ssl_write(&(tlsDataParams->ssl), pMsg + written_so_far, len - written_so_far)) <= 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
ERROR(" failed\n ! mbedtls_ssl_write returned -0x%x\n\n", -ret);
/* All other negative return values indicate connection needs to be reset.
* Will be caught in ping request so ignored here */
isErrorFlag = true;
break;
}
}
if(isErrorFlag) {
break;
}
}
*written_len = written_so_far;
if(isErrorFlag) {
return NETWORK_SSL_WRITE_ERROR;
} else if(has_timer_expired(timer) && written_so_far != len) {
return NETWORK_SSL_WRITE_TIMEOUT_ERROR;
}
return SUCCESS;
}
IoT_Error_t iot_tls_read(Network *pNetwork, unsigned char *pMsg, size_t len, Timer *timer, size_t *read_len) {
size_t rxLen = 0;
bool isErrorFlag = false;
bool isCompleteFlag = false;
uint32_t timerLeftVal = left_ms(timer);
TLSDataParams *tlsDataParams = &(pNetwork->tlsDataParams);
int ret = 0;
do {
//mbedtls_ssl_conf_read_timeout(&(tlsDataParams->conf), timerLeftVal);
ret = mbedtls_ssl_read(&(tlsDataParams->ssl), pMsg, len);
if (ret >= 0) { /* 0 is for EOF */
rxLen += ret;
} else if (ret != MBEDTLS_ERR_SSL_WANT_READ) {
isErrorFlag = true;
}
/* All other negative return values indicate connection needs to be reset.
* Will be caught in ping request so ignored here */
if (rxLen >= len) {
isCompleteFlag = true;
}
timerLeftVal = left_ms(timer);
} while(!isErrorFlag && !isCompleteFlag && timerLeftVal > 0);
*read_len = rxLen;
if(0 == rxLen && isErrorFlag) {
return NETWORK_SSL_NOTHING_TO_READ;
} else if(has_timer_expired(timer) && !isCompleteFlag) {
return NETWORK_SSL_READ_TIMEOUT_ERROR;
}
return SUCCESS;
}
IoT_Error_t iot_tls_disconnect(Network *pNetwork) {
mbedtls_ssl_context *ssl = &(pNetwork->tlsDataParams.ssl);
int ret = 0;
do {
ret = mbedtls_ssl_close_notify(ssl);
} while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
/* All other negative return values indicate connection needs to be reset.
* No further action required since this is disconnect call */
return SUCCESS;
}
IoT_Error_t iot_tls_destroy(Network *pNetwork) {
TLSDataParams *tlsDataParams = &(pNetwork->tlsDataParams);
mbedtls_net_free(&(tlsDataParams->server_fd));
mbedtls_x509_crt_free(&(tlsDataParams->clicert));
mbedtls_x509_crt_free(&(tlsDataParams->cacert));
mbedtls_pk_free(&(tlsDataParams->pkey));
mbedtls_ssl_free(&(tlsDataParams->ssl));
mbedtls_ssl_config_free(&(tlsDataParams->conf));
mbedtls_ctr_drbg_free(&(tlsDataParams->ctr_drbg));
mbedtls_entropy_free(&(tlsDataParams->entropy));
return SUCCESS;
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#ifndef IOTSDKC_NETWORK_MBEDTLS_PLATFORM_H_H
#include "mbedtls/config.h"
#include "mbedtls/net.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/certs.h"
#include "mbedtls/x509.h"
#include "mbedtls/error.h"
#include "mbedtls/debug.h"
#include "mbedtls/timing.h"
/**
* @brief TLS Connection Parameters
*
* Defines a type containing TLS specific parameters to be passed down to the
* TLS networking layer to create a TLS secured socket.
*/
typedef struct _TLSDataParams {
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
uint32_t flags;
mbedtls_x509_crt cacert;
mbedtls_x509_crt clicert;
mbedtls_pk_context pkey;
mbedtls_net_context server_fd;
}TLSDataParams;
#define IOTSDKC_NETWORK_MBEDTLS_PLATFORM_H_H
#endif //IOTSDKC_NETWORK_MBEDTLS_PLATFORM_H_H

View File

@@ -13,12 +13,23 @@
* permissions and limitations under the License.
*/
#ifndef SRC_PROTOCOL_MQTT_PAHO_EMBEDDEDC_PLATFORM_LINUX_HOSTNAME_COMPARE_H_
#define SRC_PROTOCOL_MQTT_PAHO_EMBEDDEDC_PLATFORM_LINUX_HOSTNAME_COMPARE_H_
#include "threads_interface.h"
#ifdef _ENABLE_THREAD_SUPPORT_
#ifndef IOTSDKC_THREADS_PLATFORM_H_H
#define IOTSDKC_THREADS_PLATFORM_H_H
#define CURL_HOST_MATCH 1
#define CURL_HOST_NOMATCH 0
#include <pthread.h>
int hostmatch(const char *hostname, const char *pattern);
/**
* @brief Mutex Type
*
* definition of the Mutex struct. Platform specific
*
*/
struct _IoT_Mutex_t {
pthread_mutex_t lock;
};
#endif /* IOTSDKC_THREADS_PLATFORM_H_H */
#endif /* _ENABLE_THREAD_SUPPORT_ */
#endif /* SRC_PROTOCOL_MQTT_PAHO_EMBEDDEDC_PLATFORM_LINUX_HOSTNAME_COMPARE_H_ */

View File

@@ -0,0 +1,103 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#include "threads_platform.h"
#ifdef _ENABLE_THREAD_SUPPORT_
/**
* @brief Initialize the provided mutex
*
* Call this function to initialize the mutex
*
* @param IoT_Mutex_t - pointer to the mutex to be initialized
* @return IoT_Error_t - error code indicating result of operation
*/
IoT_Error_t aws_iot_thread_mutex_init(IoT_Mutex_t *pMutex) {
if(0 != pthread_mutex_init(&(pMutex->lock), NULL)) {
return MUTEX_INIT_ERROR;
}
return SUCCESS;
}
/**
* @brief Lock the provided mutex
*
* Call this function to lock the mutex before performing a state change
* Blocking, thread will block until lock request fails
*
* @param IoT_Mutex_t - pointer to the mutex to be locked
* @return IoT_Error_t - error code indicating result of operation
*/
IoT_Error_t aws_iot_thread_mutex_lock(IoT_Mutex_t *pMutex) {
int rc = pthread_mutex_lock(&(pMutex->lock));
if(0 != rc) {
return MUTEX_LOCK_ERROR;
}
return SUCCESS;
}
/**
* @brief Try to lock the provided mutex
*
* Call this function to attempt to lock the mutex before performing a state change
* Non-Blocking, immediately returns with failure if lock attempt fails
*
* @param IoT_Mutex_t - pointer to the mutex to be locked
* @return IoT_Error_t - error code indicating result of operation
*/
IoT_Error_t aws_iot_thread_mutex_trylock(IoT_Mutex_t *pMutex) {
int rc = pthread_mutex_trylock(&(pMutex->lock));
if(0 != rc) {
return MUTEX_LOCK_ERROR;
}
return SUCCESS;
}
/**
* @brief Unlock the provided mutex
*
* Call this function to unlock the mutex before performing a state change
*
* @param IoT_Mutex_t - pointer to the mutex to be unlocked
* @return IoT_Error_t - error code indicating result of operation
*/
IoT_Error_t aws_iot_thread_mutex_unlock(IoT_Mutex_t *pMutex) {
if(0 != pthread_mutex_unlock(&(pMutex->lock))) {
return MUTEX_UNLOCK_ERROR;
}
return SUCCESS;
}
/**
* @brief Destroy the provided mutex
*
* Call this function to destroy the mutex
*
* @param IoT_Mutex_t - pointer to the mutex to be destroyed
* @return IoT_Error_t - error code indicating result of operation
*/
IoT_Error_t aws_iot_thread_mutex_destroy(IoT_Mutex_t *pMutex) {
if(0 != pthread_mutex_destroy(&(pMutex->lock))) {
return MUTEX_DESTROY_ERROR;
}
return SUCCESS;
}
#endif /* _ENABLE_THREAD_SUPPORT_ */

View File

@@ -1,91 +0,0 @@
.prevent_execution:
exit 0
#This target is to ensure accidental execution of Makefile as a bash script will not execute commands like rm in unexpected directories and exit gracefully.
CC = gcc
#remove @ for no make command prints
DEBUG=@
APP_DIR = .
APP_INCLUDE_DIRS += -I $(APP_DIR)
APP_NAME=shadow_sample
APP_SRC_FILES=$(APP_NAME).c
#IoT client directory
IOT_CLIENT_DIR=../../aws_iot_src
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux
IOT_INCLUDE_DIRS += -I $(PLATFORM_COMMON_DIR)
IOT_INCLUDE_DIRS += -I $(PLATFORM_DIR)
IOT_INCLUDE_DIRS += -I $(SHADOW_SRC_DIR)
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/utils
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/shadow
PLATFORM_DIR = $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux/mbedtls
PLATFORM_COMMON_DIR = $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux/common
SHADOW_SRC_DIR= $(IOT_CLIENT_DIR)/shadow
IOT_SRC_FILES += $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/aws_iot_mqtt_embedded_client_wrapper.c
IOT_SRC_FILES += $(IOT_CLIENT_DIR)/utils/jsmn.c
IOT_SRC_FILES += $(IOT_CLIENT_DIR)/utils/aws_iot_json_utils.c
IOT_SRC_FILES += $(shell find $(PLATFORM_DIR)/ -name '*.c')
IOT_SRC_FILES += $(shell find $(SHADOW_SRC_DIR)/ -name '*.c')
IOT_SRC_FILES += $(shell find $(PLATFORM_COMMON_DIR)/ -name '*.c')
#MQTT Paho Embedded C client directory
MQTT_DIR = ../../aws_mqtt_embedded_client_lib
MQTT_C_DIR = $(MQTT_DIR)/MQTTClient-C/src
MQTT_EMB_DIR = $(MQTT_DIR)/MQTTPacket/src
MQTT_INCLUDE_DIR += -I $(MQTT_EMB_DIR)
MQTT_INCLUDE_DIR += -I $(MQTT_C_DIR)
MQTT_SRC_FILES += $(shell find $(MQTT_EMB_DIR)/ -name '*.c')
MQTT_SRC_FILES += $(MQTT_C_DIR)/MQTTClient.c
#TLS - mbedtls
MBEDTLS_DIR=../../mbedtls_lib
TLS_LIB_DIR = $(MBEDTLS_DIR)/library
TLS_INCLUDE_DIR = -I $(MBEDTLS_DIR)/include
EXTERNAL_LIBS += -L$(TLS_LIB_DIR)
LD_FLAG += -Wl,-rpath,$(TLS_LIB_DIR)
LD_FLAG += -ldl $(TLS_LIB_DIR)/libmbedtls.a $(TLS_LIB_DIR)/libmbedcrypto.a $(TLS_LIB_DIR)/libmbedx509.a
#Aggregate all include and src directories
INCLUDE_ALL_DIRS += $(IOT_INCLUDE_DIRS)
INCLUDE_ALL_DIRS += $(MQTT_INCLUDE_DIR)
INCLUDE_ALL_DIRS += $(TLS_INCLUDE_DIR)
INCLUDE_ALL_DIRS += $(APP_INCLUDE_DIRS)
SRC_FILES += $(MQTT_SRC_FILES)
SRC_FILES += $(APP_SRC_FILES)
SRC_FILES += $(IOT_SRC_FILES)
# Logging level control
LOG_FLAGS += -DIOT_DEBUG
LOG_FLAGS += -DIOT_INFO
LOG_FLAGS += -DIOT_WARN
LOG_FLAGS += -DIOT_ERROR
COMPILER_FLAGS += -g
COMPILER_FLAGS += $(LOG_FLAGS)
#If the processor is big endian uncomment the compiler flag
#COMPILER_FLAGS += -DREVERSED
MBED_TLS_MAKE_CMD = cd $(MBEDTLS_DIR) && make
PRE_MAKE_CMD = $(MBED_TLS_MAKE_CMD)
MAKE_CMD = $(CC) $(SRC_FILES) $(COMPILER_FLAGS) -o $(APP_NAME) $(LD_FLAG) $(EXTERNAL_LIBS) $(INCLUDE_ALL_DIRS)
all:
$(PRE_MAKE_CMD)
$(DEBUG)$(MAKE_CMD)
$(POST_MAKE_CMD)
clean:
rm -f $(APP_DIR)/$(APP_NAME)
$(MBED_TLS_MAKE_CMD) clean

View File

@@ -1,86 +0,0 @@
.prevent_execution:
exit 0
#This target is to ensure accidental execution of Makefile as a bash script will not execute commands like rm in unexpected directories and exit gracefully.
CC = gcc
#remove @ for no make command prints
DEBUG=@
APP_DIR = .
APP_NAME=shadow_sample
APP_INCLUDE_DIRS += -I $(APP_DIR)
APP_SRC_FILES=$(APP_NAME).c
#IoT client directory
IOT_CLIENT_DIR=../../aws_iot_src
PLATFORM_DIR = $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux/openssl
PLATFORM_COMMON_DIR = $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux/common
SHADOW_SRC_DIR= $(IOT_CLIENT_DIR)/shadow
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux
IOT_INCLUDE_DIRS += -I $(PLATFORM_COMMON_DIR)
IOT_INCLUDE_DIRS += -I $(PLATFORM_DIR)
IOT_INCLUDE_DIRS += -I $(SHADOW_SRC_DIR)
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/utils
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/shadow
IOT_SRC_FILES += $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/aws_iot_mqtt_embedded_client_wrapper.c
IOT_SRC_FILES += $(IOT_CLIENT_DIR)/utils/jsmn.c
IOT_SRC_FILES += $(IOT_CLIENT_DIR)/utils/aws_iot_json_utils.c
IOT_SRC_FILES += $(shell find $(SHADOW_SRC_DIR)/ -name '*.c')
IOT_SRC_FILES += $(shell find $(PLATFORM_DIR)/ -name '*.c')
IOT_SRC_FILES += $(shell find $(PLATFORM_COMMON_DIR)/ -name '*.c')
#MQTT Paho Embedded C client directory
MQTT_DIR = ../../aws_mqtt_embedded_client_lib
MQTT_C_DIR = $(MQTT_DIR)/MQTTClient-C/src
MQTT_EMB_DIR = $(MQTT_DIR)/MQTTPacket/src
MQTT_INCLUDE_DIR += -I $(MQTT_EMB_DIR)
MQTT_INCLUDE_DIR += -I $(MQTT_C_DIR)
MQTT_SRC_FILES += $(shell find $(MQTT_EMB_DIR)/ -name '*.c')
MQTT_SRC_FILES += $(MQTT_C_DIR)/MQTTClient.c
#TLS - openSSL
TLS_LIB_DIR = /usr/lib/
TLS_INCLUDE_DIR = -I /usr/include/openssl
EXTERNAL_LIBS += -L$(TLS_LIB_DIR)
LD_FLAG := -ldl -lssl -lcrypto
LD_FLAG += -Wl,-rpath,$(TLS_LIB_DIR)
#Aggregate all include and src directories
INCLUDE_ALL_DIRS += $(IOT_INCLUDE_DIRS)
INCLUDE_ALL_DIRS += $(MQTT_INCLUDE_DIR)
INCLUDE_ALL_DIRS += $(TLS_INCLUDE_DIR)
INCLUDE_ALL_DIRS += $(APP_INCLUDE_DIRS)
SRC_FILES += $(MQTT_SRC_FILES)
SRC_FILES += $(APP_SRC_FILES)
SRC_FILES += $(IOT_SRC_FILES)
# Logging level control
LOG_FLAGS += -DIOT_DEBUG
LOG_FLAGS += -DIOT_INFO
LOG_FLAGS += -DIOT_WARN
LOG_FLAGS += -DIOT_ERROR
COMPILER_FLAGS += -g
COMPILER_FLAGS += $(LOG_FLAGS)
#If the processor is big endian uncomment the compiler flag
#COMPILER_FLAGS += -DREVERSED
MAKE_CMD = $(CC) $(SRC_FILES) $(COMPILER_FLAGS) -o $(APP_NAME) $(EXTERNAL_LIBS) $(LD_FLAG) $(INCLUDE_ALL_DIRS)
all:
$(DEBUG)$(MAKE_CMD)
clean:
rm -f $(APP_DIR)/$(APP_NAME)

View File

@@ -1,92 +0,0 @@
.prevent_execution:
exit 0
#This target is to ensure accidental execution of Makefile as a bash script will not execute commands like rm in unexpected directories and exit gracefully.
CC = gcc
#remove @ for no make command prints
DEBUG=@
APP_DIR = .
APP_INCLUDE_DIRS += -I $(APP_DIR)
APP_NAME=shadow_console_echo
APP_SRC_FILES=$(APP_NAME).c
#IoT client directory
IOT_CLIENT_DIR=../../aws_iot_src
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux
IOT_INCLUDE_DIRS += -I $(PLATFORM_COMMON_DIR)
IOT_INCLUDE_DIRS += -I $(PLATFORM_DIR)
IOT_INCLUDE_DIRS += -I $(SHADOW_SRC_DIR)
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/utils
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/shadow
PLATFORM_DIR = $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux/mbedtls
PLATFORM_COMMON_DIR = $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux/common
SHADOW_SRC_DIR= $(IOT_CLIENT_DIR)/shadow
IOT_SRC_FILES += $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/aws_iot_mqtt_embedded_client_wrapper.c
IOT_SRC_FILES += $(IOT_CLIENT_DIR)/utils/jsmn.c
IOT_SRC_FILES += $(IOT_CLIENT_DIR)/utils/aws_iot_json_utils.c
IOT_SRC_FILES += $(shell find $(PLATFORM_DIR)/ -name '*.c')
IOT_SRC_FILES += $(shell find $(SHADOW_SRC_DIR)/ -name '*.c')
IOT_SRC_FILES += $(shell find $(PLATFORM_COMMON_DIR)/ -name '*.c')
#MQTT Paho Embedded C client directory
MQTT_DIR = ../../aws_mqtt_embedded_client_lib
MQTT_C_DIR = $(MQTT_DIR)/MQTTClient-C/src
MQTT_EMB_DIR = $(MQTT_DIR)/MQTTPacket/src
MQTT_INCLUDE_DIR += -I $(MQTT_EMB_DIR)
MQTT_INCLUDE_DIR += -I $(MQTT_C_DIR)
MQTT_SRC_FILES += $(shell find $(MQTT_EMB_DIR)/ -name '*.c')
MQTT_SRC_FILES += $(MQTT_C_DIR)/MQTTClient.c
#TLS - mbedtls
MBEDTLS_DIR=../../mbedtls_lib
TLS_LIB_DIR = $(MBEDTLS_DIR)/library
TLS_INCLUDE_DIR = -I $(MBEDTLS_DIR)/include
EXTERNAL_LIBS += -L$(TLS_LIB_DIR)
LD_FLAG += -Wl,-rpath,$(TLS_LIB_DIR)
LD_FLAG += -ldl $(TLS_LIB_DIR)/libmbedtls.a $(TLS_LIB_DIR)/libmbedcrypto.a $(TLS_LIB_DIR)/libmbedx509.a
#Aggregate all include and src directories
INCLUDE_ALL_DIRS += $(IOT_INCLUDE_DIRS)
INCLUDE_ALL_DIRS += $(MQTT_INCLUDE_DIR)
INCLUDE_ALL_DIRS += $(TLS_INCLUDE_DIR)
INCLUDE_ALL_DIRS += $(APP_INCLUDE_DIRS)
SRC_FILES += $(MQTT_SRC_FILES)
SRC_FILES += $(APP_SRC_FILES)
SRC_FILES += $(IOT_SRC_FILES)
# Logging level control
LOG_FLAGS += -DIOT_DEBUG
LOG_FLAGS += -DIOT_INFO
LOG_FLAGS += -DIOT_WARN
LOG_FLAGS += -DIOT_ERROR
COMPILER_FLAGS += -g
COMPILER_FLAGS += $(LOG_FLAGS)
#If the processor is big endian uncomment the compiler flag
#COMPILER_FLAGS += -DREVERSED
MBED_TLS_MAKE_CMD = cd $(MBEDTLS_DIR) && make
PRE_MAKE_CMD = $(MBED_TLS_MAKE_CMD)
MAKE_CMD = $(CC) $(SRC_FILES) $(COMPILER_FLAGS) -o $(APP_NAME) $(LD_FLAG) $(EXTERNAL_LIBS) $(INCLUDE_ALL_DIRS)
all:
$(PRE_MAKE_CMD)
$(DEBUG)$(MAKE_CMD)
$(POST_MAKE_CMD)
clean:
rm -f $(APP_DIR)/$(APP_NAME)
$(MBED_TLS_MAKE_CMD) clean

View File

@@ -1,87 +0,0 @@
.prevent_execution:
exit 0
#This target is to ensure accidental execution of Makefile as a bash script will not execute commands like rm in unexpected directories and exit gracefully.
CC = gcc
#remove @ for no make command prints
DEBUG=@
APP_DIR = .
APP_NAME=shadow_console_echo
APP_INCLUDE_DIRS += -I $(APP_DIR)
APP_SRC_FILES=$(APP_NAME).c
#IoT client directory
IOT_CLIENT_DIR=../../aws_iot_src
PLATFORM_DIR = $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux/openssl
PLATFORM_COMMON_DIR = $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux/common
SHADOW_SRC_DIR= $(IOT_CLIENT_DIR)/shadow
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux
IOT_INCLUDE_DIRS += -I $(PLATFORM_COMMON_DIR)
IOT_INCLUDE_DIRS += -I $(PLATFORM_DIR)
IOT_INCLUDE_DIRS += -I $(SHADOW_SRC_DIR)
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/utils
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/shadow
IOT_SRC_FILES += $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/aws_iot_mqtt_embedded_client_wrapper.c
IOT_SRC_FILES += $(IOT_CLIENT_DIR)/utils/jsmn.c
IOT_SRC_FILES += $(IOT_CLIENT_DIR)/utils/aws_iot_json_utils.c
IOT_SRC_FILES += $(shell find $(SHADOW_SRC_DIR)/ -name '*.c')
IOT_SRC_FILES += $(shell find $(PLATFORM_DIR)/ -name '*.c')
IOT_SRC_FILES += $(shell find $(PLATFORM_COMMON_DIR)/ -name '*.c')
#MQTT Paho Embedded C client directory
MQTT_DIR = ../../aws_mqtt_embedded_client_lib
MQTT_C_DIR = $(MQTT_DIR)/MQTTClient-C/src
MQTT_EMB_DIR = $(MQTT_DIR)/MQTTPacket/src
MQTT_INCLUDE_DIR += -I $(MQTT_EMB_DIR)
MQTT_INCLUDE_DIR += -I $(MQTT_C_DIR)
MQTT_SRC_FILES += $(shell find $(MQTT_EMB_DIR)/ -name '*.c')
MQTT_SRC_FILES += $(MQTT_C_DIR)/MQTTClient.c
#TLS - openSSL
TLS_LIB_DIR = /usr/lib/
TLS_INCLUDE_DIR = -I /usr/include/openssl
EXTERNAL_LIBS += -L$(TLS_LIB_DIR)
LD_FLAG := -ldl -lssl -lcrypto
LD_FLAG += -Wl,-rpath,$(TLS_LIB_DIR)
#Aggregate all include and src directories
INCLUDE_ALL_DIRS += $(IOT_INCLUDE_DIRS)
INCLUDE_ALL_DIRS += $(MQTT_INCLUDE_DIR)
INCLUDE_ALL_DIRS += $(TLS_INCLUDE_DIR)
INCLUDE_ALL_DIRS += $(APP_INCLUDE_DIRS)
SRC_FILES += $(MQTT_SRC_FILES)
SRC_FILES += $(APP_SRC_FILES)
SRC_FILES += $(IOT_SRC_FILES)
# Logging level control
LOG_FLAGS += -DIOT_DEBUG
LOG_FLAGS += -DIOT_INFO
LOG_FLAGS += -DIOT_WARN
LOG_FLAGS += -DIOT_ERROR
COMPILER_FLAGS += -g
COMPILER_FLAGS += $(LOG_FLAGS)
#If the processor is big endian uncomment the compiler flag
#COMPILER_FLAGS += -DREVERSED
MAKE_CMD = $(CC) $(SRC_FILES) $(COMPILER_FLAGS) -o $(APP_NAME) $(EXTERNAL_LIBS) $(LD_FLAG) $(INCLUDE_ALL_DIRS)
all:
$(DEBUG)$(MAKE_CMD)
clean:
rm -f $(APP_DIR)/$(APP_NAME)

View File

@@ -1,84 +0,0 @@
.prevent_execution:
exit 0
#This target is to ensure accidental execution of Makefile as a bash script will not execute commands like rm in unexpected directories and exit gracefully.
CC = gcc
#remove @ for no make command prints
DEBUG=@
APP_DIR = .
APP_INCLUDE_DIRS += -I $(APP_DIR)
APP_NAME=subscribe_publish_sample
APP_SRC_FILES=$(APP_NAME).c
#IoT client directory
IOT_CLIENT_DIR=../../aws_iot_src
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux/common
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux/mbedtls
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/utils
PLATFORM_DIR = $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux/mbedtls
PLATFORM_COMMON_DIR = $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux/common
IOT_SRC_FILES += $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/aws_iot_mqtt_embedded_client_wrapper.c
IOT_SRC_FILES += $(shell find $(PLATFORM_DIR)/ -name '*.c')
IOT_SRC_FILES += $(shell find $(PLATFORM_COMMON_DIR)/ -name '*.c')
#MQTT Paho Embedded C client directory
MQTT_DIR = ../../aws_mqtt_embedded_client_lib
MQTT_C_DIR = $(MQTT_DIR)/MQTTClient-C/src
MQTT_EMB_DIR = $(MQTT_DIR)/MQTTPacket/src
MQTT_INCLUDE_DIR += -I $(MQTT_EMB_DIR)
MQTT_INCLUDE_DIR += -I $(MQTT_C_DIR)
MQTT_SRC_FILES += $(shell find $(MQTT_EMB_DIR)/ -name '*.c')
MQTT_SRC_FILES += $(MQTT_C_DIR)/MQTTClient.c
#TLS - mbedtls
MBEDTLS_DIR=../../mbedtls_lib
TLS_LIB_DIR = $(MBEDTLS_DIR)/library
TLS_INCLUDE_DIR = -I $(MBEDTLS_DIR)/include
EXTERNAL_LIBS += -L$(TLS_LIB_DIR)
LD_FLAG += -Wl,-rpath,$(TLS_LIB_DIR)
LD_FLAG += -ldl $(TLS_LIB_DIR)/libmbedtls.a $(TLS_LIB_DIR)/libmbedcrypto.a $(TLS_LIB_DIR)/libmbedx509.a
#Aggregate all include and src directories
INCLUDE_ALL_DIRS += $(IOT_INCLUDE_DIRS)
INCLUDE_ALL_DIRS += $(MQTT_INCLUDE_DIR)
INCLUDE_ALL_DIRS += $(TLS_INCLUDE_DIR)
INCLUDE_ALL_DIRS += $(APP_INCLUDE_DIRS)
SRC_FILES += $(MQTT_SRC_FILES)
SRC_FILES += $(APP_SRC_FILES)
SRC_FILES += $(IOT_SRC_FILES)
# Logging level control
LOG_FLAGS += -DIOT_DEBUG
LOG_FLAGS += -DIOT_INFO
LOG_FLAGS += -DIOT_WARN
LOG_FLAGS += -DIOT_ERROR
COMPILER_FLAGS += -g
COMPILER_FLAGS += $(LOG_FLAGS)
#If the processor is big endian uncomment the compiler flag
#COMPILER_FLAGS += -DREVERSED
MBED_TLS_MAKE_CMD = cd $(MBEDTLS_DIR) && make
PRE_MAKE_CMD = $(MBED_TLS_MAKE_CMD)
MAKE_CMD = $(CC) $(SRC_FILES) $(COMPILER_FLAGS) -o $(APP_NAME) $(LD_FLAG) $(EXTERNAL_LIBS) $(INCLUDE_ALL_DIRS)
all:
$(PRE_MAKE_CMD)
$(DEBUG)$(MAKE_CMD)
$(POST_MAKE_CMD)
clean:
rm -f $(APP_DIR)/$(APP_NAME)
$(MBED_TLS_MAKE_CMD) clean

View File

@@ -1,79 +0,0 @@
.prevent_execution:
exit 0
#This target is to ensure accidental execution of Makefile as a bash script will not execute commands like rm in unexpected directories and exit gracefully.
CC = gcc
#remove @ for no make command prints
DEBUG=@
APP_DIR = .
APP_INCLUDE_DIRS += -I $(APP_DIR)
APP_NAME=subscribe_publish_sample
APP_SRC_FILES=$(APP_NAME).c
#IoT client directory
IOT_CLIENT_DIR=../../aws_iot_src
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux/common
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux/openssl
IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/utils
PLATFORM_DIR = $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux/openssl
PLATFORM_COMMON_DIR = $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux/common
IOT_SRC_FILES += $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/aws_iot_mqtt_embedded_client_wrapper.c
IOT_SRC_FILES += $(shell find $(PLATFORM_DIR)/ -name '*.c')
IOT_SRC_FILES += $(shell find $(PLATFORM_COMMON_DIR)/ -name '*.c')
#MQTT Paho Embedded C client directory
MQTT_DIR = ../../aws_mqtt_embedded_client_lib
MQTT_C_DIR = $(MQTT_DIR)/MQTTClient-C/src
MQTT_EMB_DIR = $(MQTT_DIR)/MQTTPacket/src
MQTT_INCLUDE_DIR += -I $(MQTT_EMB_DIR)
MQTT_INCLUDE_DIR += -I $(MQTT_C_DIR)
MQTT_SRC_FILES += $(shell find $(MQTT_EMB_DIR)/ -name '*.c')
MQTT_SRC_FILES += $(MQTT_C_DIR)/MQTTClient.c
#TLS - openSSL
TLS_LIB_DIR = /usr/lib/
TLS_INCLUDE_DIR = -I /usr/include/openssl
EXTERNAL_LIBS += -L$(TLS_LIB_DIR)
LD_FLAG := -ldl -lssl -lcrypto
LD_FLAG += -Wl,-rpath,$(TLS_LIB_DIR)
#Aggregate all include and src directories
INCLUDE_ALL_DIRS += $(IOT_INCLUDE_DIRS)
INCLUDE_ALL_DIRS += $(MQTT_INCLUDE_DIR)
INCLUDE_ALL_DIRS += $(TLS_INCLUDE_DIR)
INCLUDE_ALL_DIRS += $(APP_INCLUDE_DIRS)
SRC_FILES += $(MQTT_SRC_FILES)
SRC_FILES += $(APP_SRC_FILES)
SRC_FILES += $(IOT_SRC_FILES)
# Logging level control
LOG_FLAGS += -DIOT_DEBUG
LOG_FLAGS += -DIOT_INFO
LOG_FLAGS += -DIOT_WARN
LOG_FLAGS += -DIOT_ERROR
COMPILER_FLAGS += -g
COMPILER_FLAGS += $(LOG_FLAGS)
#If the processor is big endian uncomment the compiler flag
#COMPILER_FLAGS += -DREVERSED
MAKE_CMD = $(CC) $(SRC_FILES) $(COMPILER_FLAGS) -o $(APP_NAME) $(LD_FLAG) $(EXTERNAL_LIBS) $(INCLUDE_ALL_DIRS)
all:
$(PRE_MAKE_CMD)
$(DEBUG)$(MAKE_CMD)
$(POST_MAKE_CMD)
clean:
rm -f $(APP_DIR)/$(APP_NAME)

33
samples/README.md Normal file
View File

@@ -0,0 +1,33 @@
## Overview
This folder contains several samples that demonstrate various SDK functions. The Readme file also includes a walk-through of the subscribe publish sample to explain how the SDK is used. The samples are currently provided with Makefiles for building them on linux. For each sample:
* Explore the makefile. The makefile for each sample provides a reference on how to set up makefiles for client applications
* Explore the example. It connects to AWS IoT platform using MQTT and demonstrates few actions that can be performed by the SDK
* Download certificate authority CA file from [Symantec](https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem) and place in location referenced in the example (certs/)
* Place device identity cert and private key in locations referenced in the example (certs/)
* Ensure the names of the cert files are the same as in the `aws_iot_config.h` file
* Ensure the certificate has an attached policy which allows the proper permissions for AWS IoT
* Build the example using make (`make`)
* Run sample application (./subscribe_publish_sample or ./shadow_sample). The sample will print status messages to stdout
* The following sample applications are included:
* `subscribe_publish_sample` - a simple pub/sub MQTT example
* `shadow_sample` - a simple device shadow example using a connected window example
* `shadow_sample_console_echo` - a sample to work with the AWS IoT Console interactive guide
## Subscribe Publish Sample
This is a simple pub/sub MQTT example. It connects a single MQTT client to the server and subscribes to a test topic. Then it proceeds to publish messages on this topic and yields after each publish to ensure that the message was received.
* The sample first creates an instance of the AWS_IoT_Client
* The next step is to initialize the client. The aws_iot_mqtt_init API is called for this purpose. The API takes the client instance and an IoT_Client_Init_Params variable to set the initial values for the client. The Init params include values like host URL, port, certificates, disconnect handler etc.
* If the call to the init API was successful, we can proceed to call connect. The API is called aws_iot_mqtt_connect. It takes the client instance and IoT_Client_Connect_Params variable as arguments. The IoT_Client_Connect_Params is optional after the first call to connect as the client retains the original values that were provided to support reconnect. The Connect params include values like Client Id, MQTT Version etc.
* If the connect API call was successful, we can proceed to subscribe and publish on this connect. The connect API call will return an error code, specific to the type of error that occurred, in case the call fails.
* It is important to remember here that there is no dynamic memory allocation in the SDK. Any values that are passed as a pointer to the APIs should not be freed unless they are not required any further. For example, if the variable that stores the certificate path is freed after the init call is made, the connect call will fail. Similarly, if it is freed after the connect API returns success, any future connect calls (including reconnects) will fail.
* The next step for this sample is to subscribe to the test topic. The API to be called for subscribe is aws_iot_mqtt_subscribe. It takes as arguments, the IoT Client instance, topic name, the length of the topic name, QoS, the subscribe callback handler and an optional pointer to some data to be returned to the subscribe handler
* The next step it to call the publish API to send a message on the test topic. The sample sends two different messages, one QoS0 and one QoS1. The
* The publish API takes the client instance, topic name to publish to, topic name length and a variable of type IoT_Publish_Message_Params. The IoT_Publish_Message_Params contains the payload, length of the payload and QoS.
* If the publish API calls are successful, the sample proceeds to call the yield API. The yield API takes the client instance and a timeout value in milliseconds as arguments.
* The yield API is called to let the SDK process any incoming messages. It also periodically sends out the PING request to prevent disconnect and, if enabled, it also performs auto-reconnect and resubscribe.
* The yield API should be called periodically to process the PING request as well as read any messages in the receive buffer. It should be called once at least every TTL/2 time periods to ensure disconnect does not happen. There can only be one yield in progress at a time. Therefore, in multi-threaded scenarios one thread can be a dedicated yield thread while other threads handle other operations.
* The sample sends out messages equal to the value set in publish count unless infinite publishing flag is set
For further information on each API please read the API documentation.

View File

@@ -27,7 +27,7 @@
#define AWS_IOT_MQTT_PORT 8883 ///< default port for MQTT/S
#define AWS_IOT_MQTT_CLIENT_ID "c-sdk-client-id" ///< MQTT client ID should be unique for every device
#define AWS_IOT_MY_THING_NAME "AWS-IoT-C-SDK" ///< Thing Name of the Shadow this device is associated with
#define AWS_IOT_ROOT_CA_FILENAME "aws-iot-rootCA.crt" ///< Root CA file name
#define AWS_IOT_ROOT_CA_FILENAME "rootCA.crt" ///< Root CA file name
#define AWS_IOT_CERTIFICATE_FILENAME "cert.pem" ///< device signed certificate file name
#define AWS_IOT_PRIVATE_KEY_FILENAME "privkey.pem" ///< Device private key filename
// =================================================

View File

@@ -27,13 +27,14 @@
#include <memory.h>
#include <sys/time.h>
#include <limits.h>
#include <aws_iot_shadow_interface.h>
#include "aws_iot_log.h"
#include "aws_iot_version.h"
#include "aws_iot_shadow_interface.h"
#include "aws_iot_shadow_json_data.h"
#include "aws_iot_config.h"
#include "aws_iot_mqtt_interface.h"
#include "aws_iot_mqtt_client_interface.h"
/*!
* The goal of this sample application is to demonstrate the capabilities of shadow.
@@ -91,7 +92,7 @@ void windowActuate_Callback(const char *pJsonString, uint32_t JsonStringDataLen,
}
}
char certDirectory[PATH_MAX + 1] = "../../certs";
char certDirectory[PATH_MAX + 1] = "../../../certs";
char HostAddress[255] = AWS_IOT_MQTT_HOST;
uint32_t port = AWS_IOT_MQTT_PORT;
uint8_t numPubs = 5;
@@ -137,12 +138,9 @@ void parseInputArgsForConnectParams(int argc, char** argv) {
#define MAX_LENGTH_OF_UPDATE_JSON_BUFFER 200
int main(int argc, char** argv) {
IoT_Error_t rc = NONE_ERROR;
IoT_Error_t rc = FAILURE;
int32_t i = 0;
MQTTClient_t mqttClient;
aws_iot_mqtt_init(&mqttClient);
char JsonDocumentBuffer[MAX_LENGTH_OF_UPDATE_JSON_BUFFER];
size_t sizeOfJsonDocumentBuffer = sizeof(JsonDocumentBuffer) / sizeof(JsonDocumentBuffer[0]);
char *pJsonStringToUpdate;
@@ -165,61 +163,70 @@ int main(int argc, char** argv) {
char clientCRT[PATH_MAX + 1];
char clientKey[PATH_MAX + 1];
char CurrentWD[PATH_MAX + 1];
char cafileName[] = AWS_IOT_ROOT_CA_FILENAME;
char clientCRTName[] = AWS_IOT_CERTIFICATE_FILENAME;
char clientKeyName[] = AWS_IOT_PRIVATE_KEY_FILENAME;
INFO("\nAWS IoT SDK Version %d.%d.%d-%s\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);
getcwd(CurrentWD, sizeof(CurrentWD));
snprintf(rootCA, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_ROOT_CA_FILENAME);
snprintf(clientCRT, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_CERTIFICATE_FILENAME);
snprintf(clientKey, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_PRIVATE_KEY_FILENAME);
DEBUG("rootCA %s", rootCA);
DEBUG("clientCRT %s", clientCRT);
DEBUG("clientKey %s", clientKey);
parseInputArgsForConnectParams(argc, argv);
INFO("\nAWS IoT SDK Version(dev) %d.%d.%d-%s\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);
// initialize the mqtt client
AWS_IoT_Client mqttClient;
getcwd(CurrentWD, sizeof(CurrentWD));
sprintf(rootCA, "%s/%s/%s", CurrentWD, certDirectory, cafileName);
sprintf(clientCRT, "%s/%s/%s", CurrentWD, certDirectory, clientCRTName);
sprintf(clientKey, "%s/%s/%s", CurrentWD, certDirectory, clientKeyName);
DEBUG("Using rootCA %s", rootCA);
DEBUG("Using clientCRT %s", clientCRT);
DEBUG("Using clientKey %s", clientKey);
ShadowParameters_t sp = ShadowParametersDefault;
sp.pMyThingName = AWS_IOT_MY_THING_NAME;
sp.pMqttClientId = AWS_IOT_MQTT_CLIENT_ID;
sp.pHost = HostAddress;
sp.port = port;
ShadowInitParameters_t sp = ShadowInitParametersDefault;
sp.pHost = AWS_IOT_MQTT_HOST;
sp.port = AWS_IOT_MQTT_PORT;
sp.pClientCRT = clientCRT;
sp.pClientKey = clientKey;
sp.pRootCA = rootCA;
sp.enableAutoReconnect = false;
sp.disconnectHandler = NULL;
INFO("Shadow Init");
rc = aws_iot_shadow_init(&mqttClient);
rc = aws_iot_shadow_init(&mqttClient, &sp);
if (SUCCESS != rc) {
ERROR("Shadow Connection Error");
return rc;
}
ShadowConnectParameters_t scp = ShadowConnectParametersDefault;
scp.pMyThingName = AWS_IOT_MY_THING_NAME;
scp.pMqttClientId = AWS_IOT_MQTT_CLIENT_ID;
INFO("Shadow Connect");
rc = aws_iot_shadow_connect(&mqttClient, &sp);
if (NONE_ERROR != rc) {
ERROR("Shadow Connection Error %d", rc);
rc = aws_iot_shadow_connect(&mqttClient, &scp);
if (SUCCESS != rc) {
ERROR("Shadow Connection Error");
return rc;
}
/*
* Enable Auto Reconnect functionality. Minimum and Maximum time of Exponential backoff are set in aws_iot_config.h
* #AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL
* #AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL
*/
rc = mqttClient.setAutoReconnectStatus(true);
if (NONE_ERROR != rc) {
rc = aws_iot_shadow_set_autoreconnect_status(&mqttClient, true);
if (SUCCESS != rc) {
ERROR("Unable to set Auto Reconnect to true - %d", rc);
return rc;
}
rc = aws_iot_shadow_register_delta(&mqttClient, &windowActuator);
if (NONE_ERROR != rc) {
if (SUCCESS != rc) {
ERROR("Shadow Register Delta Error");
}
temperature = STARTING_ROOMTEMPERATURE;
// loop and publish a change in temperature
while (NETWORK_ATTEMPTING_RECONNECT == rc || RECONNECT_SUCCESSFUL == rc || NONE_ERROR == rc) {
while (NETWORK_ATTEMPTING_RECONNECT == rc || NETWORK_RECONNECTED == rc || SUCCESS == rc) {
rc = aws_iot_shadow_yield(&mqttClient, 200);
if (NETWORK_ATTEMPTING_RECONNECT == rc) {
sleep(1);
@@ -231,12 +238,12 @@ int main(int argc, char** argv) {
simulateRoomTemperature(&temperature);
rc = aws_iot_shadow_init_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer);
if (rc == NONE_ERROR) {
if (rc == SUCCESS) {
rc = aws_iot_shadow_add_reported(JsonDocumentBuffer, sizeOfJsonDocumentBuffer, 2, &temperatureHandler,
&windowActuator);
if (rc == NONE_ERROR) {
if (rc == SUCCESS) {
rc = aws_iot_finalize_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer);
if (rc == NONE_ERROR) {
if (rc == SUCCESS) {
INFO("Update Shadow: %s", JsonDocumentBuffer);
rc = aws_iot_shadow_update(&mqttClient, AWS_IOT_MY_THING_NAME, JsonDocumentBuffer,
ShadowUpdateStatusCallback, NULL, 4, true);
@@ -247,14 +254,14 @@ int main(int argc, char** argv) {
sleep(1);
}
if (NONE_ERROR != rc) {
if (SUCCESS != rc) {
ERROR("An error occurred in the loop %d", rc);
}
INFO("Disconnecting");
rc = aws_iot_shadow_disconnect(&mqttClient);
if (NONE_ERROR != rc) {
if (SUCCESS != rc) {
ERROR("Disconnect error %d", rc);
}

View File

@@ -27,7 +27,7 @@
#define AWS_IOT_MQTT_PORT 8883 ///< default port for MQTT/S
#define AWS_IOT_MQTT_CLIENT_ID "c-sdk-client-id" ///< MQTT client ID should be unique for every device
#define AWS_IOT_MY_THING_NAME "AWS-IoT-C-SDK" ///< Thing Name of the Shadow this device is associated with
#define AWS_IOT_ROOT_CA_FILENAME "aws-iot-rootCA.crt" ///< Root CA file name
#define AWS_IOT_ROOT_CA_FILENAME "rootCA.crt" ///< Root CA file name
#define AWS_IOT_CERTIFICATE_FILENAME "cert.pem" ///< device signed certificate file name
#define AWS_IOT_PRIVATE_KEY_FILENAME "privkey.pem" ///< Device private key filename
// =================================================

View File

@@ -21,7 +21,7 @@
#include "aws_iot_log.h"
#include "aws_iot_version.h"
#include "aws_iot_mqtt_interface.h"
#include "aws_iot_mqtt_client_interface.h"
#include "aws_iot_shadow_interface.h"
#include "aws_iot_config.h"
@@ -53,7 +53,7 @@
* @note Ensure the buffer sizes in aws_iot_config.h are big enough to receive the delta message. The delta message will also contain the metadata with the timestamps
*/
char certDirectory[PATH_MAX + 1] = "../../certs";
char certDirectory[PATH_MAX + 1] = "../../../certs";
char HostAddress[255] = AWS_IOT_MQTT_HOST;
uint32_t port = AWS_IOT_MQTT_PORT;
bool messageArrivedOnDelta = false;
@@ -74,23 +74,20 @@ void UpdateStatusCallback(const char *pThingName, ShadowActions_t action, Shadow
const char *pReceivedJsonDocument, void *pContextData);
int main(int argc, char** argv) {
IoT_Error_t rc = NONE_ERROR;
IoT_Error_t rc = SUCCESS;
int32_t i = 0;
char rootCA[PATH_MAX + 1];
char clientCRT[PATH_MAX + 1];
char clientKey[PATH_MAX + 1];
char CurrentWD[PATH_MAX + 1];
char cafileName[] = AWS_IOT_ROOT_CA_FILENAME;
char clientCRTName[] = AWS_IOT_CERTIFICATE_FILENAME;
char clientKeyName[] = AWS_IOT_PRIVATE_KEY_FILENAME;
INFO("\nAWS IoT SDK Version %d.%d.%d-%s\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);
getcwd(CurrentWD, sizeof(CurrentWD));
sprintf(rootCA, "%s/%s/%s", CurrentWD, certDirectory, cafileName);
sprintf(clientCRT, "%s/%s/%s", CurrentWD, certDirectory, clientCRTName);
sprintf(clientKey, "%s/%s/%s", CurrentWD, certDirectory, clientKeyName);
snprintf(rootCA, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_ROOT_CA_FILENAME);
snprintf(clientCRT, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_CERTIFICATE_FILENAME);
snprintf(clientKey, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_PRIVATE_KEY_FILENAME);
DEBUG("rootCA %s", rootCA);
DEBUG("clientCRT %s", clientCRT);
@@ -99,28 +96,31 @@ int main(int argc, char** argv) {
parseInputArgsForConnectParams(argc, argv);
// initialize the mqtt client
MQTTClient_t mqttClient;
aws_iot_mqtt_init(&mqttClient);
AWS_IoT_Client mqttClient;
ShadowParameters_t sp = ShadowParametersDefault;
sp.pMyThingName = AWS_IOT_MY_THING_NAME;
sp.pMqttClientId = AWS_IOT_MQTT_CLIENT_ID;
ShadowInitParameters_t sp = ShadowInitParametersDefault;
sp.pHost = AWS_IOT_MQTT_HOST;
sp.port = AWS_IOT_MQTT_PORT;
sp.pClientCRT = clientCRT;
sp.pClientKey = clientKey;
sp.pRootCA = rootCA;
sp.enableAutoReconnect = false;
sp.disconnectHandler = NULL;
INFO("Shadow Init");
rc = aws_iot_shadow_init(&mqttClient);
if (NONE_ERROR != rc) {
rc = aws_iot_shadow_init(&mqttClient, &sp);
if (SUCCESS != rc) {
ERROR("Shadow Connection Error");
return rc;
}
ShadowConnectParameters_t scp = ShadowConnectParametersDefault;
scp.pMyThingName = AWS_IOT_MY_THING_NAME;
scp.pMqttClientId = AWS_IOT_MQTT_CLIENT_ID;
INFO("Shadow Connect");
rc = aws_iot_shadow_connect(&mqttClient, &sp);
if (NONE_ERROR != rc) {
rc = aws_iot_shadow_connect(&mqttClient, &scp);
if (SUCCESS != rc) {
ERROR("Shadow Connection Error");
return rc;
}
@@ -130,8 +130,8 @@ int main(int argc, char** argv) {
* #AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL
* #AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL
*/
rc = mqttClient.setAutoReconnectStatus(true);
if(NONE_ERROR != rc){
rc = aws_iot_shadow_set_autoreconnect_status(&mqttClient, true);
if(SUCCESS != rc){
ERROR("Unable to set Auto Reconnect to true - %d", rc);
return rc;
}
@@ -148,7 +148,7 @@ int main(int argc, char** argv) {
rc = aws_iot_shadow_register_delta(&mqttClient, &deltaObject);
// Now wait in the loop to receive any message sent from the console
while (NETWORK_ATTEMPTING_RECONNECT == rc || RECONNECT_SUCCESSFUL == rc || NONE_ERROR == rc) {
while (NETWORK_ATTEMPTING_RECONNECT == rc || NETWORK_RECONNECTED == rc || SUCCESS == rc) {
/*
* Lets check for the incoming messages for 200 ms.
*/
@@ -170,14 +170,14 @@ int main(int argc, char** argv) {
sleep(1);
}
if (NONE_ERROR != rc) {
if (SUCCESS != rc) {
ERROR("An error occurred in the loop %d", rc);
}
INFO("Disconnecting");
rc = aws_iot_shadow_disconnect(&mqttClient);
if (NONE_ERROR != rc) {
if (SUCCESS != rc) {
ERROR("Disconnect error %d", rc);
}
@@ -200,7 +200,7 @@ bool buildJSONForReported(char *pJsonDocument, size_t maxSizeOfJsonDocument, con
char tempClientTokenBuffer[MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE];
if(aws_iot_fill_with_client_token(tempClientTokenBuffer, MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE) != NONE_ERROR){
if(aws_iot_fill_with_client_token(tempClientTokenBuffer, MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE) != SUCCESS){
return false;
}

View File

@@ -27,7 +27,7 @@
#define AWS_IOT_MQTT_PORT 8883 ///< default port for MQTT/S
#define AWS_IOT_MQTT_CLIENT_ID "c-sdk-client-id" ///< MQTT client ID should be unique for every device
#define AWS_IOT_MY_THING_NAME "AWS-IoT-C-SDK" ///< Thing Name of the Shadow this device is associated with
#define AWS_IOT_ROOT_CA_FILENAME "aws-iot-rootCA.crt" ///< Root CA file name
#define AWS_IOT_ROOT_CA_FILENAME "rootCA.crt" ///< Root CA file name
#define AWS_IOT_CERTIFICATE_FILENAME "cert.pem" ///< device signed certificate file name
#define AWS_IOT_PRIVATE_KEY_FILENAME "privkey.pem" ///< Device private key filename
// =================================================

View File

@@ -34,31 +34,33 @@
#include <memory.h>
#include <sys/time.h>
#include <limits.h>
#include <aws_iot_mqtt_client.h>
#include "aws_iot_log.h"
#include "aws_iot_version.h"
#include "aws_iot_mqtt_interface.h"
#include "aws_iot_mqtt_client_interface.h"
#include "aws_iot_config.h"
int MQTTcallbackHandler(MQTTCallbackParams params) {
void MQTTcallbackHandler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
IoT_Publish_Message_Params *params, void *pData) {
INFO("Subscribe callback");
INFO("%.*s\t%.*s",
(int)params.TopicNameLen, params.pTopicName,
(int)params.MessageParams.PayloadLen, (char*)params.MessageParams.pPayload);
return 0;
INFO("%.*s\t%.*s", topicNameLen, topicName, (int)params->payloadLen, params->payload);
}
void disconnectCallbackHandler(void) {
void disconnectCallbackHandler(AWS_IoT_Client *pClient, void *data) {
WARN("MQTT Disconnect");
IoT_Error_t rc = NONE_ERROR;
if(aws_iot_is_autoreconnect_enabled()){
IoT_Error_t rc = FAILURE;
if(NULL == data) {
return;
}
AWS_IoT_Client *client = (AWS_IoT_Client *)data;
if(aws_iot_is_autoreconnect_enabled(client)){
INFO("Auto Reconnect is enabled, Reconnecting attempt will start now");
}else{
WARN("Auto Reconnect not enabled. Starting manual reconnect...");
rc = aws_iot_mqtt_attempt_reconnect();
if(RECONNECT_SUCCESSFUL == rc){
rc = aws_iot_mqtt_attempt_reconnect(client);
if(NETWORK_RECONNECTED == rc){
WARN("Manual Reconnect Successful");
}else{
WARN("Manual Reconnect Failed - %d", rc);
@@ -69,7 +71,7 @@ void disconnectCallbackHandler(void) {
/**
* @brief Default cert location
*/
char certDirectory[PATH_MAX + 1] = "../../certs";
char certDirectory[PATH_MAX + 1] = "../../../certs";
/**
* @brief Default MQTT HOST URL is pulled from the aws_iot_config.h
@@ -125,7 +127,7 @@ void parseInputArgsForConnectParams(int argc, char** argv) {
}
int main(int argc, char** argv) {
IoT_Error_t rc = NONE_ERROR;
IoT_Error_t rc = FAILURE;
int32_t i = 0;
bool infinitePublishFlag = true;
@@ -133,105 +135,119 @@ int main(int argc, char** argv) {
char clientCRT[PATH_MAX + 1];
char clientKey[PATH_MAX + 1];
char CurrentWD[PATH_MAX + 1];
char cafileName[] = AWS_IOT_ROOT_CA_FILENAME;
char clientCRTName[] = AWS_IOT_CERTIFICATE_FILENAME;
char clientKeyName[] = AWS_IOT_PRIVATE_KEY_FILENAME;
AWS_IoT_Client client;
parseInputArgsForConnectParams(argc, argv);
INFO("\nAWS IoT SDK Version %d.%d.%d-%s\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);
getcwd(CurrentWD, sizeof(CurrentWD));
sprintf(rootCA, "%s/%s/%s", CurrentWD, certDirectory, cafileName);
sprintf(clientCRT, "%s/%s/%s", CurrentWD, certDirectory, clientCRTName);
sprintf(clientKey, "%s/%s/%s", CurrentWD, certDirectory, clientKeyName);
snprintf(rootCA, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_ROOT_CA_FILENAME);
snprintf(clientCRT, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_CERTIFICATE_FILENAME);
snprintf(clientKey, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_PRIVATE_KEY_FILENAME);
DEBUG("rootCA %s", rootCA);
DEBUG("clientCRT %s", clientCRT);
DEBUG("clientKey %s", clientKey);
MQTTConnectParams connectParams = MQTTConnectParamsDefault;
IoT_Client_Init_Params mqttInitParams;
mqttInitParams.enableAutoReconnect = false; // We enable this later below
mqttInitParams.pHostURL = HostAddress;
mqttInitParams.port = port;
mqttInitParams.pRootCALocation = rootCA;
mqttInitParams.pDeviceCertLocation = clientCRT;
mqttInitParams.pDevicePrivateKeyLocation = clientKey;
mqttInitParams.mqttCommandTimeout_ms = 2000;
mqttInitParams.tlsHandshakeTimeout_ms = 5000;
mqttInitParams.isSSLHostnameVerify = true;
mqttInitParams.disconnectHandler = disconnectCallbackHandler;
mqttInitParams.disconnectHandlerData = (void *)&client;
connectParams.KeepAliveInterval_sec = 10;
connectParams.isCleansession = true;
rc = aws_iot_mqtt_init(&client, &mqttInitParams);
if(SUCCESS != rc) {
ERROR("aws_iot_mqtt_init returned error : %d ", rc);
}
IoT_Client_Connect_Params connectParams = iotClientConnectParamsDefault;
connectParams.keepAliveIntervalInSec = 10;
connectParams.isCleanSession = true;
connectParams.MQTTVersion = MQTT_3_1_1;
connectParams.pClientID = "CSDK-test-device";
connectParams.pHostURL = HostAddress;
connectParams.port = port;
connectParams.isWillMsgPresent = false;
connectParams.pRootCALocation = rootCA;
connectParams.pDeviceCertLocation = clientCRT;
connectParams.pDevicePrivateKeyLocation = clientKey;
connectParams.mqttCommandTimeout_ms = 2000;
connectParams.tlsHandshakeTimeout_ms = 5000;
connectParams.isSSLHostnameVerify = true; // ensure this is set to true for production
connectParams.disconnectHandler = disconnectCallbackHandler;
INFO("Connecting...");
rc = aws_iot_mqtt_connect(&connectParams);
if (NONE_ERROR != rc) {
ERROR("Error(%d) connecting to %s:%d", rc, connectParams.pHostURL, connectParams.port);
rc = aws_iot_mqtt_connect(&client, &connectParams);
if(SUCCESS != rc) {
ERROR("Error(%d) connecting to %s:%d", rc, mqttInitParams.pHostURL, mqttInitParams.port);
}
/*
* Enable Auto Reconnect functionality. Minimum and Maximum time of Exponential backoff are set in aws_iot_config.h
* #AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL
* #AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL
*/
rc = aws_iot_mqtt_autoreconnect_set_status(true);
if (NONE_ERROR != rc) {
rc = aws_iot_mqtt_autoreconnect_set_status(&client, true);
if(SUCCESS != rc) {
ERROR("Unable to set Auto Reconnect to true - %d", rc);
return rc;
}
MQTTSubscribeParams subParams = MQTTSubscribeParamsDefault;
subParams.mHandler = MQTTcallbackHandler;
subParams.pTopic = "sdkTest/sub";
subParams.qos = QOS_0;
if (NONE_ERROR == rc) {
INFO("Subscribing...");
rc = aws_iot_mqtt_subscribe(&subParams);
if (NONE_ERROR != rc) {
ERROR("Error subscribing");
}
INFO("Subscribing...");
rc = aws_iot_mqtt_subscribe(&client, "sdkTest/sub", 11, QOS0, MQTTcallbackHandler, NULL);
if(SUCCESS != rc) {
ERROR("Error subscribing : %d ", rc);
}
MQTTMessageParams Msg = MQTTMessageParamsDefault;
Msg.qos = QOS_0;
char cPayload[100];
sprintf(cPayload, "%s : %d ", "hello from SDK", i);
Msg.pPayload = (void *) cPayload;
MQTTPublishParams Params = MQTTPublishParamsDefault;
Params.pTopic = "sdkTest/sub";
IoT_Publish_Message_Params paramsQOS0;
paramsQOS0.qos = QOS0;
paramsQOS0.payload = (void *) cPayload;
IoT_Publish_Message_Params paramsQOS1;
paramsQOS1.qos = QOS1;
paramsQOS1.payload = (void *) cPayload;
if (publishCount != 0) {
infinitePublishFlag = false;
}
while ((NETWORK_ATTEMPTING_RECONNECT == rc || RECONNECT_SUCCESSFUL == rc || NONE_ERROR == rc)
while((NETWORK_ATTEMPTING_RECONNECT == rc || NETWORK_RECONNECTED == rc || SUCCESS == rc)
&& (publishCount > 0 || infinitePublishFlag)) {
//Max time the yield function will wait for read messages
rc = aws_iot_mqtt_yield(100);
rc = aws_iot_mqtt_yield(&client, 100);
if(NETWORK_ATTEMPTING_RECONNECT == rc){
INFO("-->sleep");
sleep(1);
// If the client is attempting to reconnect we will skip the rest of the loop.
continue;
}
INFO("-->sleep");
sleep(1);
sprintf(cPayload, "%s : %d ", "hello from SDK", i++);
Msg.PayloadLen = strlen(cPayload) + 1;
Params.MessageParams = Msg;
rc = aws_iot_mqtt_publish(&Params);
sprintf(cPayload, "%s : %d ", "hello from SDK QOS0", i++);
paramsQOS0.payloadLen = strlen(cPayload) + 1;
rc = aws_iot_mqtt_publish(&client, "sdkTest/sub", 11, &paramsQOS0);
if (publishCount > 0) {
publishCount--;
}
INFO("-->sleep");
sleep(1);
sprintf(cPayload, "%s : %d ", "hello from SDK QOS1", i++);
paramsQOS1.payloadLen = strlen(cPayload) + 1;
do {
rc = aws_iot_mqtt_publish(&client, "sdkTest/sub", 11, &paramsQOS1);
if (publishCount > 0) {
publishCount--;
}
} while(MQTT_REQUEST_TIMEOUT_ERROR == rc && (publishCount > 0 || infinitePublishFlag));
}
if (NONE_ERROR != rc) {
if(SUCCESS != rc) {
ERROR("An error occurred in the loop.\n");
} else {
INFO("Publish done\n");

View File

@@ -33,7 +33,7 @@
int8_t jsoneq(const char *json, jsmntok_t *tok, const char *s) {
if (tok->type == JSMN_STRING) {
if ((int) strlen(s) == tok->end - tok->start) {
if (strncmp(json + tok->start, s, tok->end - tok->start) == 0) {
if (strncmp(json + tok->start, s, (size_t)(tok->end - tok->start)) == 0) {
return 0;
}
}
@@ -47,12 +47,12 @@ IoT_Error_t parseUnsignedInteger32Value(uint32_t *i, const char *jsonString, jsm
return JSON_PARSE_ERROR;
}
if (1 != sscanf(jsonString + token->start, "%"PRIu32, i)) {
if (1 != sscanf(jsonString + token->start, "%"SCNu32, i)) {
WARN("Token was not an integer.");
return JSON_PARSE_ERROR;
}
return NONE_ERROR;
return SUCCESS;
}
IoT_Error_t parseUnsignedInteger16Value(uint16_t *i, const char *jsonString, jsmntok_t *token) {
@@ -61,12 +61,12 @@ IoT_Error_t parseUnsignedInteger16Value(uint16_t *i, const char *jsonString, jsm
return JSON_PARSE_ERROR;
}
if (1 != sscanf(jsonString + token->start, "%"PRIu16, i)) {
if (1 != sscanf(jsonString + token->start, "%"SCNu16, i)) {
WARN("Token was not an integer.");
return JSON_PARSE_ERROR;
}
return NONE_ERROR;
return SUCCESS;
}
IoT_Error_t parseUnsignedInteger8Value(uint8_t *i, const char *jsonString, jsmntok_t *token) {
@@ -75,12 +75,12 @@ IoT_Error_t parseUnsignedInteger8Value(uint8_t *i, const char *jsonString, jsmnt
return JSON_PARSE_ERROR;
}
if (1 != sscanf(jsonString + token->start, "%"PRIu8, i)) {
if (1 != sscanf(jsonString + token->start, "%"SCNu8, i)) {
WARN("Token was not an integer.");
return JSON_PARSE_ERROR;
}
return NONE_ERROR;
return SUCCESS;
}
IoT_Error_t parseInteger32Value(int32_t *i, const char *jsonString, jsmntok_t *token) {
@@ -89,12 +89,12 @@ IoT_Error_t parseInteger32Value(int32_t *i, const char *jsonString, jsmntok_t *t
return JSON_PARSE_ERROR;
}
if (1 != sscanf(jsonString + token->start, "%"PRIi32, i)) {
if (1 != sscanf(jsonString + token->start, "%"SCNi32, i)) {
WARN("Token was not an integer.");
return JSON_PARSE_ERROR;
}
return NONE_ERROR;
return SUCCESS;
}
IoT_Error_t parseInteger16Value(int16_t *i, const char *jsonString, jsmntok_t *token) {
@@ -103,12 +103,12 @@ IoT_Error_t parseInteger16Value(int16_t *i, const char *jsonString, jsmntok_t *t
return JSON_PARSE_ERROR;
}
if (1 != sscanf(jsonString + token->start, "%"PRIi16, i)) {
if (1 != sscanf(jsonString + token->start, "%"SCNi16, i)) {
WARN("Token was not an integer.");
return JSON_PARSE_ERROR;
}
return NONE_ERROR;
return SUCCESS;
}
IoT_Error_t parseInteger8Value(int8_t *i, const char *jsonString, jsmntok_t *token) {
@@ -117,12 +117,12 @@ IoT_Error_t parseInteger8Value(int8_t *i, const char *jsonString, jsmntok_t *tok
return JSON_PARSE_ERROR;
}
if (1 != sscanf(jsonString + token->start, "%"PRIi8, i)) {
if (1 != sscanf(jsonString + token->start, "%"SCNi8, i)) {
WARN("Token was not an integer.");
return JSON_PARSE_ERROR;
}
return NONE_ERROR;
return SUCCESS;
}
IoT_Error_t parseFloatValue(float *f, const char *jsonString, jsmntok_t *token) {
@@ -136,7 +136,7 @@ IoT_Error_t parseFloatValue(float *f, const char *jsonString, jsmntok_t *token)
return JSON_PARSE_ERROR;
}
return NONE_ERROR;
return SUCCESS;
}
IoT_Error_t parseDoubleValue(double *d, const char *jsonString, jsmntok_t *token) {
@@ -150,7 +150,7 @@ IoT_Error_t parseDoubleValue(double *d, const char *jsonString, jsmntok_t *token
return JSON_PARSE_ERROR;
}
return NONE_ERROR;
return SUCCESS;
}
IoT_Error_t parseBooleanValue(bool *b, const char *jsonString, jsmntok_t *token) {
@@ -169,7 +169,7 @@ IoT_Error_t parseBooleanValue(bool *b, const char *jsonString, jsmntok_t *token)
WARN("Token was not a bool.");
return JSON_PARSE_ERROR;
}
return NONE_ERROR;
return SUCCESS;
}
IoT_Error_t parseStringValue(char *buf, const char *jsonString, jsmntok_t *token) {
@@ -178,8 +178,8 @@ IoT_Error_t parseStringValue(char *buf, const char *jsonString, jsmntok_t *token
WARN("Token was not a string.");
return JSON_PARSE_ERROR;
}
size = token->end - token->start;
size = (uint16_t)(token->end - token->start);
memcpy(buf, jsonString + token->start, size);
buf[size] = '\0';
return NONE_ERROR;
return SUCCESS;
}

297
src/aws_iot_mqtt_client.c Normal file
View File

@@ -0,0 +1,297 @@
/*
* Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
// Based on Eclipse Paho.
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
/**
* @file aws_iot_mqtt_client.c
* @brief MQTT client API definitions
*/
#include "aws_iot_log.h"
#include "aws_iot_mqtt_client_interface.h"
#ifdef _ENABLE_THREAD_SUPPORT_
#include "threads_interface.h"
#endif
const IoT_MQTT_Will_Options iotMqttWillOptionsDefault = IoT_MQTT_Will_Options_Initializer;
const IoT_Client_Connect_Params iotClientConnectParamsDefault = IoT_Client_Connect_Params_initializer;
ClientState aws_iot_mqtt_get_client_state(AWS_IoT_Client *pClient) {
FUNC_ENTRY;
if(NULL == pClient) {
return CLIENT_STATE_INVALID;
}
FUNC_EXIT_RC(pClient->clientStatus.clientState);
}
#ifdef _ENABLE_THREAD_SUPPORT_
IoT_Error_t aws_iot_mqtt_client_lock_mutex(AWS_IoT_Client *pClient, IoT_Mutex_t *pMutex) {
FUNC_ENTRY;
IoT_Error_t threadRc = FAILURE;
if(NULL == pClient || NULL == pMutex){
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
if(false == pClient->clientData.isBlockOnThreadLockEnabled) {
threadRc = aws_iot_thread_mutex_trylock(pMutex);
} else {
threadRc = aws_iot_thread_mutex_lock(pMutex);
/* Should never return Error because the above request blocks until lock is obtained */
}
if(SUCCESS != threadRc) {
FUNC_EXIT_RC(threadRc);
}
FUNC_EXIT_RC(SUCCESS);
}
IoT_Error_t aws_iot_mqtt_client_unlock_mutex(AWS_IoT_Client *pClient, IoT_Mutex_t *pMutex) {
if(NULL == pClient || NULL == pMutex) {
return NULL_VALUE_ERROR;
}
IOT_UNUSED(pClient);
return aws_iot_thread_mutex_unlock(pMutex);
}
#endif
IoT_Error_t aws_iot_mqtt_set_client_state(AWS_IoT_Client *pClient, ClientState expectedCurrentState,
ClientState newState) {
IoT_Error_t rc;
#ifdef _ENABLE_THREAD_SUPPORT_
IoT_Error_t threadRc = FAILURE;
#endif
FUNC_ENTRY;
if(NULL == pClient) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
#ifdef _ENABLE_THREAD_SUPPORT_
rc = aws_iot_mqtt_client_lock_mutex(pClient, &(pClient->clientData.state_change_mutex));
if(SUCCESS != rc) {
return rc;
}
#endif
if(expectedCurrentState == aws_iot_mqtt_get_client_state(pClient)) {
pClient->clientStatus.clientState = newState;
rc = SUCCESS;
} else {
rc = MQTT_UNEXPECTED_CLIENT_STATE_ERROR;
}
#ifdef _ENABLE_THREAD_SUPPORT_
threadRc = aws_iot_mqtt_client_unlock_mutex(pClient, &(pClient->clientData.state_change_mutex));
if(SUCCESS == rc && SUCCESS != threadRc) {
rc = threadRc;
}
#endif
FUNC_EXIT_RC(rc);
}
IoT_Error_t aws_iot_mqtt_set_connect_params(AWS_IoT_Client *pClient, IoT_Client_Connect_Params *pNewConnectParams) {
FUNC_ENTRY;
if(NULL == pClient || NULL == pNewConnectParams) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
pClient->clientData.options.isWillMsgPresent = pNewConnectParams->isWillMsgPresent;
pClient->clientData.options.MQTTVersion = pNewConnectParams->MQTTVersion;
pClient->clientData.options.pClientID = pNewConnectParams->pClientID;
pClient->clientData.options.clientIDLen = pNewConnectParams->clientIDLen;
pClient->clientData.options.pUsername = pNewConnectParams->pUsername;
pClient->clientData.options.usernameLen = pNewConnectParams->usernameLen;
pClient->clientData.options.pPassword = pNewConnectParams->pUsername;
pClient->clientData.options.passwordLen = pNewConnectParams->passwordLen;
pClient->clientData.options.will.pTopicName = pNewConnectParams->will.pTopicName;
pClient->clientData.options.will.topicNameLen = pNewConnectParams->will.topicNameLen;
pClient->clientData.options.will.pMessage = pNewConnectParams->will.pMessage;
pClient->clientData.options.will.msgLen = pNewConnectParams->will.msgLen;
pClient->clientData.options.will.qos = pNewConnectParams->will.qos;
pClient->clientData.options.will.isRetained = pNewConnectParams->will.isRetained;
pClient->clientData.options.keepAliveIntervalInSec = pNewConnectParams->keepAliveIntervalInSec;
pClient->clientData.options.isCleanSession = pNewConnectParams->isCleanSession;
FUNC_EXIT_RC(SUCCESS);
}
IoT_Error_t aws_iot_mqtt_init(AWS_IoT_Client *pClient, IoT_Client_Init_Params *pInitParams) {
uint32_t i;
IoT_Error_t rc;
IoT_Client_Connect_Params default_options = IoT_Client_Connect_Params_initializer;
FUNC_ENTRY;
if(NULL == pClient || NULL == pInitParams || NULL == pInitParams->pHostURL || pInitParams->port == 0) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
for(i = 0; i < AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS; ++i) {
pClient->clientData.messageHandlers[i].topicName = NULL;
pClient->clientData.messageHandlers[i].pApplicationHandler = NULL;
pClient->clientData.messageHandlers[i].pApplicationHandlerData = NULL;
pClient->clientData.messageHandlers[i].qos = QOS0;
}
pClient->clientData.commandTimeoutMs = pInitParams->mqttCommandTimeout_ms;
pClient->clientData.writeBufSize = AWS_IOT_MQTT_TX_BUF_LEN;
pClient->clientData.readBufSize = AWS_IOT_MQTT_RX_BUF_LEN;
pClient->clientData.counterNetworkDisconnected = 0;
pClient->clientData.disconnectHandler = pInitParams->disconnectHandler;
pClient->clientData.disconnectHandlerData = pInitParams->disconnectHandlerData;
/* Initialize default connection options */
rc = aws_iot_mqtt_set_connect_params(pClient, &default_options);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
#ifdef _ENABLE_THREAD_SUPPORT_
pClient->clientData.isBlockOnThreadLockEnabled = pInitParams->isBlockOnThreadLockEnabled;
rc = aws_iot_thread_mutex_init(&(pClient->clientData.state_change_mutex));
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
rc = aws_iot_thread_mutex_init(&(pClient->clientData.tls_read_mutex));
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
rc = aws_iot_thread_mutex_init(&(pClient->clientData.tls_write_mutex));
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
#endif
pClient->clientStatus.isPingOutstanding = 0;
pClient->clientStatus.isAutoReconnectEnabled = pInitParams->enableAutoReconnect;
rc = iot_tls_init(&(pClient->networkStack), pInitParams->pRootCALocation, pInitParams->pDeviceCertLocation,
pInitParams->pDevicePrivateKeyLocation, pInitParams->pHostURL, pInitParams->port,
pInitParams->tlsHandshakeTimeout_ms, pInitParams->isSSLHostnameVerify);
if(SUCCESS != rc) {
pClient->clientStatus.clientState = CLIENT_STATE_INVALID;
FUNC_EXIT_RC(rc);
}
init_timer(&(pClient->pingTimer));
init_timer(&(pClient->reconnectDelayTimer));
pClient->clientStatus.clientState = CLIENT_STATE_INITIALIZED;
FUNC_EXIT_RC(SUCCESS);
}
uint16_t aws_iot_mqtt_get_next_packet_id(AWS_IoT_Client *pClient) {
return pClient->clientData.nextPacketId = (uint16_t)((MAX_PACKET_ID == pClient->clientData.nextPacketId) ? 1 : (
pClient->clientData.nextPacketId + 1));
}
bool aws_iot_mqtt_is_client_connected(AWS_IoT_Client *pClient) {
bool isConnected;
FUNC_ENTRY;
if(NULL == pClient) {
WARN(" Client is null! ");
FUNC_EXIT_RC(false);
}
switch(pClient->clientStatus.clientState) {
case CLIENT_STATE_INVALID:
case CLIENT_STATE_INITIALIZED:
case CLIENT_STATE_CONNECTING:
isConnected = false;
break;
case CLIENT_STATE_CONNECTED_IDLE:
case CLIENT_STATE_CONNECTED_YIELD_IN_PROGRESS:
case CLIENT_STATE_CONNECTED_PUBLISH_IN_PROGRESS:
case CLIENT_STATE_CONNECTED_SUBSCRIBE_IN_PROGRESS:
case CLIENT_STATE_CONNECTED_UNSUBSCRIBE_IN_PROGRESS:
case CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS:
case CLIENT_STATE_CONNECTED_WAIT_FOR_CB_RETURN:
isConnected = true;
break;
case CLIENT_STATE_DISCONNECTING:
case CLIENT_STATE_DISCONNECTED_ERROR:
case CLIENT_STATE_DISCONNECTED_MANUALLY:
case CLIENT_STATE_PENDING_RECONNECT:
default:
isConnected = false;
break;
}
FUNC_EXIT_RC(isConnected);
}
bool aws_iot_is_autoreconnect_enabled(AWS_IoT_Client *pClient) {
FUNC_ENTRY;
if(NULL == pClient) {
WARN(" Client is null! ");
FUNC_EXIT_RC(false);
}
FUNC_EXIT_RC(pClient->clientStatus.isAutoReconnectEnabled);
}
IoT_Error_t aws_iot_mqtt_autoreconnect_set_status(AWS_IoT_Client *pClient, bool newStatus) {
FUNC_ENTRY;
if(NULL == pClient) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
pClient->clientStatus.isAutoReconnectEnabled = newStatus;
FUNC_EXIT_RC(SUCCESS);
}
IoT_Error_t aws_iot_mqtt_set_disconnect_handler(AWS_IoT_Client *pClient, iot_disconnect_handler pDisconnectHandler,
void *pDisconnectHandlerData) {
FUNC_ENTRY;
if(NULL == pClient || NULL == pDisconnectHandler) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
pClient->clientData.disconnectHandler = pDisconnectHandler;
pClient->clientData.disconnectHandlerData = pDisconnectHandlerData;
FUNC_EXIT_RC(SUCCESS);
}
uint32_t aws_iot_mqtt_get_network_disconnected_count(AWS_IoT_Client *pClient) {
return pClient->clientData.counterNetworkDisconnected;
}
void aws_iot_mqtt_reset_network_disconnected_count(AWS_IoT_Client *pClient) {
pClient->clientData.counterNetworkDisconnected = 0;
}

View File

@@ -0,0 +1,660 @@
/*
* Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
// Based on Eclipse Paho.
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Sergio R. Caprile - non-blocking packet read functions for stream transport
*******************************************************************************/
/**
* @file aws_iot_mqtt_client_common_internal.c
* @brief MQTT client internal API definitions
*/
#include <aws_iot_mqtt_client.h>
#include <unistd.h>
#include "aws_iot_mqtt_client_common_internal.h"
/* Max length of packet header */
#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4
/**
* Encodes the message length according to the MQTT algorithm
* @param buf the buffer into which the encoded data is written
* @param length the length to be encoded
* @return the number of bytes written to buffer
*/
size_t aws_iot_mqtt_internal_write_len_to_buffer(unsigned char *buf, uint32_t length) {
size_t outLen = 0;
unsigned char encodedByte;
FUNC_ENTRY;
do {
encodedByte = (unsigned char)(length % 128);
length /= 128;
/* if there are more digits to encode, set the top bit of this digit */
if(length > 0) {
encodedByte |= 0x80;
}
buf[outLen++] = encodedByte;
}while(length > 0);
FUNC_EXIT_RC(outLen);
}
/**
* Decodes the message length according to the MQTT algorithm
* @param the buffer containing the message
* @param value the decoded length returned
* @return the number of bytes read from the socket
*/
IoT_Error_t aws_iot_mqtt_internal_decode_remaining_length_from_buffer(unsigned char *buf, uint32_t *decodedLen,
uint32_t *readBytesLen) {
unsigned char encodedByte;
uint32_t multiplier, len;
FUNC_ENTRY;
multiplier = 1;
len = 0;
*decodedLen = 0;
do {
if(++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) {
/* bad data */
FUNC_EXIT_RC(MQTT_DECODE_REMAINING_LENGTH_ERROR);
}
encodedByte = *buf;
buf++;
*decodedLen += (encodedByte & 127) * multiplier;
multiplier *= 128;
} while((encodedByte & 128) != 0);
*readBytesLen = len;
FUNC_EXIT_RC(SUCCESS);
}
uint32_t aws_iot_mqtt_internal_get_final_packet_length_from_remaining_length(uint32_t rem_len) {
rem_len += 1; /* header byte */
/* now remaining_length field (MQTT 3.1.1 - 2.2.3)*/
if(rem_len < 128) {
rem_len += 1;
} else if (rem_len < 16384) {
rem_len += 2;
} else if (rem_len < 2097152) {
rem_len += 3;
} else {
rem_len += 4;
}
return rem_len;
}
/**
* Calculates uint16 packet id from two bytes read from the input buffer
* Checks Endianness at runtime
*
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
* @return the value calculated
*/
uint16_t aws_iot_mqtt_internal_read_uint16_t(unsigned char **pptr) {
unsigned char *ptr = *pptr;
uint16_t len = 0;
uint8_t firstByte = (uint8_t)(*ptr);
uint8_t secondByte = (uint8_t)(*(ptr + 1));
len = (uint16_t) (secondByte + (256 * firstByte));
*pptr += 2;
return len;
}
/**
* Writes an integer as 2 bytes to an output buffer.
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param anInt the integer to write
*/
void aws_iot_mqtt_internal_write_uint_16(unsigned char **pptr, uint16_t anInt) {
**pptr = (unsigned char)(anInt / 256);
(*pptr)++;
**pptr = (unsigned char)(anInt % 256);
(*pptr)++;
}
/**
* Reads one character from the input buffer.
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
* @return the character read
*/
unsigned char aws_iot_mqtt_internal_read_char(unsigned char **pptr) {
unsigned char c = **pptr;
(*pptr)++;
return c;
}
/**
* Writes one character to an output buffer.
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param c the character to write
*/
void aws_iot_mqtt_internal_write_char(unsigned char **pptr, unsigned char c) {
**pptr = c;
(*pptr)++;
}
void aws_iot_mqtt_internal_write_utf8_string(unsigned char **pptr, const char *string, uint16_t stringLen) {
/* Nothing that calls this function will have a size larger than 2 bytes (MQTT 3.1.1 - 1.5.3) */
aws_iot_mqtt_internal_write_uint_16(pptr, stringLen);
memcpy(*pptr, string, stringLen);
*pptr += stringLen;
}
/**
* Initialize the MQTTHeader structure. Used to ensure that Header bits are
* always initialized using the proper mappings. No Endianness issues here since
* the individual fields are all less than a byte. Also generates no warnings since
* all fields are initialized using hex constants
*/
IoT_Error_t aws_iot_mqtt_internal_init_header(MQTTHeader *pHeader, MessageTypes message_type,
QoS qos, uint8_t dup, uint8_t retained) {
FUNC_ENTRY;
if(NULL == pHeader) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
/* Set all bits to zero */
pHeader->byte = 0;
switch(message_type) {
case UNKNOWN:
/* Should never happen */
return FAILURE;
case CONNECT:
pHeader->bits.type = 0x01;
break;
case CONNACK:
pHeader->bits.type = 0x02;
break;
case PUBLISH:
pHeader->bits.type = 0x03;
break;
case PUBACK:
pHeader->bits.type = 0x04;
break;
case PUBREC:
pHeader->bits.type = 0x05;
break;
case PUBREL:
pHeader->bits.type = 0x06;
break;
case PUBCOMP:
pHeader->bits.type = 0x07;
break;
case SUBSCRIBE:
pHeader->bits.type = 0x08;
break;
case SUBACK:
pHeader->bits.type = 0x09;
break;
case UNSUBSCRIBE:
pHeader->bits.type = 0x0A;
break;
case UNSUBACK:
pHeader->bits.type = 0x0B;
break;
case PINGREQ:
pHeader->bits.type = 0x0C;
break;
case PINGRESP:
pHeader->bits.type = 0x0D;
break;
case DISCONNECT:
pHeader->bits.type = 0x0E;
break;
default:
/* Should never happen */
FUNC_EXIT_RC(FAILURE);
}
pHeader->bits.dup = (1 == dup) ? 0x01 : 0x00;
switch(qos) {
case QOS0:
pHeader->bits.qos = 0x00;
break;
case QOS1:
pHeader->bits.qos = 0x01;
break;
default:
/* Using QOS0 as default */
pHeader->bits.qos = 0x00;
break;
}
pHeader->bits.retain = (1 == retained) ? 0x01 : 0x00;
FUNC_EXIT_RC(SUCCESS);
}
IoT_Error_t aws_iot_mqtt_internal_send_packet(AWS_IoT_Client *pClient, size_t length, Timer *pTimer) {
size_t sentLen, sent;
IoT_Error_t rc;
FUNC_ENTRY;
if(NULL == pClient || NULL == pTimer) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
if(length >= pClient->clientData.writeBufSize) {
FUNC_EXIT_RC(MQTT_TX_BUFFER_TOO_SHORT_ERROR);
}
#ifdef _ENABLE_THREAD_SUPPORT_
rc = aws_iot_mqtt_client_lock_mutex(pClient, &(pClient->clientData.tls_write_mutex));
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
#endif
sentLen = 0;
sent = 0;
while(sent < length && !has_timer_expired(pTimer)) {
rc = pClient->networkStack.write(&(pClient->networkStack), &pClient->clientData.writeBuf[sent], length, pTimer, &sentLen);
if(SUCCESS != rc) {
/* there was an error writing the data */
break;
}
sent += sentLen;
}
#ifdef _ENABLE_THREAD_SUPPORT_
rc = aws_iot_mqtt_client_unlock_mutex(pClient, &(pClient->clientData.tls_write_mutex));
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
#endif
if(sent == length) {
/* record the fact that we have successfully sent the packet */
//countdown_sec(&c->pingTimer, c->clientData.keepAliveInterval);
FUNC_EXIT_RC(SUCCESS);
}
FUNC_EXIT_RC(FAILURE);
}
static IoT_Error_t _aws_iot_mqtt_internal_decode_packet_remaining_len(AWS_IoT_Client *pClient,
size_t *rem_len, Timer *pTimer) {
unsigned char encodedByte;
size_t multiplier, len;
IoT_Error_t rc;
FUNC_ENTRY;
multiplier = 1;
len = 0;
*rem_len = 0;
do {
if(++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) {
/* bad data */
FUNC_EXIT_RC(MQTT_DECODE_REMAINING_LENGTH_ERROR);
}
rc = pClient->networkStack.read(&(pClient->networkStack), &encodedByte, 1, pTimer, &len);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
*rem_len += ((encodedByte & 127) * multiplier);
multiplier *= 128;
} while((encodedByte & 128) != 0);
FUNC_EXIT_RC(rc);
}
static IoT_Error_t _aws_iot_mqtt_internal_read_packet(AWS_IoT_Client *pClient, Timer *pTimer, uint8_t *pPacketType) {
size_t len, rem_len, total_bytes_read, bytes_to_be_read, read_len;
IoT_Error_t rc;
MQTTHeader header = {0};
len = 0;
rem_len = 0;
total_bytes_read = 0;
bytes_to_be_read = 0;
read_len = 0;
rc = pClient->networkStack.read(&(pClient->networkStack), pClient->clientData.readBuf, 1, pTimer, &read_len);
/* 1. read the header byte. This has the packet type in it */
if(NETWORK_SSL_NOTHING_TO_READ == rc) {
return MQTT_NOTHING_TO_READ;
}
len = 1;
/* 2. read the remaining length. This is variable in itself */
rc = _aws_iot_mqtt_internal_decode_packet_remaining_len(pClient, &rem_len, pTimer);
if(SUCCESS != rc) {
return rc;
}
/* if the buffer is too short then the message will be dropped silently */
if (rem_len >= pClient->clientData.readBufSize) {
bytes_to_be_read = pClient->clientData.readBufSize;
do {
rc = pClient->networkStack.read(&(pClient->networkStack), pClient->clientData.readBuf, bytes_to_be_read,
pTimer, &read_len);
if(SUCCESS == rc) {
total_bytes_read += read_len;
if((rem_len - total_bytes_read) >= pClient->clientData.readBufSize){
bytes_to_be_read = pClient->clientData.readBufSize;
} else {
bytes_to_be_read = rem_len - total_bytes_read;
}
}
} while(total_bytes_read < rem_len && SUCCESS == rc);
return MQTT_RX_BUFFER_TOO_SHORT_ERROR;
}
/* put the original remaining length into the read buffer */
len += aws_iot_mqtt_internal_write_len_to_buffer(pClient->clientData.readBuf + 1, (uint32_t)rem_len);
/* 3. read the rest of the buffer using a callback to supply the rest of the data */
if(rem_len > 0) {
rc = pClient->networkStack.read(&(pClient->networkStack), pClient->clientData.readBuf + len, rem_len, pTimer, &read_len);
if(SUCCESS != rc || read_len != rem_len) {
return FAILURE;
}
}
header.byte = pClient->clientData.readBuf[0];
*pPacketType = header.bits.type;
FUNC_EXIT_RC(rc);
}
// assume topic filter and name is in correct format
// # can only be at end
// + and # can only be next to separator
static char _aws_iot_mqtt_internal_is_topic_matched(char *pTopicFilter, char *pTopicName, uint16_t topicNameLen) {
char *curf, *curn, *curn_end;
if(NULL == pTopicFilter || NULL == pTopicName) {
return NULL_VALUE_ERROR;
}
curf = pTopicFilter;
curn = pTopicName;
curn_end = curn + topicNameLen;
while(*curf && (curn < curn_end)) {
if(*curn == '/' && *curf != '/') {
break;
}
if(*curf != '+' && *curf != '#' && *curf != *curn) {
break;
}
if(*curf == '+') {
/* skip until we meet the next separator, or end of string */
char *nextpos = curn + 1;
while(nextpos < curn_end && *nextpos != '/')
nextpos = ++curn + 1;
} else if(*curf == '#') {
/* skip until end of string */
curn = curn_end - 1;
}
curf++;
curn++;
};
return (curn == curn_end) && (*curf == '\0');
}
static IoT_Error_t _aws_iot_mqtt_internal_deliver_message(AWS_IoT_Client *pClient, char *pTopicName,
uint16_t topicNameLen,
IoT_Publish_Message_Params *pMessageParams) {
uint32_t itr;
IoT_Error_t rc;
ClientState clientState;
FUNC_ENTRY;
if(NULL == pTopicName) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
/* This function can be called from all MQTT APIs
* But while callback return is in progress, Yield should not be called.
* The state for CB_RETURN accomplishes that, as yield cannot be called while in that state */
clientState = aws_iot_mqtt_get_client_state(pClient);
rc = aws_iot_mqtt_set_client_state(pClient, clientState, CLIENT_STATE_CONNECTED_WAIT_FOR_CB_RETURN);
/* Find the right message handler - indexed by topic */
for(itr = 0; itr < AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS; ++itr) {
if(NULL != pClient->clientData.messageHandlers[itr].topicName) {
if (((topicNameLen == pClient->clientData.messageHandlers[itr].topicNameLen)
&& (strncmp(pTopicName, (char *) pClient->clientData.messageHandlers[itr].topicName, topicNameLen) == 0))
|| _aws_iot_mqtt_internal_is_topic_matched((char *) pClient->clientData.messageHandlers[itr].topicName,
pTopicName, topicNameLen)) {
if(NULL != pClient->clientData.messageHandlers[itr].pApplicationHandler) {
pClient->clientData.messageHandlers[itr].pApplicationHandler(pClient, pTopicName, topicNameLen,
pMessageParams,
pClient->clientData.messageHandlers[itr].pApplicationHandlerData);
}
}
}
}
rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_WAIT_FOR_CB_RETURN, clientState);
FUNC_EXIT_RC(rc);
}
static IoT_Error_t _aws_iot_mqtt_internal_handle_publish(AWS_IoT_Client *pClient, Timer *pTimer) {
char *topicName;
uint16_t topicNameLen;
uint32_t len;
IoT_Error_t rc;
IoT_Publish_Message_Params msg;
FUNC_ENTRY;
topicName = NULL;
topicNameLen = 0;
len = 0;
rc = aws_iot_mqtt_internal_deserialize_publish(&msg.isDup, &msg.qos, &msg.isRetained,
&msg.id, &topicName, &topicNameLen,
(unsigned char **) &msg.payload, &msg.payloadLen, pClient->clientData.readBuf,
pClient->clientData.readBufSize);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
rc = _aws_iot_mqtt_internal_deliver_message(pClient, topicName, topicNameLen, &msg);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
if(QOS0 == msg.qos) {
/* No further processing required for QoS0 */
FUNC_EXIT_RC(SUCCESS);
}
/* Message assumed to be QoS1 since we do not support QoS2 at this time */
rc = aws_iot_mqtt_internal_serialize_ack(pClient->clientData.writeBuf, pClient->clientData.writeBufSize,
PUBACK, 0, msg.id, &len);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
rc = aws_iot_mqtt_internal_send_packet(pClient, len, pTimer);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
FUNC_EXIT_RC(SUCCESS);
}
IoT_Error_t aws_iot_mqtt_internal_cycle_read(AWS_IoT_Client *pClient, Timer *pTimer, uint8_t *pPacketType) {
IoT_Error_t rc;
#ifdef _ENABLE_THREAD_SUPPORT_
IoT_Error_t threadRc;
#endif
if(NULL == pClient || NULL == pTimer) {
return NULL_VALUE_ERROR;
}
#ifdef _ENABLE_THREAD_SUPPORT_
threadRc = aws_iot_mqtt_client_lock_mutex(pClient, &(pClient->clientData.tls_read_mutex));
if(SUCCESS != threadRc) {
FUNC_EXIT_RC(threadRc);
}
#endif
/* read the socket, see what work is due */
rc = _aws_iot_mqtt_internal_read_packet(pClient, pTimer, pPacketType);
#ifdef _ENABLE_THREAD_SUPPORT_
threadRc = aws_iot_mqtt_client_unlock_mutex(pClient, &(pClient->clientData.tls_read_mutex));
if(SUCCESS != threadRc && (MQTT_NOTHING_TO_READ == rc || SUCCESS == rc)) {
return threadRc;
}
#endif
if(MQTT_NOTHING_TO_READ == rc) {
/* Nothing to read, not a cycle failure */
return SUCCESS;
} else if(SUCCESS != rc) {
return rc;
}
switch(*pPacketType) {
case CONNACK:
case PUBACK:
case SUBACK:
case UNSUBACK:
/* SDK is blocking, these responses will be forwarded to calling function to process */
break;
case PUBLISH: {
rc = _aws_iot_mqtt_internal_handle_publish(pClient, pTimer);
break;
}
case PUBREC:
case PUBCOMP:
/* QoS2 not supported at this time */
break;
case PINGRESP: {
pClient->clientStatus.isPingOutstanding = 0;
countdown_sec(&pClient->pingTimer, pClient->clientData.keepAliveInterval);
break;
}
default: {
/* Either unknown packet type or Failure occurred
* Should not happen */
rc = MQTT_RX_MESSAGE_PACKET_TYPE_INVALID_ERROR;
break;
}
}
return rc;
}
/* only used in single-threaded mode where one command at a time is in process */
IoT_Error_t aws_iot_mqtt_internal_wait_for_read(AWS_IoT_Client *pClient, uint8_t packetType, Timer *pTimer) {
IoT_Error_t rc;
uint8_t read_packet_type;
FUNC_ENTRY;
if(NULL == pClient || NULL == pTimer) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
read_packet_type = 0;
do {
if(has_timer_expired(pTimer)) {
/* we timed out */
rc = MQTT_REQUEST_TIMEOUT_ERROR;
break;
}
rc = aws_iot_mqtt_internal_cycle_read(pClient, pTimer, &read_packet_type);
}while(NETWORK_DISCONNECTED_ERROR != rc && read_packet_type != packetType);
if(MQTT_REQUEST_TIMEOUT_ERROR != rc && NETWORK_DISCONNECTED_ERROR != rc && read_packet_type != packetType) {
FUNC_EXIT_RC(FAILURE);
}
/* Something failed or we didn't receive the expected packet, return error code */
FUNC_EXIT_RC(rc);
}
/**
* Serializes a 0-length packet into the supplied buffer, ready for writing to a socket
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer, to avoid overruns
* @param packettype the message type
* @param serialized length
* @return IoT_Error_t indicating function execution status
*/
IoT_Error_t aws_iot_mqtt_internal_serialize_zero(unsigned char *pTxBuf, size_t txBufLen, MessageTypes packetType,
size_t *pSerializedLength) {
unsigned char *ptr;
IoT_Error_t rc;
MQTTHeader header = {0};
FUNC_ENTRY;
if(NULL == pTxBuf || NULL == pSerializedLength) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
/* Buffer should have at least 2 bytes for the header */
if(4 > txBufLen) {
FUNC_EXIT_RC(MQTT_TX_BUFFER_TOO_SHORT_ERROR);
}
ptr = pTxBuf;
rc = aws_iot_mqtt_internal_init_header(&header, packetType, QOS0, 0, 0);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
/* write header */
aws_iot_mqtt_internal_write_char(&ptr, header.byte);
/* write remaining length */
ptr += aws_iot_mqtt_internal_write_len_to_buffer(ptr, 0);
*pSerializedLength = (uint32_t)(ptr - pTxBuf);
FUNC_EXIT_RC(SUCCESS);
}

View File

@@ -0,0 +1,585 @@
/*
* Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
// Based on Eclipse Paho.
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
/**
* @file aws_iot_mqtt_client_connect.c
* @brief MQTT client connect API definition and related functions
*/
#include <aws_iot_mqtt_client.h>
#include "aws_iot_mqtt_client_interface.h"
#include "aws_iot_mqtt_client_common_internal.h"
typedef union {
uint8_t all; /**< all connect flags */
#if defined(REVERSED)
struct
{
unsigned int username : 1; /**< 3.1 user name */
unsigned int password : 1; /**< 3.1 password */
unsigned int willRetain : 1; /**< will retain setting */
unsigned int willQoS : 2; /**< will QoS value */
unsigned int will : 1; /**< will flag */
unsigned int cleansession : 1; /**< clean session flag */
unsigned int : 1; /**< unused */
} bits;
#else
struct
{
unsigned int : 1; /**< unused */
unsigned int cleansession : 1; /**< cleansession flag */
unsigned int will : 1; /**< will flag */
unsigned int willQoS : 2; /**< will QoS value */
unsigned int willRetain : 1; /**< will retain setting */
unsigned int password : 1; /**< 3.1 password */
unsigned int username : 1; /**< 3.1 user name */
} bits;
#endif
} MQTT_Connect_Header_Flags; /**< connect flags byte */
typedef union {
uint8_t all; /**< all connack flags */
#if defined(REVERSED)
struct
{
unsigned int sessionpresent : 1; /**< session present flag */
unsigned int : 7; /**< unused */
} bits;
#else
struct
{
unsigned int : 7; /**< unused */
unsigned int sessionpresent : 1; /**< session present flag */
} bits;
#endif
} MQTT_Connack_Header_Flags; /**< connack flags byte */
typedef enum {
CONNACK_CONNECTION_ACCEPTED = 0,
CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR = 1,
CONNACK_IDENTIFIER_REJECTED_ERROR = 2,
CONNACK_SERVER_UNAVAILABLE_ERROR = 3,
CONNACK_BAD_USERDATA_ERROR = 4,
CONNACK_NOT_AUTHORIZED_ERROR = 5
} MQTT_Connack_Return_Codes; /**< Connect request response codes from server */
/**
* Determines the length of the MQTT connect packet that would be produced using the supplied connect options.
* @param options the options to be used to build the connect packet
* @param the length of buffer needed to contain the serialized version of the packet
* @return IoT_Error_t indicating function execution status
*/
static uint32_t _aws_iot_get_connect_packet_length(IoT_Client_Connect_Params *pConnectParams) {
uint32_t len;
/* Enable when adding further MQTT versions */
/*size_t len = 0;
switch(pConnectParams->MQTTVersion) {
case MQTT_3_1_1:
len = 10;
break;
}*/
FUNC_ENTRY;
len = 10; // Len = 10 for MQTT_3_1_1
len = len + pConnectParams->clientIDLen + 2;
if(pConnectParams->isWillMsgPresent) {
len = len + pConnectParams->will.topicNameLen + 2 + pConnectParams->will.msgLen + 2;
}
if(NULL != pConnectParams->pUsername) {
len = len + pConnectParams->usernameLen + 2;
}
if(NULL != pConnectParams->pPassword) {
len = len + pConnectParams->passwordLen + 2;
}
FUNC_EXIT_RC(len);
}
/**
* Serializes the connect options into the buffer.
* @param buf the buffer into which the packet will be serialized
* @param len the length in bytes of the supplied buffer
* @param options the options to be used to build the connect packet
* @param serialized length
* @return IoT_Error_t indicating function execution status
*/
static IoT_Error_t _aws_iot_mqtt_serialize_connect(unsigned char *pTxBuf, size_t txBufLen,
IoT_Client_Connect_Params *pConnectParams,
size_t *pSerializedLen) {
unsigned char *ptr;
uint32_t len;
IoT_Error_t rc;
MQTTHeader header = {0};
MQTT_Connect_Header_Flags flags = {0};
FUNC_ENTRY;
if(NULL == pTxBuf || NULL == pConnectParams || NULL == pSerializedLen) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
ptr = pTxBuf;
len = _aws_iot_get_connect_packet_length(pConnectParams);
if(aws_iot_mqtt_internal_get_final_packet_length_from_remaining_length(len) > txBufLen) {
FUNC_EXIT_RC(MQTT_TX_BUFFER_TOO_SHORT_ERROR);
}
rc = aws_iot_mqtt_internal_init_header(&header, CONNECT, QOS0, 0, 0);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
aws_iot_mqtt_internal_write_char(&ptr, header.byte); /* write header */
ptr += aws_iot_mqtt_internal_write_len_to_buffer(ptr, len); /* write remaining length */
// Enable if adding support for more versions
//if(MQTT_3_1_1 == pConnectParams->MQTTVersion) {
aws_iot_mqtt_internal_write_utf8_string(&ptr, "MQTT", 4);
aws_iot_mqtt_internal_write_char(&ptr, (char) 4);
//}
flags.all = 0;
flags.bits.cleansession = (pConnectParams->isCleanSession) ? 1 : 0;
flags.bits.will = (pConnectParams->isWillMsgPresent) ? 1 : 0;
if(flags.bits.will) {
flags.bits.willQoS = pConnectParams->will.qos;
flags.bits.willRetain = (pConnectParams->will.isRetained) ? 1 : 0;
}
if(pConnectParams->pUsername) {
flags.bits.username = 1;
}
if(pConnectParams->pPassword) {
flags.bits.password = 1;
}
aws_iot_mqtt_internal_write_char(&ptr, flags.all);
aws_iot_mqtt_internal_write_uint_16(&ptr, pConnectParams->keepAliveIntervalInSec);
aws_iot_mqtt_internal_write_utf8_string(&ptr, pConnectParams->pClientID, pConnectParams->clientIDLen);
if(pConnectParams->isWillMsgPresent) {
aws_iot_mqtt_internal_write_utf8_string(&ptr, pConnectParams->will.pTopicName, pConnectParams->will.topicNameLen);
aws_iot_mqtt_internal_write_utf8_string(&ptr, pConnectParams->will.pMessage, pConnectParams->will.msgLen);
}
if(flags.bits.username) {
aws_iot_mqtt_internal_write_utf8_string(&ptr, pConnectParams->pUsername, pConnectParams->usernameLen);
}
if(flags.bits.password) {
aws_iot_mqtt_internal_write_utf8_string(&ptr, pConnectParams->pPassword, pConnectParams->passwordLen);
}
*pSerializedLen = (size_t)(ptr - pTxBuf);
FUNC_EXIT_RC(SUCCESS);
}
/**
* Deserializes the supplied (wire) buffer into connack data - return code
* @param sessionPresent the session present flag returned (only for MQTT 3.1.1)
* @param connack_rc returned integer value of the connack return code
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return IoT_Error_t indicating function execution status
*/
static IoT_Error_t _aws_iot_mqtt_deserialize_connack(unsigned char *pSessionPresent, IoT_Error_t *pConnackRc,
unsigned char *pRxBuf, size_t rxBufLen) {
unsigned char *curdata, *enddata;
unsigned char connack_rc_char;
uint32_t decodedLen, readBytesLen;
IoT_Error_t rc;
MQTT_Connack_Header_Flags flags = {0};
MQTTHeader header = {0};
FUNC_ENTRY;
if(NULL == pSessionPresent || NULL == pConnackRc || NULL == pRxBuf) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
/* CONNACK header size is fixed at two bytes for fixed and 2 bytes for variable,
* using that as minimum size
* MQTT v3.1.1 Specification 3.2.1 */
if(4 > rxBufLen) {
FUNC_EXIT_RC(MQTT_RX_BUFFER_TOO_SHORT_ERROR);
}
curdata = pRxBuf;
enddata = NULL;
decodedLen = 0;
readBytesLen = 0;
header.byte = aws_iot_mqtt_internal_read_char(&curdata);
if(CONNACK != header.bits.type) {
FUNC_EXIT_RC(FAILURE);
}
/* read remaining length */
rc = aws_iot_mqtt_internal_decode_remaining_length_from_buffer(curdata, &decodedLen, &readBytesLen);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
curdata += (readBytesLen);
enddata = curdata + decodedLen;
if(enddata - curdata < 2) {
FUNC_EXIT_RC(FAILURE);
}
flags.all = aws_iot_mqtt_internal_read_char(&curdata);
*pSessionPresent = flags.bits.sessionpresent;
connack_rc_char = aws_iot_mqtt_internal_read_char(&curdata);
switch(connack_rc_char) {
case CONNACK_CONNECTION_ACCEPTED:
*pConnackRc = MQTT_CONNACK_CONNECTION_ACCEPTED;
break;
case CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR:
*pConnackRc = MQTT_CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR;
break;
case CONNACK_IDENTIFIER_REJECTED_ERROR:
*pConnackRc = MQTT_CONNACK_IDENTIFIER_REJECTED_ERROR;
break;
case CONNACK_SERVER_UNAVAILABLE_ERROR:
*pConnackRc = MQTT_CONNACK_SERVER_UNAVAILABLE_ERROR;
break;
case CONNACK_BAD_USERDATA_ERROR:
*pConnackRc = MQTT_CONNACK_BAD_USERDATA_ERROR;
break;
case CONNACK_NOT_AUTHORIZED_ERROR:
*pConnackRc = MQTT_CONNACK_NOT_AUTHORIZED_ERROR;
break;
default:
*pConnackRc = MQTT_CONNACK_UNKNOWN_ERROR;
break;
}
FUNC_EXIT_RC(SUCCESS);
}
/**
* @brief Check if client state is valid for a connect request
*
* Called to check if client state is valid for a connect request
* @param pClient Reference to the IoT Client
*
* @return bool true = state is valid, false = not valid
*/
static bool _aws_iot_mqtt_is_client_state_valid_for_connect(ClientState clientState) {
bool isValid = false;
switch(clientState) {
case CLIENT_STATE_INVALID:
isValid = false;
break;
case CLIENT_STATE_INITIALIZED:
isValid = true;
break;
case CLIENT_STATE_CONNECTING:
case CLIENT_STATE_CONNECTED_IDLE:
case CLIENT_STATE_CONNECTED_YIELD_IN_PROGRESS:
case CLIENT_STATE_CONNECTED_PUBLISH_IN_PROGRESS:
case CLIENT_STATE_CONNECTED_SUBSCRIBE_IN_PROGRESS:
case CLIENT_STATE_CONNECTED_UNSUBSCRIBE_IN_PROGRESS:
case CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS:
case CLIENT_STATE_CONNECTED_WAIT_FOR_CB_RETURN:
case CLIENT_STATE_DISCONNECTING:
isValid = false;
break;
case CLIENT_STATE_DISCONNECTED_ERROR:
case CLIENT_STATE_DISCONNECTED_MANUALLY:
case CLIENT_STATE_PENDING_RECONNECT:
isValid = true;
break;
default:
break;
}
return isValid;
}
/**
* @brief MQTT Connection Function
*
* Called to establish an MQTT connection with the AWS IoT Service
* This is the internal function which is called by the connect API to perform the operation.
* Not meant to be called directly as it doesn't do validations or client state changes
*
* @param pClient Reference to the IoT Client
* @param pConnectParams Pointer to MQTT connection parameters
*
* @return An IoT Error Type defining successful/failed connection
*/
static IoT_Error_t _aws_iot_mqtt_internal_connect(AWS_IoT_Client *pClient, IoT_Client_Connect_Params *pConnectParams) {
Timer connect_timer;
IoT_Error_t connack_rc = FAILURE;
char sessionPresent = 0;
size_t len = 0;
IoT_Error_t rc = FAILURE;
FUNC_ENTRY;
init_timer(&connect_timer);
countdown_ms(&connect_timer, pClient->clientData.commandTimeoutMs);
if(NULL != pConnectParams) {
/* override default options if new options were supplied */
rc = aws_iot_mqtt_set_connect_params(pClient, pConnectParams);
if(SUCCESS != rc) {
FUNC_EXIT_RC(MQTT_CONNECTION_ERROR);
}
}
rc = pClient->networkStack.connect(&(pClient->networkStack), NULL);
if(SUCCESS != rc) {
/* TLS Connect failed, return error */
FUNC_EXIT_RC(rc);
}
pClient->clientData.keepAliveInterval = pClient->clientData.options.keepAliveIntervalInSec;
rc = _aws_iot_mqtt_serialize_connect(pClient->clientData.writeBuf, pClient->clientData.writeBufSize, &(pClient->clientData.options), &len);
if(SUCCESS != rc || 0 >= len) {
FUNC_EXIT_RC(MQTT_CONNECTION_ERROR);
}
/* send the connect packet */
rc = aws_iot_mqtt_internal_send_packet(pClient, len, &connect_timer);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
/* this will be a blocking call, wait for the CONNACK */
rc = aws_iot_mqtt_internal_wait_for_read(pClient, CONNACK, &connect_timer);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
/* Received CONNACK, check the return code */
rc = _aws_iot_mqtt_deserialize_connack((unsigned char *)&sessionPresent, &connack_rc, pClient->clientData.readBuf, pClient->clientData.readBufSize);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
if(MQTT_CONNACK_CONNECTION_ACCEPTED != connack_rc) {
FUNC_EXIT_RC(connack_rc);
}
pClient->clientStatus.isPingOutstanding = 0;
countdown_sec(&pClient->pingTimer, pClient->clientData.keepAliveInterval);
FUNC_EXIT_RC(SUCCESS);
}
/**
* @brief MQTT Connection Function
*
* Called to establish an MQTT connection with the AWS IoT Service
* This is the outer function which does the validations and calls the internal connect above
* to perform the actual operation. It is also responsible for client state changes
*
* @param pClient Reference to the IoT Client
* @param pConnectParams Pointer to MQTT connection parameters
*
* @return An IoT Error Type defining successful/failed connection
*/
IoT_Error_t aws_iot_mqtt_connect(AWS_IoT_Client *pClient, IoT_Client_Connect_Params *pConnectParams) {
IoT_Error_t rc, disconRc;
ClientState clientState;
FUNC_ENTRY;
if(NULL == pClient) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
clientState = aws_iot_mqtt_get_client_state(pClient);
if(false == _aws_iot_mqtt_is_client_state_valid_for_connect(clientState)) {
/* Don't send connect packet again if we are already connected
* or in the process of connecting/disconnecting */
FUNC_EXIT_RC(NETWORK_ALREADY_CONNECTED_ERROR);
}
aws_iot_mqtt_set_client_state(pClient, clientState, CLIENT_STATE_CONNECTING);
rc = _aws_iot_mqtt_internal_connect(pClient, pConnectParams);
if(SUCCESS != rc) {
pClient->networkStack.disconnect(&(pClient->networkStack));
disconRc = pClient->networkStack.destroy(&(pClient->networkStack));
aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTING, CLIENT_STATE_DISCONNECTED_ERROR);
} else {
aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTING, CLIENT_STATE_CONNECTED_IDLE);
}
FUNC_EXIT_RC(rc);
}
/**
* @brief Disconnect an MQTT Connection
*
* Called to send a disconnect message to the broker.
* This is the internal function which is called by the disconnect API to perform the operation.
* Not meant to be called directly as it doesn't do validations or client state changes
*
* @param pClient Reference to the IoT Client
*
* @return An IoT Error Type defining successful/failed send of the disconnect control packet.
*/
IoT_Error_t _aws_iot_mqtt_internal_disconnect(AWS_IoT_Client *pClient) {
/* We might wait for incomplete incoming publishes to complete */
Timer timer;
size_t serialized_len = 0;
IoT_Error_t rc;
FUNC_ENTRY;
rc = aws_iot_mqtt_internal_serialize_zero(pClient->clientData.writeBuf, pClient->clientData.writeBufSize, DISCONNECT,
&serialized_len);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
init_timer(&timer);
countdown_ms(&timer, pClient->clientData.commandTimeoutMs);
/* send the disconnect packet */
if(serialized_len > 0) {
rc = aws_iot_mqtt_internal_send_packet(pClient, serialized_len, &timer);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
}
/* Clean network stack */
pClient->networkStack.disconnect(&(pClient->networkStack));
rc = pClient->networkStack.destroy(&(pClient->networkStack));
if(0 != rc) {
/* TLS Destroy failed, return error */
FUNC_EXIT_RC(FAILURE);
}
FUNC_EXIT_RC(SUCCESS);
}
/**
* @brief Disconnect an MQTT Connection
*
* Called to send a disconnect message to the broker.
* This is the outer function which does the validations and calls the internal disconnect above
* to perform the actual operation. It is also responsible for client state changes
*
* @param pClient Reference to the IoT Client
*
* @return An IoT Error Type defining successful/failed send of the disconnect control packet.
*/
IoT_Error_t aws_iot_mqtt_disconnect(AWS_IoT_Client *pClient) {
ClientState clientState;
IoT_Error_t rc;
FUNC_ENTRY;
if(NULL == pClient) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
clientState = aws_iot_mqtt_get_client_state(pClient);
if(!aws_iot_mqtt_is_client_connected(pClient)) {
/* Network is already disconnected. Do nothing */
FUNC_EXIT_RC(NETWORK_DISCONNECTED_ERROR);
}
rc = aws_iot_mqtt_set_client_state(pClient, clientState, CLIENT_STATE_DISCONNECTING);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
rc = _aws_iot_mqtt_internal_disconnect(pClient);
if(SUCCESS != rc) {
pClient->clientStatus.clientState = clientState;
} else {
/* If called from Keepalive, this gets set to CLIENT_STATE_DISCONNECTED_ERROR */
pClient->clientStatus.clientState = CLIENT_STATE_DISCONNECTED_MANUALLY;
}
FUNC_EXIT_RC(rc);
}
/**
* @brief MQTT Manual Re-Connection Function
*
* Called to establish an MQTT connection with the AWS IoT Service
* using parameters from the last time a connection was attempted
* Use after disconnect to start the reconnect process manually
* Makes only one reconnect attempt. Sets the client state to
* pending reconnect in case of failure
*
* @param pClient Reference to the IoT Client
*
* @return An IoT Error Type defining successful/failed connection
*/
IoT_Error_t aws_iot_mqtt_attempt_reconnect(AWS_IoT_Client *pClient) {
IoT_Error_t rc;
FUNC_ENTRY;
if(NULL == pClient) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
if(aws_iot_mqtt_is_client_connected(pClient)) {
FUNC_EXIT_RC(NETWORK_ALREADY_CONNECTED_ERROR);
}
/* Ignoring return code. failures expected if network is disconnected */
rc = aws_iot_mqtt_connect(pClient, NULL);
/* If still disconnected handle disconnect */
if(CLIENT_STATE_CONNECTED_IDLE != aws_iot_mqtt_get_client_state(pClient)) {
aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_DISCONNECTED_ERROR, CLIENT_STATE_PENDING_RECONNECT);
FUNC_EXIT_RC(NETWORK_ATTEMPTING_RECONNECT);
}
rc = aws_iot_mqtt_resubscribe(pClient);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
FUNC_EXIT_RC(NETWORK_RECONNECTED);
}

View File

@@ -0,0 +1,420 @@
/*
* Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
// Based on Eclipse Paho.
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Ian Craggs - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=453144
*******************************************************************************/
/**
* @file aws_iot_mqtt_client_publish.c
* @brief MQTT client publish API definitions
*/
#include "aws_iot_mqtt_client_common_internal.h"
/**
* @param stringVar pointer to the String into which the data is to be read
* @param stringLen pointer to variable which has the length of the string
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param enddata pointer to the end of the data: do not read beyond
* @return SUCCESS if successful, FAILURE if not
*/
static IoT_Error_t _aws_iot_mqtt_read_string_with_len(char **stringVar, uint16_t *stringLen,
unsigned char **pptr, unsigned char *enddata) {
IoT_Error_t rc = FAILURE;
FUNC_ENTRY;
/* the first two bytes are the length of the string */
/* enough length to read the integer? */
if(enddata - (*pptr) > 1) {
*stringLen = aws_iot_mqtt_internal_read_uint16_t(pptr); /* increments pptr to point past length */
if(&(*pptr)[*stringLen] <= enddata) {
*stringVar = (char*)*pptr;
*pptr += *stringLen;
rc = SUCCESS;
}
}
FUNC_EXIT_RC(rc);
}
/**
* Serializes the supplied publish data into the supplied buffer, ready for sending
* @param pTxBuf the buffer into which the packet will be serialized
* @param txBufLen the length in bytes of the supplied buffer
* @param dup uint8_t - the MQTT dup flag
* @param qos QoS - the MQTT QoS value
* @param retained uint8_t - the MQTT retained flag
* @param packetId uint16_t - the MQTT packet identifier
* @param pTopicName char * - the MQTT topic in the publish
* @param topicNameLen uint16_t - the length of the Topic Name
* @param pPayload byte buffer - the MQTT publish payload
* @param payloadLen size_t - the length of the MQTT payload
* @param pSerializedLen uint32_t - pointer to the variable that stores serialized len
*
* @return An IoT Error Type defining successful/failed call
*/
static IoT_Error_t _aws_iot_mqtt_internal_serialize_publish(unsigned char *pTxBuf, size_t txBufLen, uint8_t dup,
QoS qos, uint8_t retained, uint16_t packetId,
const char *pTopicName, uint16_t topicNameLen,
const unsigned char *pPayload, size_t payloadLen,
uint32_t *pSerializedLen) {
unsigned char *ptr;
uint32_t rem_len;
MQTTHeader header = {0};
FUNC_ENTRY;
if(NULL == pTxBuf || NULL == pPayload || NULL == pSerializedLen) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
ptr = pTxBuf;
rem_len = 0;
rem_len += (uint32_t)(topicNameLen + payloadLen + 2);
if(qos > 0) {
rem_len += 2; /* packetId */
}
if(aws_iot_mqtt_internal_get_final_packet_length_from_remaining_length(rem_len) > txBufLen) {
FUNC_EXIT_RC(MQTT_TX_BUFFER_TOO_SHORT_ERROR);
}
IoT_Error_t rc = aws_iot_mqtt_internal_init_header(&header, PUBLISH, qos, dup, retained);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
aws_iot_mqtt_internal_write_char(&ptr, header.byte); /* write header */
ptr += aws_iot_mqtt_internal_write_len_to_buffer(ptr, rem_len); /* write remaining length */;
aws_iot_mqtt_internal_write_utf8_string(&ptr, pTopicName, topicNameLen);
if(qos > 0) {
aws_iot_mqtt_internal_write_uint_16(&ptr, packetId);
}
memcpy(ptr, pPayload, payloadLen);
ptr += payloadLen;
*pSerializedLen = (uint32_t)(ptr - pTxBuf);
FUNC_EXIT_RC(SUCCESS);
}
/**
* Serializes the ack packet into the supplied buffer.
* @param pTxBuf the buffer into which the packet will be serialized
* @param txBufLen the length in bytes of the supplied buffer
* @param msgType the MQTT packet type
* @param dup the MQTT dup flag
* @param packetId the MQTT packet identifier
* @param pSerializedLen uint32_t - pointer to the variable that stores serialized len
*
* @return An IoT Error Type defining successful/failed call
*/
IoT_Error_t aws_iot_mqtt_internal_serialize_ack(unsigned char *pTxBuf, size_t txBufLen,
MessageTypes msgType, uint8_t dup, uint16_t packetId,
uint32_t *pSerializedLen) {
unsigned char *ptr;
QoS requestQoS;
IoT_Error_t rc;
MQTTHeader header = {0};
FUNC_ENTRY;
if(NULL == pTxBuf || pSerializedLen == NULL) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
ptr = pTxBuf;
/* Minimum byte length required by ACK headers is
* 2 for fixed and 2 for variable part */
if(4 > txBufLen) {
FUNC_EXIT_RC(MQTT_TX_BUFFER_TOO_SHORT_ERROR);
}
requestQoS = (PUBREL == msgType) ? QOS1 : QOS0;
rc = aws_iot_mqtt_internal_init_header(&header, msgType, requestQoS, dup, 0);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
aws_iot_mqtt_internal_write_char(&ptr, header.byte); /* write header */
ptr += aws_iot_mqtt_internal_write_len_to_buffer(ptr, 2); /* write remaining length */
aws_iot_mqtt_internal_write_uint_16(&ptr, packetId);
*pSerializedLen = (uint32_t)(ptr - pTxBuf);
FUNC_EXIT_RC(SUCCESS);
}
/**
* @brief Publish an MQTT message on a topic
*
* Called to publish an MQTT message on a topic.
* @note Call is blocking. In the case of a QoS 0 message the function returns
* after the message was successfully passed to the TLS layer. In the case of QoS 1
* the function returns after the receipt of the PUBACK control packet.
* This is the internal function which is called by the publish API to perform the operation.
* Not meant to be called directly as it doesn't do validations or client state changes
*
* @param pClient Reference to the IoT Client
* @param pTopicName Topic Name to publish to
* @param topicNameLen Length of the topic name
* @param pParams Pointer to Publish Message parameters
*
* @return An IoT Error Type defining successful/failed publish
*/
static IoT_Error_t _aws_iot_mqtt_internal_publish(AWS_IoT_Client *pClient, const char *pTopicName,
uint16_t topicNameLen, IoT_Publish_Message_Params *pParams) {
Timer timer;
uint32_t len = 0;
uint16_t packet_id;
unsigned char dup, type;
IoT_Error_t rc;
FUNC_ENTRY;
init_timer(&timer);
countdown_ms(&timer, pClient->clientData.commandTimeoutMs);
if(QOS1 == pParams->qos) {
pParams->id = aws_iot_mqtt_get_next_packet_id(pClient);
}
rc = _aws_iot_mqtt_internal_serialize_publish(pClient->clientData.writeBuf, pClient->clientData.writeBufSize, 0,
pParams->qos, pParams->isRetained, pParams->id, pTopicName,
topicNameLen, (unsigned char *) pParams->payload,
pParams->payloadLen, &len);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
/* send the publish packet */
rc = aws_iot_mqtt_internal_send_packet(pClient, len, &timer);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
/* Wait for ack if QoS1 */
if(QOS1 == pParams->qos) {
rc = aws_iot_mqtt_internal_wait_for_read(pClient, PUBACK, &timer);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
rc = aws_iot_mqtt_internal_deserialize_ack(&type, &dup, &packet_id, pClient->clientData.readBuf,
pClient->clientData.readBufSize);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
}
FUNC_EXIT_RC(SUCCESS);
}
/**
* @brief Publish an MQTT message on a topic
*
* Called to publish an MQTT message on a topic.
* @note Call is blocking. In the case of a QoS 0 message the function returns
* after the message was successfully passed to the TLS layer. In the case of QoS 1
* the function returns after the receipt of the PUBACK control packet.
* This is the outer function which does the validations and calls the internal publish above
* to perform the actual operation. It is also responsible for client state changes
*
* @param pClient Reference to the IoT Client
* @param pTopicName Topic Name to publish to
* @param topicNameLen Length of the topic name
* @param pParams Pointer to Publish Message parameters
*
* @return An IoT Error Type defining successful/failed publish
*/
IoT_Error_t aws_iot_mqtt_publish(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen,
IoT_Publish_Message_Params *pParams) {
IoT_Error_t rc, pubRc;
ClientState clientState;
FUNC_ENTRY;
if(NULL == pClient || NULL == pTopicName || NULL == pParams) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
if(!aws_iot_mqtt_is_client_connected(pClient)) {
FUNC_EXIT_RC(NETWORK_DISCONNECTED_ERROR);
}
clientState = aws_iot_mqtt_get_client_state(pClient);
if(CLIENT_STATE_CONNECTED_IDLE != clientState && CLIENT_STATE_CONNECTED_WAIT_FOR_CB_RETURN != clientState) {
FUNC_EXIT_RC(MQTT_CLIENT_NOT_IDLE_ERROR);
}
rc = aws_iot_mqtt_set_client_state(pClient, clientState, CLIENT_STATE_CONNECTED_PUBLISH_IN_PROGRESS);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
pubRc = _aws_iot_mqtt_internal_publish(pClient, pTopicName, topicNameLen, pParams);
rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_PUBLISH_IN_PROGRESS, clientState);
if(SUCCESS == pubRc && SUCCESS != rc) {
pubRc = rc;
}
FUNC_EXIT_RC(pubRc);
}
/**
* Deserializes the supplied (wire) buffer into publish data
* @param dup returned uint8_t - the MQTT dup flag
* @param qos returned QoS type - the MQTT QoS value
* @param retained returned uint8_t - the MQTT retained flag
* @param pPacketId returned uint16_t - the MQTT packet identifier
* @param pTopicName returned String - the MQTT topic in the publish
* @param topicNameLen returned uint16_t - the length of the MQTT topic in the publish
* @param payload returned byte buffer - the MQTT publish payload
* @param payloadlen returned size_t - the length of the MQTT payload
* @param pRxBuf the raw buffer data, of the correct length determined by the remaining length field
* @param rxBufLen the length in bytes of the data in the supplied buffer
*
* @return An IoT Error Type defining successful/failed call
*/
IoT_Error_t aws_iot_mqtt_internal_deserialize_publish(uint8_t *dup, QoS *qos,
uint8_t *retained, uint16_t *pPacketId,
char **pTopicName, uint16_t *topicNameLen,
unsigned char **payload, size_t *payloadLen,
unsigned char *pRxBuf, size_t rxBufLen) {
unsigned char *curData = pRxBuf;
unsigned char *endData = NULL;
IoT_Error_t rc = FAILURE;
uint32_t decodedLen = 0;
uint32_t readBytesLen = 0;
MQTTHeader header = {0};
FUNC_ENTRY;
if(NULL == dup || NULL == qos || NULL == retained || NULL == pPacketId) {
FUNC_EXIT_RC(FAILURE);
}
/* Publish header size is at least four bytes.
* Fixed header is two bytes.
* Variable header size depends on QoS And Topic Name.
* QoS level 0 doesn't have a message identifier (0 - 2 bytes)
* Topic Name length fields decide size of topic name field (at least 2 bytes)
* MQTT v3.1.1 Specification 3.3.1 */
if(4 > rxBufLen) {
FUNC_EXIT_RC(MQTT_RX_BUFFER_TOO_SHORT_ERROR);
}
header.byte = aws_iot_mqtt_internal_read_char(&curData);
if(PUBLISH != header.bits.type) {
FUNC_EXIT_RC(FAILURE);
}
*dup = header.bits.dup;
*qos = (QoS)header.bits.qos;
*retained = header.bits.retain;
/* read remaining length */
rc = aws_iot_mqtt_internal_decode_remaining_length_from_buffer(curData, &decodedLen, &readBytesLen);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
return rc;
}
curData += (readBytesLen);
endData = curData + decodedLen;
/* do we have enough data to read the protocol version byte? */
if(SUCCESS != _aws_iot_mqtt_read_string_with_len(pTopicName, topicNameLen, &curData, endData)
|| (0 > (endData - curData))) {
FUNC_EXIT_RC(FAILURE);
}
if(QOS0 != *qos) {
*pPacketId = aws_iot_mqtt_internal_read_uint16_t(&curData);
}
*payloadLen = (size_t)(endData - curData);
*payload = curData;
FUNC_EXIT_RC(SUCCESS);
}
/**
* Deserializes the supplied (wire) buffer into an ack
* @param pPacketType returned integer - the MQTT packet type
* @param dup returned integer - the MQTT dup flag
* @param pPacketId returned integer - the MQTT packet identifier
* @param pRxBuf the raw buffer data, of the correct length determined by the remaining length field
* @param rxBuflen the length in bytes of the data in the supplied buffer
*
* @return An IoT Error Type defining successful/failed call
*/
IoT_Error_t aws_iot_mqtt_internal_deserialize_ack(unsigned char *pPacketType, unsigned char *dup,
uint16_t *pPacketId, unsigned char *pRxBuf,
size_t rxBuflen) {
IoT_Error_t rc = FAILURE;
unsigned char *curdata = pRxBuf;
unsigned char *enddata = NULL;
uint32_t decodedLen = 0;
uint32_t readBytesLen = 0;
MQTTHeader header = {0};
FUNC_ENTRY;
if(NULL == pPacketType || NULL == dup || NULL == pPacketId || NULL == pRxBuf) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
/* PUBACK fixed header size is two bytes, variable header is 2 bytes, MQTT v3.1.1 Specification 3.4.1 */
if(4 > rxBuflen) {
FUNC_EXIT_RC(MQTT_RX_BUFFER_TOO_SHORT_ERROR);
}
header.byte = aws_iot_mqtt_internal_read_char(&curdata);
*dup = header.bits.dup;
*pPacketType = header.bits.type;
/* read remaining length */
rc = aws_iot_mqtt_internal_decode_remaining_length_from_buffer(curdata, &decodedLen, &readBytesLen);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
curdata += (readBytesLen);
enddata = curdata + decodedLen;
if(enddata - curdata < 2) {
FUNC_EXIT_RC(FAILURE);
}
*pPacketId = aws_iot_mqtt_internal_read_uint16_t(&curdata);
FUNC_EXIT_RC(SUCCESS);
}

View File

@@ -0,0 +1,426 @@
/*
* Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
// Based on Eclipse Paho.
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
/**
* @file aws_iot_mqtt_client_subscribe.c
* @brief MQTT client subscribe API definitions
*/
#include "aws_iot_mqtt_client_common_internal.h"
/**
* Serializes the supplied subscribe data into the supplied buffer, ready for sending
* @param pTxBuf the buffer into which the packet will be serialized
* @param txBufLen the length in bytes of the supplied buffer
* @param dup unsigned char - the MQTT dup flag
* @param packetId uint16_t - the MQTT packet identifier
* @param topicCount - number of members in the topicFilters and reqQos arrays
* @param pTopicNameList - array of topic filter names
* @param pTopicNameLenList - array of length of topic filter names
* @param pRequestedQoSs - array of requested QoS
* @param pSerializedLen - the length of the serialized data
*
* @return An IoT Error Type defining successful/failed operation
*/
static IoT_Error_t _aws_iot_mqtt_serialize_subscribe(unsigned char *pTxBuf, size_t txBufLen,
unsigned char dup, uint16_t packetId, uint32_t topicCount,
const char **pTopicNameList, uint16_t *pTopicNameLenList,
QoS *pRequestedQoSs, uint32_t *pSerializedLen) {
unsigned char *ptr;
uint32_t itr, rem_len;
MQTTHeader header = {0};
FUNC_ENTRY;
if(NULL == pTxBuf || NULL == pSerializedLen) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
ptr = pTxBuf;
rem_len = 2; /* packetId */
for(itr = 0; itr < topicCount; ++itr) {
rem_len += (uint32_t)(pTopicNameLenList[itr] + 2 + 1); /* topic + length + req_qos */
}
if(aws_iot_mqtt_internal_get_final_packet_length_from_remaining_length(rem_len) > txBufLen) {
FUNC_EXIT_RC(MQTT_TX_BUFFER_TOO_SHORT_ERROR);
}
IoT_Error_t rc = aws_iot_mqtt_internal_init_header(&header, SUBSCRIBE, QOS1, dup, 0);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
/* write header */
aws_iot_mqtt_internal_write_char(&ptr, header.byte);
/* write remaining length */
ptr += aws_iot_mqtt_internal_write_len_to_buffer(ptr, rem_len);
aws_iot_mqtt_internal_write_uint_16(&ptr, packetId);
for(itr = 0; itr < topicCount; ++itr) {
aws_iot_mqtt_internal_write_utf8_string(&ptr, pTopicNameList[itr], pTopicNameLenList[itr]);
aws_iot_mqtt_internal_write_char(&ptr, (unsigned char) pRequestedQoSs[itr]);
}
*pSerializedLen = (uint32_t)(ptr - pTxBuf);
FUNC_EXIT_RC(SUCCESS);
}
/**
* Deserializes the supplied (wire) buffer into suback data
* @param pPacketId returned integer - the MQTT packet identifier
* @param maxExpectedQoSCount - the maximum number of members allowed in the grantedQoSs array
* @param pGrantedQoSCount returned uint32_t - number of members in the grantedQoSs array
* @param pGrantedQoSs returned array of QoS type - the granted qualities of service
* @param pRxBuf the raw buffer data, of the correct length determined by the remaining length field
* @param rxBufLen the length in bytes of the data in the supplied buffer
*
* @return An IoT Error Type defining successful/failed operation
*/
static IoT_Error_t _aws_iot_mqtt_deserialize_suback(uint16_t *pPacketId, uint32_t maxExpectedQoSCount,
uint32_t *pGrantedQoSCount, QoS *pGrantedQoSs,
unsigned char *pRxBuf, size_t rxBufLen) {
unsigned char *curData, *endData;
uint32_t decodedLen, readBytesLen;
IoT_Error_t decodeRc;
MQTTHeader header = {0};
FUNC_ENTRY;
if(NULL == pPacketId || NULL == pGrantedQoSCount || NULL == pGrantedQoSs) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
curData = pRxBuf;
endData = NULL;
decodeRc = FAILURE;
decodedLen = 0;
readBytesLen = 0;
/* SUBACK header size is 4 bytes for header and at least one byte for QoS payload
* Need at least a 5 bytes buffer. MQTT3.1.1 specification 3.9
*/
if(5 > rxBufLen) {
FUNC_EXIT_RC(MQTT_RX_BUFFER_TOO_SHORT_ERROR);
}
header.byte = aws_iot_mqtt_internal_read_char(&curData);
if (SUBACK != header.bits.type) {
FUNC_EXIT_RC(FAILURE);
}
/* read remaining length */
decodeRc = aws_iot_mqtt_internal_decode_remaining_length_from_buffer(curData, &decodedLen, &readBytesLen);
if(SUCCESS != decodeRc) {
FUNC_EXIT_RC(decodeRc);
}
curData += (readBytesLen);
endData = curData + decodedLen;
if (endData - curData < 2) {
FUNC_EXIT_RC(FAILURE);
}
*pPacketId = aws_iot_mqtt_internal_read_uint16_t(&curData);
*pGrantedQoSCount = 0;
while(curData < endData) {
if(*pGrantedQoSCount > maxExpectedQoSCount) {
FUNC_EXIT_RC(FAILURE);
}
pGrantedQoSs[(*pGrantedQoSCount)++] = (QoS)aws_iot_mqtt_internal_read_char(&curData);
}
FUNC_EXIT_RC(SUCCESS);
}
/* Returns MAX_MESSAGE_HANDLERS value if no free index is available */
static uint32_t _aws_iot_mqtt_get_free_message_handler_index(AWS_IoT_Client *pClient) {
uint32_t itr;
FUNC_ENTRY;
for(itr = 0; itr < AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS; itr++) {
if(pClient->clientData.messageHandlers[itr].topicName == NULL) {
break;
}
}
FUNC_EXIT_RC(itr);
}
/**
* @brief Subscribe to an MQTT topic.
*
* Called to send a subscribe message to the broker requesting a subscription
* to an MQTT topic. This is the internal function which is called by the
* subscribe API to perform the operation. Not meant to be called directly as
* it doesn't do validations or client state changes
* @note Call is blocking. The call returns after the receipt of the SUBACK control packet.
*
* @param pClient Reference to the IoT Client
* @param pTopicName Topic Name to publish to
* @param topicNameLen Length of the topic name
* @param pApplicationHandler_t Reference to the handler function for this subscription
*
* @return An IoT Error Type defining successful/failed subscription
*/
static IoT_Error_t _aws_iot_mqtt_internal_subscribe(AWS_IoT_Client *pClient, const char *pTopicName,
uint16_t topicNameLen, QoS qos,
pApplicationHandler_t pApplicationHandler,
void *pApplicationHandlerData) {
uint16_t txPacketId, rxPacketId;
uint32_t serializedLen, indexOfFreeMessageHandler, count;
IoT_Error_t rc;
Timer timer;
QoS grantedQoS[3] = {QOS0, QOS0, QOS0};
FUNC_ENTRY;
init_timer(&timer);
countdown_ms(&timer, pClient->clientData.commandTimeoutMs);
serializedLen = 0;
count = 0;
txPacketId = aws_iot_mqtt_get_next_packet_id(pClient);
rxPacketId = 0;
rc = _aws_iot_mqtt_serialize_subscribe(pClient->clientData.writeBuf, pClient->clientData.writeBufSize, 0,
txPacketId, 1, &pTopicName, &topicNameLen, &qos, &serializedLen);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
indexOfFreeMessageHandler = _aws_iot_mqtt_get_free_message_handler_index(pClient);
if(AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS <= indexOfFreeMessageHandler) {
FUNC_EXIT_RC(MQTT_MAX_SUBSCRIPTIONS_REACHED_ERROR);
}
/* send the subscribe packet */
rc = aws_iot_mqtt_internal_send_packet(pClient, serializedLen, &timer);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
/* wait for suback */
rc = aws_iot_mqtt_internal_wait_for_read(pClient, SUBACK, &timer);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
/* Granted QoS can be 0, 1 or 2 */
rc = _aws_iot_mqtt_deserialize_suback(&rxPacketId, 1, &count, grantedQoS, pClient->clientData.readBuf,
pClient->clientData.readBufSize);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
/* TODO : Figure out how to test this before activating this check */
//if(txPacketId != rxPacketId) {
/* Different SUBACK received than expected. Return error
* This can cause issues if the request timeout value is too small */
// return RX_MESSAGE_INVALID_ERROR;
//}
pClient->clientData.messageHandlers[indexOfFreeMessageHandler].topicName =
pTopicName;
pClient->clientData.messageHandlers[indexOfFreeMessageHandler].topicNameLen =
topicNameLen;
pClient->clientData.messageHandlers[indexOfFreeMessageHandler].pApplicationHandler =
pApplicationHandler;
pClient->clientData.messageHandlers[indexOfFreeMessageHandler].pApplicationHandlerData =
pApplicationHandlerData;
pClient->clientData.messageHandlers[indexOfFreeMessageHandler].qos = qos;
FUNC_EXIT_RC(SUCCESS);
}
/**
* @brief Subscribe to an MQTT topic.
*
* Called to send a subscribe message to the broker requesting a subscription
* to an MQTT topic. This is the outer function which does the validations and
* calls the internal subscribe above to perform the actual operation.
* It is also responsible for client state changes
* @note Call is blocking. The call returns after the receipt of the SUBACK control packet.
*
* @param pClient Reference to the IoT Client
* @param pTopicName Topic Name to publish to
* @param topicNameLen Length of the topic name
* @param pApplicationHandler_t Reference to the handler function for this subscription
*
* @return An IoT Error Type defining successful/failed subscription
*/
IoT_Error_t aws_iot_mqtt_subscribe(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen,
QoS qos, pApplicationHandler_t pApplicationHandler, void *pApplicationHandlerData) {
ClientState clientState;
IoT_Error_t rc, subRc;
FUNC_ENTRY;
if(NULL == pClient || NULL == pTopicName || NULL == pApplicationHandler) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
if(!aws_iot_mqtt_is_client_connected(pClient)) {
FUNC_EXIT_RC(NETWORK_DISCONNECTED_ERROR);
}
clientState = aws_iot_mqtt_get_client_state(pClient);
if(CLIENT_STATE_CONNECTED_IDLE != clientState && CLIENT_STATE_CONNECTED_WAIT_FOR_CB_RETURN != clientState) {
FUNC_EXIT_RC(MQTT_CLIENT_NOT_IDLE_ERROR);
}
rc = aws_iot_mqtt_set_client_state(pClient, clientState, CLIENT_STATE_CONNECTED_SUBSCRIBE_IN_PROGRESS);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
subRc = _aws_iot_mqtt_internal_subscribe(pClient, pTopicName, topicNameLen, qos,
pApplicationHandler, pApplicationHandlerData);
rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_SUBSCRIBE_IN_PROGRESS, clientState);
if(SUCCESS == subRc && SUCCESS != rc) {
subRc = rc;
}
FUNC_EXIT_RC(subRc);
}
/**
* @brief Subscribe to an MQTT topic.
*
* Called to send a subscribe message to the broker requesting a subscription
* to an MQTT topic.
* This is the internal function which is called by the resubscribe API to perform the operation.
* Not meant to be called directly as it doesn't do validations or client state changes
* @note Call is blocking. The call returns after the receipt of the SUBACK control packet.
*
* @param pClient Reference to the IoT Client
*
* @return An IoT Error Type defining successful/failed subscription
*/
static IoT_Error_t _aws_iot_mqtt_internal_resubscribe(AWS_IoT_Client *pClient) {
uint16_t packetId;
uint32_t len, count, existingSubCount, itr;
IoT_Error_t rc;
Timer timer;
QoS grantedQoS[3] = {QOS0, QOS0, QOS0};
FUNC_ENTRY;
packetId = 0;
len = 0;
count = 0;
existingSubCount = _aws_iot_mqtt_get_free_message_handler_index(pClient);
for(itr = 0; itr < existingSubCount; itr++) {
init_timer(&timer);
countdown_ms(&timer, pClient->clientData.commandTimeoutMs);
rc = _aws_iot_mqtt_serialize_subscribe(pClient->clientData.writeBuf, pClient->clientData.writeBufSize, 0,
aws_iot_mqtt_get_next_packet_id(pClient), 1,
&(pClient->clientData.messageHandlers[itr].topicName),
&(pClient->clientData.messageHandlers[itr].topicNameLen),
&(pClient->clientData.messageHandlers[itr].qos), &len);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
/* send the subscribe packet */
rc = aws_iot_mqtt_internal_send_packet(pClient, len, &timer);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
/* wait for suback */
rc = aws_iot_mqtt_internal_wait_for_read(pClient, SUBACK, &timer);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
/* Granted QoS can be 0, 1 or 2 */
rc = _aws_iot_mqtt_deserialize_suback(&packetId, 1, &count, grantedQoS, pClient->clientData.readBuf,
pClient->clientData.readBufSize);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
}
FUNC_EXIT_RC(SUCCESS);
}
/**
* @brief Subscribe to an MQTT topic.
*
* Called to send a subscribe message to the broker requesting a subscription
* to an MQTT topic.
* This is the outer function which does the validations and calls the internal resubscribe above
* to perform the actual operation. It is also responsible for client state changes
* @note Call is blocking. The call returns after the receipt of the SUBACK control packet.
*
* @param pClient Reference to the IoT Client
*
* @return An IoT Error Type defining successful/failed subscription
*/
IoT_Error_t aws_iot_mqtt_resubscribe(AWS_IoT_Client *pClient) {
IoT_Error_t rc, resubRc;
FUNC_ENTRY;
if(NULL == pClient) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
if(false == aws_iot_mqtt_is_client_connected(pClient)) {
FUNC_EXIT_RC(NETWORK_DISCONNECTED_ERROR);
}
if(CLIENT_STATE_CONNECTED_IDLE != aws_iot_mqtt_get_client_state(pClient)) {
FUNC_EXIT_RC(MQTT_CLIENT_NOT_IDLE_ERROR);
}
rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_IDLE, CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
resubRc = _aws_iot_mqtt_internal_resubscribe(pClient);
rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS, CLIENT_STATE_CONNECTED_IDLE);
if(SUCCESS == resubRc && SUCCESS != rc) {
resubRc = rc;
}
FUNC_EXIT_RC(resubRc);
}

View File

@@ -0,0 +1,223 @@
/*
* Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
// Based on Eclipse Paho.
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
/**
* @file aws_iot_mqtt_client_unsubscribe.c
* @brief MQTT client unsubscribe API definitions
*/
#include "aws_iot_mqtt_client_common_internal.h"
/**
* Serializes the supplied unsubscribe data into the supplied buffer, ready for sending
* @param pTxBuf the raw buffer data, of the correct length determined by the remaining length field
* @param txBufLen the length in bytes of the data in the supplied buffer
* @param dup integer - the MQTT dup flag
* @param packetId integer - the MQTT packet identifier
* @param count - number of members in the topicFilters array
* @param pTopicNameList - array of topic filter names
* @param pTopicNameLenList - array of length of topic filter names in pTopicNameList
* @param pSerializedLen - the length of the serialized data
* @return IoT_Error_t indicating function execution status
*/
static IoT_Error_t _aws_iot_mqtt_serialize_unsubscribe(unsigned char *pTxBuf, size_t txBufLen,
uint8_t dup, uint16_t packetId,
uint32_t count, const char **pTopicNameList,
uint16_t *pTopicNameLenList, uint32_t *pSerializedLen) {
unsigned char *ptr = pTxBuf;
MQTTHeader header = {0};
uint32_t i = 0;
uint32_t rem_len = 2; /* packetId */
FUNC_ENTRY;
for(i = 0; i < count; ++i) {
rem_len += (uint32_t)(pTopicNameLenList[i] + 2); /* topic + length */
}
if(aws_iot_mqtt_internal_get_final_packet_length_from_remaining_length(rem_len) > txBufLen) {
FUNC_EXIT_RC(MQTT_TX_BUFFER_TOO_SHORT_ERROR);
}
IoT_Error_t rc = aws_iot_mqtt_internal_init_header(&header, UNSUBSCRIBE, QOS1, dup, 0);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
aws_iot_mqtt_internal_write_char(&ptr, header.byte); /* write header */
ptr += aws_iot_mqtt_internal_write_len_to_buffer(ptr, rem_len); /* write remaining length */
aws_iot_mqtt_internal_write_uint_16(&ptr, packetId);
for(i = 0; i < count; ++i) {
aws_iot_mqtt_internal_write_utf8_string(&ptr, pTopicNameList[i], pTopicNameLenList[i]);
}
*pSerializedLen = (uint32_t)(ptr - pTxBuf);
FUNC_EXIT_RC(SUCCESS);
}
/**
* Deserializes the supplied (wire) buffer into unsuback data
* @param pPacketId returned integer - the MQTT packet identifier
* @param pRxBuf the raw buffer data, of the correct length determined by the remaining length field
* @param rxBufLen the length in bytes of the data in the supplied buffer
* @return IoT_Error_t indicating function execution status
*/
static IoT_Error_t _aws_iot_mqtt_deserialize_unsuback(uint16_t *pPacketId, unsigned char *pRxBuf, size_t rxBufLen) {
unsigned char type = 0;
unsigned char dup = 0;
IoT_Error_t rc;
FUNC_ENTRY;
rc = aws_iot_mqtt_internal_deserialize_ack(&type, &dup, pPacketId, pRxBuf, rxBufLen);
if(SUCCESS == rc && UNSUBACK != type) {
rc = FAILURE;
}
FUNC_EXIT_RC(rc);
}
/**
* @brief Unsubscribe to an MQTT topic.
*
* Called to send an unsubscribe message to the broker requesting removal of a subscription
* to an MQTT topic.
* @note Call is blocking. The call returns after the receipt of the UNSUBACK control packet.
* This is the internal function which is called by the unsubscribe API to perform the operation.
* Not meant to be called directly as it doesn't do validations or client state changes
*
* @param pClient Reference to the IoT Client
* @param pTopicName Topic Name to publish to
* @param topicNameLen Length of the topic name
*
* @return An IoT Error Type defining successful/failed unsubscribe call
*/
static IoT_Error_t _aws_iot_mqtt_internal_unsubscribe(AWS_IoT_Client *pClient, const char *pTopicFilter, uint16_t topicFilterLen) {
/* No NULL checks because this is a static internal function */
Timer timer;
uint32_t serializedLen = 0;
uint32_t i = 0;
IoT_Error_t rc;
FUNC_ENTRY;
init_timer(&timer);
countdown_ms(&timer, pClient->clientData.commandTimeoutMs);
rc = _aws_iot_mqtt_serialize_unsubscribe(pClient->clientData.writeBuf, pClient->clientData.writeBufSize, 0,
aws_iot_mqtt_get_next_packet_id(pClient), 1, &pTopicFilter,
&topicFilterLen, &serializedLen);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
/* send the unsubscribe packet */
rc = aws_iot_mqtt_internal_send_packet(pClient, serializedLen, &timer);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
rc = aws_iot_mqtt_internal_wait_for_read(pClient, UNSUBACK, &timer);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
uint16_t packet_id;
rc = _aws_iot_mqtt_deserialize_unsuback(&packet_id, pClient->clientData.readBuf, pClient->clientData.readBufSize);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
/* Remove from message handler array */
for(i = 0; i < AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS; ++i) {
if(pClient->clientData.messageHandlers[i].topicName != NULL &&
(strcmp(pClient->clientData.messageHandlers[i].topicName, pTopicFilter) == 0)) {
pClient->clientData.messageHandlers[i].topicName = NULL;
/* We don't want to break here, in case the same topic is registered
* with 2 callbacks. Unlikely scenario */
}
}
FUNC_EXIT_RC(SUCCESS);
}
/**
* @brief Unsubscribe to an MQTT topic.
*
* Called to send an unsubscribe message to the broker requesting removal of a subscription
* to an MQTT topic.
* @note Call is blocking. The call returns after the receipt of the UNSUBACK control packet.
* This is the outer function which does the validations and calls the internal unsubscribe above
* to perform the actual operation. It is also responsible for client state changes
*
* @param pClient Reference to the IoT Client
* @param pTopicName Topic Name to publish to
* @param topicNameLen Length of the topic name
*
* @return An IoT Error Type defining successful/failed unsubscribe call
*/
IoT_Error_t aws_iot_mqtt_unsubscribe(AWS_IoT_Client *pClient, const char *pTopicFilter, uint16_t topicFilterLen) {
if(NULL == pClient || NULL == pTopicFilter) {
return NULL_VALUE_ERROR;
}
if(!aws_iot_mqtt_is_client_connected(pClient)) {
return NETWORK_DISCONNECTED_ERROR;
}
ClientState clientState = aws_iot_mqtt_get_client_state(pClient);
if(CLIENT_STATE_CONNECTED_IDLE != clientState && CLIENT_STATE_CONNECTED_WAIT_FOR_CB_RETURN != clientState) {
return MQTT_CLIENT_NOT_IDLE_ERROR;
}
IoT_Error_t rc = aws_iot_mqtt_set_client_state(pClient, clientState, CLIENT_STATE_CONNECTED_UNSUBSCRIBE_IN_PROGRESS);
if(SUCCESS != rc) {
rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_UNSUBSCRIBE_IN_PROGRESS, clientState);
return rc;
}
IoT_Error_t unsubRc = _aws_iot_mqtt_internal_unsubscribe(pClient, pTopicFilter, topicFilterLen);
rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_UNSUBSCRIBE_IN_PROGRESS, clientState);
if(SUCCESS == unsubRc && SUCCESS != rc) {
unsubRc = rc;
}
return unsubRc;
}

View File

@@ -0,0 +1,293 @@
/*
* Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
// Based on Eclipse Paho.
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
/**
* @file aws_iot_mqtt_client_yield.c
* @brief MQTT client yield API definitions
*/
#include "aws_iot_mqtt_client_common_internal.h"
/**
* This is for the case when the aws_iot_mqtt_internal_send_packet Fails.
*/
static void _aws_iot_mqtt_force_client_disconnect(AWS_IoT_Client *pClient) {
pClient->clientStatus.clientState = CLIENT_STATE_DISCONNECTED_ERROR;
pClient->networkStack.disconnect(&(pClient->networkStack));
pClient->networkStack.destroy(&(pClient->networkStack));
}
static IoT_Error_t _aws_iot_mqtt_handle_disconnect(AWS_IoT_Client *pClient) {
IoT_Error_t rc;
FUNC_ENTRY;
rc = aws_iot_mqtt_disconnect(pClient);
if(rc != SUCCESS) {
// If the aws_iot_mqtt_internal_send_packet prevents us from sending a disconnect packet then we have to clean the stack
_aws_iot_mqtt_force_client_disconnect(pClient);
}
if(NULL != pClient->clientData.disconnectHandler) {
pClient->clientData.disconnectHandler(pClient, pClient->clientData.disconnectHandlerData);
}
/* Reset to 0 since this was not a manual disconnect */
pClient->clientStatus.clientState = CLIENT_STATE_DISCONNECTED_ERROR;
FUNC_EXIT_RC(NETWORK_DISCONNECTED_ERROR);
}
static IoT_Error_t _aws_iot_mqtt_handle_reconnect(AWS_IoT_Client *pClient) {
IoT_Error_t rc;
FUNC_ENTRY;
if(!has_timer_expired(&(pClient->reconnectDelayTimer))) {
/* Timer has not expired. Not time to attempt reconnect yet.
* Return attempting reconnect */
FUNC_EXIT_RC(NETWORK_ATTEMPTING_RECONNECT);
}
rc = NETWORK_PHYSICAL_LAYER_DISCONNECTED;
if(NULL != pClient->networkStack.isConnected) {
rc = pClient->networkStack.isConnected(&(pClient->networkStack));
}
if(NETWORK_PHYSICAL_LAYER_CONNECTED == rc) {
rc = aws_iot_mqtt_attempt_reconnect(pClient);
if(NETWORK_RECONNECTED == rc) {
rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_IDLE,
CLIENT_STATE_CONNECTED_YIELD_IN_PROGRESS);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
FUNC_EXIT_RC(NETWORK_RECONNECTED);
}
}
pClient->clientData.currentReconnectWaitInterval *= 2;
if(AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL < pClient->clientData.currentReconnectWaitInterval) {
FUNC_EXIT_RC(NETWORK_RECONNECT_TIMED_OUT_ERROR);
}
countdown_ms(&(pClient->reconnectDelayTimer), pClient->clientData.currentReconnectWaitInterval);
FUNC_EXIT_RC(rc);
}
static IoT_Error_t _aws_iot_mqtt_keep_alive(AWS_IoT_Client *pClient) {
IoT_Error_t rc = SUCCESS;
Timer timer;
size_t serialized_len;
if(NULL == pClient) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
if(0 == pClient->clientData.keepAliveInterval) {
FUNC_EXIT_RC(SUCCESS);
}
if(!has_timer_expired(&pClient->pingTimer)) {
FUNC_EXIT_RC(SUCCESS);
}
if(pClient->clientStatus.isPingOutstanding) {
rc = _aws_iot_mqtt_handle_disconnect(pClient);
FUNC_EXIT_RC(rc);
}
/* there is no ping outstanding - send one */
init_timer(&timer);
countdown_ms(&timer, pClient->clientData.commandTimeoutMs);
serialized_len = 0;
rc = aws_iot_mqtt_internal_serialize_zero(pClient->clientData.writeBuf, pClient->clientData.writeBufSize,
PINGREQ, &serialized_len);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
/* send the ping packet */
rc = aws_iot_mqtt_internal_send_packet(pClient, serialized_len, &timer);
if(SUCCESS != rc) {
//If sending a PING fails we can no longer determine if we are connected. In this case we decide we are disconnected and begin reconnection attempts
rc = _aws_iot_mqtt_handle_disconnect(pClient);
FUNC_EXIT_RC(rc);
}
pClient->clientStatus.isPingOutstanding = 1;
/* start a timer to wait for PINGRESP from server */
countdown_sec(&pClient->pingTimer, pClient->clientData.keepAliveInterval / (uint32_t)2);
FUNC_EXIT_RC(SUCCESS);
}
/**
* @brief Yield to the MQTT client
*
* Called to yield the current thread to the underlying MQTT client. This time is used by
* the MQTT client to manage PING requests to monitor the health of the TCP connection as
* well as periodically check the socket receive buffer for subscribe messages. Yield()
* must be called at a rate faster than the keepalive interval. It must also be called
* at a rate faster than the incoming message rate as this is the only way the client receives
* processing time to manage incoming messages.
* This is the internal function which is called by the yield API to perform the operation.
* Not meant to be called directly as it doesn't do validations or client state changes
*
* @param pClient Reference to the IoT Client
* @param timeout_ms Maximum number of milliseconds to pass thread execution to the client.
*
* @return An IoT Error Type defining successful/failed client processing.
* If this call results in an error it is likely the MQTT connection has dropped.
* iot_is_mqtt_connected can be called to confirm.
*/
static IoT_Error_t _aws_iot_mqtt_internal_yield(AWS_IoT_Client *pClient, uint32_t timeout_ms) {
IoT_Error_t yieldRc = SUCCESS;
uint8_t packet_type;
ClientState clientState;
Timer timer;
init_timer(&timer);
countdown_ms(&timer, timeout_ms);
FUNC_ENTRY;
while(!has_timer_expired(&timer)) {
clientState = aws_iot_mqtt_get_client_state(pClient);
if(CLIENT_STATE_PENDING_RECONNECT == clientState) {
if(AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL < pClient->clientData.currentReconnectWaitInterval) {
yieldRc = NETWORK_RECONNECT_TIMED_OUT_ERROR;
break;
}
yieldRc = _aws_iot_mqtt_handle_reconnect(pClient);
/* Network reconnect attempted, check if yield timer expired before
* doing anything else */
continue;
}
yieldRc = aws_iot_mqtt_internal_cycle_read(pClient, &timer, &packet_type);
if(SUCCESS != yieldRc) {
break;
}
yieldRc = _aws_iot_mqtt_keep_alive(pClient);
if(NETWORK_DISCONNECTED_ERROR == yieldRc) {
pClient->clientData.counterNetworkDisconnected++;
if(1 == pClient->clientStatus.isAutoReconnectEnabled) {
yieldRc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_DISCONNECTED_ERROR,
CLIENT_STATE_PENDING_RECONNECT);
if (SUCCESS != yieldRc) {
FUNC_EXIT_RC(yieldRc);
}
pClient->clientData.currentReconnectWaitInterval = AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL;
countdown_ms(&(pClient->reconnectDelayTimer), pClient->clientData.currentReconnectWaitInterval);
/* Depending on timer values, it is possible that yield timer has expired
* Set to rc to attempting reconnect to inform client that autoreconnect
* attempt has started */
yieldRc = NETWORK_ATTEMPTING_RECONNECT;
} else {
break;
}
} else if(SUCCESS != yieldRc) {
break;
}
}
FUNC_EXIT_RC(yieldRc);
}
/**
* @brief Yield to the MQTT client
*
* Called to yield the current thread to the underlying MQTT client. This time is used by
* the MQTT client to manage PING requests to monitor the health of the TCP connection as
* well as periodically check the socket receive buffer for subscribe messages. Yield()
* must be called at a rate faster than the keepalive interval. It must also be called
* at a rate faster than the incoming message rate as this is the only way the client receives
* processing time to manage incoming messages.
* This is the outer function which does the validations and calls the internal yield above
* to perform the actual operation. It is also responsible for client state changes
*
* @param pClient Reference to the IoT Client
* @param timeout_ms Maximum number of milliseconds to pass thread execution to the client.
*
* @return An IoT Error Type defining successful/failed client processing.
* If this call results in an error it is likely the MQTT connection has dropped.
* iot_is_mqtt_connected can be called to confirm.
*/
IoT_Error_t aws_iot_mqtt_yield(AWS_IoT_Client *pClient, uint32_t timeout_ms) {
IoT_Error_t rc, yieldRc;
ClientState clientState;
if(NULL == pClient) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
clientState = aws_iot_mqtt_get_client_state(pClient);
/* Check if network was manually disconnected */
if(CLIENT_STATE_DISCONNECTED_MANUALLY == clientState) {
FUNC_EXIT_RC(NETWORK_MANUALLY_DISCONNECTED);
}
/* If we are in the pending reconnect state, skip other checks.
* Pending reconnect state is only set when auto-reconnect is enabled */
if(CLIENT_STATE_PENDING_RECONNECT != clientState) {
/* Check if network is disconnected and auto-reconnect is not enabled */
if(!aws_iot_mqtt_is_client_connected(pClient)) {
FUNC_EXIT_RC(NETWORK_DISCONNECTED_ERROR);
}
/* Check if client is idle, if not another operation is in progress and we should return */
if(CLIENT_STATE_CONNECTED_IDLE != clientState) {
FUNC_EXIT_RC(MQTT_CLIENT_NOT_IDLE_ERROR);
}
rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_IDLE,
CLIENT_STATE_CONNECTED_YIELD_IN_PROGRESS);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
}
yieldRc = _aws_iot_mqtt_internal_yield(pClient, timeout_ms);
if(NETWORK_DISCONNECTED_ERROR != yieldRc && NETWORK_ATTEMPTING_RECONNECT != yieldRc) {
rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_YIELD_IN_PROGRESS, CLIENT_STATE_CONNECTED_IDLE);
if (SUCCESS == yieldRc && SUCCESS != rc) {
yieldRc = rc;
}
}
FUNC_EXIT_RC(yieldRc);
}

185
src/aws_iot_shadow.c Normal file
View File

@@ -0,0 +1,185 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#include <aws_iot_mqtt_client_interface.h>
#include <aws_iot_shadow_interface.h>
#include "aws_iot_error.h"
#include "aws_iot_log.h"
#include "aws_iot_shadow_actions.h"
#include "aws_iot_shadow_json.h"
#include "aws_iot_shadow_key.h"
#include "aws_iot_shadow_records.h"
const ShadowInitParameters_t ShadowInitParametersDefault = {
.pHost = AWS_IOT_MQTT_HOST,
.port = AWS_IOT_MQTT_PORT,
.pRootCA = NULL,
.pClientCRT = NULL,
.pClientKey = NULL
};
const ShadowConnectParameters_t ShadowConnectParametersDefault = {
.pMyThingName = AWS_IOT_MY_THING_NAME,
.pMqttClientId = AWS_IOT_MQTT_CLIENT_ID
};
void aws_iot_shadow_reset_last_received_version(void) {
shadowJsonVersionNum = 0;
}
uint32_t aws_iot_shadow_get_last_received_version(void) {
return shadowJsonVersionNum;
}
void aws_iot_shadow_enable_discard_old_delta_msgs(void) {
shadowDiscardOldDeltaFlag = true;
}
void aws_iot_shadow_disable_discard_old_delta_msgs(void) {
shadowDiscardOldDeltaFlag = false;
}
IoT_Error_t aws_iot_shadow_init(AWS_IoT_Client *pClient, ShadowInitParameters_t *pParams) {
if (pClient == NULL) {
return NULL_VALUE_ERROR;
}
IoT_Client_Init_Params mqttInitParams;
mqttInitParams.enableAutoReconnect = pParams->enableAutoReconnect;
mqttInitParams.pHostURL = pParams->pHost;
mqttInitParams.port = pParams->port;
mqttInitParams.pRootCALocation = pParams->pRootCA;
mqttInitParams.pDeviceCertLocation = pParams->pClientCRT;
mqttInitParams.pDevicePrivateKeyLocation = pParams->pClientKey;
mqttInitParams.mqttCommandTimeout_ms = 2000;
mqttInitParams.tlsHandshakeTimeout_ms = 10000;
mqttInitParams.isSSLHostnameVerify = true;
mqttInitParams.disconnectHandler = pParams->disconnectHandler;
IoT_Error_t rc = aws_iot_mqtt_init(pClient, &mqttInitParams);
if(SUCCESS != rc) {
return rc;
}
resetClientTokenSequenceNum();
aws_iot_shadow_reset_last_received_version();
initDeltaTokens();
return SUCCESS;
}
IoT_Error_t aws_iot_shadow_connect(AWS_IoT_Client *pClient, ShadowConnectParameters_t *pParams) {
if(NULL == pClient || NULL == pParams || NULL == pParams->pMqttClientId) {
return NULL_VALUE_ERROR;
}
IoT_Error_t rc = SUCCESS;
IoT_Client_Connect_Params ConnectParams = iotClientConnectParamsDefault;
snprintf(myThingName, MAX_SIZE_OF_THING_NAME, "%s", pParams->pMyThingName);
snprintf(mqttClientID, MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES, "%s", pParams->pMqttClientId);
DEBUG("Thing Name %s", myThingName);
DEBUG("MQTT Client ID %s", mqttClientID);
ConnectParams.keepAliveIntervalInSec = 10;
ConnectParams.MQTTVersion = MQTT_3_1_1;
ConnectParams.isCleanSession = true;
ConnectParams.isWillMsgPresent = false;
ConnectParams.pClientID = pParams->pMqttClientId;
ConnectParams.pPassword = NULL;
ConnectParams.pUsername = NULL;
rc = aws_iot_mqtt_connect(pClient, &ConnectParams);
if(SUCCESS == rc) {
initializeRecords(pClient);
}
return rc;
}
IoT_Error_t aws_iot_shadow_register_delta(AWS_IoT_Client *pMqttClient, jsonStruct_t *pStruct) {
if(NULL == pMqttClient || NULL == pStruct) {
return NULL_VALUE_ERROR;
}
if(!aws_iot_mqtt_is_client_connected(pMqttClient)) {
return MQTT_CONNECTION_ERROR;
}
return registerJsonTokenOnDelta(pStruct);
}
IoT_Error_t aws_iot_shadow_yield(AWS_IoT_Client *pClient, uint32_t timeout) {
HandleExpiredResponseCallbacks();
return aws_iot_mqtt_yield(pClient, timeout);
}
IoT_Error_t aws_iot_shadow_disconnect(AWS_IoT_Client *pClient) {return aws_iot_mqtt_disconnect(pClient);
}
IoT_Error_t aws_iot_shadow_update(AWS_IoT_Client *pClient, const char *pThingName, char *pJsonString,
fpActionCallback_t callback, void *pContextData, uint8_t timeout_seconds,
bool isPersistentSubscribe) {
if(NULL == pClient) {
return NULL_VALUE_ERROR;
}
if(!aws_iot_mqtt_is_client_connected(pClient)) {
return MQTT_CONNECTION_ERROR;
}
return iot_shadow_action(pThingName, SHADOW_UPDATE, pJsonString, callback, pContextData,
timeout_seconds, isPersistentSubscribe);
}
IoT_Error_t aws_iot_shadow_delete(AWS_IoT_Client *pClient, const char *pThingName, fpActionCallback_t callback,
void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscribe) {
if(NULL == pClient) {
return NULL_VALUE_ERROR;
}
if (!aws_iot_mqtt_is_client_connected(pClient)) {
return MQTT_CONNECTION_ERROR;
}
char deleteRequestJsonBuf[MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE];
iot_shadow_delete_request_json(deleteRequestJsonBuf);
return iot_shadow_action(pThingName, SHADOW_DELETE, deleteRequestJsonBuf, callback, pContextData,
timeout_seconds, isPersistentSubscribe);
}
IoT_Error_t aws_iot_shadow_get(AWS_IoT_Client *pClient, const char *pThingName, fpActionCallback_t callback,
void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscribe) {
if(NULL == pClient) {
return NULL_VALUE_ERROR;
}
if (!aws_iot_mqtt_is_client_connected(pClient)) {
return MQTT_CONNECTION_ERROR;
}
char getRequestJsonBuf[MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE];
iot_shadow_get_request_json(getRequestJsonBuf);
return iot_shadow_action(pThingName, SHADOW_GET, getRequestJsonBuf, callback, pContextData,
timeout_seconds, isPersistentSubscribe);
}
IoT_Error_t aws_iot_shadow_set_autoreconnect_status(AWS_IoT_Client *pClient, bool newStatus) {
return aws_iot_mqtt_autoreconnect_set_status(pClient, newStatus);
}

View File

@@ -20,17 +20,17 @@
#include "aws_iot_shadow_records.h"
#include "aws_iot_config.h"
IoT_Error_t iot_shadow_action(MQTTClient_t *pClient, const char *pThingName, ShadowActions_t action,
IoT_Error_t iot_shadow_action(const char *pThingName, ShadowActions_t action,
const char *pJsonDocumentToBeSent, fpActionCallback_t callback, void *pCallbackContext,
uint32_t timeout_seconds, bool isSticky) {
IoT_Error_t ret_val = NONE_ERROR;
IoT_Error_t ret_val = SUCCESS;
bool isCallbackPresent = false;
bool isClientTokenPresent = false;
bool isAckWaitListFree = false;
uint8_t indexAckWaitList;
if(pClient == NULL || pThingName == NULL || pJsonDocumentToBeSent == NULL){
if(pThingName == NULL || pJsonDocumentToBeSent == NULL){
return NULL_VALUE_ERROR;
}
@@ -54,16 +54,16 @@ IoT_Error_t iot_shadow_action(MQTTClient_t *pClient, const char *pThingName, Sha
}
}
else {
ret_val = GENERIC_ERROR;
ret_val = FAILURE;
}
}
if (ret_val == NONE_ERROR) {
if (ret_val == SUCCESS) {
ret_val = publishToShadowAction(pThingName, action, pJsonDocumentToBeSent);
}
if (isClientTokenPresent && isCallbackPresent && ret_val == NONE_ERROR && isAckWaitListFree) {
if (isClientTokenPresent && isCallbackPresent && ret_val == SUCCESS && isAckWaitListFree) {
addToAckWaitList(indexAckWaitList, pThingName, action, extractedClientToken, callback, pCallbackContext,
timeout_seconds);
}

View File

@@ -29,7 +29,7 @@ static uint32_t clientTokenNum = 0;
//helper functions
static IoT_Error_t convertDataToString(char *pStringBuffer, size_t maxSizoStringBuffer, JsonPrimitiveType type,
void *pData);
void *pData);
void resetClientTokenSequenceNum(void) {
clientTokenNum = 0;
@@ -50,21 +50,20 @@ void iot_shadow_delete_request_json(char *pJsonDocument) {
}
static inline IoT_Error_t checkReturnValueOfSnPrintf(int32_t snPrintfReturn, size_t maxSizeOfJsonDocument) {
if (snPrintfReturn >= maxSizeOfJsonDocument) {
return SHADOW_JSON_BUFFER_TRUNCATED;
} else if (snPrintfReturn < 0) {
if(snPrintfReturn < 0) {
return SHADOW_JSON_ERROR;
} else if((size_t)snPrintfReturn >= maxSizeOfJsonDocument) {
return SHADOW_JSON_BUFFER_TRUNCATED;
}
return NONE_ERROR;
return SUCCESS;
}
IoT_Error_t aws_iot_shadow_init_json_document(char *pJsonDocument, size_t maxSizeOfJsonDocument) {
IoT_Error_t ret_val = NONE_ERROR;
IoT_Error_t ret_val = SUCCESS;
int32_t snPrintfReturn = 0;
if (pJsonDocument == NULL) {
if(pJsonDocument == NULL) {
return NULL_VALUE_ERROR;
}
snPrintfReturn = snprintf(pJsonDocument, maxSizeOfJsonDocument, "{\"state\":{");
@@ -76,8 +75,8 @@ IoT_Error_t aws_iot_shadow_init_json_document(char *pJsonDocument, size_t maxSiz
}
IoT_Error_t aws_iot_shadow_add_desired(char *pJsonDocument, size_t maxSizeOfJsonDocument, uint8_t count, ...) {
IoT_Error_t ret_val = NONE_ERROR;
int32_t tempSize = 0;
IoT_Error_t ret_val = SUCCESS;
size_t tempSize = 0;
int8_t i;
size_t remSizeOfJsonBuffer = maxSizeOfJsonDocument;
int32_t snPrintfReturn = 0;
@@ -85,44 +84,44 @@ IoT_Error_t aws_iot_shadow_add_desired(char *pJsonDocument, size_t maxSizeOfJson
va_start(pArgs, count);
jsonStruct_t *pTemporary;
if (pJsonDocument == NULL) {
if(pJsonDocument == NULL) {
return NULL_VALUE_ERROR;
}
tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
if(tempSize <= 1){
return SHADOW_JSON_ERROR;
}
remSizeOfJsonBuffer = tempSize;
if(tempSize <= 1) {
return SHADOW_JSON_ERROR;
}
remSizeOfJsonBuffer = tempSize;
snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"desired\":{");
ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
if (ret_val != NONE_ERROR) {
if(ret_val != SUCCESS) {
return ret_val;
}
for (i = 0; i < count; i++) {
for(i = 0; i < count; i++) {
tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
if(tempSize <= 1){
return SHADOW_JSON_ERROR;
}
remSizeOfJsonBuffer = tempSize;
if(tempSize <= 1) {
return SHADOW_JSON_ERROR;
}
remSizeOfJsonBuffer = tempSize;
pTemporary = va_arg (pArgs, jsonStruct_t *);
if (pTemporary != NULL) {
if(pTemporary != NULL) {
snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"%s\":",
pTemporary->pKey);
pTemporary->pKey);
ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
if (ret_val != NONE_ERROR) {
if(ret_val != SUCCESS) {
return ret_val;
}
if (pTemporary->pKey != NULL && pTemporary->pData != NULL) {
if(pTemporary->pKey != NULL && pTemporary->pData != NULL) {
ret_val = convertDataToString(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer,
pTemporary->type, pTemporary->pData);
pTemporary->type, pTemporary->pData);
} else {
return NULL_VALUE_ERROR;
}
if (ret_val != NONE_ERROR) {
if(ret_val != SUCCESS) {
return ret_val;
}
} else {
@@ -137,23 +136,23 @@ IoT_Error_t aws_iot_shadow_add_desired(char *pJsonDocument, size_t maxSizeOfJson
}
IoT_Error_t aws_iot_shadow_add_reported(char *pJsonDocument, size_t maxSizeOfJsonDocument, uint8_t count, ...) {
IoT_Error_t ret_val = NONE_ERROR;
IoT_Error_t ret_val = SUCCESS;
int8_t i;
size_t remSizeOfJsonBuffer = maxSizeOfJsonDocument;
int32_t snPrintfReturn = 0;
int32_t tempSize = 0;
size_t tempSize = 0;
va_list pArgs;
va_start(pArgs, count);
jsonStruct_t *pTemporary;
if (pJsonDocument == NULL) {
if(pJsonDocument == NULL) {
return NULL_VALUE_ERROR;
}
tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
if(tempSize <= 1){
if(tempSize <= 1) {
return SHADOW_JSON_ERROR;
}
remSizeOfJsonBuffer = tempSize;
@@ -161,32 +160,32 @@ IoT_Error_t aws_iot_shadow_add_reported(char *pJsonDocument, size_t maxSizeOfJso
snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"reported\":{");
ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
if (ret_val != NONE_ERROR) {
if(ret_val != SUCCESS) {
return ret_val;
}
for (i = 0; i < count; i++) {
for(i = 0; i < count; i++) {
tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
if(tempSize <= 1){
if(tempSize <= 1) {
return SHADOW_JSON_ERROR;
}
remSizeOfJsonBuffer = tempSize;
pTemporary = va_arg (pArgs, jsonStruct_t *);
if (pTemporary != NULL) {
if(pTemporary != NULL) {
snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"%s\":",
pTemporary->pKey);
pTemporary->pKey);
ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
if (ret_val != NONE_ERROR) {
if(ret_val != SUCCESS) {
return ret_val;
}
if (pTemporary->pKey != NULL && pTemporary->pData != NULL) {
if(pTemporary->pKey != NULL && pTemporary->pData != NULL) {
ret_val = convertDataToString(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer,
pTemporary->type, pTemporary->pData);
pTemporary->type, pTemporary->pData);
} else {
return NULL_VALUE_ERROR;
}
if (ret_val != NONE_ERROR) {
if(ret_val != SUCCESS) {
return ret_val;
}
} else {
@@ -204,12 +203,12 @@ IoT_Error_t aws_iot_shadow_add_reported(char *pJsonDocument, size_t maxSizeOfJso
int32_t FillWithClientTokenSize(char *pBufferToBeUpdatedWithClientToken, size_t maxSizeOfJsonDocument) {
int32_t snPrintfReturn;
snPrintfReturn = snprintf(pBufferToBeUpdatedWithClientToken, maxSizeOfJsonDocument, "%s-%d", mqttClientID,
clientTokenNum++);
clientTokenNum++);
return snPrintfReturn;
}
IoT_Error_t aws_iot_fill_with_client_token(char *pBufferToBeUpdatedWithClientToken, size_t maxSizeOfJsonDocument){
IoT_Error_t aws_iot_fill_with_client_token(char *pBufferToBeUpdatedWithClientToken, size_t maxSizeOfJsonDocument) {
int32_t snPrintfRet = 0;
snPrintfRet = FillWithClientTokenSize(pBufferToBeUpdatedWithClientToken, maxSizeOfJsonDocument);
@@ -220,30 +219,30 @@ IoT_Error_t aws_iot_fill_with_client_token(char *pBufferToBeUpdatedWithClientTok
IoT_Error_t aws_iot_finalize_json_document(char *pJsonDocument, size_t maxSizeOfJsonDocument) {
size_t remSizeOfJsonBuffer = maxSizeOfJsonDocument;
int32_t snPrintfReturn = 0;
int32_t tempSize = 0;
IoT_Error_t ret_val = NONE_ERROR;
size_t tempSize = 0;
IoT_Error_t ret_val = SUCCESS;
if (pJsonDocument == NULL) {
if(pJsonDocument == NULL) {
return NULL_VALUE_ERROR;
}
tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
if(tempSize <= 1){
if(tempSize <= 1) {
return SHADOW_JSON_ERROR;
}
remSizeOfJsonBuffer = tempSize;
// strlen(ShadowTxBuffer) - 1 is to ensure we remove the last ,(comma) that was added
snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument) - 1, remSizeOfJsonBuffer, "}, \"%s\":\"",
SHADOW_CLIENT_TOKEN_STRING);
SHADOW_CLIENT_TOKEN_STRING);
ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
if (ret_val != NONE_ERROR) {
if(ret_val != SUCCESS) {
return ret_val;
}
// refactor this XXX repeated code
tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
if(tempSize <= 1){
if(tempSize <= 1) {
return SHADOW_JSON_ERROR;
}
remSizeOfJsonBuffer = tempSize;
@@ -252,11 +251,11 @@ IoT_Error_t aws_iot_finalize_json_document(char *pJsonDocument, size_t maxSizeOf
snPrintfReturn = FillWithClientTokenSize(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer);
ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
if (ret_val != NONE_ERROR) {
if(ret_val != SUCCESS) {
return ret_val;
}
tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
if(tempSize <= 1){
if(tempSize <= 1) {
return SHADOW_JSON_ERROR;
}
remSizeOfJsonBuffer = tempSize;
@@ -273,40 +272,41 @@ void FillWithClientToken(char *pBufferToBeUpdatedWithClientToken) {
}
static IoT_Error_t convertDataToString(char *pStringBuffer, size_t maxSizoStringBuffer, JsonPrimitiveType type,
void *pData) {
void *pData) {
int32_t snPrintfReturn = 0;
IoT_Error_t ret_val = NONE_ERROR;
IoT_Error_t ret_val = SUCCESS;
if (maxSizoStringBuffer == 0) {
if(maxSizoStringBuffer == 0) {
return SHADOW_JSON_ERROR;
}
if (type == SHADOW_JSON_INT32) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIi32",", *(int32_t * )(pData));
} else if (type == SHADOW_JSON_INT16) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIi16",", *(int16_t * )(pData));
} else if (type == SHADOW_JSON_INT8) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIi8",", *(int8_t * )(pData));
} else if (type == SHADOW_JSON_UINT32) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIu32",", *(uint32_t * )(pData));
} else if (type == SHADOW_JSON_UINT16) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIu16",", *(uint16_t * )(pData));
} else if (type == SHADOW_JSON_UINT8) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIu8",", *(uint8_t * )(pData));
} else if (type == SHADOW_JSON_DOUBLE) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%f,", *(double * )(pData));
} else if (type == SHADOW_JSON_FLOAT) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%f,", *(float * )(pData));
} else if (type == SHADOW_JSON_BOOL) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%s,", *(bool *)(pData)?"true":"false");
} else if (type == SHADOW_JSON_STRING) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "\"%s\",", (char * )(pData));
if(type == SHADOW_JSON_INT32) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIi32",", *(int32_t *) (pData));
} else if(type == SHADOW_JSON_INT16) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIi16",", *(int16_t *) (pData));
} else if(type == SHADOW_JSON_INT8) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIi8",", *(int8_t *) (pData));
} else if(type == SHADOW_JSON_UINT32) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIu32",", *(uint32_t *) (pData));
} else if(type == SHADOW_JSON_UINT16) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIu16",", *(uint16_t *) (pData));
} else if(type == SHADOW_JSON_UINT8) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIu8",", *(uint8_t *) (pData));
} else if(type == SHADOW_JSON_DOUBLE) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%f,", *(double *) (pData));
} else if(type == SHADOW_JSON_FLOAT) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%f,", *(float *) (pData));
} else if(type == SHADOW_JSON_BOOL) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%s,", *(bool *) (pData) ? "true" : "false");
} else if(type == SHADOW_JSON_STRING) {
snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "\"%s\",", (char *) (pData));
}
ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, maxSizoStringBuffer);
return ret_val;
}
static jsmn_parser shadowJsonParser;
static jsmntok_t jsonTokenStruct[MAX_JSON_TOKEN_EXPECTED];
@@ -316,15 +316,15 @@ bool isJsonValidAndParse(const char *pJsonDocument, void *pJsonHandler, int32_t
jsmn_init(&shadowJsonParser);
tokenCount = jsmn_parse(&shadowJsonParser, pJsonDocument, strlen(pJsonDocument), jsonTokenStruct,
sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0]));
sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0]));
if (tokenCount < 0) {
if(tokenCount < 0) {
WARN("Failed to parse JSON: %d\n", tokenCount);
return false;
}
/* Assume the top-level element is an object */
if (tokenCount < 1 || jsonTokenStruct[0].type != JSMN_OBJECT) {
if(tokenCount < 1 || jsonTokenStruct[0].type != JSMN_OBJECT) {
WARN("Top Level is not an object\n");
return false;
}
@@ -336,24 +336,24 @@ bool isJsonValidAndParse(const char *pJsonDocument, void *pJsonHandler, int32_t
}
static IoT_Error_t UpdateValueIfNoObject(const char *pJsonString, jsonStruct_t *pDataStruct, jsmntok_t token) {
IoT_Error_t ret_val = NONE_ERROR;
if (pDataStruct->type == SHADOW_JSON_BOOL) {
IoT_Error_t ret_val = SUCCESS;
if(pDataStruct->type == SHADOW_JSON_BOOL) {
ret_val = parseBooleanValue(pDataStruct->pData, pJsonString, &token);
} else if (pDataStruct->type == SHADOW_JSON_INT32) {
} else if(pDataStruct->type == SHADOW_JSON_INT32) {
ret_val = parseInteger32Value(pDataStruct->pData, pJsonString, &token);
} else if (pDataStruct->type == SHADOW_JSON_INT16) {
} else if(pDataStruct->type == SHADOW_JSON_INT16) {
ret_val = parseInteger16Value(pDataStruct->pData, pJsonString, &token);
} else if (pDataStruct->type == SHADOW_JSON_INT8) {
} else if(pDataStruct->type == SHADOW_JSON_INT8) {
ret_val = parseInteger8Value(pDataStruct->pData, pJsonString, &token);
} else if (pDataStruct->type == SHADOW_JSON_UINT32) {
} else if(pDataStruct->type == SHADOW_JSON_UINT32) {
ret_val = parseUnsignedInteger32Value(pDataStruct->pData, pJsonString, &token);
} else if (pDataStruct->type == SHADOW_JSON_UINT16) {
} else if(pDataStruct->type == SHADOW_JSON_UINT16) {
ret_val = parseUnsignedInteger16Value(pDataStruct->pData, pJsonString, &token);
} else if (pDataStruct->type == SHADOW_JSON_UINT8) {
} else if(pDataStruct->type == SHADOW_JSON_UINT8) {
ret_val = parseUnsignedInteger8Value(pDataStruct->pData, pJsonString, &token);
} else if (pDataStruct->type == SHADOW_JSON_FLOAT) {
} else if(pDataStruct->type == SHADOW_JSON_FLOAT) {
ret_val = parseFloatValue(pDataStruct->pData, pJsonString, &token);
} else if (pDataStruct->type == SHADOW_JSON_DOUBLE) {
} else if(pDataStruct->type == SHADOW_JSON_DOUBLE) {
ret_val = parseDoubleValue(pDataStruct->pData, pJsonString, &token);
}
@@ -361,16 +361,17 @@ static IoT_Error_t UpdateValueIfNoObject(const char *pJsonString, jsonStruct_t *
}
bool isJsonKeyMatchingAndUpdateValue(const char *pJsonDocument, void *pJsonHandler, int32_t tokenCount,
jsonStruct_t *pDataStruct, uint32_t *pDataLength, int32_t *pDataPosition) {
jsonStruct_t *pDataStruct, uint32_t *pDataLength, int32_t *pDataPosition) {
int32_t i;
uint32_t dataLength;
jsmntok_t *pJsonTokenStruct;
jsmntok_t dataToken;
pJsonTokenStruct = (jsmntok_t *) pJsonHandler;
for (i = 1; i < tokenCount; i++) {
if (jsoneq(pJsonDocument, &(jsonTokenStruct[i]), pDataStruct->pKey) == 0) {
jsmntok_t dataToken = jsonTokenStruct[i + 1];
uint32_t dataLength = dataToken.end - dataToken.start;
for(i = 1; i < tokenCount; i++) {
if(jsoneq(pJsonDocument, &(jsonTokenStruct[i]), pDataStruct->pKey) == 0) {
dataToken = jsonTokenStruct[i + 1];
dataLength = (uint32_t)(dataToken.end - dataToken.start);
UpdateValueIfNoObject(pJsonDocument, pDataStruct, dataToken);
*pDataPosition = dataToken.start;
*pDataLength = dataLength;
@@ -386,15 +387,15 @@ bool isReceivedJsonValid(const char *pJsonDocument) {
jsmn_init(&shadowJsonParser);
tokenCount = jsmn_parse(&shadowJsonParser, pJsonDocument, strlen(pJsonDocument), jsonTokenStruct,
sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0]));
sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0]));
if (tokenCount < 0) {
if(tokenCount < 0) {
WARN("Failed to parse JSON: %d\n", tokenCount);
return false;
}
/* Assume the top-level element is an object */
if (tokenCount < 1 || jsonTokenStruct[0].type != JSMN_OBJECT) {
if(tokenCount < 1 || jsonTokenStruct[0].type != JSMN_OBJECT) {
return false;
}
@@ -402,28 +403,28 @@ bool isReceivedJsonValid(const char *pJsonDocument) {
}
bool extractClientToken(const char *pJsonDocument, char *pExtractedClientToken) {
bool ret_val = false;
jsmn_init(&shadowJsonParser);
int32_t tokenCount, i;
uint8_t length;
jsmntok_t ClientJsonToken;
tokenCount = jsmn_parse(&shadowJsonParser, pJsonDocument, strlen(pJsonDocument), jsonTokenStruct,
sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0]));
sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0]));
if (tokenCount < 0) {
if(tokenCount < 0) {
WARN("Failed to parse JSON: %d\n", tokenCount);
return false;
}
/* Assume the top-level element is an object */
if (tokenCount < 1 || jsonTokenStruct[0].type != JSMN_OBJECT) {
if(tokenCount < 1 || jsonTokenStruct[0].type != JSMN_OBJECT) {
return false;
}
for (i = 1; i < tokenCount; i++) {
if (jsoneq(pJsonDocument, &jsonTokenStruct[i], SHADOW_CLIENT_TOKEN_STRING) == 0) {
for(i = 1; i < tokenCount; i++) {
if(jsoneq(pJsonDocument, &jsonTokenStruct[i], SHADOW_CLIENT_TOKEN_STRING) == 0) {
ClientJsonToken = jsonTokenStruct[i + 1];
uint8_t length = ClientJsonToken.end - ClientJsonToken.start;
length = (uint8_t)(ClientJsonToken.end - ClientJsonToken.start);
strncpy(pExtractedClientToken, pJsonDocument + ClientJsonToken.start, length);
pExtractedClientToken[length] = '\0';
return true;
@@ -435,16 +436,14 @@ bool extractClientToken(const char *pJsonDocument, char *pExtractedClientToken)
bool extractVersionNumber(const char *pJsonDocument, void *pJsonHandler, int32_t tokenCount, uint32_t *pVersionNumber) {
int32_t i;
jsmntok_t *pJsonTokenStruct;
IoT_Error_t ret_val = NONE_ERROR;
IoT_Error_t ret_val = SUCCESS;
pJsonTokenStruct = (jsmntok_t *) pJsonHandler;
for (i = 1; i < tokenCount; i++) {
if (jsoneq(pJsonDocument, &(jsonTokenStruct[i]), SHADOW_VERSION_STRING) == 0) {
jsmntok_t dataToken = jsonTokenStruct[i + 1];
uint32_t dataLength = dataToken.end - dataToken.start;
ret_val = parseUnsignedInteger32Value(pVersionNumber, pJsonDocument, &dataToken);
if (ret_val == NONE_ERROR) {
IOT_UNUSED(pJsonHandler);
for(i = 1; i < tokenCount; i++) {
if(jsoneq(pJsonDocument, &(jsonTokenStruct[i]), SHADOW_VERSION_STRING) == 0) {
ret_val = parseUnsignedInteger32Value(pVersionNumber, pJsonDocument, &jsonTokenStruct[i + 1]);
if(ret_val == SUCCESS) {
return true;
}
}

View File

@@ -54,7 +54,7 @@ typedef enum {
ToBeReceivedAckRecord_t AckWaitList[MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME];
MQTTClient_t *pMqttClient;
AWS_IoT_Client *pMqttClient;
char myThingName[MAX_SIZE_OF_THING_NAME];
char mqttClientID[MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES];
@@ -74,16 +74,22 @@ uint32_t shadowJsonVersionNum = 0;
bool shadowDiscardOldDeltaFlag = true;
// local helper functions
static int AckStatusCallback(MQTTCallbackParams params);
static int shadow_delta_callback(MQTTCallbackParams params);
static void AckStatusCallback(AWS_IoT_Client *pClient, char *topicName,
uint16_t topicNameLen, IoT_Publish_Message_Params *params, void *pData);
static void shadow_delta_callback(AWS_IoT_Client *pClient, char *topicName,
uint16_t topicNameLen, IoT_Publish_Message_Params *params, void *pData);
static void topicNameFromThingAndAction(char *pTopic, const char *pThingName, ShadowActions_t action,
ShadowAckTopicTypes_t ackType);
ShadowAckTopicTypes_t ackType);
static int16_t getNextFreeIndexOfSubscriptionList(void);
static void unsubscribeFromAcceptedAndRejected(uint8_t index);
void initDeltaTokens(void) {
uint32_t i;
for (i = 0; i < MAX_JSON_TOKEN_EXPECTED; i++) {
for(i = 0; i < MAX_JSON_TOKEN_EXPECTED; i++) {
tokenTable[i].isFree = true;
}
tokenTableIndex = 0;
@@ -92,21 +98,18 @@ void initDeltaTokens(void) {
IoT_Error_t registerJsonTokenOnDelta(jsonStruct_t *pStruct) {
IoT_Error_t rc = NONE_ERROR;
IoT_Error_t rc = SUCCESS;
if (!deltaTopicSubscribedFlag) {
MQTTSubscribeParams subParams;
subParams.mHandler = shadow_delta_callback;
snprintf(shadowDeltaTopic,MAX_SHADOW_TOPIC_LENGTH_BYTES, "$aws/things/%s/shadow/update/delta", myThingName);
subParams.pTopic = shadowDeltaTopic;
subParams.qos = QOS_0;
rc = pMqttClient->subscribe(&subParams);
if(!deltaTopicSubscribedFlag) {
snprintf(shadowDeltaTopic, MAX_SHADOW_TOPIC_LENGTH_BYTES, "$aws/things/%s/shadow/update/delta", myThingName);
rc = aws_iot_mqtt_subscribe(pMqttClient, shadowDeltaTopic, (uint16_t) strlen(shadowDeltaTopic), QOS0,
shadow_delta_callback, NULL);
DEBUG("delta topic %s", shadowDeltaTopic);
deltaTopicSubscribedFlag = true;
}
if (tokenTableIndex >= MAX_JSON_TOKEN_EXPECTED) {
return GENERIC_ERROR;
if(tokenTableIndex >= MAX_JSON_TOKEN_EXPECTED) {
return FAILURE;
}
tokenTable[tokenTableIndex].pKey = pStruct->pKey;
@@ -120,8 +123,8 @@ IoT_Error_t registerJsonTokenOnDelta(jsonStruct_t *pStruct) {
static int16_t getNextFreeIndexOfSubscriptionList(void) {
uint8_t i;
for (i = 0; i < MAX_TOPICS_AT_ANY_GIVEN_TIME; i++) {
if (SubscriptionList[i].isFree) {
for(i = 0; i < MAX_TOPICS_AT_ANY_GIVEN_TIME; i++) {
if(SubscriptionList[i].isFree) {
SubscriptionList[i].isFree = false;
return i;
}
@@ -130,26 +133,26 @@ static int16_t getNextFreeIndexOfSubscriptionList(void) {
}
static void topicNameFromThingAndAction(char *pTopic, const char *pThingName, ShadowActions_t action,
ShadowAckTopicTypes_t ackType) {
ShadowAckTopicTypes_t ackType) {
char actionBuf[10];
char ackTypeBuf[10];
if (action == SHADOW_GET) {
if(action == SHADOW_GET) {
strcpy(actionBuf, "get");
} else if (action == SHADOW_UPDATE) {
} else if(action == SHADOW_UPDATE) {
strcpy(actionBuf, "update");
} else if (action == SHADOW_DELETE) {
} else if(action == SHADOW_DELETE) {
strcpy(actionBuf, "delete");
}
if (ackType == SHADOW_ACCEPTED) {
if(ackType == SHADOW_ACCEPTED) {
strcpy(ackTypeBuf, "accepted");
} else if (ackType == SHADOW_REJECTED) {
} else if(ackType == SHADOW_REJECTED) {
strcpy(ackTypeBuf, "rejected");
}
if (ackType == SHADOW_ACTION) {
if(ackType == SHADOW_ACTION) {
sprintf(pTopic, "$aws/things/%s/shadow/%s", pThingName, actionBuf);
} else {
sprintf(pTopic, "$aws/things/%s/shadow/%s/%s", pThingName, actionBuf, ackTypeBuf);
@@ -157,71 +160,76 @@ static void topicNameFromThingAndAction(char *pTopic, const char *pThingName, Sh
}
static bool isAckForMyThingName(const char *pTopicName) {
if (strstr(pTopicName, myThingName) != NULL && ((strstr(pTopicName, "get/accepted") != NULL) || (strstr(pTopicName, "delta") != NULL))) {
if(strstr(pTopicName, myThingName) != NULL &&
((strstr(pTopicName, "get/accepted") != NULL) || (strstr(pTopicName, "delta") != NULL))) {
return true;
}
return false;
}
static int AckStatusCallback(MQTTCallbackParams params) {
static void AckStatusCallback(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
IoT_Publish_Message_Params *params, void *pData) {
int32_t tokenCount;
int32_t i;
void *pJsonHandler;
char temporaryClientToken[MAX_SIZE_CLIENT_ID_WITH_SEQUENCE];
uint8_t i;
void *pJsonHandler = NULL;
char temporaryClientToken[MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE];
if (params.MessageParams.PayloadLen > SHADOW_MAX_SIZE_OF_RX_BUFFER) {
return GENERIC_ERROR;
IOT_UNUSED(pClient);
IOT_UNUSED(topicNameLen);
IOT_UNUSED(pData);
if(params->payloadLen > SHADOW_MAX_SIZE_OF_RX_BUFFER) {
WARN("Payload larger than RX Buffer");
return;
}
memcpy(shadowRxBuf, params.MessageParams.pPayload, params.MessageParams.PayloadLen);
shadowRxBuf[params.MessageParams.PayloadLen] = '\0'; // jsmn_parse relies on a string
memcpy(shadowRxBuf, params->payload, params->payloadLen);
shadowRxBuf[params->payloadLen] = '\0'; // jsmn_parse relies on a string
if (!isJsonValidAndParse(shadowRxBuf, pJsonHandler, &tokenCount)) {
if(!isJsonValidAndParse(shadowRxBuf, pJsonHandler, &tokenCount)) {
WARN("Received JSON is not valid");
return GENERIC_ERROR;
return;
}
if (isAckForMyThingName(params.pTopicName)) {
if(isAckForMyThingName(topicName)) {
uint32_t tempVersionNumber = 0;
if (extractVersionNumber(shadowRxBuf, pJsonHandler, tokenCount, &tempVersionNumber)) {
if (tempVersionNumber > shadowJsonVersionNum) {
if(extractVersionNumber(shadowRxBuf, pJsonHandler, tokenCount, &tempVersionNumber)) {
if(tempVersionNumber > shadowJsonVersionNum) {
shadowJsonVersionNum = tempVersionNumber;
}
}
}
if (extractClientToken(shadowRxBuf, temporaryClientToken)) {
for (i = 0; i < MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME; i++) {
if (!AckWaitList[i].isFree) {
if (strcmp(AckWaitList[i].clientTokenID, temporaryClientToken) == 0) {
if(extractClientToken(shadowRxBuf, temporaryClientToken)) {
for(i = 0; i < MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME; i++) {
if(!AckWaitList[i].isFree) {
if(strcmp(AckWaitList[i].clientTokenID, temporaryClientToken) == 0) {
Shadow_Ack_Status_t status;
if (strstr(params.pTopicName, "accepted") != NULL) {
if(strstr(topicName, "accepted") != NULL) {
status = SHADOW_ACK_ACCEPTED;
} else if (strstr(params.pTopicName, "rejected") != NULL) {
} else if(strstr(topicName, "rejected") != NULL) {
status = SHADOW_ACK_REJECTED;
}
if (status == SHADOW_ACK_ACCEPTED || status == SHADOW_ACK_REJECTED) {
if (AckWaitList[i].callback != NULL) {
if(status == SHADOW_ACK_ACCEPTED || status == SHADOW_ACK_REJECTED) {
if(AckWaitList[i].callback != NULL) {
AckWaitList[i].callback(AckWaitList[i].thingName, AckWaitList[i].action, status,
shadowRxBuf, AckWaitList[i].pCallbackContext);
shadowRxBuf, AckWaitList[i].pCallbackContext);
}
unsubscribeFromAcceptedAndRejected(i);
AckWaitList[i].isFree = true;
return NONE_ERROR;
return;
}
}
}
}
}
return GENERIC_ERROR;
}
static int16_t findIndexOfSubscriptionList(const char *pTopic) {
uint8_t i;
for (i = 0; i < MAX_TOPICS_AT_ANY_GIVEN_TIME; i++) {
if (!SubscriptionList[i].isFree) {
if ((strcmp(pTopic, SubscriptionList[i].Topic) == 0)) {
for(i = 0; i < MAX_TOPICS_AT_ANY_GIVEN_TIME; i++) {
if(!SubscriptionList[i].isFree) {
if((strcmp(pTopic, SubscriptionList[i].Topic) == 0)) {
return i;
}
}
@@ -233,50 +241,53 @@ static void unsubscribeFromAcceptedAndRejected(uint8_t index) {
char TemporaryTopicNameAccepted[MAX_SHADOW_TOPIC_LENGTH_BYTES];
char TemporaryTopicNameRejected[MAX_SHADOW_TOPIC_LENGTH_BYTES];
IoT_Error_t ret_val = NONE_ERROR;
IoT_Error_t ret_val = SUCCESS;
topicNameFromThingAndAction(TemporaryTopicNameAccepted, AckWaitList[index].thingName, AckWaitList[index].action,
SHADOW_ACCEPTED);
SHADOW_ACCEPTED);
topicNameFromThingAndAction(TemporaryTopicNameRejected, AckWaitList[index].thingName, AckWaitList[index].action,
SHADOW_REJECTED);
SHADOW_REJECTED);
int16_t indexSubList;
indexSubList = findIndexOfSubscriptionList(TemporaryTopicNameAccepted);
if ((indexSubList >= 0)) {
if (!SubscriptionList[indexSubList].isSticky && (SubscriptionList[indexSubList].count == 1)) {
ret_val = pMqttClient->unsubscribe(TemporaryTopicNameAccepted);
if (ret_val == NONE_ERROR) {
if((indexSubList >= 0)) {
if(!SubscriptionList[indexSubList].isSticky && (SubscriptionList[indexSubList].count == 1)) {
ret_val = aws_iot_mqtt_unsubscribe(pMqttClient, TemporaryTopicNameAccepted,
(uint16_t)strlen(TemporaryTopicNameAccepted));
if(ret_val == SUCCESS) {
SubscriptionList[indexSubList].isFree = true;
}
} else if (SubscriptionList[indexSubList].count > 1) {
} else if(SubscriptionList[indexSubList].count > 1) {
SubscriptionList[indexSubList].count--;
}
}
indexSubList = findIndexOfSubscriptionList(TemporaryTopicNameRejected);
if ((indexSubList >= 0)) {
if (!SubscriptionList[indexSubList].isSticky && (SubscriptionList[indexSubList].count == 1)) {
ret_val = pMqttClient->unsubscribe(TemporaryTopicNameRejected);
if (ret_val == NONE_ERROR) {
if((indexSubList >= 0)) {
if(!SubscriptionList[indexSubList].isSticky && (SubscriptionList[indexSubList].count == 1)) {
ret_val = aws_iot_mqtt_unsubscribe(pMqttClient, TemporaryTopicNameRejected,
(uint16_t)strlen(TemporaryTopicNameRejected));
if(ret_val == SUCCESS) {
SubscriptionList[indexSubList].isFree = true;
}
} else if (SubscriptionList[indexSubList].count > 1) {
} else if(SubscriptionList[indexSubList].count > 1) {
SubscriptionList[indexSubList].count--;
}
}
}
void initializeRecords(MQTTClient_t *pClient) {
void initializeRecords(AWS_IoT_Client *pClient) {
uint8_t i;
for (i = 0; i < MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME; i++) {
for(i = 0; i < MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME; i++) {
AckWaitList[i].isFree = true;
}
for (i = 0; i < MAX_TOPICS_AT_ANY_GIVEN_TIME; i++) {
for(i = 0; i < MAX_TOPICS_AT_ANY_GIVEN_TIME; i++) {
SubscriptionList[i].isFree = true;
SubscriptionList[i].count = 0;
SubscriptionList[i].isSticky = false;
}
pMqttClient = pClient;
}
@@ -291,17 +302,17 @@ bool isSubscriptionPresent(const char *pThingName, ShadowActions_t action) {
topicNameFromThingAndAction(TemporaryTopicNameAccepted, pThingName, action, SHADOW_ACCEPTED);
topicNameFromThingAndAction(TemporaryTopicNameRejected, pThingName, action, SHADOW_REJECTED);
for (i = 0; i < MAX_TOPICS_AT_ANY_GIVEN_TIME; i++) {
if (!SubscriptionList[i].isFree) {
if ((strcmp(TemporaryTopicNameAccepted, SubscriptionList[i].Topic) == 0)) {
for(i = 0; i < MAX_TOPICS_AT_ANY_GIVEN_TIME; i++) {
if(!SubscriptionList[i].isFree) {
if((strcmp(TemporaryTopicNameAccepted, SubscriptionList[i].Topic) == 0)) {
isAcceptedPresent = true;
} else if ((strcmp(TemporaryTopicNameRejected, SubscriptionList[i].Topic) == 0)) {
} else if((strcmp(TemporaryTopicNameRejected, SubscriptionList[i].Topic) == 0)) {
isRejectedPresent = true;
}
}
}
if (isRejectedPresent && isAcceptedPresent) {
if(isRejectedPresent && isAcceptedPresent) {
return true;
}
@@ -309,8 +320,7 @@ bool isSubscriptionPresent(const char *pThingName, ShadowActions_t action) {
}
IoT_Error_t subscribeToShadowActionAcks(const char *pThingName, ShadowActions_t action, bool isSticky) {
IoT_Error_t ret_val = NONE_ERROR;
MQTTSubscribeParams subParams = MQTTSubscribeParamsDefault;
IoT_Error_t ret_val = SUCCESS;
bool clearBothEntriesFromList = true;
int16_t indexAcceptedSubList = 0;
@@ -318,42 +328,43 @@ IoT_Error_t subscribeToShadowActionAcks(const char *pThingName, ShadowActions_t
indexAcceptedSubList = getNextFreeIndexOfSubscriptionList();
indexRejectedSubList = getNextFreeIndexOfSubscriptionList();
if (indexAcceptedSubList >= 0 && indexRejectedSubList >= 0) {
if(indexAcceptedSubList >= 0 && indexRejectedSubList >= 0) {
topicNameFromThingAndAction(SubscriptionList[indexAcceptedSubList].Topic, pThingName, action, SHADOW_ACCEPTED);
subParams.mHandler = AckStatusCallback;
subParams.qos = QOS_0;
subParams.pTopic = SubscriptionList[indexAcceptedSubList].Topic;
ret_val = pMqttClient->subscribe(&subParams);
if (ret_val == NONE_ERROR) {
ret_val = aws_iot_mqtt_subscribe(pMqttClient, SubscriptionList[indexAcceptedSubList].Topic,
(uint16_t)strlen(SubscriptionList[indexAcceptedSubList].Topic), QOS0,
AckStatusCallback, NULL);
if(ret_val == SUCCESS) {
SubscriptionList[indexAcceptedSubList].count = 1;
SubscriptionList[indexAcceptedSubList].isSticky = isSticky;
topicNameFromThingAndAction(SubscriptionList[indexRejectedSubList].Topic, pThingName, action,
SHADOW_REJECTED);
subParams.pTopic = SubscriptionList[indexRejectedSubList].Topic;
ret_val = pMqttClient->subscribe(&subParams);
if (ret_val == NONE_ERROR) {
SHADOW_REJECTED);
ret_val = aws_iot_mqtt_subscribe(pMqttClient, SubscriptionList[indexRejectedSubList].Topic,
(uint16_t)strlen(SubscriptionList[indexRejectedSubList].Topic), QOS0,
AckStatusCallback, NULL);
if(ret_val == SUCCESS) {
SubscriptionList[indexRejectedSubList].count = 1;
SubscriptionList[indexRejectedSubList].isSticky = isSticky;
clearBothEntriesFromList = false;
// wait for SUBSCRIBE_SETTLING_TIME seconds to let the subscription take effect
Timer subSettlingtimer;
InitTimer(&subSettlingtimer);
countdown(&subSettlingtimer, SUBSCRIBE_SETTLING_TIME);
while(!expired(&subSettlingtimer));
init_timer(&subSettlingtimer);
countdown_sec(&subSettlingtimer, SUBSCRIBE_SETTLING_TIME);
while(!has_timer_expired(&subSettlingtimer));
}
}
}
if (clearBothEntriesFromList) {
if (indexAcceptedSubList >= 0) {
if(clearBothEntriesFromList) {
if(indexAcceptedSubList >= 0) {
SubscriptionList[indexAcceptedSubList].isFree = true;
} else if (indexRejectedSubList >= 0) {
} else if(indexRejectedSubList >= 0) {
SubscriptionList[indexRejectedSubList].isFree = true;
}
if (SubscriptionList[indexAcceptedSubList].count == 1) {
pMqttClient->unsubscribe(SubscriptionList[indexAcceptedSubList].Topic);
if(SubscriptionList[indexAcceptedSubList].count == 1) {
aws_iot_mqtt_unsubscribe(pMqttClient, SubscriptionList[indexAcceptedSubList].Topic,
(uint16_t)strlen(SubscriptionList[indexAcceptedSubList].Topic));
}
}
@@ -367,10 +378,10 @@ void incrementSubscriptionCnt(const char *pThingName, ShadowActions_t action, bo
topicNameFromThingAndAction(TemporaryTopicNameAccepted, pThingName, action, SHADOW_ACCEPTED);
topicNameFromThingAndAction(TemporaryTopicNameRejected, pThingName, action, SHADOW_REJECTED);
for (i = 0; i < MAX_TOPICS_AT_ANY_GIVEN_TIME; i++) {
if (!SubscriptionList[i].isFree) {
if ((strcmp(TemporaryTopicNameAccepted, SubscriptionList[i].Topic) == 0)
|| (strcmp(TemporaryTopicNameRejected, SubscriptionList[i].Topic) == 0)) {
for(i = 0; i < MAX_TOPICS_AT_ANY_GIVEN_TIME; i++) {
if(!SubscriptionList[i].isFree) {
if((strcmp(TemporaryTopicNameAccepted, SubscriptionList[i].Topic) == 0)
|| (strcmp(TemporaryTopicNameRejected, SubscriptionList[i].Topic) == 0)) {
SubscriptionList[i].count++;
SubscriptionList[i].isSticky = isSticky;
}
@@ -378,28 +389,25 @@ void incrementSubscriptionCnt(const char *pThingName, ShadowActions_t action, bo
}
}
IoT_Error_t publishToShadowAction(const char * pThingName, ShadowActions_t action, const char *pJsonDocumentToBeSent) {
IoT_Error_t ret_val = NONE_ERROR;
IoT_Error_t publishToShadowAction(const char *pThingName, ShadowActions_t action, const char *pJsonDocumentToBeSent) {
IoT_Error_t ret_val = SUCCESS;
char TemporaryTopicName[MAX_SHADOW_TOPIC_LENGTH_BYTES];
topicNameFromThingAndAction(TemporaryTopicName, pThingName, action, SHADOW_ACTION);
MQTTPublishParams pubParams = MQTTPublishParamsDefault;
pubParams.pTopic = TemporaryTopicName;
MQTTMessageParams msgParams = MQTTMessageParamsDefault;
msgParams.qos = QOS_0;
msgParams.PayloadLen = strlen(pJsonDocumentToBeSent) + 1;
msgParams.pPayload = (char *) pJsonDocumentToBeSent;
pubParams.MessageParams = msgParams;
ret_val = pMqttClient->publish(&pubParams);
IoT_Publish_Message_Params msgParams;// = MQTTMessageParamsDefault;
msgParams.qos = QOS0;
msgParams.payloadLen = strlen(pJsonDocumentToBeSent) + 1;
msgParams.payload = (char *) pJsonDocumentToBeSent;
ret_val = aws_iot_mqtt_publish(pMqttClient, TemporaryTopicName, (uint16_t)strlen(TemporaryTopicName), &msgParams);
return ret_val;
}
bool getNextFreeIndexOfAckWaitList(uint8_t *pIndex) {
uint8_t i;
if (pIndex != NULL) {
for (i = 0; i < MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME; i++) {
if (AckWaitList[i].isFree) {
if(pIndex != NULL) {
for(i = 0; i < MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME; i++) {
if(AckWaitList[i].isFree) {
*pIndex = i;
return true;
}
@@ -409,26 +417,26 @@ bool getNextFreeIndexOfAckWaitList(uint8_t *pIndex) {
}
void addToAckWaitList(uint8_t indexAckWaitList, const char *pThingName, ShadowActions_t action,
const char *pExtractedClientToken, fpActionCallback_t callback, void *pCallbackContext,
uint32_t timeout_seconds) {
const char *pExtractedClientToken, fpActionCallback_t callback, void *pCallbackContext,
uint32_t timeout_seconds) {
AckWaitList[indexAckWaitList].callback = callback;
strncpy(AckWaitList[indexAckWaitList].clientTokenID, pExtractedClientToken, MAX_SIZE_CLIENT_ID_WITH_SEQUENCE);
strncpy(AckWaitList[indexAckWaitList].thingName, pThingName, MAX_SIZE_OF_THING_NAME);
AckWaitList[indexAckWaitList].pCallbackContext = pCallbackContext;
AckWaitList[indexAckWaitList].action = action;
InitTimer(&(AckWaitList[indexAckWaitList].timer));
countdown(&(AckWaitList[indexAckWaitList].timer), timeout_seconds);
init_timer(&(AckWaitList[indexAckWaitList].timer));
countdown_sec(&(AckWaitList[indexAckWaitList].timer), timeout_seconds);
AckWaitList[indexAckWaitList].isFree = false;
}
void HandleExpiredResponseCallbacks(void) {
uint8_t i;
for (i = 0; i < MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME; i++) {
if (!AckWaitList[i].isFree) {
if (expired(&(AckWaitList[i].timer))) {
if (AckWaitList[i].callback != NULL) {
for(i = 0; i < MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME; i++) {
if(!AckWaitList[i].isFree) {
if(has_timer_expired(&(AckWaitList[i].timer))) {
if(AckWaitList[i].callback != NULL) {
AckWaitList[i].callback(AckWaitList[i].thingName, AckWaitList[i].action, SHADOW_ACK_TIMEOUT,
shadowRxBuf, AckWaitList[i].pCallbackContext);
shadowRxBuf, AckWaitList[i].pCallbackContext);
}
AckWaitList[i].isFree = true;
unsubscribeFromAcceptedAndRejected(i);
@@ -437,49 +445,53 @@ void HandleExpiredResponseCallbacks(void) {
}
}
static int shadow_delta_callback(MQTTCallbackParams params) {
static void shadow_delta_callback(AWS_IoT_Client *pClient, char *topicName,
uint16_t topicNameLen, IoT_Publish_Message_Params *params, void *pData) {
int32_t tokenCount;
uint32_t i = 0;
void *pJsonHandler;
void *pJsonHandler = NULL;
int32_t DataPosition;
uint32_t dataLength;
if (params.MessageParams.PayloadLen > SHADOW_MAX_SIZE_OF_RX_BUFFER) {
return GENERIC_ERROR;
IOT_UNUSED(pClient);
IOT_UNUSED(topicName);
IOT_UNUSED(topicNameLen);
IOT_UNUSED(pData);
if(params->payloadLen > SHADOW_MAX_SIZE_OF_RX_BUFFER) {
WARN("Payload larger than RX Buffer");
return;
}
memcpy(shadowRxBuf, params.MessageParams.pPayload, params.MessageParams.PayloadLen);
shadowRxBuf[params.MessageParams.PayloadLen] = '\0'; // jsmn_parse relies on a string
memcpy(shadowRxBuf, params->payload, params->payloadLen);
shadowRxBuf[params->payloadLen] = '\0'; // jsmn_parse relies on a string
if (!isJsonValidAndParse(shadowRxBuf, pJsonHandler, &tokenCount)) {
if(!isJsonValidAndParse(shadowRxBuf, pJsonHandler, &tokenCount)) {
WARN("Received JSON is not valid");
return GENERIC_ERROR;
return;
}
if (shadowDiscardOldDeltaFlag) {
if(shadowDiscardOldDeltaFlag) {
uint32_t tempVersionNumber = 0;
if (extractVersionNumber(shadowRxBuf, pJsonHandler, tokenCount, &tempVersionNumber)) {
if (tempVersionNumber > shadowJsonVersionNum) {
if(extractVersionNumber(shadowRxBuf, pJsonHandler, tokenCount, &tempVersionNumber)) {
if(tempVersionNumber > shadowJsonVersionNum) {
shadowJsonVersionNum = tempVersionNumber;
DEBUG("New Version number: %d", shadowJsonVersionNum);
} else {
WARN("Old Delta Message received - Ignoring rx: %d local: %d", tempVersionNumber, shadowJsonVersionNum);
return GENERIC_ERROR;
return;
}
}
}
for (i = 0; i < tokenTableIndex; i++) {
if (!tokenTable[i].isFree) {
if (isJsonKeyMatchingAndUpdateValue(shadowRxBuf, pJsonHandler, tokenCount, tokenTable[i].pStruct,
&dataLength, &DataPosition)) {
if (tokenTable[i].callback != NULL) {
for(i = 0; i < tokenTableIndex; i++) {
if(!tokenTable[i].isFree) {
if(isJsonKeyMatchingAndUpdateValue(shadowRxBuf, pJsonHandler, tokenCount, tokenTable[i].pStruct,
&dataLength, &DataPosition)) {
if(tokenTable[i].callback != NULL) {
tokenTable[i].callback(shadowRxBuf + DataPosition, dataLength, tokenTable[i].pStruct);
}
}
}
}
return NONE_ERROR;
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#ifndef SRC_SHADOW_IOT_SHADOW_CONFIG_H_
#define SRC_SHADOW_IOT_SHADOW_CONFIG_H_
// Get from console
// =================================================
#define AWS_IOT_MQTT_HOST "" ///< Customer specific MQTT HOST. The same will be used for Thing Shadow
#define AWS_IOT_MQTT_PORT 8883 ///< default port for MQTT/S
#define AWS_IOT_MQTT_CLIENT_ID "c-sdk-client-id" ///< MQTT client ID should be unique for every device
#define AWS_IOT_MY_THING_NAME "AWS-IoT-C-SDK" ///< Thing Name of the Shadow this device is associated with
#define AWS_IOT_ROOT_CA_FILENAME "rootCA.crt" ///< Root CA file name
#define AWS_IOT_CERTIFICATE_FILENAME "cert.pem" ///< device signed certificate file name
#define AWS_IOT_PRIVATE_KEY_FILENAME "privkey.pem" ///< Device private key filename
// =================================================
// MQTT PubSub
#define AWS_IOT_MQTT_TX_BUF_LEN 512 ///< Any time a message is sent out through the MQTT layer. The message is copied into this buffer anytime a publish is done. This will also be used in the case of Thing Shadow
#define AWS_IOT_MQTT_RX_BUF_LEN 512 ///< Any message that comes into the device should be less than this buffer size. If a received message is bigger than this buffer size the message will be dropped.
#define AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS 5 ///< Maximum number of topic filters the MQTT client can handle at any given time. This should be increased appropriately when using Thing Shadow
// Thing Shadow specific configs
#define SHADOW_MAX_SIZE_OF_RX_BUFFER AWS_IOT_MQTT_RX_BUF_LEN+1 ///< Maximum size of the SHADOW buffer to store the received Shadow message
#define MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES 80 ///< Maximum size of the Unique Client Id. For More info on the Client Id refer \ref response "Acknowledgments"
#define MAX_SIZE_CLIENT_ID_WITH_SEQUENCE MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES + 10 ///< This is size of the extra sequence number that will be appended to the Unique client Id
#define MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE MAX_SIZE_CLIENT_ID_WITH_SEQUENCE + 20 ///< This is size of the the total clientToken key and value pair in the JSON
#define MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME 10 ///< At Any given time we will wait for this many responses. This will correlate to the rate at which the shadow actions are requested
#define MAX_THINGNAME_HANDLED_AT_ANY_GIVEN_TIME 10 ///< We could perform shadow action on any thing Name and this is maximum Thing Names we can act on at any given time
#define MAX_JSON_TOKEN_EXPECTED 120 ///< These are the max tokens that is expected to be in the Shadow JSON document. Include the metadata that gets published
#define MAX_SHADOW_TOPIC_LENGTH_WITHOUT_THINGNAME 60 ///< All shadow actions have to be published or subscribed to a topic which is of the format $aws/things/{thingName}/shadow/update/accepted. This refers to the size of the topic without the Thing Name
#define MAX_SIZE_OF_THING_NAME 20 ///< The Thing Name should not be bigger than this value. Modify this if the Thing Name needs to be bigger
#define MAX_SHADOW_TOPIC_LENGTH_BYTES MAX_SHADOW_TOPIC_LENGTH_WITHOUT_THINGNAME + MAX_SIZE_OF_THING_NAME ///< This size includes the length of topic with Thing Name
// Auto Reconnect specific config
#define AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL 1000 ///< Minimum time before the First reconnect attempt is made as part of the exponential back-off algorithm
#define AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL 8000 ///< Maximum time interval after which exponential back-off will stop attempting to reconnect.
#endif /* SRC_SHADOW_IOT_SHADOW_CONFIG_H_ */

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#ifndef TESTS_INTEGRATION_INTEG_TESTS_CONFIG_H_
#define TESTS_INTEGRATION_INTEG_TESTS_CONFIG_H_
/* Number of messages to publish in each publish thread */
#define PUBLISH_COUNT 100
/* Maximum number of threads to create for the multi-threading test */
#define MAX_PUB_THREAD_COUNT 3
/* Minimum percentage of messages that must be received back by the yield thread.
* This is here ONLY because sometimes the yield thread doesn't get scheduled before the publish
* thread when it is created. In every other case, 100% messages should be received. */
#define RX_RECEIVE_PERCENTAGE 99.0f
/* Max number of initial connect retries */
#define CONNECT_MAX_ATTEMPT_COUNT 3
/* Interval that each thread sleeps for */
#define THREAD_SLEEP_INTERVAL_USEC 500000
/* Test topic to publish on */
#define INTEGRATION_TEST_TOPIC "Tests/Integration/EmbeddedC"
/* Client ID to be used for single client tests */
#define INTEGRATION_TEST_CLIENT_ID "EMB_C_SDK_INTEG_TESTER"
/* Client IDs to be used for multiple client tests */
#define INTEGRATION_TEST_CLIENT_ID_PUB "EMB_C_SDK_INTEG_TESTER_PUB"
#define INTEGRATION_TEST_CLIENT_ID_SUB "EMB_C_SDK_INTEG_TESTER_SUB"
#endif /* TESTS_INTEGRATION_INTEG_TESTS_CONFIG_H_ */

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/**
* @file aws_iot_test_integration_common.h
* @brief Integration Test common header
*/
#ifndef TESTS_INTEGRATION_H_
#define TESTS_INTEGRATION_H_
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <limits.h>
#include <getopt.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/time.h>
#include "aws_iot_mqtt_client_interface.h"
#include "aws_iot_log.h"
#include "aws_iot_integ_tests_config.h"
int aws_iot_mqtt_tests_basic_connectivity();
int aws_iot_mqtt_tests_multiple_clients();
int autoReconnectTests();
#endif /* TESTS_INTEGRATION_COMMON_H_ */

View File

@@ -0,0 +1,347 @@
/*
* multithreadedTest.c
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <getopt.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/time.h>
#include "aws_iot_mqtt_client_interface.h"
#include "aws_iot_log.h"
#include "aws_iot_integ_tests_config.h"
static bool terminate_yield_thread;
static bool terminate_subUnsub_thread;
static unsigned int countArray[MAX_PUB_THREAD_COUNT][PUBLISH_COUNT];
static unsigned int rxMsgBufferTooBigCounter;
static unsigned int rxUnexpectedNumberCounter;
static unsigned int rePublishCount;
static unsigned int wrongYieldCount;
static unsigned int threadStatus[MAX_PUB_THREAD_COUNT];
typedef struct ThreadData {
int threadId;
AWS_IoT_Client *client;
} ThreadData;
static void aws_iot_mqtt_tests_message_aggregator(AWS_IoT_Client *pClient, char *topicName,
uint16_t topicNameLen, IoT_Publish_Message_Params *params, void *pData) {
char tempBuf[30];
char *temp = NULL;
unsigned int tempRow = 0, tempCol = 0;
IoT_Error_t rc;
IOT_UNUSED(pClient);
IOT_UNUSED(topicName);
IOT_UNUSED(topicNameLen);
IOT_UNUSED(pData);
if(30 >= params->payloadLen) {
snprintf(tempBuf, params->payloadLen, params->payload);
printf("\n Message received : %s", tempBuf);
temp = strtok(tempBuf, " ,:");
temp = strtok(NULL, " ,:");
if(NULL == temp) {
return;
}
tempRow = atoi(temp);
temp = strtok(NULL, " ,:");
temp = strtok(NULL, " ,:");
tempCol = atoi(temp);
if(NULL == temp) {
return;
}
if(((tempRow - 1) < MAX_PUB_THREAD_COUNT) && (tempCol < PUBLISH_COUNT)) {
countArray[tempRow - 1][tempCol]++;
} else {
WARN(" \nUnexpected Thread : %d, Message : %d ", tempRow, tempCol);
rxUnexpectedNumberCounter++;
}
rc = aws_iot_mqtt_yield(pClient, 10);
if(MQTT_CLIENT_NOT_IDLE_ERROR != rc) {
ERROR("\n Yield succeeded in callback!!! Client state : %d Rc : %d\n",
aws_iot_mqtt_get_client_state(pClient), rc);
wrongYieldCount++;
}
} else {
rxMsgBufferTooBigCounter++;
}
}
static void aws_iot_mqtt_tests_disconnect_callback_handler(AWS_IoT_Client *pClient, void *param) {
IOT_UNUSED(pClient);
IOT_UNUSED(param);
}
static IoT_Error_t aws_iot_mqtt_tests_subscribe_to_test_topic(AWS_IoT_Client *pClient, QoS qos, struct timeval *pSubscribeTime) {
IoT_Error_t rc = SUCCESS;
struct timeval start, end;
gettimeofday(&start, NULL);
rc = aws_iot_mqtt_subscribe(pClient, INTEGRATION_TEST_TOPIC, strlen(INTEGRATION_TEST_TOPIC), qos,
aws_iot_mqtt_tests_message_aggregator, NULL);
DEBUG(" Sub response : %d\n", rc);
gettimeofday(&end, NULL);
timersub(&end, &start, pSubscribeTime);
return rc;
}
static void *aws_iot_mqtt_tests_yield_thread_runner(void *ptr) {
IoT_Error_t rc = SUCCESS;
AWS_IoT_Client *pClient = (AWS_IoT_Client *) ptr;
while(SUCCESS == rc && false == terminate_yield_thread) {
do {
usleep(THREAD_SLEEP_INTERVAL_USEC);
//DEBUG("\n Yielding \n");
rc = aws_iot_mqtt_yield(pClient, 100);
} while(MQTT_CLIENT_NOT_IDLE_ERROR == rc);
if(SUCCESS != rc) {
ERROR("\nYield Returned : %d ", rc);
}
}
}
static void *aws_iot_mqtt_tests_publish_thread_runner(void *ptr) {
int itr = 0;
char cPayload[30];
IoT_Publish_Message_Params params;
IoT_Error_t rc = SUCCESS;
ThreadData *threadData = (ThreadData *) ptr;
AWS_IoT_Client *pClient = threadData->client;
int threadId = threadData->threadId;
for(itr = 0; itr < PUBLISH_COUNT; itr++) {
snprintf(cPayload, 30, "Thread : %d, Msg : %d", threadId, itr);
printf("\nMsg being published: %s \n", cPayload);
params.payload = (void *) cPayload;
params.payloadLen = strlen(cPayload) + 1;
params.qos = QOS1;
params.isRetained = 0;
do {
rc = aws_iot_mqtt_publish(pClient, INTEGRATION_TEST_TOPIC, strlen(INTEGRATION_TEST_TOPIC), &params);
usleep(THREAD_SLEEP_INTERVAL_USEC);
} while(MUTEX_LOCK_ERROR == rc || MQTT_CLIENT_NOT_IDLE_ERROR == rc);
if(SUCCESS != rc) {
WARN("\nFailed attempt 1 Publishing Thread : %d, Msg : %d, cs : %d --> %d\n ", threadId, itr, rc,
aws_iot_mqtt_get_client_state(pClient));
do {
rc = aws_iot_mqtt_publish(pClient, INTEGRATION_TEST_TOPIC, strlen(INTEGRATION_TEST_TOPIC), &params);
usleep(THREAD_SLEEP_INTERVAL_USEC);
} while(MUTEX_LOCK_ERROR == rc || MQTT_CLIENT_NOT_IDLE_ERROR == rc);
rePublishCount++;
if(SUCCESS != rc) {
ERROR("\nFailed attempt 2 Publishing Thread : %d, Msg : %d, cs : %d --> %d Second Attempt \n", threadId,
itr, rc, aws_iot_mqtt_get_client_state(pClient));
}
}
}
threadStatus[threadId - 1] = 1;
return 0;
}
static void *aws_iot_mqtt_tests_sub_unsub_thread_runner(void *ptr) {
IoT_Error_t rc = SUCCESS;
AWS_IoT_Client *pClient = (AWS_IoT_Client *) ptr;
char testTopic[50];
snprintf(testTopic, 50, "%s_temp", INTEGRATION_TEST_TOPIC);
while(SUCCESS == rc && false == terminate_subUnsub_thread) {
do {
usleep(THREAD_SLEEP_INTERVAL_USEC);
rc = aws_iot_mqtt_subscribe(pClient, testTopic, strlen(testTopic), QOS1,
aws_iot_mqtt_tests_message_aggregator, NULL);
} while(MQTT_CLIENT_NOT_IDLE_ERROR == rc);
if(SUCCESS != rc) {
ERROR("Subscribe Returned : %d ", rc);
}
do {
usleep(THREAD_SLEEP_INTERVAL_USEC);
rc = aws_iot_mqtt_unsubscribe(pClient, testTopic, strlen(testTopic));
} while(MQTT_CLIENT_NOT_IDLE_ERROR == rc);
if(SUCCESS != rc) {
ERROR("Unsubscribe Returned : %d ", rc);
}
}
}
int aws_iot_mqtt_tests_multi_threading_validation() {
pthread_t publish_thread[MAX_PUB_THREAD_COUNT], yield_thread, sub_unsub_thread;
char certDirectory[15] = "../../certs";
char clientCRT[PATH_MAX + 1];
char clientKey[PATH_MAX + 1];
char CurrentWD[PATH_MAX + 1];
char root_CA[PATH_MAX + 1];
char clientId[50];
IoT_Client_Init_Params initParams;
IoT_Client_Connect_Params connectParams;
int threadId[MAX_PUB_THREAD_COUNT];
int pubThreadReturn[MAX_PUB_THREAD_COUNT];
int yieldThreadReturn = 0, subUnsubThreadReturn = 0;
float percentOfRxMsg = 0.0;
int finishedThreadCount = 0;
IoT_Error_t rc = SUCCESS;
int i, rxMsgCount = 0, j = 0;
struct timeval connectTime, subscribeTopic;
unsigned int connectCounter = 0;
int test_result = 0;
ThreadData threadData[MAX_PUB_THREAD_COUNT];
AWS_IoT_Client client;
terminate_yield_thread = false;
rxMsgBufferTooBigCounter = 0;
rxUnexpectedNumberCounter = 0;
rePublishCount = 0;
wrongYieldCount = 0;
for(j = 0; j < MAX_PUB_THREAD_COUNT; j++) {
threadId[j] = j + 1;
threadStatus[j] = 0;
for(i = 0; i < PUBLISH_COUNT; i++) {
countArray[j][i] = 0;
}
}
printf("\nConnecting Client ");
do {
getcwd(CurrentWD, sizeof(CurrentWD));
snprintf(root_CA, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_ROOT_CA_FILENAME);
snprintf(clientCRT, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_CERTIFICATE_FILENAME);
snprintf(clientKey, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_PRIVATE_KEY_FILENAME);
srand((unsigned int)time(NULL));
snprintf(clientId, 50, "%s_%d", INTEGRATION_TEST_CLIENT_ID, rand() % 10000);
DEBUG(" Root CA Path : %s\n clientCRT : %s\n clientKey : %s\n", root_CA, clientCRT, clientKey);
initParams.pHostURL = AWS_IOT_MQTT_HOST;
initParams.port = 8883;
initParams.pRootCALocation = root_CA;
initParams.pDeviceCertLocation = clientCRT;
initParams.pDevicePrivateKeyLocation = clientKey;
initParams.mqttCommandTimeout_ms = 10000;
initParams.tlsHandshakeTimeout_ms = 10000;
initParams.disconnectHandler = aws_iot_mqtt_tests_disconnect_callback_handler;
initParams.enableAutoReconnect = false;
initParams.isBlockOnThreadLockEnabled = true;
aws_iot_mqtt_init(&client, &initParams);
connectParams.keepAliveIntervalInSec = 10;
connectParams.isCleanSession = true;
connectParams.MQTTVersion = MQTT_3_1_1;
connectParams.pClientID = (char *)&clientId;
connectParams.clientIDLen = strlen(clientId);
connectParams.isWillMsgPresent = false;
connectParams.pUsername = NULL;
connectParams.usernameLen = 0;
connectParams.pPassword = NULL;
connectParams.passwordLen = 0;
rc = aws_iot_mqtt_connect(&client, &connectParams);
if(SUCCESS != rc) {
ERROR("ERROR Connecting %d\n", rc);
return -1;
}
connectCounter++;
} while(SUCCESS != rc && connectCounter < CONNECT_MAX_ATTEMPT_COUNT);
if(SUCCESS == rc) {
printf("\n## Connect Success. Time sec: %d, usec: %d\n", connectTime.tv_sec, connectTime.tv_usec);
} else {
ERROR("## Connect Failed. error code %d\n", rc);
return -1;
}
aws_iot_mqtt_tests_subscribe_to_test_topic(&client, QOS1, &subscribeTopic);
printf("\nRunning Test! ");
yieldThreadReturn = pthread_create(&yield_thread, NULL, aws_iot_mqtt_tests_yield_thread_runner, &client);
subUnsubThreadReturn = pthread_create(&sub_unsub_thread, NULL, aws_iot_mqtt_tests_sub_unsub_thread_runner, &client);
for(i = 0; i < MAX_PUB_THREAD_COUNT; i++) {
threadData[i].client = &client;
threadData[i].threadId = threadId[i];
pubThreadReturn[i] = pthread_create(&publish_thread[i], NULL, aws_iot_mqtt_tests_publish_thread_runner,
&threadData[i]);
}
/* Wait until all publish threads have finished */
do {
finishedThreadCount = 0;
for(i = 0; i < MAX_PUB_THREAD_COUNT; i++) { finishedThreadCount += threadStatus[i]; }
printf("\nFinished thread count : %d \n", finishedThreadCount);
sleep(1);
} while(finishedThreadCount < MAX_PUB_THREAD_COUNT);
printf("\nFinished publishing!!");
terminate_yield_thread = true;
terminate_subUnsub_thread = true;
/* Allow time for yield_thread and sub_sunsub thread to exit */
sleep(1);
/* Not using pthread_join because all threads should have terminated gracefully at this point. If they haven't,
* which should not be possible, something below will fail. */
printf("\n\nCalculating Results!! \n\n");
for(i = 0; i < PUBLISH_COUNT; i++) {
for(j = 0; j < MAX_PUB_THREAD_COUNT; j++) {
if(countArray[j][i] > 0) {
rxMsgCount++;
}
}
}
printf("\n\nResult : \n");
percentOfRxMsg = (float) rxMsgCount * 100 / (PUBLISH_COUNT * MAX_PUB_THREAD_COUNT);
if(RX_RECEIVE_PERCENTAGE <= percentOfRxMsg && 0 == rxMsgBufferTooBigCounter && 0 == rxUnexpectedNumberCounter &&
0 == wrongYieldCount) {
printf("\nSuccess: %f \%\n", percentOfRxMsg);
printf("Published Messages: %d , Received Messages: %d \n", PUBLISH_COUNT * MAX_PUB_THREAD_COUNT, rxMsgCount);
printf("QoS 1 re publish count %d\n", rePublishCount);
printf("Connection Attempts %d\n", connectCounter);
printf("Yield count without error during callback %d\n", wrongYieldCount);
test_result = 0;
} else {
printf("\nFailure: %f\n", percentOfRxMsg);
printf("\"Received message was too big than anything sent\" count: %d\n", rxMsgBufferTooBigCounter);
printf("\"The number received is out of the range\" count: %d\n", rxUnexpectedNumberCounter);
printf("Yield count without error during callback %d\n", wrongYieldCount);
test_result = -2;
}
aws_iot_mqtt_disconnect(&client);
return test_result;
}
int main() {
printf("\n\n");
printf("******************************************************************\n");
printf("* Starting MQTT Version 3.1.1 Multithreading Validation Test *\n");
printf("******************************************************************\n");
int rc = aws_iot_mqtt_tests_multi_threading_validation();
if(0 != rc) {
printf("\n*******************************************************************\n");
printf("*MQTT Version 3.1.1 Multithreading Validation Test FAILED! RC : %d \n", rc);
printf("*******************************************************************\n");
return 1;
}
printf("******************************************************************\n");
printf("* MQTT Version 3.1.1 Multithreading Validation Test SUCCESS!! *\n");
printf("******************************************************************\n");
return 0;
}

View File

@@ -0,0 +1,235 @@
/*
* Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/**
* @file aws_iot_test_auto_reconnect.c
* @brief Integration Test for automatic reconnect
*/
#include "aws_iot_test_integration_common.h"
static char ModifiedPathBuffer[PATH_MAX + 1];
char root_CA[PATH_MAX + 1];
bool terminate_yield_with_rc_thread = false;
IoT_Error_t yieldRC;
bool captureYieldReturnCode = false;
/**
* This function renames the rootCA.crt file to a temporary name to cause connect failure
*/
int aws_iot_mqtt_tests_block_tls_connect() {
char replaceFileName[] = { "rootCATemp.crt" };
char *pFileNamePosition = NULL;
char mvCommand[2 * PATH_MAX + 10];
strcpy(ModifiedPathBuffer, root_CA);
pFileNamePosition = strstr(ModifiedPathBuffer, AWS_IOT_ROOT_CA_FILENAME);
strncpy(pFileNamePosition, replaceFileName, strlen(replaceFileName));
snprintf(mvCommand, 2 * PATH_MAX + 10, "mv %s %s", root_CA, ModifiedPathBuffer);
return system(mvCommand);
}
/**
* Always ensure this function is called after block_tls_connect
*/
int aws_iot_mqtt_tests_unblock_tls_connect() {
char mvCommand[2 * PATH_MAX + 10];
snprintf(mvCommand, 2 * PATH_MAX + 10, "mv %s %s", ModifiedPathBuffer, root_CA);
return system(mvCommand);
}
void *aws_iot_mqtt_tests_yield_with_rc(void *ptr) {
IoT_Error_t rc = SUCCESS;
struct timeval start, end, result;
static int cntr = 0;
AWS_IoT_Client *pClient = (AWS_IoT_Client *)ptr;
while(terminate_yield_with_rc_thread == false
&& (NETWORK_ATTEMPTING_RECONNECT == rc || NETWORK_RECONNECTED == rc || SUCCESS == rc)) {
usleep(500000);
printf(" Client state : %d ", aws_iot_mqtt_get_client_state(pClient));
rc = aws_iot_mqtt_yield(pClient, 100);
printf("yield rc %d\n", rc);
if(captureYieldReturnCode && SUCCESS != rc) {
printf("yield rc capture %d\n", rc);
captureYieldReturnCode = false;
yieldRC = rc;
}
}
}
unsigned int disconnectedCounter = 0;
void aws_iot_mqtt_tests_disconnect_callback_handler(AWS_IoT_Client *pClient, void *param) {
disconnectedCounter++;
}
int aws_iot_mqtt_tests_auto_reconnect() {
pthread_t reconnectTester_thread, yield_thread;
int yieldThreadReturn = 0;
int test_result = 0;
char certDirectory[15] = "../../certs";
char CurrentWD[PATH_MAX + 1];
char clientCRT[PATH_MAX + 1];
char clientKey[PATH_MAX + 1];
char clientId[50];
AWS_IoT_Client client;
IoT_Error_t rc = SUCCESS;
getcwd(CurrentWD, sizeof(CurrentWD));
snprintf(root_CA, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_ROOT_CA_FILENAME);
snprintf(clientCRT, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_CERTIFICATE_FILENAME);
snprintf(clientKey, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_PRIVATE_KEY_FILENAME);
srand((unsigned int)time(NULL));
snprintf(clientId, 50, "%s_%d", INTEGRATION_TEST_CLIENT_ID, rand() % 10000);
printf(" Root CA Path : %s\n clientCRT : %s\n clientKey : %s\n", root_CA, clientCRT, clientKey);
IoT_Client_Init_Params initParams;
initParams.pHostURL = AWS_IOT_MQTT_HOST;
initParams.port = 8883;
initParams.pRootCALocation = root_CA;
initParams.pDeviceCertLocation = clientCRT;
initParams.pDevicePrivateKeyLocation = clientKey;
initParams.mqttCommandTimeout_ms = 5000;
initParams.tlsHandshakeTimeout_ms = 2000;
initParams.disconnectHandler = aws_iot_mqtt_tests_disconnect_callback_handler;
initParams.enableAutoReconnect = false;
aws_iot_mqtt_init(&client, &initParams);
IoT_Client_Connect_Params connectParams;
connectParams.keepAliveIntervalInSec = 5;
connectParams.isCleanSession = true;
connectParams.MQTTVersion = MQTT_3_1_1;
connectParams.pClientID = (char *)&clientId;
connectParams.clientIDLen = strlen(clientId);
connectParams.isWillMsgPresent = 0;
connectParams.pUsername = NULL;
connectParams.usernameLen = 0;
connectParams.pPassword = NULL;
connectParams.passwordLen = 0;
rc = aws_iot_mqtt_connect(&client, &connectParams);
if (rc != SUCCESS) {
printf("ERROR Connecting %d\n", rc);
return -1;
}
yieldThreadReturn = pthread_create(&yield_thread, NULL, aws_iot_mqtt_tests_yield_with_rc, &client);
/*
* Test disconnect handler
*/
printf("1. Test Disconnect Handler\n");
aws_iot_mqtt_tests_block_tls_connect();
iot_tls_disconnect(&(client.networkStack));
sleep(10);
if (disconnectedCounter == 1) {
printf("Success invoking Disconnect Handler\n");
} else {
aws_iot_mqtt_tests_unblock_tls_connect();
printf("Failure to invoke Disconnect Handler\n");
return -1;
}
aws_iot_mqtt_tests_unblock_tls_connect();
terminate_yield_with_rc_thread = true;
pthread_join(yield_thread, NULL);
/*
* Manual Reconnect Test
*/
printf("2. Test Manual Reconnect, Current Client state : %d \n", aws_iot_mqtt_get_client_state(&client));
rc = aws_iot_mqtt_attempt_reconnect(&client);
if (rc != NETWORK_RECONNECTED) {
printf("ERROR reconnecting manually %d\n", rc);
return -4;
}
terminate_yield_with_rc_thread = false;
yieldThreadReturn = pthread_create(&yield_thread, NULL, aws_iot_mqtt_tests_yield_with_rc, &client);
yieldRC = FAILURE;
captureYieldReturnCode = true;
// ensure atleast 1 cycle of yield is executed to get the yield status to SUCCESS
sleep(1);
if (!captureYieldReturnCode) {
if (yieldRC == NETWORK_ATTEMPTING_RECONNECT) {
printf("Success reconnecting manually\n");
} else {
printf("Failure to reconnect manually\n");
return -3;
}
}
terminate_yield_with_rc_thread = true;
/*
* Auto Reconnect Test
*/
printf("3. Test Auto_reconnect \n");
rc = aws_iot_mqtt_autoreconnect_set_status(&client, true);
if (rc != SUCCESS) {
printf("Error: Failed to enable auto-reconnect %d \n", rc);
}
yieldRC = FAILURE;
captureYieldReturnCode = true;
// Disconnect
aws_iot_mqtt_tests_block_tls_connect();
iot_tls_disconnect(&(client.networkStack));
terminate_yield_with_rc_thread = false;
yieldThreadReturn = pthread_create(&yield_thread, NULL, aws_iot_mqtt_tests_yield_with_rc, &client);
sleep(10);
if (!captureYieldReturnCode) {
if (yieldRC == NETWORK_ATTEMPTING_RECONNECT) {
printf("Success attempting reconnect\n");
} else {
printf("Failure to attempt to reconnect\n");
return -6;
}
}
if(disconnectedCounter == 2){
printf("Success: disconnect handler invoked on enabling auto-reconnect\n");
} else{
printf("Failure: disconnect handler not invoked on enabling auto-reconnect : %d\n", disconnectedCounter);
return -7;
}
aws_iot_mqtt_tests_unblock_tls_connect();
sleep(10);
captureYieldReturnCode = true;
sleep(5);
if (!captureYieldReturnCode) {
if (yieldRC == SUCCESS) {
printf("Success attempting reconnect\n");
} else {
printf("Failure to attempt to reconnect\n");
return -6;
}
}
if(true == aws_iot_mqtt_is_client_connected(&client)){
printf("Success: is Mqtt connected api\n");
} else{
printf("Failure: is Mqtt Connected api\n");
return -7;
}
rc = aws_iot_mqtt_disconnect(&client);
return rc;
}

View File

@@ -0,0 +1,276 @@
/*
* Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/**
* @file aws_iot_test_basic_connectivity.c
* @brief Integration Test for basic client connectivity
*/
#include "aws_iot_test_integration_common.h"
static bool terminate_yield_thread;
static bool isPubThreadFinished;
static unsigned int countArray[PUBLISH_COUNT];
static unsigned int rxMsgBufferTooBigCounter;
static unsigned int rxUnexpectedNumberCounter;
static unsigned int rePublishCount;
static unsigned int wrongYieldCount;
typedef struct ThreadData {
AWS_IoT_Client *client;
int threadId;
} ThreadData;
static void aws_iot_mqtt_tests_message_aggregator(AWS_IoT_Client *pClient, char *topicName,
uint16_t topicNameLen, IoT_Publish_Message_Params *params, void *pData) {
char tempBuf[30];
char *temp = NULL;
unsigned int tempRow = 0, tempCol = 0;
IoT_Error_t rc;
if(params->payloadLen <= 30) {
snprintf(tempBuf, params->payloadLen, params->payload);
printf("\nMsg received : %s", tempBuf);
temp = strtok(tempBuf, " ,:");
temp = strtok(NULL, " ,:");
if(NULL == temp) {
return;
}
tempRow = atoi(temp);
temp = strtok(NULL, " ,:");
temp = strtok(NULL, " ,:");
tempCol = atoi(temp);
if(NULL == temp) {
return;
}
if(tempCol > 0 && tempCol <= PUBLISH_COUNT) {
countArray[tempCol - 1]++;
} else {
WARN(" \n Thread : %d, Msg : %d ", tempRow, tempCol);
rxUnexpectedNumberCounter++;
}
rc = aws_iot_mqtt_yield(pClient, 10);
if(MQTT_CLIENT_NOT_IDLE_ERROR != rc) {
ERROR("\n Yield succeeded in callback!!! Client state : %d Rc : %d\n",
aws_iot_mqtt_get_client_state(pClient), rc);
wrongYieldCount++;
}
} else {
rxMsgBufferTooBigCounter++;
}
}
static void aws_iot_mqtt_tests_disconnect_callback_handler(AWS_IoT_Client *pClient, void *param) {
}
static IoT_Error_t aws_iot_mqtt_tests_subscribe_to_test_topic(AWS_IoT_Client *pClient, QoS qos,
struct timeval *pSubscribeTime) {
IoT_Error_t rc = SUCCESS;
struct timeval start, end;
gettimeofday(&start, NULL);
rc = aws_iot_mqtt_subscribe(pClient, INTEGRATION_TEST_TOPIC, strlen(INTEGRATION_TEST_TOPIC), qos,
aws_iot_mqtt_tests_message_aggregator, NULL);
DEBUG("Sub response : %d\n", rc);
gettimeofday(&end, NULL);
timersub(&end, &start, pSubscribeTime);
return rc;
}
static void *aws_iot_mqtt_tests_yield_thread_runner(void *ptr) {
IoT_Error_t rc = SUCCESS;
AWS_IoT_Client *pClient = (AWS_IoT_Client *) ptr;
while(SUCCESS == rc && terminate_yield_thread == false) {
do {
usleep(THREAD_SLEEP_INTERVAL_USEC);
rc = aws_iot_mqtt_yield(pClient, 100);
} while(MQTT_CLIENT_NOT_IDLE_ERROR == rc); // Client is busy, wait to get lock
if(SUCCESS != rc) {
DEBUG("\nYield Returned : %d ", rc);
}
}
}
static void *aws_iot_mqtt_tests_publish_thread_runner(void *ptr) {
int i = 0;
char cPayload[100];
IoT_Publish_Message_Params params;
IoT_Error_t rc = SUCCESS;
ThreadData *threadData = (ThreadData *) ptr;
AWS_IoT_Client *pClient = threadData->client;
int threadId = threadData->threadId;
for(i = 0; i < PUBLISH_COUNT; i++) {
snprintf(cPayload, 100, "Thread : %d, Msg : %d", threadId, i + 1);
printf("\nMsg being published: %s \n", cPayload);
params.payload = (void *) cPayload;
params.payloadLen = strlen(cPayload) + 1;
params.qos = QOS1;
params.isRetained = 0;
do {
rc = aws_iot_mqtt_publish(pClient, INTEGRATION_TEST_TOPIC, strlen(INTEGRATION_TEST_TOPIC), &params);
usleep(THREAD_SLEEP_INTERVAL_USEC);
} while(MUTEX_LOCK_ERROR == rc || MQTT_CLIENT_NOT_IDLE_ERROR == rc);
if(rc != SUCCESS) {
WARN("Error Publishing #%d --> %d\n ", i, rc);
do {
rc = aws_iot_mqtt_publish(pClient, INTEGRATION_TEST_TOPIC, strlen(INTEGRATION_TEST_TOPIC), &params);
usleep(THREAD_SLEEP_INTERVAL_USEC);
} while(MUTEX_LOCK_ERROR == rc || MQTT_CLIENT_NOT_IDLE_ERROR == rc);
rePublishCount++;
if(rc != SUCCESS) {
ERROR("Error Publishing #%d --> %d Second Attempt \n", i, rc);
}
}
}
isPubThreadFinished = true;
return 0;
}
int aws_iot_mqtt_tests_basic_connectivity() {
pthread_t publish_thread, yield_thread;
char certDirectory[15] = "../../certs";
char clientCRT[PATH_MAX + 1];
char root_CA[PATH_MAX + 1];
char clientKey[PATH_MAX + 1];
char CurrentWD[PATH_MAX + 1];
char clientId[50];
IoT_Client_Init_Params initParams;
IoT_Client_Connect_Params connectParams;
int pubThreadReturn;
int yieldThreadReturn = 0;
float percentOfRxMsg = 0.0;
IoT_Error_t rc = SUCCESS;
int i, rxMsgCount = 0, j = 0;
struct timeval connectTime, subscribeTopic;
unsigned int connectCounter = 0;
int test_result = 0;
ThreadData threadData;
AWS_IoT_Client client;
terminate_yield_thread = false;
isPubThreadFinished = false;
rxMsgBufferTooBigCounter = 0;
rxUnexpectedNumberCounter = 0;
rePublishCount = 0;
wrongYieldCount = 0;
for(i = 0; i < PUBLISH_COUNT; i++) {
countArray[i] = 0;
}
DEBUG("\nConnecting Client ");
do {
getcwd(CurrentWD, sizeof(CurrentWD));
snprintf(root_CA, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_ROOT_CA_FILENAME);
snprintf(clientCRT, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_CERTIFICATE_FILENAME);
snprintf(clientKey, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_PRIVATE_KEY_FILENAME);
srand((unsigned int)time(NULL));
snprintf(clientId, 50, "%s_%d", INTEGRATION_TEST_CLIENT_ID, rand() % 10000);
printf("\n\nClient ID : %s \n", clientId);
DEBUG("Root CA Path : %s\n clientCRT : %s\n clientKey : %s\n", root_CA, clientCRT, clientKey);
initParams.pHostURL = AWS_IOT_MQTT_HOST;
initParams.port = 8883;
initParams.pRootCALocation = root_CA;
initParams.pDeviceCertLocation = clientCRT;
initParams.pDevicePrivateKeyLocation = clientKey;
initParams.mqttCommandTimeout_ms = 10000;
initParams.tlsHandshakeTimeout_ms = 10000;
initParams.disconnectHandler = aws_iot_mqtt_tests_disconnect_callback_handler;
initParams.enableAutoReconnect = false;
aws_iot_mqtt_init(&client, &initParams);
connectParams.keepAliveIntervalInSec = 10;
connectParams.isCleanSession = true;
connectParams.MQTTVersion = MQTT_3_1_1;
connectParams.pClientID = (char *)&clientId;
connectParams.clientIDLen = strlen(clientId);
connectParams.isWillMsgPresent = false;
connectParams.pUsername = NULL;
connectParams.usernameLen = 0;
connectParams.pPassword = NULL;
connectParams.passwordLen = 0;
rc = aws_iot_mqtt_connect(&client, &connectParams);
if(rc != SUCCESS) {
ERROR("\nERROR Connecting %d\n", rc);
return -1;
}
connectCounter++;
} while(rc != SUCCESS && connectCounter < CONNECT_MAX_ATTEMPT_COUNT);
if(rc == SUCCESS) {
DEBUG("## Connect Success. Time sec: %d, usec: %d\n", connectTime.tv_sec, connectTime.tv_usec);
} else {
ERROR("## Connect Failed. error code %d\n", rc);
return -1;
}
aws_iot_mqtt_tests_subscribe_to_test_topic(&client, QOS1, &subscribeTopic);
yieldThreadReturn = pthread_create(&yield_thread, NULL, aws_iot_mqtt_tests_yield_thread_runner, &client);
sleep(1);
threadData.client = &client;
threadData.threadId = 1;
pubThreadReturn = pthread_create(&publish_thread, NULL, aws_iot_mqtt_tests_publish_thread_runner, &threadData);
do {
sleep(1); //Let all threads run
} while(!isPubThreadFinished);
// This sleep is to ensure that the last publish message has enough time to be received by us
sleep(1);
terminate_yield_thread = true;
sleep(1);
/* Not using pthread_join because all threads should have terminated gracefully at this point. If they haven't,
* which should not be possible, something below will fail. */
for(i = 0; i < PUBLISH_COUNT; i++) {
if(countArray[i] > 0) {
rxMsgCount++;
}
}
DEBUG("\n\nResult : \n");
percentOfRxMsg = (float) rxMsgCount * 100 / PUBLISH_COUNT;
if(percentOfRxMsg >= RX_RECEIVE_PERCENTAGE && rxMsgBufferTooBigCounter == 0 && rxUnexpectedNumberCounter == 0 &&
wrongYieldCount == 0) {
DEBUG("\n\nSuccess: %f \%\n", percentOfRxMsg);
DEBUG("Published Messages: %d , Received Messages: %d \n", PUBLISH_COUNT, rxMsgCount);
DEBUG("QoS 1 re publish count %d\n", rePublishCount);
DEBUG("Connection Attempts %d\n", connectCounter);
DEBUG("Yield count without error during callback %d\n", wrongYieldCount);
test_result = 0;
} else {
ERROR("\n\nFailure: %f\n", percentOfRxMsg);
ERROR("\"Received message was too big than anything sent\" count: %d\n", rxMsgBufferTooBigCounter);
ERROR("\"The number received is out of the range\" count: %d\n", rxUnexpectedNumberCounter);
ERROR("Yield count without error during callback %d\n", wrongYieldCount);
test_result = -2;
}
aws_iot_mqtt_disconnect(&client);
return test_result;
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/**
* @file aws_iot_test_integration_runner.c
* @brief Integration Test runner
*/
#include "aws_iot_test_integration_common.h"
int main() {
int rc = 0;
printf("\n\n");
printf("*************************************************************************************************\n");
printf("* Starting TEST 1 MQTT Version 3.1.1 Basic Subscribe QoS 1 Publish QoS 1 with Single Client *\n");
printf("*************************************************************************************************\n");
rc = aws_iot_mqtt_tests_basic_connectivity();
if(0 != rc) {
printf("\n********************************************************************************************************\n");
printf("* TEST 1 MQTT Version 3.1.1 Basic Subscribe QoS 1 Publish QoS 1 with Single Client FAILED! RC : %4d *\n", rc);
printf("********************************************************************************************************\n");
return 1;
}
printf("\n*************************************************************************************************\n");
printf("* Test 1 MQTT Version 3.1.1 Basic Subscribe QoS 1 Publish QoS 1 with Single Client SUCCESS!! *\n");
printf("*************************************************************************************************\n");
printf("\n\n");
printf("************************************************************************************************************\n");
printf("* Starting TEST 2 MQTT Version 3.1.1 Multithreaded Subscribe QoS 1 Publish QoS 1 with Multiple Clients *\n");
printf("************************************************************************************************************\n");
rc = aws_iot_mqtt_tests_multiple_clients();
if(0 != rc) {
printf("\n*******************************************************************************************************************\n");
printf("* TEST 2 MQTT Version 3.1.1 Multithreaded Subscribe QoS 1 Publish QoS 1 with Multiple Clients FAILED! RC : %4d *\n", rc);
printf("*******************************************************************************************************************\n");
return 1;
}
printf("\n*************************************************************************************************************\n");
printf("* TEST 2 MQTT Version 3.1.1 Multithreaded Subscribe QoS 1 Publish QoS 1 with Multiple Clients SUCCESS!! *\n");
printf("*************************************************************************************************************\n");
printf("\n\n");
printf("*********************************************************\n");
printf("* Starting TEST 3 MQTT Version 3.1.1 Auto Reconnect *\n");
printf("*********************************************************\n");
rc = aws_iot_mqtt_tests_auto_reconnect();
if(0 != rc) {
printf("\n***************************************************************\n");
printf("* TEST 3 MQTT Version 3.1.1 Auto Reconnect FAILED! RC : %4d *\n", rc);
printf("***************************************************************\n");
return 1;
}
printf("\n**********************************************************\n");
printf("* TEST 3 MQTT Version 3.1.1 Auto Reconnect SUCCESS!! *\n");
printf("**********************************************************\n");
return 0;
}

View File

@@ -0,0 +1,271 @@
/*
* Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/**
* @file aws_iot_test_multiple_clients.c
* @brief Integration Test for multiple clients from the same application
*/
#include "aws_iot_test_integration_common.h"
static bool terminate_yield_thread;
static bool isPubThreadFinished;
static unsigned int countArray[PUBLISH_COUNT];
static unsigned int rxMsgBufferTooBigCounter;
static unsigned int rxUnexpectedNumberCounter;
static unsigned int rePublishCount;
static void aws_iot_mqtt_tests_message_aggregator(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
IoT_Publish_Message_Params *params, void *pData) {
char tempBuf[10];
unsigned int tempInt = 0;
IOT_UNUSED(pClient);
IOT_UNUSED(topicName);
IOT_UNUSED(topicNameLen);
IOT_UNUSED(pData);
if(10 >= params->payloadLen) {
snprintf(tempBuf, params->payloadLen, params->payload);
tempInt = atoi(tempBuf);
if(0 < tempInt && PUBLISH_COUNT >= tempInt) {
countArray[tempInt - 1]++;
} else {
rxUnexpectedNumberCounter++;
}
} else {
rxMsgBufferTooBigCounter++;
}
}
static void aws_iot_mqtt_tests_disconnect_callback_handler(AWS_IoT_Client *pClient, void *param) {
IOT_UNUSED(pClient);
IOT_UNUSED(param);
}
static IoT_Error_t aws_iot_mqtt_tests_connect_client_to_service(AWS_IoT_Client *pClient, struct timeval *pConnectTime,
char *clientId, char *rootCA, char *clientCRT,
char *clientKey) {
IoT_Client_Init_Params initParams;
IoT_Client_Connect_Params connectParams;
IoT_Error_t rc;
struct timeval start, end;
initParams.pHostURL = AWS_IOT_MQTT_HOST;
initParams.port = 8883;
initParams.pRootCALocation = rootCA;
initParams.pDeviceCertLocation = clientCRT;
initParams.pDevicePrivateKeyLocation = clientKey;
initParams.mqttCommandTimeout_ms = 5000;
initParams.tlsHandshakeTimeout_ms = 2000;
initParams.disconnectHandler = aws_iot_mqtt_tests_disconnect_callback_handler;
initParams.enableAutoReconnect = false;
rc = aws_iot_mqtt_init(pClient, &initParams);
printf("\n Init response : %d", rc);
printf("\nRoot CA Path : %s\nClientCRT : %s\nClientKey : %s \nClient ID : %s", rootCA, clientCRT,
clientKey, clientId);
connectParams.keepAliveIntervalInSec = 5;
connectParams.isCleanSession = true;
connectParams.MQTTVersion = MQTT_3_1_1;
connectParams.pClientID = clientId;
connectParams.clientIDLen = strlen(clientId);
connectParams.isWillMsgPresent = 0;
connectParams.pUsername = NULL;
connectParams.usernameLen = 0;
connectParams.pPassword = NULL;
connectParams.passwordLen = 0;
gettimeofday(&start, NULL);
rc = aws_iot_mqtt_connect(pClient, &connectParams);
printf("\nConnect response : %d ", rc);
gettimeofday(&end, NULL);
timersub(&end, &start, pConnectTime);
return rc;
}
static IoT_Error_t aws_iot_mqtt_tests_subscribe_to_test_topic(AWS_IoT_Client *pClient, QoS qos, struct timeval *pSubscribeTime) {
IoT_Error_t rc = SUCCESS;
struct timeval start, end;
gettimeofday(&start, NULL);
rc = aws_iot_mqtt_subscribe(pClient, INTEGRATION_TEST_TOPIC, strlen(INTEGRATION_TEST_TOPIC), qos,
aws_iot_mqtt_tests_message_aggregator, NULL);
printf("\nSub response : %d\n", rc);
gettimeofday(&end, NULL);
timersub(&end, &start, pSubscribeTime);
return rc;
}
static void *aws_iot_mqtt_tests_yield_thread_runner(void *ptr) {
IoT_Error_t rc = SUCCESS;
static int cntr = 0;
AWS_IoT_Client *pClient = (AWS_IoT_Client *) ptr;
while(SUCCESS == rc && false == terminate_yield_thread) {
usleep(500000);
rc = aws_iot_mqtt_yield(pClient, 100);
if(SUCCESS != rc) {
printf("\nYield Returned : %d ", rc);
}
}
}
static void *aws_iot_mqtt_tests_publish_thread_runner(void *ptr) {
int itr = 0;
char cPayload[10];
IoT_Publish_Message_Params params;
IoT_Error_t rc = SUCCESS;
AWS_IoT_Client *pClient = (AWS_IoT_Client *) ptr;
for(itr = 0; itr < PUBLISH_COUNT; itr++) {
sprintf(cPayload, "%d", itr + 1);
params.payload = (void *) cPayload;
params.payloadLen = strlen(cPayload) + 1;
params.qos = QOS1;
params.isRetained = 0;
rc = aws_iot_mqtt_publish(pClient, INTEGRATION_TEST_TOPIC, strlen(INTEGRATION_TEST_TOPIC), &params);
printf("\n Publishing %s", cPayload);
if(SUCCESS != rc) {
printf("Error Publishing #%d --> %d\n ", itr, rc);
usleep(300000);
rc = aws_iot_mqtt_publish(pClient, INTEGRATION_TEST_TOPIC, strlen(INTEGRATION_TEST_TOPIC), &params);
rePublishCount++;
if(SUCCESS != rc) {
printf("Error Publishing #%d --> %d Second Attempt \n", itr, rc);
}
}
usleep(300000);
}
isPubThreadFinished = true;
}
int aws_iot_mqtt_tests_multiple_clients() {
char certDirectory[15] = "../../certs";
char CurrentWD[PATH_MAX + 1];
char rootCA[PATH_MAX + 1];
char clientCRT[PATH_MAX + 1];
char clientKey[PATH_MAX + 1];
char subClientId[50];
char pubClientId[50];
int itr = 0;
int rxMsgCount = 0;
int test_result = 0;
int pubThreadReturn = 0;
int yieldThreadReturn = 0;
unsigned int connectCounter = 0;
float percentOfRxMsg = 0.0;
IoT_Error_t rc = SUCCESS;
pthread_t yield_thread;
pthread_t publish_thread;
struct timeval connectTime;
struct timeval subscribeTopic;
AWS_IoT_Client pubClient;
AWS_IoT_Client subClient;
terminate_yield_thread = false;
isPubThreadFinished = false;
rxMsgBufferTooBigCounter = 0;
rxUnexpectedNumberCounter = 0;
rePublishCount = 0;
srand((unsigned int)time(NULL));
snprintf(subClientId, 50, "%s_%d", INTEGRATION_TEST_CLIENT_ID_SUB, rand() % 10000);
snprintf(pubClientId, 50, "%s_%d", INTEGRATION_TEST_CLIENT_ID_PUB, rand() % 10000);
getcwd(CurrentWD, sizeof(CurrentWD));
snprintf(rootCA, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_ROOT_CA_FILENAME);
snprintf(clientCRT, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_CERTIFICATE_FILENAME);
snprintf(clientKey, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_PRIVATE_KEY_FILENAME);
for(itr = 0; itr < PUBLISH_COUNT; itr++) {
countArray[itr] = 0;
}
printf(" \n Connecting Pub Client ");
do {
rc = aws_iot_mqtt_tests_connect_client_to_service(&pubClient, &connectTime, pubClientId, rootCA,
clientCRT, clientKey);
connectCounter++;
} while(SUCCESS != rc && CONNECT_MAX_ATTEMPT_COUNT > connectCounter);
if(SUCCESS == rc) {
printf("\n## Connect Success. Time sec: %d, usec: %d\n", connectTime.tv_sec, connectTime.tv_usec);
} else {
printf("\n## Connect Failed. error code %d\n", rc);
return -1;
}
printf("\n Connecting Sub Client ");
do {
rc = aws_iot_mqtt_tests_connect_client_to_service(&subClient, &connectTime, subClientId, rootCA,
clientCRT, clientKey);
connectCounter++;
} while(SUCCESS != rc && connectCounter < CONNECT_MAX_ATTEMPT_COUNT);
if(SUCCESS == rc) {
printf("## Connect Success. Time sec: %d, usec: %d\n", connectTime.tv_sec, connectTime.tv_usec);
} else {
printf("## Connect Failed. error code %d\n", rc);
return -1;
}
aws_iot_mqtt_tests_subscribe_to_test_topic(&subClient, QOS1, &subscribeTopic);
yieldThreadReturn = pthread_create(&yield_thread, NULL, aws_iot_mqtt_tests_yield_thread_runner, &subClient);
pubThreadReturn = pthread_create(&publish_thread, NULL, aws_iot_mqtt_tests_publish_thread_runner, &pubClient);
/* This sleep is to ensure that the last publish message has enough time to be received by us */
do {
sleep(1);
} while(!isPubThreadFinished);
/* Kill yield thread */
terminate_yield_thread = true;
sleep(1);
aws_iot_mqtt_disconnect(&pubClient);
aws_iot_mqtt_disconnect(&subClient);
for(itr = 0; itr < PUBLISH_COUNT; itr++) {
if(countArray[itr] > 0) {
rxMsgCount++;
}
}
percentOfRxMsg = (float) rxMsgCount * 100 / PUBLISH_COUNT;
if(percentOfRxMsg >= RX_RECEIVE_PERCENTAGE && rxMsgBufferTooBigCounter == 0 && rxUnexpectedNumberCounter == 0) {
printf("\nSuccess: %f \%\n", percentOfRxMsg);
printf("Published Messages: %d , Received Messages: %d \n", PUBLISH_COUNT, rxMsgCount);
printf("QoS 1 re publish count %d\n", rePublishCount);
printf("Connection Attempts %d\n", connectCounter);
test_result = 0;
} else {
printf("\nFailure: %f\n", percentOfRxMsg);
printf("\"Received message was too big than anything sent\" count: %d\n", rxMsgBufferTooBigCounter);
printf("\"The number received is out of the range\" count: %d\n", rxUnexpectedNumberCounter);
test_result = -2;
}
return test_result;
}