Changes to enabled on-line compiler

Committer:
JMF
Date:
Wed May 30 20:59:51 2018 +0000
Revision:
0:082731ede69f
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
JMF 0:082731ede69f 1 /*
JMF 0:082731ede69f 2 * Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
JMF 0:082731ede69f 3 *
JMF 0:082731ede69f 4 * Licensed under the Apache License, Version 2.0 (the "License").
JMF 0:082731ede69f 5 * You may not use this file except in compliance with the License.
JMF 0:082731ede69f 6 * A copy of the License is located at
JMF 0:082731ede69f 7 *
JMF 0:082731ede69f 8 * http://aws.amazon.com/apache2.0
JMF 0:082731ede69f 9 *
JMF 0:082731ede69f 10 * or in the "license" file accompanying this file. This file is distributed
JMF 0:082731ede69f 11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
JMF 0:082731ede69f 12 * express or implied. See the License for the specific language governing
JMF 0:082731ede69f 13 * permissions and limitations under the License.
JMF 0:082731ede69f 14 */
JMF 0:082731ede69f 15
JMF 0:082731ede69f 16 // Based on Eclipse Paho.
JMF 0:082731ede69f 17 /*******************************************************************************
JMF 0:082731ede69f 18 * Copyright (c) 2014 IBM Corp.
JMF 0:082731ede69f 19 *
JMF 0:082731ede69f 20 * All rights reserved. This program and the accompanying materials
JMF 0:082731ede69f 21 * are made available under the terms of the Eclipse Public License v1.0
JMF 0:082731ede69f 22 * and Eclipse Distribution License v1.0 which accompany this distribution.
JMF 0:082731ede69f 23 *
JMF 0:082731ede69f 24 * The Eclipse Public License is available at
JMF 0:082731ede69f 25 * http://www.eclipse.org/legal/epl-v10.html
JMF 0:082731ede69f 26 * and the Eclipse Distribution License is available at
JMF 0:082731ede69f 27 * http://www.eclipse.org/org/documents/edl-v10.php.
JMF 0:082731ede69f 28 *
JMF 0:082731ede69f 29 * Contributors:
JMF 0:082731ede69f 30 * Ian Craggs - initial API and implementation and/or initial documentation
JMF 0:082731ede69f 31 *******************************************************************************/
JMF 0:082731ede69f 32
JMF 0:082731ede69f 33 /**
JMF 0:082731ede69f 34 * @file aws_iot_mqtt_client_unsubscribe.c
JMF 0:082731ede69f 35 * @brief MQTT client unsubscribe API definitions
JMF 0:082731ede69f 36 */
JMF 0:082731ede69f 37
JMF 0:082731ede69f 38 #ifdef __cplusplus
JMF 0:082731ede69f 39 extern "C" {
JMF 0:082731ede69f 40 #endif
JMF 0:082731ede69f 41
JMF 0:082731ede69f 42 #include "aws_iot_mqtt_client_common_internal.h"
JMF 0:082731ede69f 43
JMF 0:082731ede69f 44 /**
JMF 0:082731ede69f 45 * Serializes the supplied unsubscribe data into the supplied buffer, ready for sending
JMF 0:082731ede69f 46 * @param pTxBuf the raw buffer data, of the correct length determined by the remaining length field
JMF 0:082731ede69f 47 * @param txBufLen the length in bytes of the data in the supplied buffer
JMF 0:082731ede69f 48 * @param dup integer - the MQTT dup flag
JMF 0:082731ede69f 49 * @param packetId integer - the MQTT packet identifier
JMF 0:082731ede69f 50 * @param count - number of members in the topicFilters array
JMF 0:082731ede69f 51 * @param pTopicNameList - array of topic filter names
JMF 0:082731ede69f 52 * @param pTopicNameLenList - array of length of topic filter names in pTopicNameList
JMF 0:082731ede69f 53 * @param pSerializedLen - the length of the serialized data
JMF 0:082731ede69f 54 * @return IoT_Error_t indicating function execution status
JMF 0:082731ede69f 55 */
JMF 0:082731ede69f 56 static IoT_Error_t _aws_iot_mqtt_serialize_unsubscribe(unsigned char *pTxBuf, size_t txBufLen,
JMF 0:082731ede69f 57 uint8_t dup, uint16_t packetId,
JMF 0:082731ede69f 58 uint32_t count, const char **pTopicNameList,
JMF 0:082731ede69f 59 uint16_t *pTopicNameLenList, uint32_t *pSerializedLen) {
JMF 0:082731ede69f 60 unsigned char *ptr = pTxBuf;
JMF 0:082731ede69f 61 uint32_t i = 0;
JMF 0:082731ede69f 62 uint32_t rem_len = 2; /* packetId */
JMF 0:082731ede69f 63 IoT_Error_t rc;
JMF 0:082731ede69f 64 MQTTHeader header = {0};
JMF 0:082731ede69f 65
JMF 0:082731ede69f 66 FUNC_ENTRY;
JMF 0:082731ede69f 67
JMF 0:082731ede69f 68 for(i = 0; i < count; ++i) {
JMF 0:082731ede69f 69 rem_len += (uint32_t) (pTopicNameLenList[i] + 2); /* topic + length */
JMF 0:082731ede69f 70 }
JMF 0:082731ede69f 71
JMF 0:082731ede69f 72 if(aws_iot_mqtt_internal_get_final_packet_length_from_remaining_length(rem_len) > txBufLen) {
JMF 0:082731ede69f 73 FUNC_EXIT_RC(MQTT_TX_BUFFER_TOO_SHORT_ERROR);
JMF 0:082731ede69f 74 }
JMF 0:082731ede69f 75
JMF 0:082731ede69f 76 rc = aws_iot_mqtt_internal_init_header(&header, UNSUBSCRIBE, QOS1, dup, 0);
JMF 0:082731ede69f 77 if(AWS_SUCCESS != rc) {
JMF 0:082731ede69f 78 FUNC_EXIT_RC(rc);
JMF 0:082731ede69f 79 }
JMF 0:082731ede69f 80 aws_iot_mqtt_internal_write_char(&ptr, header.byte); /* write header */
JMF 0:082731ede69f 81
JMF 0:082731ede69f 82 ptr += aws_iot_mqtt_internal_write_len_to_buffer(ptr, rem_len); /* write remaining length */
JMF 0:082731ede69f 83
JMF 0:082731ede69f 84 aws_iot_mqtt_internal_write_uint_16(&ptr, packetId);
JMF 0:082731ede69f 85
JMF 0:082731ede69f 86 for(i = 0; i < count; ++i) {
JMF 0:082731ede69f 87 aws_iot_mqtt_internal_write_utf8_string(&ptr, pTopicNameList[i], pTopicNameLenList[i]);
JMF 0:082731ede69f 88 }
JMF 0:082731ede69f 89
JMF 0:082731ede69f 90 *pSerializedLen = (uint32_t) (ptr - pTxBuf);
JMF 0:082731ede69f 91
JMF 0:082731ede69f 92 FUNC_EXIT_RC(AWS_SUCCESS);
JMF 0:082731ede69f 93 }
JMF 0:082731ede69f 94
JMF 0:082731ede69f 95
JMF 0:082731ede69f 96 /**
JMF 0:082731ede69f 97 * Deserializes the supplied (wire) buffer into unsuback data
JMF 0:082731ede69f 98 * @param pPacketId returned integer - the MQTT packet identifier
JMF 0:082731ede69f 99 * @param pRxBuf the raw buffer data, of the correct length determined by the remaining length field
JMF 0:082731ede69f 100 * @param rxBufLen the length in bytes of the data in the supplied buffer
JMF 0:082731ede69f 101 * @return IoT_Error_t indicating function execution status
JMF 0:082731ede69f 102 */
JMF 0:082731ede69f 103 static IoT_Error_t _aws_iot_mqtt_deserialize_unsuback(uint16_t *pPacketId, unsigned char *pRxBuf, size_t rxBufLen) {
JMF 0:082731ede69f 104 unsigned char type = 0;
JMF 0:082731ede69f 105 unsigned char dup = 0;
JMF 0:082731ede69f 106 IoT_Error_t rc;
JMF 0:082731ede69f 107
JMF 0:082731ede69f 108 FUNC_ENTRY;
JMF 0:082731ede69f 109
JMF 0:082731ede69f 110 rc = aws_iot_mqtt_internal_deserialize_ack(&type, &dup, pPacketId, pRxBuf, rxBufLen);
JMF 0:082731ede69f 111 if(AWS_SUCCESS == rc && UNSUBACK != type) {
JMF 0:082731ede69f 112 rc = FAILURE;
JMF 0:082731ede69f 113 }
JMF 0:082731ede69f 114
JMF 0:082731ede69f 115 FUNC_EXIT_RC(rc);
JMF 0:082731ede69f 116 }
JMF 0:082731ede69f 117
JMF 0:082731ede69f 118 /**
JMF 0:082731ede69f 119 * @brief Unsubscribe to an MQTT topic.
JMF 0:082731ede69f 120 *
JMF 0:082731ede69f 121 * Called to send an unsubscribe message to the broker requesting removal of a subscription
JMF 0:082731ede69f 122 * to an MQTT topic.
JMF 0:082731ede69f 123 * @note Call is blocking. The call returns after the receipt of the UNSUBACK control packet.
JMF 0:082731ede69f 124 * This is the internal function which is called by the unsubscribe API to perform the operation.
JMF 0:082731ede69f 125 * Not meant to be called directly as it doesn't do validations or client state changes
JMF 0:082731ede69f 126 *
JMF 0:082731ede69f 127 * @param pClient Reference to the IoT Client
JMF 0:082731ede69f 128 * @param pTopicName Topic Name to publish to
JMF 0:082731ede69f 129 * @param topicNameLen Length of the topic name
JMF 0:082731ede69f 130 *
JMF 0:082731ede69f 131 * @return An IoT Error Type defining successful/failed unsubscribe call
JMF 0:082731ede69f 132 */
JMF 0:082731ede69f 133 static IoT_Error_t _aws_iot_mqtt_internal_unsubscribe(AWS_IoT_Client *pClient, const char *pTopicFilter,
JMF 0:082731ede69f 134 uint16_t topicFilterLen) {
JMF 0:082731ede69f 135 /* No NULL checks because this is a static internal function */
JMF 0:082731ede69f 136
JMF 0:082731ede69f 137 awsTimer timer;
JMF 0:082731ede69f 138
JMF 0:082731ede69f 139 uint16_t packet_id;
JMF 0:082731ede69f 140 uint32_t serializedLen = 0;
JMF 0:082731ede69f 141 uint32_t i = 0;
JMF 0:082731ede69f 142 IoT_Error_t rc;
JMF 0:082731ede69f 143 bool subscriptionExists = false;
JMF 0:082731ede69f 144
JMF 0:082731ede69f 145 FUNC_ENTRY;
JMF 0:082731ede69f 146
JMF 0:082731ede69f 147 /* Remove from message handler array */
JMF 0:082731ede69f 148 for(i = 0; i < AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS; ++i) {
JMF 0:082731ede69f 149 if(pClient->clientData.messageHandlers[i].topicName != NULL &&
JMF 0:082731ede69f 150 (strcmp(pClient->clientData.messageHandlers[i].topicName, pTopicFilter) == 0)) {
JMF 0:082731ede69f 151 subscriptionExists = true;
JMF 0:082731ede69f 152 break;
JMF 0:082731ede69f 153 }
JMF 0:082731ede69f 154 }
JMF 0:082731ede69f 155
JMF 0:082731ede69f 156 if(false == subscriptionExists) {
JMF 0:082731ede69f 157 FUNC_EXIT_RC(FAILURE);
JMF 0:082731ede69f 158 }
JMF 0:082731ede69f 159
JMF 0:082731ede69f 160 init_timer(&timer);
JMF 0:082731ede69f 161 countdown_ms(&timer, pClient->clientData.commandTimeoutMs);
JMF 0:082731ede69f 162
JMF 0:082731ede69f 163 rc = _aws_iot_mqtt_serialize_unsubscribe(pClient->clientData.writeBuf, pClient->clientData.writeBufSize, 0,
JMF 0:082731ede69f 164 aws_iot_mqtt_get_next_packet_id(pClient), 1, &pTopicFilter,
JMF 0:082731ede69f 165 &topicFilterLen, &serializedLen);
JMF 0:082731ede69f 166 if(AWS_SUCCESS != rc) {
JMF 0:082731ede69f 167 FUNC_EXIT_RC(rc);
JMF 0:082731ede69f 168 }
JMF 0:082731ede69f 169
JMF 0:082731ede69f 170 /* send the unsubscribe packet */
JMF 0:082731ede69f 171 rc = aws_iot_mqtt_internal_send_packet(pClient, serializedLen, &timer);
JMF 0:082731ede69f 172 if(AWS_SUCCESS != rc) {
JMF 0:082731ede69f 173 FUNC_EXIT_RC(rc);
JMF 0:082731ede69f 174 }
JMF 0:082731ede69f 175
JMF 0:082731ede69f 176 rc = aws_iot_mqtt_internal_wait_for_read(pClient, UNSUBACK, &timer);
JMF 0:082731ede69f 177 if(AWS_SUCCESS != rc) {
JMF 0:082731ede69f 178 FUNC_EXIT_RC(rc);
JMF 0:082731ede69f 179 }
JMF 0:082731ede69f 180
JMF 0:082731ede69f 181 rc = _aws_iot_mqtt_deserialize_unsuback(&packet_id, pClient->clientData.readBuf, pClient->clientData.readBufSize);
JMF 0:082731ede69f 182 if(AWS_SUCCESS != rc) {
JMF 0:082731ede69f 183 FUNC_EXIT_RC(rc);
JMF 0:082731ede69f 184 }
JMF 0:082731ede69f 185
JMF 0:082731ede69f 186 /* Remove from message handler array */
JMF 0:082731ede69f 187 for(i = 0; i < AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS; ++i) {
JMF 0:082731ede69f 188 if(pClient->clientData.messageHandlers[i].topicName != NULL &&
JMF 0:082731ede69f 189 (strcmp(pClient->clientData.messageHandlers[i].topicName, pTopicFilter) == 0)) {
JMF 0:082731ede69f 190 pClient->clientData.messageHandlers[i].topicName = NULL;
JMF 0:082731ede69f 191 /* We don't want to break here, in case the same topic is registered
JMF 0:082731ede69f 192 * with 2 callbacks. Unlikely scenario */
JMF 0:082731ede69f 193 }
JMF 0:082731ede69f 194 }
JMF 0:082731ede69f 195
JMF 0:082731ede69f 196 FUNC_EXIT_RC(AWS_SUCCESS);
JMF 0:082731ede69f 197 }
JMF 0:082731ede69f 198
JMF 0:082731ede69f 199 /**
JMF 0:082731ede69f 200 * @brief Unsubscribe to an MQTT topic.
JMF 0:082731ede69f 201 *
JMF 0:082731ede69f 202 * Called to send an unsubscribe message to the broker requesting removal of a subscription
JMF 0:082731ede69f 203 * to an MQTT topic.
JMF 0:082731ede69f 204 * @note Call is blocking. The call returns after the receipt of the UNSUBACK control packet.
JMF 0:082731ede69f 205 * This is the outer function which does the validations and calls the internal unsubscribe above
JMF 0:082731ede69f 206 * to perform the actual operation. It is also responsible for client state changes
JMF 0:082731ede69f 207 *
JMF 0:082731ede69f 208 * @param pClient Reference to the IoT Client
JMF 0:082731ede69f 209 * @param pTopicName Topic Name to publish to
JMF 0:082731ede69f 210 * @param topicNameLen Length of the topic name
JMF 0:082731ede69f 211 *
JMF 0:082731ede69f 212 * @return An IoT Error Type defining successful/failed unsubscribe call
JMF 0:082731ede69f 213 */
JMF 0:082731ede69f 214 IoT_Error_t aws_iot_mqtt_unsubscribe(AWS_IoT_Client *pClient, const char *pTopicFilter, uint16_t topicFilterLen) {
JMF 0:082731ede69f 215 IoT_Error_t rc, unsubRc;
JMF 0:082731ede69f 216 ClientState clientState;
JMF 0:082731ede69f 217
JMF 0:082731ede69f 218 if(NULL == pClient || NULL == pTopicFilter) {
JMF 0:082731ede69f 219 return NULL_VALUE_ERROR;
JMF 0:082731ede69f 220 }
JMF 0:082731ede69f 221
JMF 0:082731ede69f 222 if(!aws_iot_mqtt_is_client_connected(pClient)) {
JMF 0:082731ede69f 223 return NETWORK_DISCONNECTED_ERROR;
JMF 0:082731ede69f 224 }
JMF 0:082731ede69f 225
JMF 0:082731ede69f 226 clientState = aws_iot_mqtt_get_client_state(pClient);
JMF 0:082731ede69f 227 if(CLIENT_STATE_CONNECTED_IDLE != clientState && CLIENT_STATE_CONNECTED_WAIT_FOR_CB_RETURN != clientState) {
JMF 0:082731ede69f 228 return MQTT_CLIENT_NOT_IDLE_ERROR;
JMF 0:082731ede69f 229 }
JMF 0:082731ede69f 230
JMF 0:082731ede69f 231 rc = aws_iot_mqtt_set_client_state(pClient, clientState, CLIENT_STATE_CONNECTED_UNSUBSCRIBE_IN_PROGRESS);
JMF 0:082731ede69f 232 if(AWS_SUCCESS != rc) {
JMF 0:082731ede69f 233 rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_UNSUBSCRIBE_IN_PROGRESS, clientState);
JMF 0:082731ede69f 234 return rc;
JMF 0:082731ede69f 235 }
JMF 0:082731ede69f 236
JMF 0:082731ede69f 237 unsubRc = _aws_iot_mqtt_internal_unsubscribe(pClient, pTopicFilter, topicFilterLen);
JMF 0:082731ede69f 238
JMF 0:082731ede69f 239 rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_UNSUBSCRIBE_IN_PROGRESS, clientState);
JMF 0:082731ede69f 240 if(AWS_SUCCESS == unsubRc && AWS_SUCCESS != rc) {
JMF 0:082731ede69f 241 unsubRc = rc;
JMF 0:082731ede69f 242 }
JMF 0:082731ede69f 243
JMF 0:082731ede69f 244 return unsubRc;
JMF 0:082731ede69f 245 }
JMF 0:082731ede69f 246
JMF 0:082731ede69f 247 #ifdef __cplusplus
JMF 0:082731ede69f 248 }
JMF 0:082731ede69f 249 #endif
JMF 0:082731ede69f 250