int keepalive (Client *c) { int rc = FAILURE; if (c->keepAliveInterval == 0) { rc = SUCCESS; goto exit; } if (expired(&c->ping_timer)) { if (!c->ping_outstanding) { Timer timer; InitTimer (&timer); countdown_ms (&timer, 1000); int len = MQTTSerialize_pingreq (c->buf, c->buf_size); if (len > 0 && (rc = sendPacket(c, len, &timer)) == SUCCESS) // send the ping packet c->ping_outstanding = 1; } } exit: return 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) { aws_iot_mqtt_internal_send_packet(pClient, serialized_len, &timer); } /* 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); }
int MQTTUnsubscribe (Client *c, const char *topicFilter) { int rc = FAILURE; int len = 0; Timer timer; MQTTString topic = MQTTString_initializer; topic.cstring = (char*) topicFilter; InitTimer (&timer); countdown_ms (&timer, c->command_timeout_ms); if (!c->isconnected) goto exit; if ((len = MQTTSerialize_unsubscribe(c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topic)) <= 0) goto exit; if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet goto exit; // there was a problem if (waitfor(c, UNSUBACK, &timer) == UNSUBACK) { unsigned short mypacketid; // should be the same as the packetid above if (MQTTDeserialize_unsuback(&mypacketid, c->readbuf, c->readbuf_size) == 1) rc = 0; } else rc = FAILURE; // timed out - no UNSUBACK received exit: return rc; }
int MQTTSubscribe(Client* c, const char* topicFilter, enum QoS qos, messageHandler messageHandler, pApplicationHandler_t applicationHandler) { int rc = FAILURE; Timer timer; int len = 0; int indexOfFreemessageHandler; MQTTString topic = MQTTString_initializer; topic.cstring = (char *)topicFilter; unsigned char isMessageHandlerFree = 0; InitTimer(&timer); countdown_ms(&timer, c->command_timeout_ms); if (!c->isconnected) goto exit; len = MQTTSerialize_subscribe(c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topic, (int*)&qos); if (len <= 0) goto exit; for (indexOfFreemessageHandler = 0; indexOfFreemessageHandler < MAX_MESSAGE_HANDLERS; ++indexOfFreemessageHandler){ if (c->messageHandlers[indexOfFreemessageHandler].topicFilter == 0){ isMessageHandlerFree = 1; break; } } if(isMessageHandlerFree == 0){ goto exit; } if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet goto exit; // there was a problem if (waitfor(c, SUBACK, &timer) == SUBACK) // wait for suback { int count = 0, grantedQoS = -1; unsigned short mypacketid; if (MQTTDeserialize_suback(&mypacketid, 1, &count, &grantedQoS, c->readbuf, c->readbuf_size) == 1) rc = grantedQoS; // 0, 1, 2 or 0x80 if (rc != 0x80) { c->messageHandlers[indexOfFreemessageHandler].topicFilter = topicFilter; c->messageHandlers[indexOfFreemessageHandler].fp = messageHandler; c->messageHandlers[indexOfFreemessageHandler].applicationHandler = applicationHandler; rc = 0; } } else rc = FAILURE; exit: DeInitTimer(&timer); //STM : added this line return rc; }
int MQTTPublish(Client* c, const char* topicName, MQTTMessage* message) { int rc = FAILURE; Timer timer; MQTTString topic = MQTTString_initializer; topic.cstring = (char *)topicName; int len = 0; InitTimer(&timer); countdown_ms(&timer, c->command_timeout_ms); if (!c->isconnected) goto exit; if (message->qos == QOS1 || message->qos == QOS2) message->id = getNextPacketId(c); len = MQTTSerialize_publish(c->buf, c->buf_size, 0, message->qos, message->retained, message->id, topic, (unsigned char*)message->payload, message->payloadlen); if (len <= 0) goto exit; if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the publish packet goto exit; // there was a problem if (message->qos == QOS1) { if (waitfor(c, PUBACK, &timer) == PUBACK) { unsigned short mypacketid; unsigned char dup, type; if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1) rc = FAILURE; } else rc = FAILURE; } else if (message->qos == QOS2) { if (waitfor(c, PUBCOMP, &timer) == PUBCOMP) { unsigned short mypacketid; unsigned char dup, type; if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1) rc = FAILURE; } else rc = FAILURE; } exit: DeInitTimer(&timer); //STM: added this line return rc; }
int MQTTSubscribe (Client *c, const char *topicFilter, enum QoS qos, messageHandler messageHandler) { int i; int rc = FAILURE; Timer timer; int len = 0; MQTTString topic = MQTTString_initializer; topic.cstring = (char*) topicFilter; InitTimer (&timer); countdown_ms (&timer, c->command_timeout_ms); // default is 1 second timeouts if ( ! c->isconnected) goto exit; len = MQTTSerialize_subscribe (c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topic, (int*) &qos); if (len <= 0) goto exit; if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet goto exit; // there was a problem if (waitfor(c, SUBACK, &timer) == SUBACK) // wait for suback { int count = 0, grantedQoS = -1; unsigned short mypacketid; if (MQTTDeserialize_suback(&mypacketid, 1, &count, &grantedQoS, c->readbuf, c->readbuf_size) == 1) rc = grantedQoS; // will be 0, 1, 2 or 0x80 if (rc != 0x80) { for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) { if (c->messageHandlers[i].topicFilter == 0) { c->messageHandlers[i].topicFilter = topicFilter; c->messageHandlers[i].fp = messageHandler; rc = 0; // denote success break; } } } } else rc = FAILURE; // timed out - no SUBACK received exit: return rc; }
/** * @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(AWS_SUCCESS != rc) { FUNC_EXIT_RC(rc); } /* send the subscribe packet */ rc = aws_iot_mqtt_internal_send_packet(pClient, len, &timer); if(AWS_SUCCESS != rc) { FUNC_EXIT_RC(rc); } /* wait for suback */ rc = aws_iot_mqtt_internal_wait_for_read(pClient, SUBACK, &timer); if(AWS_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(AWS_SUCCESS != rc) { FUNC_EXIT_RC(rc); } } FUNC_EXIT_RC(AWS_SUCCESS); }
int MQTTConnect (Client *c, MQTTPacket_connectData *options) { Timer connect_timer; int rc = FAILURE; int len = 0; MQTTPacket_connectData default_options = MQTTPacket_connectData_initializer; InitTimer (&connect_timer); countdown_ms (&connect_timer, c->command_timeout_ms); if (c->isconnected) // don't send connect packet again if we are already connected goto exit; if (options == 0) options = &default_options; // set default options if none were supplied c->keepAliveInterval = options->keepAliveInterval; countdown (&c->ping_timer, c->keepAliveInterval); //-------------------------------------------------------------------- // Generate a MQTT "Connect" packet, and send it to the remote Broker //-------------------------------------------------------------------- len = MQTTSerialize_connect (c->buf, c->buf_size, options); if (len <= 0) goto exit; // supplied buffer is too small rc = sendPacket (c, len, &connect_timer); // send the connect packet if (rc != SUCCESS) goto exit; // there was a problem //-------------------------------------------------------------------- // Wait for and read in the MQTT "ConnAck" reply packet. //-------------------------------------------------------------------- // this will be a blocking call, wait for the connack if (waitfor(c, CONNACK, &connect_timer) == CONNACK) { unsigned char connack_rc = 255; char sessionPresent = 0; if (MQTTDeserialize_connack((unsigned char*) &sessionPresent, &connack_rc, c->readbuf, c->readbuf_size) == 1) rc = connack_rc; else rc = FAILURE; } else rc = FAILURE; exit: if (rc == SUCCESS) c->isconnected = 1; return rc; }
int MQTTDisconnect(Client* c) { int rc = FAILURE; Timer timer; // we might wait for incomplete incoming publishes to complete int len = MQTTSerialize_disconnect(c->buf, c->buf_size); InitTimer(&timer); countdown_ms(&timer, c->command_timeout_ms); if (len > 0) rc = sendPacket(c, len, &timer); // send the disconnect packet c->isconnected = 0; return rc; }
int keepalive(Client* c) { int rc = FAILURE; if (c->keepAliveInterval == 0) { return SUCCESS; } if (expired(&c->ping_timer)) { if (!c->ping_outstanding) { // there is not a ping outstanding - send one Timer timer; InitTimer(&timer); countdown_ms(&timer, 2000); //STM: modified the value from 1000 to 2000 int len = MQTTSerialize_pingreq(c->buf, c->buf_size); INFO("-->keepalive"); rc = sendPacket(c, len, &timer); // send the ping packet DeInitTimer(&timer); //STM: added this line if (len > 0 && rc == SUCCESS) { c->ping_outstanding = 1; // start a timer to wait for PINGRESP from server countdown(&c->ping_timer, c->keepAliveInterval / 2); } else { rc = FAILURE; } } else { // timer expired while waiting for a ping - decide we are disconnected MQTTDisconnect(c); if (c->disconnectHandler != NULL) { c->disconnectHandler(); } } } else { rc = SUCCESS; } return rc; }
int MQTTConnect(Client* c, MQTTPacket_connectData* options) { Timer connect_timer; int rc = FAILURE; MQTTPacket_connectData default_options = MQTTPacket_connectData_initializer; int len = 0; InitTimer(&connect_timer); countdown_ms(&connect_timer, c->command_timeout_ms); if (c->isconnected) // don't send connect packet again if we are already connected goto exit; if (options == 0) options = &default_options; // set default options if none were supplied c->keepAliveInterval = options->keepAliveInterval; countdown(&c->ping_timer, c->keepAliveInterval); if ((len = MQTTSerialize_connect(c->buf, c->buf_size, options)) <= 0) goto exit; if ((rc = sendPacket(c, len, &connect_timer)) != SUCCESS) // send the connect packet goto exit; // there was a problem // this will be a blocking call, wait for the connack if (waitfor(c, CONNACK, &connect_timer) == CONNACK) { unsigned char connack_rc = 255; char sessionPresent = 0; if (MQTTDeserialize_connack((unsigned char*)&sessionPresent, &connack_rc, c->readbuf, c->readbuf_size) == 1) rc = connack_rc; else rc = FAILURE; } else rc = FAILURE; exit: if (rc == SUCCESS) c->isconnected = 1; DeInitTimer(&connect_timer); //STM: added this line of code return rc; }
int MQTTYield(Client* c, int timeout_ms) { int rc = SUCCESS; Timer timer; InitTimer(&timer); countdown_ms(&timer, timeout_ms); while (!expired(&timer)) { if (cycle(c, &timer) == FAILURE) { rc = FAILURE; break; } } return rc; }
int MQTTYield (Client *c, int timeout_ms) { int rc = SUCCESS; Timer timer; InitTimer (&timer); countdown_ms (&timer, timeout_ms); while ( ! expired(&timer)) { if (cycle(c, &timer) == FAILURE) // see if any MQTT packets were received { rc = FAILURE; // no packets were received this pass break; } } return rc; }
// Network Headers & Variables & Functions int s7g2_read(Network* n, unsigned char* buffer, int len, int timeout_ms) { ULONG copied_idx = 0; Timer t; countdown_ms(&t , timeout_ms); while(len != 0){ ULONG left_len; ULONG recv_len = 0; ULONG bytes_copied = 0; if(prepend_offset == 0){ nx_tcp_socket_receive(&n->my_socket, &read_packet_ptr, timeout_ms); } nx_packet_length_get(read_packet_ptr, &recv_len); left_len = recv_len - prepend_offset; if(recv_len == 0){ if(expired(&t))break; } if( left_len >= len ) { nx_packet_data_extract_offset(read_packet_ptr, prepend_offset, &buffer[copied_idx], len, &bytes_copied); if( left_len == bytes_copied ){ prepend_offset = 0; nx_packet_release(read_packet_ptr); read_packet_ptr = NULL; } else { prepend_offset += bytes_copied; } } else { nx_packet_data_extract_offset(read_packet_ptr, prepend_offset, &buffer[copied_idx], left_len, &bytes_copied); prepend_offset = 0; nx_packet_release(read_packet_ptr); read_packet_ptr = NULL; } len -= bytes_copied; copied_idx += bytes_copied; } return copied_idx; }
int MQTTUnsubscribe(Client* c, const char* topicFilter) { int rc = FAILURE; Timer timer; MQTTString topic = MQTTString_initializer; topic.cstring = (char *)topicFilter; int len = 0; int i=0; InitTimer(&timer); countdown_ms(&timer, c->command_timeout_ms); if (!c->isconnected) goto exit; if ((len = MQTTSerialize_unsubscribe(c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topic)) <= 0) goto exit; if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the unsubscribe packet goto exit; // there was a problem if (waitfor(c, UNSUBACK, &timer) == UNSUBACK) { unsigned short mypacketid; // should be the same as the packetid above if (MQTTDeserialize_unsuback(&mypacketid, c->readbuf, c->readbuf_size) == 1){ for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i){ if (c->messageHandlers[i].topicFilter != 0 && (strcmp(c->messageHandlers[i].topicFilter, topicFilter)==0)){ c->messageHandlers[i].topicFilter = 0; // We dont want to break here, if the same topic is registered with 2 callbacks. Unlikeley scenario. } } rc = 0; } } else rc = FAILURE; exit: DeInitTimer(&timer); //STM: added this line return rc; }
/** * * @brief MQTT Paho client read interface * * @param n pointer to the Network stucture * @param buffer buffer to read into * @param length number of bytes to into * @timeout timeout_ms timeout * * @return Number of by bytes read * * \NOMANUAL */ int mqtt_read(Network* n, unsigned char* buffer, int length, int timeout_ms) { int availableBytes; int count; Timer t; EthernetClient* client = (EthernetClient*)n->client; InitTimer(&t); countdown_ms(&t, timeout_ms); // try to do stuff until timer expires while (!(availableBytes = client->available()) && (!expired(&t))); count = (length < availableBytes) ? length : availableBytes; for (int i = 0; i < count; i++) { buffer[i] = (unsigned char)client->read(); } return count; }
int MQTTYield(Client* c, int timeout_ms) { int rc = SUCCESS; Timer timer; if (!c->isconnected) { return FAILURE; } InitTimer(&timer); countdown_ms(&timer, timeout_ms); while (!expired(&timer)) { if (cycle(c, &timer) == FAILURE) { rc = FAILURE; break; } } DeInitTimer(&timer); //STM: added this line return rc; }
/** * * @brief Starts a timer countdown by a timeeout in seconds; used by MQTT Client and this glue logic * * @param timer pointer to the timer to start. * @param timeout the timeout value in seconds. * * \NOMANUAL */ void countdown(Timer* timer, unsigned int timeout) { countdown_ms(timer, timeout*1000); }
/** * @brief Create a timer (seconds) * * 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 */ void countdown(Timer* timer, unsigned int time_s) { // printf("++ countdown\r\n"); countdown_ms(timer, time_s * 1000); }
/** * * @param seconds */ void countdown(int seconds) { countdown_ms((unsigned long)seconds * 1000L); }
/** * * @param ms */ countdown_t(int ms) { countdown_ms(ms); }
void countdown_sec(Timer *timer, uint32_t timeout) { countdown_ms(timer, timeout*1000); }
Countdown(int ms) { countdown_ms(ms); }
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}; Timer packetTimer; init_timer(&packetTimer); countdown_ms(&packetTimer, pClient->clientData.packetTimeoutMs); 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; } else if(AWS_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(AWS_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(AWS_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 && AWS_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(AWS_SUCCESS != rc || read_len != rem_len) { return AWS_FAILURE; } } header.byte = pClient->clientData.readBuf[0]; *pPacketType = header.bits.type; FUNC_EXIT_RC(rc); }
/** * @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; 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); } init_timer(&connect_timer); countdown_ms(&connect_timer, pClient->clientData.commandTimeoutMs); 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(rc); } /* 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 = false; countdown_sec(&pClient->pingTimer, pClient->clientData.keepAliveInterval); 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 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(AWS_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(AWS_SUCCESS != rc) { FUNC_EXIT_RC(rc); } /* wait for suback */ rc = aws_iot_mqtt_internal_wait_for_read(pClient, SUBACK, &timer); if(AWS_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(AWS_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(AWS_SUCCESS); }