Jim Flynn / Mbed OS aws-iot-device-sdk-mbed-c
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers aws_iot_mqtt_client.c Source File

aws_iot_mqtt_client.c

Go to the documentation of this file.
00001 /*
00002 * Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
00003 *
00004 * Licensed under the Apache License, Version 2.0 (the "License").
00005 * You may not use this file except in compliance with the License.
00006 * A copy of the License is located at
00007 *
00008 * http://aws.amazon.com/apache2.0
00009 *
00010 * or in the "license" file accompanying this file. This file is distributed
00011 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
00012 * express or implied. See the License for the specific language governing
00013 * permissions and limitations under the License.
00014 */
00015 
00016 // Based on Eclipse Paho.
00017 /*******************************************************************************
00018  * Copyright (c) 2014 IBM Corp.
00019  *
00020  * All rights reserved. This program and the accompanying materials
00021  * are made available under the terms of the Eclipse Public License v1.0
00022  * and Eclipse Distribution License v1.0 which accompany this distribution.
00023  *
00024  * The Eclipse Public License is available at
00025  *    http://www.eclipse.org/legal/epl-v10.html
00026  * and the Eclipse Distribution License is available at
00027  *   http://www.eclipse.org/org/documents/edl-v10.php.
00028  *
00029  * Contributors:
00030  *    Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation
00031  *******************************************************************************/
00032 
00033 /**
00034  * @file aws_iot_mqtt_client.c
00035  * @brief MQTT client API definitions
00036  */
00037 
00038 #ifdef __cplusplus
00039 extern "C" {
00040 #endif
00041 
00042 #include <string.h>
00043 
00044 #include "aws_iot_log.h"
00045 #include "aws_iot_mqtt_client_interface.h"
00046 #include "aws_iot_version.h"
00047 
00048 #if !DISABLE_METRICS
00049 #define SDK_METRICS_LEN 25
00050 #define SDK_METRICS_TEMPLATE "?SDK=C&Version=%d.%d.%d"
00051 static char pUsernameTemp[SDK_METRICS_LEN] = {0};
00052 #endif
00053 
00054 #ifdef _ENABLE_THREAD_SUPPORT_
00055 #include "threads_interface.h"
00056 #endif
00057 
00058 const IoT_Client_Init_Params iotClientInitParamsDefault = IoT_Client_Init_Params_initializer;
00059 const IoT_MQTT_Will_Options iotMqttWillOptionsDefault = IoT_MQTT_Will_Options_Initializer;
00060 const IoT_Client_Connect_Params iotClientConnectParamsDefault = IoT_Client_Connect_Params_initializer;
00061 
00062 ClientState aws_iot_mqtt_get_client_state(AWS_IoT_Client *pClient) {
00063     FUNC_ENTRY;
00064     if(NULL == pClient) {
00065         return CLIENT_STATE_INVALID;
00066     }
00067 
00068     FUNC_EXIT_RC(pClient->clientStatus.clientState);
00069 }
00070 
00071 #ifdef _ENABLE_THREAD_SUPPORT_
00072 IoT_Error_t aws_iot_mqtt_client_lock_mutex(AWS_IoT_Client *pClient, IoT_Mutex_t *pMutex) {
00073     FUNC_ENTRY;
00074     IoT_Error_t threadRc = FAILURE;
00075 
00076     if(NULL == pClient || NULL == pMutex){
00077         FUNC_EXIT_RC(NULL_VALUE_ERROR);
00078     }
00079 
00080     if(false == pClient->clientData.isBlockOnThreadLockEnabled) {
00081         threadRc = aws_iot_thread_mutex_trylock(pMutex);
00082     } else {
00083         threadRc = aws_iot_thread_mutex_lock(pMutex);
00084         /* Should never return Error because the above request blocks until lock is obtained */
00085     }
00086 
00087     if(AWS_SUCCESS != threadRc) {
00088         FUNC_EXIT_RC(threadRc);
00089     }
00090 
00091     FUNC_EXIT_RC(AWS_SUCCESS);
00092 }
00093 
00094 IoT_Error_t aws_iot_mqtt_client_unlock_mutex(AWS_IoT_Client *pClient, IoT_Mutex_t *pMutex) {
00095     if(NULL == pClient || NULL == pMutex) {
00096         return NULL_VALUE_ERROR;
00097     }
00098     IOT_UNUSED(pClient);
00099     return aws_iot_thread_mutex_unlock(pMutex);
00100 }
00101 #endif
00102 
00103 IoT_Error_t aws_iot_mqtt_set_client_state(AWS_IoT_Client *pClient, ClientState expectedCurrentState,
00104                                           ClientState newState) {
00105     IoT_Error_t rc;
00106 #ifdef _ENABLE_THREAD_SUPPORT_
00107     IoT_Error_t threadRc = FAILURE;
00108 #endif
00109 
00110     FUNC_ENTRY;
00111     if(NULL == pClient) {
00112         FUNC_EXIT_RC(NULL_VALUE_ERROR);
00113     }
00114 
00115 #ifdef _ENABLE_THREAD_SUPPORT_
00116     rc = aws_iot_mqtt_client_lock_mutex(pClient, &(pClient->clientData.state_change_mutex));
00117     if(AWS_SUCCESS != rc) {
00118         return rc;
00119     }
00120 #endif
00121     if(expectedCurrentState == aws_iot_mqtt_get_client_state(pClient)) {
00122         pClient->clientStatus.clientState = newState;
00123         rc = AWS_SUCCESS;
00124     } else {
00125         rc = MQTT_UNEXPECTED_CLIENT_STATE_ERROR;
00126     }
00127 
00128 #ifdef _ENABLE_THREAD_SUPPORT_
00129     threadRc = aws_iot_mqtt_client_unlock_mutex(pClient, &(pClient->clientData.state_change_mutex));
00130     if(AWS_SUCCESS == rc && AWS_SUCCESS != threadRc) {
00131         rc = threadRc;
00132     }
00133 #endif
00134 
00135     FUNC_EXIT_RC(rc);
00136 }
00137 
00138 IoT_Error_t aws_iot_mqtt_set_connect_params(AWS_IoT_Client *pClient, IoT_Client_Connect_Params *pNewConnectParams) {
00139     FUNC_ENTRY;
00140     if(NULL == pClient || NULL == pNewConnectParams) {
00141         FUNC_EXIT_RC(NULL_VALUE_ERROR);
00142     }
00143 
00144     pClient->clientData.options.isWillMsgPresent = pNewConnectParams->isWillMsgPresent;
00145     pClient->clientData.options.MQTTVersion = pNewConnectParams->MQTTVersion;
00146     pClient->clientData.options.pClientID = pNewConnectParams->pClientID;
00147     pClient->clientData.options.clientIDLen = pNewConnectParams->clientIDLen;
00148 #if !DISABLE_METRICS
00149     if (0 == strlen(pUsernameTemp)) {
00150         snprintf(pUsernameTemp, SDK_METRICS_LEN, SDK_METRICS_TEMPLATE, VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
00151     }
00152     pClient->clientData.options.pUsername = (char*)&pUsernameTemp[0];
00153     pClient->clientData.options.usernameLen = strlen(pUsernameTemp);
00154 #else
00155     pClient->clientData.options.pUsername = pNewConnectParams->pUsername;
00156     pClient->clientData.options.usernameLen = pNewConnectParams->usernameLen;
00157 #endif
00158     pClient->clientData.options.pPassword = pNewConnectParams->pPassword;
00159     pClient->clientData.options.passwordLen = pNewConnectParams->passwordLen;
00160     pClient->clientData.options.will.pTopicName = pNewConnectParams->will.pTopicName;
00161     pClient->clientData.options.will.topicNameLen = pNewConnectParams->will.topicNameLen;
00162     pClient->clientData.options.will.pMessage = pNewConnectParams->will.pMessage;
00163     pClient->clientData.options.will.msgLen = pNewConnectParams->will.msgLen;
00164     pClient->clientData.options.will.qos = pNewConnectParams->will.qos;
00165     pClient->clientData.options.will.isRetained = pNewConnectParams->will.isRetained;
00166     pClient->clientData.options.keepAliveIntervalInSec = pNewConnectParams->keepAliveIntervalInSec;
00167     pClient->clientData.options.isCleanSession = pNewConnectParams->isCleanSession;
00168 
00169     FUNC_EXIT_RC(AWS_SUCCESS);
00170 }
00171 
00172 IoT_Error_t aws_iot_mqtt_free(AWS_IoT_Client *pClient)
00173 {
00174     IoT_Error_t rc = AWS_SUCCESS;
00175 
00176     if (NULL == pClient) {
00177         rc = NULL_VALUE_ERROR;
00178     }else
00179     {
00180     #ifdef _ENABLE_THREAD_SUPPORT_
00181         if (rc == AWS_SUCCESS)
00182         {
00183             rc = aws_iot_thread_mutex_destroy(&(pClient->clientData.state_change_mutex));
00184         }
00185 
00186         if (rc == AWS_SUCCESS)
00187         {
00188             rc = aws_iot_thread_mutex_destroy(&(pClient->clientData.tls_read_mutex));
00189         }else{
00190             (void)aws_iot_thread_mutex_destroy(&(pClient->clientData.tls_read_mutex));
00191         }
00192 
00193         if (rc == AWS_SUCCESS)
00194         {
00195             rc = aws_iot_thread_mutex_destroy(&(pClient->clientData.tls_write_mutex));
00196         }else{
00197             (void)aws_iot_thread_mutex_destroy(&(pClient->clientData.tls_write_mutex));
00198         }
00199     #endif
00200     }
00201 
00202     FUNC_EXIT_RC(rc);
00203 }
00204 
00205 IoT_Error_t aws_iot_mqtt_init(AWS_IoT_Client *pClient, IoT_Client_Init_Params *pInitParams) {
00206     uint32_t i;
00207     IoT_Error_t rc;
00208     IoT_Client_Connect_Params default_options = IoT_Client_Connect_Params_initializer;
00209     FUNC_ENTRY;
00210 
00211     if(NULL == pClient || NULL == pInitParams || NULL == pInitParams->pHostURL || 0 == pInitParams->port ||
00212        NULL == pInitParams->pRootCALocation || NULL == pInitParams->pDevicePrivateKeyLocation ||
00213        NULL == pInitParams->pDeviceCertLocation) {
00214         FUNC_EXIT_RC(NULL_VALUE_ERROR);
00215     }
00216 
00217     for(i = 0; i < AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS; ++i) {
00218         pClient->clientData.messageHandlers[i].topicName = NULL;
00219         pClient->clientData.messageHandlers[i].pApplicationHandler = NULL;
00220         pClient->clientData.messageHandlers[i].pApplicationHandlerData = NULL;
00221         pClient->clientData.messageHandlers[i].qos = QOS0;
00222     }
00223 
00224     pClient->clientData.packetTimeoutMs = pInitParams->mqttPacketTimeout_ms;
00225     pClient->clientData.commandTimeoutMs = pInitParams->mqttCommandTimeout_ms;
00226     pClient->clientData.writeBufSize = AWS_IOT_MQTT_TX_BUF_LEN;
00227     pClient->clientData.readBufSize = AWS_IOT_MQTT_RX_BUF_LEN;
00228     pClient->clientData.counterNetworkDisconnected = 0;
00229     pClient->clientData.disconnectHandler = pInitParams->disconnectHandler;
00230     pClient->clientData.disconnectHandlerData = pInitParams->disconnectHandlerData;
00231     pClient->clientData.nextPacketId = 1;
00232 
00233     pClient->clientData.packetTimeoutMs = pInitParams->mqttPacketTimeout_ms;
00234     /* Initialize default connection options */
00235     rc = aws_iot_mqtt_set_connect_params(pClient, &default_options);
00236     if(AWS_SUCCESS != rc) {
00237         FUNC_EXIT_RC(rc);
00238     }
00239 
00240 #ifdef _ENABLE_THREAD_SUPPORT_
00241     pClient->clientData.isBlockOnThreadLockEnabled = pInitParams->isBlockOnThreadLockEnabled;
00242     rc = aws_iot_thread_mutex_init(&(pClient->clientData.state_change_mutex));
00243     if(AWS_SUCCESS != rc) {
00244         FUNC_EXIT_RC(rc);
00245     }
00246     rc = aws_iot_thread_mutex_init(&(pClient->clientData.tls_read_mutex));
00247     if(AWS_SUCCESS != rc) {
00248         (void)aws_iot_thread_mutex_destroy(&(pClient->clientData.state_change_mutex));
00249         FUNC_EXIT_RC(rc);
00250     }
00251     rc = aws_iot_thread_mutex_init(&(pClient->clientData.tls_write_mutex));
00252     if(AWS_SUCCESS != rc) {
00253         (void)aws_iot_thread_mutex_destroy(&(pClient->clientData.tls_read_mutex));
00254         (void)aws_iot_thread_mutex_destroy(&(pClient->clientData.state_change_mutex));
00255         FUNC_EXIT_RC(rc);
00256     }
00257 #endif
00258 
00259     pClient->clientStatus.isPingOutstanding = 0;
00260     pClient->clientStatus.isAutoReconnectEnabled = pInitParams->enableAutoReconnect;
00261 
00262     rc = iot_tls_init(&(pClient->networkStack), pInitParams->pRootCALocation, pInitParams->pDeviceCertLocation,
00263                       pInitParams->pDevicePrivateKeyLocation, pInitParams->pHostURL, pInitParams->port,
00264                       pInitParams->tlsHandshakeTimeout_ms, pInitParams->isSSLHostnameVerify);
00265 
00266     if(AWS_SUCCESS != rc) {
00267         #ifdef _ENABLE_THREAD_SUPPORT_
00268         (void)aws_iot_thread_mutex_destroy(&(pClient->clientData.tls_read_mutex));
00269         (void)aws_iot_thread_mutex_destroy(&(pClient->clientData.state_change_mutex));
00270         (void)aws_iot_thread_mutex_destroy(&(pClient->clientData.tls_write_mutex));
00271         #endif
00272         pClient->clientStatus.clientState = CLIENT_STATE_INVALID;
00273         FUNC_EXIT_RC(rc);
00274     }
00275 
00276     init_timer(&(pClient->pingTimer));
00277     init_timer(&(pClient->reconnectDelayTimer));
00278 
00279     pClient->clientStatus.clientState = CLIENT_STATE_INITIALIZED;
00280 
00281     FUNC_EXIT_RC(AWS_SUCCESS);
00282 }
00283 
00284 uint16_t aws_iot_mqtt_get_next_packet_id(AWS_IoT_Client *pClient) {
00285     return pClient->clientData.nextPacketId = (uint16_t) ((MAX_PACKET_ID == pClient->clientData.nextPacketId) ? 1 : (
00286             pClient->clientData.nextPacketId + 1));
00287 }
00288 
00289 bool aws_iot_mqtt_is_client_connected(AWS_IoT_Client *pClient) {
00290     bool isConnected;
00291 
00292     FUNC_ENTRY;
00293 
00294     if(NULL == pClient) {
00295         IOT_WARN(" Client is null! ");
00296         FUNC_EXIT_RC(false);
00297     }
00298 
00299     switch(pClient->clientStatus.clientState) {
00300         case CLIENT_STATE_INVALID:
00301         case CLIENT_STATE_INITIALIZED:
00302         case CLIENT_STATE_CONNECTING:
00303             isConnected = false;
00304             break;
00305         case CLIENT_STATE_CONNECTED_IDLE:
00306         case CLIENT_STATE_CONNECTED_YIELD_IN_PROGRESS:
00307         case CLIENT_STATE_CONNECTED_PUBLISH_IN_PROGRESS:
00308         case CLIENT_STATE_CONNECTED_SUBSCRIBE_IN_PROGRESS:
00309         case CLIENT_STATE_CONNECTED_UNSUBSCRIBE_IN_PROGRESS:
00310         case CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS:
00311         case CLIENT_STATE_CONNECTED_WAIT_FOR_CB_RETURN:
00312             isConnected = true;
00313             break;
00314         case CLIENT_STATE_DISCONNECTING:
00315         case CLIENT_STATE_DISCONNECTED_ERROR:
00316         case CLIENT_STATE_DISCONNECTED_MANUALLY:
00317         case CLIENT_STATE_PENDING_RECONNECT:
00318         default:
00319             isConnected = false;
00320             break;
00321     }
00322 
00323     FUNC_EXIT_RC(isConnected);
00324 }
00325 
00326 bool aws_iot_is_autoreconnect_enabled(AWS_IoT_Client *pClient) {
00327     FUNC_ENTRY;
00328     if(NULL == pClient) {
00329         IOT_WARN(" Client is null! ");
00330         FUNC_EXIT_RC(false);
00331     }
00332 
00333     FUNC_EXIT_RC(pClient->clientStatus.isAutoReconnectEnabled);
00334 }
00335 
00336 IoT_Error_t aws_iot_mqtt_autoreconnect_set_status(AWS_IoT_Client *pClient, bool newStatus) {
00337     FUNC_ENTRY;
00338     if(NULL == pClient) {
00339         FUNC_EXIT_RC(NULL_VALUE_ERROR);
00340     }
00341     pClient->clientStatus.isAutoReconnectEnabled = newStatus;
00342     FUNC_EXIT_RC(AWS_SUCCESS);
00343 }
00344 
00345 IoT_Error_t aws_iot_mqtt_set_disconnect_handler(AWS_IoT_Client *pClient, iot_disconnect_handler pDisconnectHandler,
00346                                                 void *pDisconnectHandlerData) {
00347     FUNC_ENTRY;
00348     if(NULL == pClient || NULL == pDisconnectHandler) {
00349         FUNC_EXIT_RC(NULL_VALUE_ERROR);
00350     }
00351 
00352     pClient->clientData.disconnectHandler = pDisconnectHandler;
00353     pClient->clientData.disconnectHandlerData = pDisconnectHandlerData;
00354     FUNC_EXIT_RC(AWS_SUCCESS);
00355 }
00356 
00357 uint32_t aws_iot_mqtt_get_network_disconnected_count(AWS_IoT_Client *pClient) {
00358     return pClient->clientData.counterNetworkDisconnected;
00359 }
00360 
00361 void aws_iot_mqtt_reset_network_disconnected_count(AWS_IoT_Client *pClient) {
00362     pClient->clientData.counterNetworkDisconnected = 0;
00363 }
00364 
00365 #ifdef __cplusplus
00366 }
00367 #endif
00368