From 70071112bd5e1c5b9f150894fafe199637b4f63a Mon Sep 17 00:00:00 2001 From: chaurah Date: Thu, 15 Sep 2016 20:16:20 +0000 Subject: [PATCH] Release of version 2.1.1 --- CHANGELOG.md | 8 + PortingGuide.md | 4 +- README.md | 4 +- external_libs/jsmn/jsmn.c | 495 +++++++++--------- external_libs/jsmn/jsmn.h | 59 ++- include/aws_iot_log.h | 12 +- include/aws_iot_mqtt_client.h | 6 +- include/aws_iot_version.h | 2 +- include/network_interface.h | 2 +- platform/linux/common/timer.c | 6 +- .../linux/mbedtls/network_mbedtls_wrapper.c | 61 ++- .../subscribe_publish_cpp_sample.cpp | 14 +- .../subscribe_publish_library_sample.c | 14 +- .../subscribe_publish_sample.c | 14 +- src/aws_iot_mqtt_client.c | 1 + src/aws_iot_mqtt_client_common_internal.c | 11 + src/aws_iot_mqtt_client_connect.c | 2 +- src/aws_iot_mqtt_client_publish.c | 3 +- src/aws_iot_mqtt_client_subscribe.c | 3 +- src/aws_iot_mqtt_client_unsubscribe.c | 17 +- src/aws_iot_mqtt_client_yield.c | 19 +- src/aws_iot_shadow_json.c | 6 +- src/aws_iot_shadow_records.c | 6 +- .../src/aws_iot_tests_unit_yield_helper.c | 32 +- 24 files changed, 422 insertions(+), 379 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1df8e92bd5..f8acdf8f67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,12 @@ #Change Log +## [2.1.1](https://github.com/aws/aws-iot-device-sdk-embedded-C/releases/tag/v2.1.1) (Sep 5, 2016) + +Bugfixes/Improvements: + + - Network layer interface improvements to address reported issues + - Incorporated GitHub pull request [#41](https://github.com/aws/aws-iot-device-sdk-embedded-c/pull/41) + - Bugfixes for issues [#36](https://github.com/aws/aws-iot-device-sdk-embedded-C/issues/36) and [#33](https://github.com/aws/aws-iot-device-sdk-embedded-C/issues/33) + ## [2.1.0](https://github.com/aws/aws-iot-device-sdk-embedded-C/releases/tag/v2.1.0) (Jun 15, 2016) New features: diff --git a/PortingGuide.md b/PortingGuide.md index 5eb2061c52..ab393a276c 100644 --- a/PortingGuide.md +++ b/PortingGuide.md @@ -6,7 +6,7 @@ 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 link: - * [mbedTLS from ARM](https://s3.amazonaws.com/aws-iot-device-sdk-embedded-c/linux_mqtt_mbedtls-2.1.0.tar) + * [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). @@ -128,7 +128,7 @@ The threading layer provides the implementation of mutexes used for thread-safe ###Sample Porting: -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/sdk/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 the SDK for their development boards. [These](https://github.com/marvell-iot/aws_starter_sdk/tree/master/sdk/external/aws_iot/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 diff --git a/README.md b/README.md index 3a25ff49ed..599278a5c8 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Ensure you understand the AWS IoT platform and create the necessary certificates 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: -* [mbedTLS from ARM](https://s3.amazonaws.com/aws-iot-device-sdk-embedded-c/linux_mqtt_mbedtls-2.1.0.tar) +* [mbedTLS from ARM](https://s3.amazonaws.com/aws-iot-device-sdk-embedded-c/linux_mqtt_mbedtls-2.1.1.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. @@ -107,4 +107,4 @@ Update Thing Shadow from a device ``` rc = aws_iot_shadow_update(&mqttClient, AWS_IOT_MY_THING_NAME, pJsonDocumentBuffer, ShadowUpdateStatusCallback, pCallbackContext, TIMEOUT_4SEC, persistenSubscription); -``` \ No newline at end of file +``` diff --git a/external_libs/jsmn/jsmn.c b/external_libs/jsmn/jsmn.c index 838a94ae50..ea82be37f1 100644 --- a/external_libs/jsmn/jsmn.c +++ b/external_libs/jsmn/jsmn.c @@ -28,315 +28,314 @@ * @see http://zserge.com/jsmn.html */ -#include - #include "jsmn.h" /** * Allocates a fresh unused token from the token pull. */ -static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens, - size_t num_tokens) { - jsmntok_t *tok; - if (parser->toknext >= num_tokens) { - return NULL; - } - tok = &tokens[parser->toknext++]; - tok->start = tok->end = -1; - tok->size = 0; +static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, + jsmntok_t *tokens, size_t num_tokens) { + jsmntok_t *tok; + if (parser->toknext >= num_tokens) { + return NULL; + } + tok = &tokens[parser->toknext++]; + tok->start = tok->end = -1; + tok->size = 0; #ifdef JSMN_PARENT_LINKS - tok->parent = -1; + tok->parent = -1; #endif - return tok; + return tok; } /** * Fills token type and boundaries. */ -static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, int start, - int end) { - token->type = type; - token->start = start; - token->end = end; - token->size = 0; +static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, + int start, int end) { + token->type = type; + token->start = start; + token->end = end; + token->size = 0; } /** * Fills next available token with JSON primitive. */ -static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js, - size_t len, jsmntok_t *tokens, size_t num_tokens) { - jsmntok_t *token; - int start; +static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, + size_t len, jsmntok_t *tokens, size_t num_tokens) { + jsmntok_t *token; + int start; - start = parser->pos; + start = parser->pos; - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - switch (js[parser->pos]) { + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + switch (js[parser->pos]) { #ifndef JSMN_STRICT - /* In strict mode primitive must be followed by "," or "}" or "]" */ - case ':': + /* In strict mode primitive must be followed by "," or "}" or "]" */ + case ':': #endif - case '\t': - case '\r': - case '\n': - case ' ': - case ',': - case ']': - case '}': - goto found; - } - if (js[parser->pos] < 32 || js[parser->pos] >= 127) { - parser->pos = start; - return JSMN_ERROR_INVAL; - } - } + case '\t' : case '\r' : case '\n' : case ' ' : + case ',' : case ']' : case '}' : + goto found; + } + if (js[parser->pos] < 32 || js[parser->pos] >= 127) { + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } #ifdef JSMN_STRICT - /* In strict mode primitive must be followed by a comma/object/array */ - parser->pos = start; - return JSMN_ERROR_PART; + /* In strict mode primitive must be followed by a comma/object/array */ + parser->pos = start; + return JSMN_ERROR_PART; #endif - found: if (tokens == NULL) { - parser->pos--; - return (jsmnerr_t) 0; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - parser->pos = start; - return JSMN_ERROR_NOMEM; - } - jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); +found: + if (tokens == NULL) { + parser->pos--; + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); #ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; + token->parent = parser->toksuper; #endif - parser->pos--; - return (jsmnerr_t) 0; + parser->pos--; + return 0; } /** - * Filsl next token with JSON string. + * Fills next token with JSON string. */ -static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js, - size_t len, jsmntok_t *tokens, size_t num_tokens) { - jsmntok_t *token; +static int jsmn_parse_string(jsmn_parser *parser, const char *js, + size_t len, jsmntok_t *tokens, size_t num_tokens) { + jsmntok_t *token; - int start = parser->pos; + int start = parser->pos; - parser->pos++; + parser->pos++; - /* Skip starting quote */ - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - char c = js[parser->pos]; + /* Skip starting quote */ + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c = js[parser->pos]; - /* Quote: end of string */ - if (c == '\"') { - if (tokens == NULL) { - return (jsmnerr_t) 0; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - parser->pos = start; - return JSMN_ERROR_NOMEM; - } - jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos); + /* Quote: end of string */ + if (c == '\"') { + if (tokens == NULL) { + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos); #ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; + token->parent = parser->toksuper; #endif - return (jsmnerr_t) 0; - } + return 0; + } - /* Backslash: Quoted symbol expected */ - if (c == '\\') { - parser->pos++; - switch (js[parser->pos]) { - /* Allowed escaped symbols */ - case '\"': - case '/': - case '\\': - case 'b': - case 'f': - case 'r': - case 'n': - case 't': - break; - /* Allows escaped symbol \uXXXX */ - case 'u': - parser->pos++; - int i; - for (i = 0; i < 4 && js[parser->pos] != '\0'; i++) { - /* If it isn't a hex character we have an error */ - if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ - (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ - (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ - parser->pos = start; - return JSMN_ERROR_INVAL; - } - parser->pos++; - } - parser->pos--; - break; - /* Unexpected symbol */ - default: - parser->pos = start; - return JSMN_ERROR_INVAL; - } - } - } - parser->pos = start; - return JSMN_ERROR_PART; + /* Backslash: Quoted symbol expected */ + if (c == '\\' && parser->pos + 1 < len) { + int i; + parser->pos++; + switch (js[parser->pos]) { + /* Allowed escaped symbols */ + case '\"': case '/' : case '\\' : case 'b' : + case 'f' : case 'r' : case 'n' : case 't' : + break; + /* Allows escaped symbol \uXXXX */ + case 'u': + parser->pos++; + for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) { + /* If it isn't a hex character we have an error */ + if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ + (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ + (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ + parser->pos = start; + return JSMN_ERROR_INVAL; + } + parser->pos++; + } + parser->pos--; + break; + /* Unexpected symbol */ + default: + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } + } + parser->pos = start; + return JSMN_ERROR_PART; } /** * Parse JSON string and fill tokens. */ -jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, - jsmntok_t *tokens, unsigned int num_tokens) { - jsmnerr_t r; - int i; - jsmntok_t *token; - int count = 0; +int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, + jsmntok_t *tokens, unsigned int num_tokens) { + int r; + int i; + jsmntok_t *token; + int count = parser->toknext; - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - char c; - jsmntype_t type; + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c; + jsmntype_t type; - c = js[parser->pos]; - switch (c) { - case '{': - case '[': - count++; - if (tokens == NULL) { - break; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) - return JSMN_ERROR_NOMEM; - if (parser->toksuper != -1) { - tokens[parser->toksuper].size++; + c = js[parser->pos]; + switch (c) { + case '{': case '[': + count++; + if (tokens == NULL) { + break; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) + return JSMN_ERROR_NOMEM; + if (parser->toksuper != -1) { + tokens[parser->toksuper].size++; #ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; + token->parent = parser->toksuper; #endif - } - token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); - token->start = parser->pos; - parser->toksuper = parser->toknext - 1; - break; - case '}': - case ']': - if (tokens == NULL) - break; - type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); + } + token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); + token->start = parser->pos; + parser->toksuper = parser->toknext - 1; + break; + case '}': case ']': + if (tokens == NULL) + break; + type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); #ifdef JSMN_PARENT_LINKS - if (parser->toknext < 1) { - return JSMN_ERROR_INVAL; - } - token = &tokens[parser->toknext - 1]; - for (;;) { - if (token->start != -1 && token->end == -1) { - if (token->type != type) { - return JSMN_ERROR_INVAL; - } - token->end = parser->pos + 1; - parser->toksuper = token->parent; - break; - } - if (token->parent == -1) { - break; - } - token = &tokens[token->parent]; - } + if (parser->toknext < 1) { + return JSMN_ERROR_INVAL; + } + token = &tokens[parser->toknext - 1]; + for (;;) { + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + token->end = parser->pos + 1; + parser->toksuper = token->parent; + break; + } + if (token->parent == -1) { + break; + } + token = &tokens[token->parent]; + } #else - for (i = parser->toknext - 1; i >= 0; i--) { - token = &tokens[i]; - if (token->start != -1 && token->end == -1) { - if (token->type != type) { - return JSMN_ERROR_INVAL; - } - parser->toksuper = -1; - token->end = parser->pos + 1; - break; - } - } - /* Error if unmatched closing bracket */ - if (i == -1) - return JSMN_ERROR_INVAL; - for (; i >= 0; i--) { - token = &tokens[i]; - if (token->start != -1 && token->end == -1) { - parser->toksuper = i; - break; - } - } + for (i = parser->toknext - 1; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + parser->toksuper = -1; + token->end = parser->pos + 1; + break; + } + } + /* Error if unmatched closing bracket */ + if (i == -1) return JSMN_ERROR_INVAL; + for (; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + parser->toksuper = i; + break; + } + } #endif - break; - case '\"': - r = jsmn_parse_string(parser, js, len, tokens, num_tokens); - if (r < 0) - return r; - count++; - if (parser->toksuper != -1 && tokens != NULL) - tokens[parser->toksuper].size++; - break; - case '\t': - case '\r': - case '\n': - case ':': - case ',': - case ' ': - break; + break; + case '\"': + r = jsmn_parse_string(parser, js, len, tokens, num_tokens); + if (r < 0) return r; + count++; + if (parser->toksuper != -1 && tokens != NULL) + tokens[parser->toksuper].size++; + break; + case '\t' : case '\r' : case '\n' : case ' ': + break; + case ':': + parser->toksuper = parser->toknext - 1; + break; + case ',': + if (tokens != NULL && parser->toksuper != -1 && + tokens[parser->toksuper].type != JSMN_ARRAY && + tokens[parser->toksuper].type != JSMN_OBJECT) { +#ifdef JSMN_PARENT_LINKS + parser->toksuper = tokens[parser->toksuper].parent; +#else + for (i = parser->toknext - 1; i >= 0; i--) { + if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { + if (tokens[i].start != -1 && tokens[i].end == -1) { + parser->toksuper = i; + break; + } + } + } +#endif + } + break; #ifdef JSMN_STRICT - /* In strict mode primitives are: numbers and booleans */ - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case 't': - case 'f': - case 'n': + /* In strict mode primitives are: numbers and booleans */ + case '-': case '0': case '1' : case '2': case '3' : case '4': + case '5': case '6': case '7' : case '8': case '9': + case 't': case 'f': case 'n' : + /* And they must not be keys of the object */ + if (tokens != NULL && parser->toksuper != -1) { + jsmntok_t *t = &tokens[parser->toksuper]; + if (t->type == JSMN_OBJECT || + (t->type == JSMN_STRING && t->size != 0)) { + return JSMN_ERROR_INVAL; + } + } #else - /* In non-strict mode every unquoted value is a primitive */ - default: + /* In non-strict mode every unquoted value is a primitive */ + default: #endif - r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); - if (r < 0) - return r; - count++; - if (parser->toksuper != -1 && tokens != NULL) - tokens[parser->toksuper].size++; - break; + r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); + if (r < 0) return r; + count++; + if (parser->toksuper != -1 && tokens != NULL) + tokens[parser->toksuper].size++; + break; #ifdef JSMN_STRICT - /* Unexpected char in strict mode */ - default: - return JSMN_ERROR_INVAL; + /* Unexpected char in strict mode */ + default: + return JSMN_ERROR_INVAL; #endif - } - } + } + } - for (i = parser->toknext - 1; i >= 0; i--) { - /* Unmatched opened object or array */ - if (tokens[i].start != -1 && tokens[i].end == -1) { - return JSMN_ERROR_PART; - } - } + if (tokens != NULL) { + for (i = parser->toknext - 1; i >= 0; i--) { + /* Unmatched opened object or array */ + if (tokens[i].start != -1 && tokens[i].end == -1) { + return JSMN_ERROR_PART; + } + } + } - return (jsmnerr_t) count; + return count; } /** - * Creates a new parser based over a given buffer with an array of tokens + * Creates a new parser based over a given buffer with an array of tokens * available. */ void jsmn_init(jsmn_parser *parser) { - parser->pos = 0; - parser->toknext = 0; - parser->toksuper = -1; + parser->pos = 0; + parser->toknext = 0; + parser->toksuper = -1; } + diff --git a/external_libs/jsmn/jsmn.h b/external_libs/jsmn/jsmn.h index 96bdb95107..1df808e394 100644 --- a/external_libs/jsmn/jsmn.h +++ b/external_libs/jsmn/jsmn.h @@ -30,45 +30,50 @@ #ifndef __JSMN_H_ #define __JSMN_H_ + #include -#define JSMN_STRICT + #ifdef __cplusplus extern "C" { #endif /** * JSON type identifier. Basic types are: - * o Object - * o Array - * o String - * o Other primitive: number, boolean (true/false) or null + * o Object + * o Array + * o String + * o Other primitive: number, boolean (true/false) or null */ typedef enum { - JSMN_PRIMITIVE = 0, JSMN_OBJECT = 1, JSMN_ARRAY = 2, JSMN_STRING = 3 + JSMN_UNDEFINED = 0, + JSMN_OBJECT = 1, + JSMN_ARRAY = 2, + JSMN_STRING = 3, + JSMN_PRIMITIVE = 4 } jsmntype_t; -typedef enum { - /* Not enough tokens were provided */ - JSMN_ERROR_NOMEM = -1, - /* Invalid character inside JSON string */ - JSMN_ERROR_INVAL = -2, - /* The string is not a full JSON packet, more bytes expected */ - JSMN_ERROR_PART = -3, -} jsmnerr_t; +enum jsmnerr { + /* Not enough tokens were provided */ + JSMN_ERROR_NOMEM = -1, + /* Invalid character inside JSON string */ + JSMN_ERROR_INVAL = -2, + /* The string is not a full JSON packet, more bytes expected */ + JSMN_ERROR_PART = -3 +}; /** * JSON token description. - * @param type type (object, array, string etc.) - * @param start start position in JSON data string - * @param end end position in JSON data string + * @param type type (object, array, string etc.) + * @param start start position in JSON data string + * @param end end position in JSON data string */ typedef struct { - jsmntype_t type; - int start; - int end; - int size; + jsmntype_t type; + int start; + int end; + int size; #ifdef JSMN_PARENT_LINKS - int parent; + int parent; #endif } jsmntok_t; @@ -77,9 +82,9 @@ typedef struct { * the string being parsed now and current position in that string */ typedef struct { - unsigned int pos; /* offset in the JSON string */ - unsigned int toknext; /* next token to allocate */ - int toksuper; /* superior token node, e.g parent object or array */ + unsigned int pos; /* offset in the JSON string */ + unsigned int toknext; /* next token to allocate */ + int toksuper; /* superior token node, e.g parent object or array */ } jsmn_parser; /** @@ -91,8 +96,8 @@ void jsmn_init(jsmn_parser *parser); * Run JSON parser. It parses a JSON data string into and array of tokens, each describing * a single JSON object. */ -jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, - jsmntok_t *tokens, unsigned int num_tokens); +int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, + jsmntok_t *tokens, unsigned int num_tokens); #ifdef __cplusplus } diff --git a/include/aws_iot_log.h b/include/aws_iot_log.h index aec761c0eb..60c26086c9 100644 --- a/include/aws_iot_log.h +++ b/include/aws_iot_log.h @@ -43,7 +43,7 @@ extern "C" { #ifdef ENABLE_IOT_DEBUG #define IOT_DEBUG(...) \ {\ - printf("DEBUG: %s L#%d ", __PRETTY_FUNCTION__, __LINE__); \ + printf("DEBUG: %s L#%d ", __func__, __LINE__); \ printf(__VA_ARGS__); \ printf("\n"); \ } @@ -59,15 +59,15 @@ extern "C" { #ifdef ENABLE_IOT_TRACE #define FUNC_ENTRY \ {\ - printf("FUNC_ENTRY: %s L#%d \n", __PRETTY_FUNCTION__, __LINE__); \ + printf("FUNC_ENTRY: %s L#%d \n", __func__, __LINE__); \ } #define FUNC_EXIT \ {\ - printf("FUNC_EXIT: %s L#%d \n", __PRETTY_FUNCTION__, __LINE__); \ + printf("FUNC_EXIT: %s L#%d \n", __func__, __LINE__); \ } #define FUNC_EXIT_RC(x) \ {\ - printf("FUNC_EXIT: %s L#%d Return Code : %d \n", __PRETTY_FUNCTION__, __LINE__, x); \ + printf("FUNC_EXIT: %s L#%d Return Code : %d \n", __func__, __LINE__, x); \ return x; \ } #else @@ -100,7 +100,7 @@ extern "C" { #ifdef ENABLE_IOT_WARN #define IOT_WARN(...) \ { \ - printf("WARN: %s L#%d ", __PRETTY_FUNCTION__, __LINE__); \ + printf("WARN: %s L#%d ", __func__, __LINE__); \ printf(__VA_ARGS__); \ printf("\n"); \ } @@ -116,7 +116,7 @@ extern "C" { #ifdef ENABLE_IOT_ERROR #define IOT_ERROR(...) \ { \ - printf("ERROR: %s L#%d ", __PRETTY_FUNCTION__, __LINE__); \ + printf("ERROR: %s L#%d ", __func__, __LINE__); \ printf(__VA_ARGS__); \ printf("\n"); \ } diff --git a/include/aws_iot_mqtt_client.h b/include/aws_iot_mqtt_client.h index 9b688b7a05..32e1481ff3 100644 --- a/include/aws_iot_mqtt_client.h +++ b/include/aws_iot_mqtt_client.h @@ -169,6 +169,7 @@ typedef struct { 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 mqttPacketTimeout_ms; ///< Timeout for reading a complete MQTT packet. In milliseconds 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 @@ -181,9 +182,9 @@ typedef struct { extern const IoT_Client_Init_Params iotClientInitParamsDefault; #ifdef _ENABLE_THREAD_SUPPORT_ -#define IoT_Client_Init_Params_initializer { true, NULL, 0, NULL, NULL, NULL, 20000, 5000, true, NULL, NULL, false } +#define IoT_Client_Init_Params_initializer { true, NULL, 0, NULL, NULL, NULL, 2000, 20000, 5000, true, NULL, NULL, false } #else -#define IoT_Client_Init_Params_initializer { true, NULL, 0, NULL, NULL, NULL, 20000, 5000, true, NULL, NULL } +#define IoT_Client_Init_Params_initializer { true, NULL, 0, NULL, NULL, NULL, 2000, 20000, 5000, true, NULL, NULL } #endif /** @@ -257,6 +258,7 @@ typedef struct _ClientStatus { typedef struct _ClientData { uint16_t nextPacketId; + uint32_t packetTimeoutMs; uint32_t commandTimeoutMs; uint16_t keepAliveInterval; uint32_t currentReconnectWaitInterval; diff --git a/include/aws_iot_version.h b/include/aws_iot_version.h index 62ff338099..832fcf4866 100644 --- a/include/aws_iot_version.h +++ b/include/aws_iot_version.h @@ -39,7 +39,7 @@ /** * @brief PATCH version when backwards-compatible bug fixes are made. */ -#define VERSION_PATCH 0 +#define VERSION_PATCH 1 /** * @brief TAG is an (optional) tag appended to the version if a more descriptive verion is needed. */ diff --git a/include/network_interface.h b/include/network_interface.h index 6eee4eff5b..cf28341062 100644 --- a/include/network_interface.h +++ b/include/network_interface.h @@ -68,7 +68,7 @@ struct Network { 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 (*isConnected)(Network *); ///< Function pointer pointing to the network function to check if TLS 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 diff --git a/platform/linux/common/timer.c b/platform/linux/common/timer.c index 9df2f870fe..47a0851432 100644 --- a/platform/linux/common/timer.c +++ b/platform/linux/common/timer.c @@ -38,20 +38,20 @@ bool has_timer_expired(Timer *timer) { void countdown_ms(Timer *timer, uint32_t timeout) { struct timeval now; - gettimeofday(&now, NULL); #ifdef __cplusplus struct timeval interval = {timeout / 1000, static_cast((timeout % 1000) * 1000)}; #else struct timeval interval = {timeout / 1000, (int)((timeout % 1000) * 1000)}; #endif + gettimeofday(&now, NULL); timeradd(&now, &interval, &timer->end_time); } uint32_t left_ms(Timer *timer) { struct timeval now, res; + uint32_t result_ms = 0; 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); } @@ -60,8 +60,8 @@ uint32_t left_ms(Timer *timer) { void countdown_sec(Timer *timer, uint32_t timeout) { struct timeval now; - gettimeofday(&now, NULL); struct timeval interval = {timeout, 0}; + gettimeofday(&now, NULL); timeradd(&now, &interval, &timer->end_time); } diff --git a/platform/linux/mbedtls/network_mbedtls_wrapper.c b/platform/linux/mbedtls/network_mbedtls_wrapper.c index ab7216bd27..8195129905 100644 --- a/platform/linux/mbedtls/network_mbedtls_wrapper.c +++ b/platform/linux/mbedtls/network_mbedtls_wrapper.c @@ -88,6 +88,15 @@ IoT_Error_t iot_tls_is_connected(Network *pNetwork) { } IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *params) { + int ret = 0; + const char *pers = "aws_iot_tls_wrapper"; + TLSDataParams *tlsDataParams = NULL; + char portBuffer[6]; + char vrfy_buf[512]; +#ifdef IOT_DEBUG + unsigned char buf[MBEDTLS_SSL_MAX_CONTENT_LEN + 1]; +#endif + if(NULL == pNetwork) { return NULL_VALUE_ERROR; } @@ -98,12 +107,7 @@ IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *params) { 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); + tlsDataParams = &(pNetwork->tlsDataParams); mbedtls_net_init(&(tlsDataParams->server_fd)); mbedtls_ssl_init(&(tlsDataParams->ssl)); @@ -143,7 +147,6 @@ IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *params) { return NETWORK_PK_PRIVATE_KEY_PARSE_ERROR; } IOT_DEBUG(" ok\n"); - char portBuffer[6]; snprintf(portBuffer, 6, "%d", pNetwork->tlsConnectParams.DestinationPort); IOT_DEBUG(" . Connecting to %s/%s...", pNetwork->tlsConnectParams.pDestinationURL, portBuffer); if((ret = mbedtls_net_connect(&(tlsDataParams->server_fd), pNetwork->tlsConnectParams.pDestinationURL, @@ -232,7 +235,6 @@ IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *params) { if(pNetwork->tlsConnectParams.ServerVerificationFlag == true) { if((tlsDataParams->flags = mbedtls_ssl_get_verify_result(&(tlsDataParams->ssl))) != 0) { - char vrfy_buf[512]; IOT_ERROR(" failed\n"); mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", tlsDataParams->flags); IOT_ERROR("%s\n", vrfy_buf); @@ -294,40 +296,37 @@ IoT_Error_t iot_tls_write(Network *pNetwork, unsigned char *pMsg, size_t len, Ti } IoT_Error_t iot_tls_read(Network *pNetwork, unsigned char *pMsg, size_t len, Timer *timer, size_t *read_len) { + mbedtls_ssl_context *ssl = &(pNetwork->tlsDataParams.ssl); size_t rxLen = 0; - bool isErrorFlag = false; - bool isCompleteFlag = false; - uint32_t timerLeftVal = left_ms(timer); - TLSDataParams *tlsDataParams = &(pNetwork->tlsDataParams); - int ret = 0; + int ret; - do { - //mbedtls_ssl_conf_read_timeout(&(tlsDataParams->conf), timerLeftVal); - ret = mbedtls_ssl_read(&(tlsDataParams->ssl), pMsg, len); - if(ret >= 0) { /* 0 is for EOF */ + while (len > 0) { + // This read will timeout after IOT_SSL_READ_TIMEOUT if there's no data to be read + ret = mbedtls_ssl_read(ssl, pMsg, len); + if (ret > 0) { rxLen += ret; - } else if(ret != MBEDTLS_ERR_SSL_WANT_READ) { - isErrorFlag = true; + pMsg += ret; + len -= ret; + } else if (ret == 0 || (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret != MBEDTLS_ERR_SSL_TIMEOUT)) { + return NETWORK_SSL_READ_ERROR; } - /* 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; + // Evaluate timeout after the read to make sure read is done at least once + if (has_timer_expired(timer)) { + break; } - timerLeftVal = left_ms(timer); - } while(!isErrorFlag && !isCompleteFlag && timerLeftVal > 0); + } - *read_len = rxLen; + if (len == 0) { + *read_len = rxLen; + return SUCCESS; + } - if(0 == rxLen && isErrorFlag) { + if (rxLen == 0) { return NETWORK_SSL_NOTHING_TO_READ; - } else if(has_timer_expired(timer) && !isCompleteFlag) { + } else { return NETWORK_SSL_READ_TIMEOUT_ERROR; } - - return SUCCESS; } IoT_Error_t iot_tls_disconnect(Network *pNetwork) { diff --git a/samples/linux/subscribe_publish_cpp_sample/subscribe_publish_cpp_sample.cpp b/samples/linux/subscribe_publish_cpp_sample/subscribe_publish_cpp_sample.cpp index d1760750c1..9f0c900184 100644 --- a/samples/linux/subscribe_publish_cpp_sample/subscribe_publish_cpp_sample.cpp +++ b/samples/linux/subscribe_publish_cpp_sample/subscribe_publish_cpp_sample.cpp @@ -242,12 +242,14 @@ int main(int argc, char **argv) { sprintf(cPayload, "%s : %d ", "hello from SDK QOS1", i++); paramsQOS1.payloadLen = strlen(cPayload); - do { - rc = aws_iot_mqtt_publish(&client, "sdkTest/sub", 11, ¶msQOS1); - if(publishCount > 0) { - publishCount--; - } - } while(MQTT_REQUEST_TIMEOUT_ERROR == rc && (publishCount > 0 || infinitePublishFlag)); + rc = aws_iot_mqtt_publish(&client, "sdkTest/sub", 11, ¶msQOS1); + if (rc == MQTT_REQUEST_TIMEOUT_ERROR) { + IOT_WARN("QOS1 publish ack not received.\n"); + rc = SUCCESS; + } + if(publishCount > 0) { + publishCount--; + } } if(SUCCESS != rc) { diff --git a/samples/linux/subscribe_publish_library_sample/subscribe_publish_library_sample.c b/samples/linux/subscribe_publish_library_sample/subscribe_publish_library_sample.c index 0b0ab1a97b..2e5c1e85f1 100644 --- a/samples/linux/subscribe_publish_library_sample/subscribe_publish_library_sample.c +++ b/samples/linux/subscribe_publish_library_sample/subscribe_publish_library_sample.c @@ -242,12 +242,14 @@ int main(int argc, char **argv) { sprintf(cPayload, "%s : %d ", "hello from SDK QOS1", i++); paramsQOS1.payloadLen = strlen(cPayload); - do { - rc = aws_iot_mqtt_publish(&client, "sdkTest/sub", 11, ¶msQOS1); - if(publishCount > 0) { - publishCount--; - } - } while(MQTT_REQUEST_TIMEOUT_ERROR == rc && (publishCount > 0 || infinitePublishFlag)); + rc = aws_iot_mqtt_publish(&client, "sdkTest/sub", 11, ¶msQOS1); + if (rc == MQTT_REQUEST_TIMEOUT_ERROR) { + IOT_WARN("QOS1 publish ack not received.\n"); + rc = SUCCESS; + } + if(publishCount > 0) { + publishCount--; + } } if(SUCCESS != rc) { diff --git a/samples/linux/subscribe_publish_sample/subscribe_publish_sample.c b/samples/linux/subscribe_publish_sample/subscribe_publish_sample.c index d8961913e7..4f92645a52 100644 --- a/samples/linux/subscribe_publish_sample/subscribe_publish_sample.c +++ b/samples/linux/subscribe_publish_sample/subscribe_publish_sample.c @@ -242,12 +242,14 @@ int main(int argc, char **argv) { sprintf(cPayload, "%s : %d ", "hello from SDK QOS1", i++); paramsQOS1.payloadLen = strlen(cPayload); - do { - rc = aws_iot_mqtt_publish(&client, "sdkTest/sub", 11, ¶msQOS1); - if(publishCount > 0) { - publishCount--; - } - } while(MQTT_REQUEST_TIMEOUT_ERROR == rc && (publishCount > 0 || infinitePublishFlag)); + rc = aws_iot_mqtt_publish(&client, "sdkTest/sub", 11, ¶msQOS1); + if (rc == MQTT_REQUEST_TIMEOUT_ERROR) { + IOT_WARN("QOS1 publish ack not received.\n"); + rc = SUCCESS; + } + if(publishCount > 0) { + publishCount--; + } } if(SUCCESS != rc) { diff --git a/src/aws_iot_mqtt_client.c b/src/aws_iot_mqtt_client.c index f77ad20482..1786f76979 100644 --- a/src/aws_iot_mqtt_client.c +++ b/src/aws_iot_mqtt_client.c @@ -172,6 +172,7 @@ IoT_Error_t aws_iot_mqtt_init(AWS_IoT_Client *pClient, IoT_Client_Init_Params *p pClient->clientData.messageHandlers[i].qos = QOS0; } + pClient->clientData.packetTimeoutMs = pInitParams->mqttPacketTimeout_ms; pClient->clientData.commandTimeoutMs = pInitParams->mqttCommandTimeout_ms; pClient->clientData.writeBufSize = AWS_IOT_MQTT_TX_BUF_LEN; pClient->clientData.readBufSize = AWS_IOT_MQTT_RX_BUF_LEN; diff --git a/src/aws_iot_mqtt_client_common_internal.c b/src/aws_iot_mqtt_client_common_internal.c index 17eeb45e6f..a7cafb7bed 100644 --- a/src/aws_iot_mqtt_client_common_internal.c +++ b/src/aws_iot_mqtt_client_common_internal.c @@ -349,6 +349,9 @@ static IoT_Error_t _aws_iot_mqtt_internal_read_packet(AWS_IoT_Client *pClient, T size_t len, rem_len, total_bytes_read, bytes_to_be_read, read_len; IoT_Error_t rc; MQTTHeader header = {0}; + Timer packetTimer; + init_timer(&packetTimer); + countdown_ms(&packetTimer, pClient->clientData.packetTimeoutMs); len = 0; rem_len = 0; @@ -360,10 +363,18 @@ static IoT_Error_t _aws_iot_mqtt_internal_read_packet(AWS_IoT_Client *pClient, T /* 1. read the header byte. This has the packet type in it */ if(NETWORK_SSL_NOTHING_TO_READ == rc) { return MQTT_NOTHING_TO_READ; + } else if(SUCCESS != rc) { + return rc; } len = 1; + /* Use the constant packet receive timeout, instead of the variable (remaining) pTimer time, to + * determine packet receiving timeout. This is done so we don't prematurely time out packet receiving + * if the remaining time in pTimer is too short. + */ + pTimer = &packetTimer; + /* 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) { diff --git a/src/aws_iot_mqtt_client_connect.c b/src/aws_iot_mqtt_client_connect.c index 6d689b9f3e..9c4f25eb6f 100644 --- a/src/aws_iot_mqtt_client_connect.c +++ b/src/aws_iot_mqtt_client_connect.c @@ -431,7 +431,7 @@ static IoT_Error_t _aws_iot_mqtt_internal_connect(AWS_IoT_Client *pClient, IoT_C } pClient->clientStatus.isPingOutstanding = false; - countdown_sec(&pClient->pingTimer, pClient->clientData.keepAliveInterval / (uint32_t) 2); + countdown_sec(&pClient->pingTimer, pClient->clientData.keepAliveInterval); FUNC_EXIT_RC(SUCCESS); } diff --git a/src/aws_iot_mqtt_client_publish.c b/src/aws_iot_mqtt_client_publish.c index f95f0cd375..6895d5213f 100644 --- a/src/aws_iot_mqtt_client_publish.c +++ b/src/aws_iot_mqtt_client_publish.c @@ -91,6 +91,7 @@ static IoT_Error_t _aws_iot_mqtt_internal_serialize_publish(unsigned char *pTxBu uint32_t *pSerializedLen) { unsigned char *ptr; uint32_t rem_len; + IoT_Error_t rc; MQTTHeader header = {0}; FUNC_ENTRY; @@ -109,7 +110,7 @@ static IoT_Error_t _aws_iot_mqtt_internal_serialize_publish(unsigned char *pTxBu FUNC_EXIT_RC(MQTT_TX_BUFFER_TOO_SHORT_ERROR); } - IoT_Error_t rc = aws_iot_mqtt_internal_init_header(&header, PUBLISH, qos, dup, retained); + rc = aws_iot_mqtt_internal_init_header(&header, PUBLISH, qos, dup, retained); if(SUCCESS != rc) { FUNC_EXIT_RC(rc); } diff --git a/src/aws_iot_mqtt_client_subscribe.c b/src/aws_iot_mqtt_client_subscribe.c index ef8cdd896e..2311f73d14 100644 --- a/src/aws_iot_mqtt_client_subscribe.c +++ b/src/aws_iot_mqtt_client_subscribe.c @@ -61,6 +61,7 @@ static IoT_Error_t _aws_iot_mqtt_serialize_subscribe(unsigned char *pTxBuf, size QoS *pRequestedQoSs, uint32_t *pSerializedLen) { unsigned char *ptr; uint32_t itr, rem_len; + IoT_Error_t rc; MQTTHeader header = {0}; FUNC_ENTRY; @@ -79,7 +80,7 @@ static IoT_Error_t _aws_iot_mqtt_serialize_subscribe(unsigned char *pTxBuf, size FUNC_EXIT_RC(MQTT_TX_BUFFER_TOO_SHORT_ERROR); } - IoT_Error_t rc = aws_iot_mqtt_internal_init_header(&header, SUBSCRIBE, QOS1, dup, 0); + rc = aws_iot_mqtt_internal_init_header(&header, SUBSCRIBE, QOS1, dup, 0); if(SUCCESS != rc) { FUNC_EXIT_RC(rc); } diff --git a/src/aws_iot_mqtt_client_unsubscribe.c b/src/aws_iot_mqtt_client_unsubscribe.c index 3aa87d6950..fcbb97a98b 100644 --- a/src/aws_iot_mqtt_client_unsubscribe.c +++ b/src/aws_iot_mqtt_client_unsubscribe.c @@ -58,9 +58,10 @@ static IoT_Error_t _aws_iot_mqtt_serialize_unsubscribe(unsigned char *pTxBuf, si 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 */ + IoT_Error_t rc; + MQTTHeader header = {0}; FUNC_ENTRY; @@ -72,7 +73,7 @@ static IoT_Error_t _aws_iot_mqtt_serialize_unsubscribe(unsigned char *pTxBuf, si FUNC_EXIT_RC(MQTT_TX_BUFFER_TOO_SHORT_ERROR); } - IoT_Error_t rc = aws_iot_mqtt_internal_init_header(&header, UNSUBSCRIBE, QOS1, dup, 0); + rc = aws_iot_mqtt_internal_init_header(&header, UNSUBSCRIBE, QOS1, dup, 0); if(SUCCESS != rc) { FUNC_EXIT_RC(rc); } @@ -135,6 +136,7 @@ static IoT_Error_t _aws_iot_mqtt_internal_unsubscribe(AWS_IoT_Client *pClient, c Timer timer; + uint16_t packet_id; uint32_t serializedLen = 0; uint32_t i = 0; IoT_Error_t rc; @@ -175,7 +177,6 @@ static IoT_Error_t _aws_iot_mqtt_internal_unsubscribe(AWS_IoT_Client *pClient, c 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); @@ -210,6 +211,9 @@ static IoT_Error_t _aws_iot_mqtt_internal_unsubscribe(AWS_IoT_Client *pClient, c * @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) { + IoT_Error_t rc, unsubRc; + ClientState clientState; + if(NULL == pClient || NULL == pTopicFilter) { return NULL_VALUE_ERROR; } @@ -218,19 +222,18 @@ IoT_Error_t aws_iot_mqtt_unsubscribe(AWS_IoT_Client *pClient, const char *pTopic return NETWORK_DISCONNECTED_ERROR; } - ClientState clientState = aws_iot_mqtt_get_client_state(pClient); + 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); + 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); + 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) { diff --git a/src/aws_iot_mqtt_client_yield.c b/src/aws_iot_mqtt_client_yield.c index b86a785164..c40bcbbb4b 100644 --- a/src/aws_iot_mqtt_client_yield.c +++ b/src/aws_iot_mqtt_client_yield.c @@ -134,6 +134,7 @@ static IoT_Error_t _aws_iot_mqtt_keep_alive(AWS_IoT_Client *pClient) { /* 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, @@ -152,7 +153,7 @@ static IoT_Error_t _aws_iot_mqtt_keep_alive(AWS_IoT_Client *pClient) { pClient->clientStatus.isPingOutstanding = true; /* start a timer to wait for PINGRESP from server */ - countdown_sec(&pClient->pingTimer, pClient->clientData.keepAliveInterval / (uint32_t) 2); + countdown_sec(&pClient->pingTimer, pClient->clientData.keepAliveInterval); FUNC_EXIT_RC(SUCCESS); } @@ -187,7 +188,8 @@ static IoT_Error_t _aws_iot_mqtt_internal_yield(AWS_IoT_Client *pClient, uint32_ FUNC_ENTRY; - while(!has_timer_expired(&timer)) { + // evaluate timeout at the end of the loop to make sure the actual yield runs at least once + do { 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) { @@ -201,11 +203,16 @@ static IoT_Error_t _aws_iot_mqtt_internal_yield(AWS_IoT_Client *pClient, uint32_ } yieldRc = aws_iot_mqtt_internal_cycle_read(pClient, &timer, &packet_type); - if(SUCCESS != yieldRc) { - break; + if(SUCCESS == yieldRc) { + yieldRc = _aws_iot_mqtt_keep_alive(pClient); + } else { + // SSL read and write errors are terminal, connection must be closed and retried + if(NETWORK_SSL_READ_ERROR == yieldRc || NETWORK_SSL_READ_TIMEOUT_ERROR == yieldRc + || NETWORK_SSL_WRITE_ERROR == yieldRc || NETWORK_SSL_WRITE_TIMEOUT_ERROR == yieldRc) { + yieldRc = _aws_iot_mqtt_handle_disconnect(pClient); + } } - yieldRc = _aws_iot_mqtt_keep_alive(pClient); if(NETWORK_DISCONNECTED_ERROR == yieldRc) { pClient->clientData.counterNetworkDisconnected++; if(1 == pClient->clientStatus.isAutoReconnectEnabled) { @@ -227,7 +234,7 @@ static IoT_Error_t _aws_iot_mqtt_internal_yield(AWS_IoT_Client *pClient, uint32_ } else if(SUCCESS != yieldRc) { break; } - } + } while(!has_timer_expired(&timer)); FUNC_EXIT_RC(yieldRc); } diff --git a/src/aws_iot_shadow_json.c b/src/aws_iot_shadow_json.c index 5ede0fb945..5d5d4ab5cb 100644 --- a/src/aws_iot_shadow_json.c +++ b/src/aws_iot_shadow_json.c @@ -95,8 +95,8 @@ IoT_Error_t aws_iot_shadow_add_desired(char *pJsonDocument, size_t maxSizeOfJson size_t remSizeOfJsonBuffer = maxSizeOfJsonDocument; int32_t snPrintfReturn = 0; va_list pArgs; + jsonStruct_t *pTemporary = NULL; va_start(pArgs, count); - jsonStruct_t *pTemporary; if(pJsonDocument == NULL) { return NULL_VALUE_ERROR; @@ -156,9 +156,9 @@ IoT_Error_t aws_iot_shadow_add_reported(char *pJsonDocument, size_t maxSizeOfJso size_t remSizeOfJsonBuffer = maxSizeOfJsonDocument; int32_t snPrintfReturn = 0; size_t tempSize = 0; + jsonStruct_t *pTemporary; va_list pArgs; va_start(pArgs, count); - jsonStruct_t *pTemporary; if(pJsonDocument == NULL) { return NULL_VALUE_ERROR; @@ -417,10 +417,10 @@ bool isReceivedJsonValid(const char *pJsonDocument) { } bool extractClientToken(const char *pJsonDocument, char *pExtractedClientToken) { - jsmn_init(&shadowJsonParser); int32_t tokenCount, i; uint8_t length; jsmntok_t ClientJsonToken; + jsmn_init(&shadowJsonParser); tokenCount = jsmn_parse(&shadowJsonParser, pJsonDocument, strlen(pJsonDocument), jsonTokenStruct, sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0])); diff --git a/src/aws_iot_shadow_records.c b/src/aws_iot_shadow_records.c index 5336fe9c9c..d572a66fb5 100644 --- a/src/aws_iot_shadow_records.c +++ b/src/aws_iot_shadow_records.c @@ -253,13 +253,13 @@ static void unsubscribeFromAcceptedAndRejected(uint8_t index) { char TemporaryTopicNameRejected[MAX_SHADOW_TOPIC_LENGTH_BYTES]; IoT_Error_t ret_val = SUCCESS; + int16_t indexSubList; + topicNameFromThingAndAction(TemporaryTopicNameAccepted, AckWaitList[index].thingName, AckWaitList[index].action, SHADOW_ACCEPTED); topicNameFromThingAndAction(TemporaryTopicNameRejected, AckWaitList[index].thingName, AckWaitList[index].action, SHADOW_REJECTED); - int16_t indexSubList; - indexSubList = findIndexOfSubscriptionList(TemporaryTopicNameAccepted); if((indexSubList >= 0)) { if(!SubscriptionList[indexSubList].isSticky && (SubscriptionList[indexSubList].count == 1)) { @@ -335,6 +335,7 @@ IoT_Error_t subscribeToShadowActionAcks(const char *pThingName, ShadowActions_t bool clearBothEntriesFromList = true; int16_t indexAcceptedSubList = 0; int16_t indexRejectedSubList = 0; + Timer subSettlingtimer; indexAcceptedSubList = getNextFreeIndexOfSubscriptionList(); indexRejectedSubList = getNextFreeIndexOfSubscriptionList(); @@ -357,7 +358,6 @@ IoT_Error_t subscribeToShadowActionAcks(const char *pThingName, ShadowActions_t clearBothEntriesFromList = false; // wait for SUBSCRIBE_SETTLING_TIME seconds to let the subscription take effect - Timer subSettlingtimer; init_timer(&subSettlingtimer); countdown_sec(&subSettlingtimer, SUBSCRIBE_SETTLING_TIME); while(!has_timer_expired(&subSettlingtimer)); diff --git a/tests/unit/src/aws_iot_tests_unit_yield_helper.c b/tests/unit/src/aws_iot_tests_unit_yield_helper.c index 5c269436a4..ca0ea33901 100644 --- a/tests/unit/src/aws_iot_tests_unit_yield_helper.c +++ b/tests/unit/src/aws_iot_tests_unit_yield_helper.c @@ -182,18 +182,18 @@ TEST_C(YieldTests, disconnectNoAutoReconnect) { /* Disable Autoreconnect, then let ping request time out and call yield */ aws_iot_mqtt_autoreconnect_set_status(&iotClient, false); - sleep((uint16_t)(iotClient.clientData.keepAliveInterval / 2)); + sleep((uint16_t)(iotClient.clientData.keepAliveInterval)); ResetTLSBuffer(); - /* Sleep for half keep alive interval to allow the first ping to be sent out */ - sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2); + /* Sleep for keep alive interval to allow the first ping to be sent out */ + sleep(iotClient.clientData.keepAliveInterval); rc = aws_iot_mqtt_yield(&iotClient, 100); CHECK_EQUAL_C_INT(SUCCESS, rc); CHECK_EQUAL_C_INT(true, isLastTLSTxMessagePingreq()); /* Let ping request time out and call yield */ - sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2 + 1); + sleep(iotClient.clientData.keepAliveInterval + 1); rc = aws_iot_mqtt_yield(&iotClient, 100); CHECK_EQUAL_C_INT(NETWORK_DISCONNECTED_ERROR, rc); CHECK_EQUAL_C_INT(1, isLastTLSTxMessageDisconnect()); @@ -273,14 +273,14 @@ TEST_C(YieldTests, disconnectAutoReconnectTimeout) { ResetTLSBuffer(); - /* Sleep for half keep alive interval to allow the first ping to be sent out */ - sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2); + /* Sleep for keep alive interval to allow the first ping to be sent out */ + sleep(iotClient.clientData.keepAliveInterval); rc = aws_iot_mqtt_yield(&iotClient, 100); CHECK_EQUAL_C_INT(SUCCESS, rc); CHECK_EQUAL_C_INT(true, isLastTLSTxMessagePingreq()); /* Let ping request time out and call yield */ - sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2 + 1); + sleep(iotClient.clientData.keepAliveInterval + 1); rc = aws_iot_mqtt_yield(&iotClient, 100); CHECK_EQUAL_C_INT(NETWORK_ATTEMPTING_RECONNECT, rc); CHECK_EQUAL_C_INT(0, aws_iot_mqtt_is_client_connected(&iotClient)); @@ -302,14 +302,14 @@ TEST_C(YieldTests, disconnectAutoReconnectSuccess) { CHECK_EQUAL_C_INT(true, aws_iot_mqtt_is_client_connected(&iotClient)); CHECK_EQUAL_C_INT(true, aws_iot_is_autoreconnect_enabled(&iotClient)); - /* Sleep for half keep alive interval to allow the first ping to be sent out */ - sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2); + /* Sleep for keep alive interval to allow the first ping to be sent out */ + sleep(iotClient.clientData.keepAliveInterval); rc = aws_iot_mqtt_yield(&iotClient, 100); CHECK_EQUAL_C_INT(SUCCESS, rc); CHECK_EQUAL_C_INT(true, isLastTLSTxMessagePingreq()); /* Let ping request time out and call yield */ - sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2 + 1); + sleep(iotClient.clientData.keepAliveInterval + 1); rc = aws_iot_mqtt_yield(&iotClient, 100); CHECK_EQUAL_C_INT(NETWORK_ATTEMPTING_RECONNECT, rc); @@ -341,14 +341,14 @@ TEST_C(YieldTests, disconnectManualAutoReconnect) { aws_iot_mqtt_autoreconnect_set_status(&iotClient, false); CHECK_C(!aws_iot_is_autoreconnect_enabled(&iotClient)); - /* Sleep for half keep alive interval to allow the first ping to be sent out */ - sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2); + /* Sleep for keep alive interval to allow the first ping to be sent out */ + sleep(iotClient.clientData.keepAliveInterval); rc = aws_iot_mqtt_yield(&iotClient, 100); CHECK_EQUAL_C_INT(SUCCESS, rc); CHECK_EQUAL_C_INT(true, isLastTLSTxMessagePingreq()); /* Let ping request time out and call yield */ - sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2 + 1); + sleep(iotClient.clientData.keepAliveInterval + 1); rc = aws_iot_mqtt_yield(&iotClient, 100); CHECK_EQUAL_C_INT(NETWORK_DISCONNECTED_ERROR, rc); CHECK_EQUAL_C_INT(1, isLastTLSTxMessageDisconnect()); @@ -415,14 +415,14 @@ TEST_C(YieldTests, resubscribeSuccessfulReconnect) { autoReconnectEnabled = aws_iot_is_autoreconnect_enabled(&iotClient); CHECK_EQUAL_C_INT(1, autoReconnectEnabled); - /* Sleep for half keep alive interval to allow the first ping to be sent out */ - sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2); + /* Sleep for keep alive interval to allow the first ping to be sent out */ + sleep(iotClient.clientData.keepAliveInterval); rc = aws_iot_mqtt_yield(&iotClient, 100); CHECK_EQUAL_C_INT(SUCCESS, rc); CHECK_EQUAL_C_INT(true, isLastTLSTxMessagePingreq()); /* Let ping request time out and call yield */ - sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2 + 1); + sleep(iotClient.clientData.keepAliveInterval + 1); rc = aws_iot_mqtt_yield(&iotClient, 100); CHECK_EQUAL_C_INT(NETWORK_ATTEMPTING_RECONNECT, rc);