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;
}
Exemple #9
0
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;
}
Exemple #12
0
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;
}
Exemple #14
0
// 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);
}
Exemple #20
0
 /**
  * 
  * @param seconds
  */
 void countdown(int seconds)
 {
     countdown_ms((unsigned long)seconds * 1000L);
 }
Exemple #21
0
 /**
  * 
  * @param ms
  */
 countdown_t(int ms)
 {
     countdown_ms(ms);   
 }
Exemple #22
0
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);
}