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_unsubscribe.c Source File

aws_iot_mqtt_client_unsubscribe.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  *    Ian Craggs - initial API and implementation and/or initial documentation
00031  *******************************************************************************/
00032 
00033 /**
00034  * @file aws_iot_mqtt_client_unsubscribe.c
00035  * @brief MQTT client unsubscribe API definitions
00036  */
00037 
00038 #ifdef __cplusplus
00039 extern "C" {
00040 #endif
00041 
00042 #include "aws_iot_mqtt_client_common_internal.h"
00043 
00044 /**
00045   * Serializes the supplied unsubscribe data into the supplied buffer, ready for sending
00046   * @param pTxBuf the raw buffer data, of the correct length determined by the remaining length field
00047   * @param txBufLen the length in bytes of the data in the supplied buffer
00048   * @param dup integer - the MQTT dup flag
00049   * @param packetId integer - the MQTT packet identifier
00050   * @param count - number of members in the topicFilters array
00051   * @param pTopicNameList - array of topic filter names
00052   * @param pTopicNameLenList - array of length of topic filter names in pTopicNameList
00053   * @param pSerializedLen - the length of the serialized data
00054   * @return IoT_Error_t indicating function execution status
00055   */
00056 static IoT_Error_t _aws_iot_mqtt_serialize_unsubscribe(unsigned char *pTxBuf, size_t txBufLen,
00057                                                        uint8_t dup, uint16_t packetId,
00058                                                        uint32_t count, const char **pTopicNameList,
00059                                                        uint16_t *pTopicNameLenList, uint32_t *pSerializedLen) {
00060     unsigned char *ptr = pTxBuf;
00061     uint32_t i = 0;
00062     uint32_t rem_len = 2; /* packetId */
00063     IoT_Error_t rc;
00064     MQTTHeader header = {0};
00065 
00066     FUNC_ENTRY;
00067 
00068     for(i = 0; i < count; ++i) {
00069         rem_len += (uint32_t) (pTopicNameLenList[i] + 2); /* topic + length */
00070     }
00071 
00072     if(aws_iot_mqtt_internal_get_final_packet_length_from_remaining_length(rem_len) > txBufLen) {
00073         FUNC_EXIT_RC(MQTT_TX_BUFFER_TOO_SHORT_ERROR);
00074     }
00075 
00076     rc = aws_iot_mqtt_internal_init_header(&header, UNSUBSCRIBE, QOS1, dup, 0);
00077     if(AWS_SUCCESS != rc) {
00078         FUNC_EXIT_RC(rc);
00079     }
00080     aws_iot_mqtt_internal_write_char(&ptr, header.byte); /* write header */
00081 
00082     ptr += aws_iot_mqtt_internal_write_len_to_buffer(ptr, rem_len); /* write remaining length */
00083 
00084     aws_iot_mqtt_internal_write_uint_16(&ptr, packetId);
00085 
00086     for(i = 0; i < count; ++i) {
00087         aws_iot_mqtt_internal_write_utf8_string(&ptr, pTopicNameList[i], pTopicNameLenList[i]);
00088     }
00089 
00090     *pSerializedLen = (uint32_t) (ptr - pTxBuf);
00091 
00092     FUNC_EXIT_RC(AWS_SUCCESS);
00093 }
00094 
00095 
00096 /**
00097   * Deserializes the supplied (wire) buffer into unsuback data
00098   * @param pPacketId returned integer - the MQTT packet identifier
00099   * @param pRxBuf the raw buffer data, of the correct length determined by the remaining length field
00100   * @param rxBufLen the length in bytes of the data in the supplied buffer
00101   * @return IoT_Error_t indicating function execution status
00102   */
00103 static IoT_Error_t _aws_iot_mqtt_deserialize_unsuback(uint16_t *pPacketId, unsigned char *pRxBuf, size_t rxBufLen) {
00104     unsigned char type = 0;
00105     unsigned char dup = 0;
00106     IoT_Error_t rc;
00107 
00108     FUNC_ENTRY;
00109 
00110     rc = aws_iot_mqtt_internal_deserialize_ack(&type, &dup, pPacketId, pRxBuf, rxBufLen);
00111     if(AWS_SUCCESS == rc && UNSUBACK != type) {
00112         rc = FAILURE;
00113     }
00114 
00115     FUNC_EXIT_RC(rc);
00116 }
00117 
00118 /**
00119  * @brief Unsubscribe to an MQTT topic.
00120  *
00121  * Called to send an unsubscribe message to the broker requesting removal of a subscription
00122  * to an MQTT topic.
00123  * @note Call is blocking.  The call returns after the receipt of the UNSUBACK control packet.
00124  * This is the internal function which is called by the unsubscribe API to perform the operation.
00125  * Not meant to be called directly as it doesn't do validations or client state changes
00126  *
00127  * @param pClient Reference to the IoT Client
00128  * @param pTopicName Topic Name to publish to
00129  * @param topicNameLen Length of the topic name
00130  *
00131  * @return An IoT Error Type defining successful/failed unsubscribe call
00132  */
00133 static IoT_Error_t _aws_iot_mqtt_internal_unsubscribe(AWS_IoT_Client *pClient, const char *pTopicFilter,
00134                                                       uint16_t topicFilterLen) {
00135     /* No NULL checks because this is a static internal function */
00136 
00137     awsTimer timer;
00138 
00139     uint16_t packet_id;
00140     uint32_t serializedLen = 0;
00141     uint32_t i = 0;
00142     IoT_Error_t rc;
00143     bool subscriptionExists = false;
00144 
00145     FUNC_ENTRY;
00146 
00147     /* Remove from message handler array */
00148     for(i = 0; i < AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS; ++i) {
00149         if(pClient->clientData.messageHandlers[i].topicName != NULL &&
00150            (strcmp(pClient->clientData.messageHandlers[i].topicName, pTopicFilter) == 0)) {
00151             subscriptionExists = true;
00152             break;
00153         }
00154     }
00155 
00156     if(false == subscriptionExists) {
00157         FUNC_EXIT_RC(FAILURE);
00158     }
00159 
00160     init_timer(&timer);
00161     countdown_ms(&timer, pClient->clientData.commandTimeoutMs);
00162 
00163     rc = _aws_iot_mqtt_serialize_unsubscribe(pClient->clientData.writeBuf, pClient->clientData.writeBufSize, 0,
00164                                              aws_iot_mqtt_get_next_packet_id(pClient), 1, &pTopicFilter,
00165                                              &topicFilterLen, &serializedLen);
00166     if(AWS_SUCCESS != rc) {
00167         FUNC_EXIT_RC(rc);
00168     }
00169 
00170     /* send the unsubscribe packet */
00171     rc = aws_iot_mqtt_internal_send_packet(pClient, serializedLen, &timer);
00172     if(AWS_SUCCESS != rc) {
00173         FUNC_EXIT_RC(rc);
00174     }
00175 
00176     rc = aws_iot_mqtt_internal_wait_for_read(pClient, UNSUBACK, &timer);
00177     if(AWS_SUCCESS != rc) {
00178         FUNC_EXIT_RC(rc);
00179     }
00180 
00181     rc = _aws_iot_mqtt_deserialize_unsuback(&packet_id, pClient->clientData.readBuf, pClient->clientData.readBufSize);
00182     if(AWS_SUCCESS != rc) {
00183         FUNC_EXIT_RC(rc);
00184     }
00185 
00186     /* Remove from message handler array */
00187     for(i = 0; i < AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS; ++i) {
00188         if(pClient->clientData.messageHandlers[i].topicName != NULL &&
00189            (strcmp(pClient->clientData.messageHandlers[i].topicName, pTopicFilter) == 0)) {
00190             pClient->clientData.messageHandlers[i].topicName = NULL;
00191             /* We don't want to break here, in case the same topic is registered
00192              * with 2 callbacks. Unlikely scenario */
00193         }
00194     }
00195 
00196     FUNC_EXIT_RC(AWS_SUCCESS);
00197 }
00198 
00199 /**
00200  * @brief Unsubscribe to an MQTT topic.
00201  *
00202  * Called to send an unsubscribe message to the broker requesting removal of a subscription
00203  * to an MQTT topic.
00204  * @note Call is blocking.  The call returns after the receipt of the UNSUBACK control packet.
00205  * This is the outer function which does the validations and calls the internal unsubscribe above
00206  * to perform the actual operation. It is also responsible for client state changes
00207  *
00208  * @param pClient Reference to the IoT Client
00209  * @param pTopicName Topic Name to publish to
00210  * @param topicNameLen Length of the topic name
00211  *
00212  * @return An IoT Error Type defining successful/failed unsubscribe call
00213  */
00214 IoT_Error_t aws_iot_mqtt_unsubscribe(AWS_IoT_Client *pClient, const char *pTopicFilter, uint16_t topicFilterLen) {
00215     IoT_Error_t rc, unsubRc;
00216     ClientState clientState;
00217 
00218     if(NULL == pClient || NULL == pTopicFilter) {
00219         return NULL_VALUE_ERROR;
00220     }
00221 
00222     if(!aws_iot_mqtt_is_client_connected(pClient)) {
00223         return NETWORK_DISCONNECTED_ERROR;
00224     }
00225 
00226     clientState = aws_iot_mqtt_get_client_state(pClient);
00227     if(CLIENT_STATE_CONNECTED_IDLE != clientState && CLIENT_STATE_CONNECTED_WAIT_FOR_CB_RETURN != clientState) {
00228         return MQTT_CLIENT_NOT_IDLE_ERROR;
00229     }
00230 
00231     rc = aws_iot_mqtt_set_client_state(pClient, clientState, CLIENT_STATE_CONNECTED_UNSUBSCRIBE_IN_PROGRESS);
00232     if(AWS_SUCCESS != rc) {
00233         rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_UNSUBSCRIBE_IN_PROGRESS, clientState);
00234         return rc;
00235     }
00236 
00237     unsubRc = _aws_iot_mqtt_internal_unsubscribe(pClient, pTopicFilter, topicFilterLen);
00238 
00239     rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_UNSUBSCRIBE_IN_PROGRESS, clientState);
00240     if(AWS_SUCCESS == unsubRc && AWS_SUCCESS != rc) {
00241         unsubRc = rc;
00242     }
00243 
00244     return unsubRc;
00245 }
00246 
00247 #ifdef __cplusplus
00248 }
00249 #endif
00250