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};

	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;
	}

	len = 1;

	/* 2. read the remaining length.  This is variable in itself */
	rc = _aws_iot_mqtt_internal_decode_packet_remaining_len(pClient, &rem_len, pTimer);
	if(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(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 && 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(SUCCESS != rc || read_len != rem_len) {
			return FAILURE;
		}
	}

	header.byte = pClient->clientData.readBuf[0];
	*pPacketType = header.bits.type;

	FUNC_EXIT_RC(rc);
}
/**
  * Serializes a 0-length packet into the supplied buffer, ready for writing to a socket
  * @param buf the buffer into which the packet will be serialized
  * @param buflen the length in bytes of the supplied buffer, to avoid overruns
  * @param packettype the message type
  * @param serialized length
  * @return IoT_Error_t indicating function execution status
  */
IoT_Error_t aws_iot_mqtt_internal_serialize_zero(unsigned char *pTxBuf, size_t txBufLen, MessageTypes packetType,
												 size_t *pSerializedLength) {
	unsigned char *ptr;
	IoT_Error_t rc;
	MQTTHeader header = {0};

	FUNC_ENTRY;
	if(NULL == pTxBuf || NULL == pSerializedLength) {
		FUNC_EXIT_RC(NULL_VALUE_ERROR);
	}

	/* Buffer should have at least 2 bytes for the header */
	if(4 > txBufLen) {
		FUNC_EXIT_RC(MQTT_TX_BUFFER_TOO_SHORT_ERROR);
	}

	ptr = pTxBuf;

	rc = aws_iot_mqtt_internal_init_header(&header, packetType, QOS0, 0, 0);
	if(SUCCESS != rc) {
		FUNC_EXIT_RC(rc);
	}

	/* write header */
	aws_iot_mqtt_internal_write_char(&ptr, header.byte);

	/* write remaining length */
	ptr += aws_iot_mqtt_internal_write_len_to_buffer(ptr, 0);
	*pSerializedLength = (uint32_t) (ptr - pTxBuf);

	FUNC_EXIT_RC(SUCCESS);
}
/**
  * Serializes the supplied subscribe data into the supplied buffer, ready for sending
  * @param pTxBuf the buffer into which the packet will be serialized
  * @param txBufLen the length in bytes of the supplied buffer
  * @param dup unsigned char - the MQTT dup flag
  * @param packetId uint16_t - the MQTT packet identifier
  * @param topicCount - number of members in the topicFilters and reqQos arrays
  * @param pTopicNameList - array of topic filter names
  * @param pTopicNameLenList - array of length of topic filter names
  * @param pRequestedQoSs - array of requested QoS
  * @param pSerializedLen - the length of the serialized data
  *
  * @return An IoT Error Type defining successful/failed operation
  */
static IoT_Error_t _aws_iot_mqtt_serialize_subscribe(unsigned char *pTxBuf, size_t txBufLen,
													 unsigned char dup, uint16_t packetId, uint32_t topicCount,
													 const char **pTopicNameList, uint16_t *pTopicNameLenList,
													 QoS *pRequestedQoSs, uint32_t *pSerializedLen) {
	unsigned char *ptr;
	uint32_t itr, rem_len;
	IoT_Error_t rc;
	MQTTHeader header = {0};

	FUNC_ENTRY;
	if(NULL == pTxBuf || NULL == pSerializedLen) {
		FUNC_EXIT_RC(NULL_VALUE_ERROR);
	}

	ptr = pTxBuf;
	rem_len = 2; /* packetId */

	for(itr = 0; itr < topicCount; ++itr) {
		rem_len += (uint32_t) (pTopicNameLenList[itr] + 2 + 1); /* topic + length + req_qos */
	}

	if(aws_iot_mqtt_internal_get_final_packet_length_from_remaining_length(rem_len) > txBufLen) {
		FUNC_EXIT_RC(MQTT_TX_BUFFER_TOO_SHORT_ERROR);
	}

	rc = aws_iot_mqtt_internal_init_header(&header, SUBSCRIBE, QOS1, dup, 0);
	if(AWS_SUCCESS != rc) {
		FUNC_EXIT_RC(rc);
	}
	/* write header */
	aws_iot_mqtt_internal_write_char(&ptr, header.byte);

	/* write remaining length */
	ptr += aws_iot_mqtt_internal_write_len_to_buffer(ptr, rem_len);

	aws_iot_mqtt_internal_write_uint_16(&ptr, packetId);

	for(itr = 0; itr < topicCount; ++itr) {
		aws_iot_mqtt_internal_write_utf8_string(&ptr, pTopicNameList[itr], pTopicNameLenList[itr]);
		aws_iot_mqtt_internal_write_char(&ptr, (unsigned char) pRequestedQoSs[itr]);
	}

	*pSerializedLen = (uint32_t) (ptr - pTxBuf);

	FUNC_EXIT_RC(AWS_SUCCESS);
}
/**
  * Serializes the connect options into the buffer.
  * @param buf the buffer into which the packet will be serialized
  * @param len the length in bytes of the supplied buffer
  * @param options the options to be used to build the connect packet
  * @param serialized length
  * @return IoT_Error_t indicating function execution status
  */
static IoT_Error_t _aws_iot_mqtt_serialize_connect(unsigned char *pTxBuf, size_t txBufLen,
												   IoT_Client_Connect_Params *pConnectParams,
												   size_t *pSerializedLen) {
	unsigned char *ptr;
	uint32_t len;
	IoT_Error_t rc;
	MQTTHeader header = {0};
	MQTT_Connect_Header_Flags flags = {0};

	FUNC_ENTRY;

	if(NULL == pTxBuf || NULL == pConnectParams || NULL == pSerializedLen ||
	   (NULL == pConnectParams->pClientID && 0 != pConnectParams->clientIDLen) ||
	   (NULL != pConnectParams->pClientID && 0 == pConnectParams->clientIDLen)) {
		FUNC_EXIT_RC(NULL_VALUE_ERROR);
	}

	/* Check needed here before we start writing to the Tx buffer */
	switch(pConnectParams->MQTTVersion) {
		case MQTT_3_1_1:
			break;
		default:
			return MQTT_CONNACK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR;
	}

	ptr = pTxBuf;
	len = _aws_iot_get_connect_packet_length(pConnectParams);
	if(aws_iot_mqtt_internal_get_final_packet_length_from_remaining_length(len) > txBufLen) {
		FUNC_EXIT_RC(MQTT_TX_BUFFER_TOO_SHORT_ERROR);
	}

	rc = aws_iot_mqtt_internal_init_header(&header, CONNECT, QOS0, 0, 0);
	if(SUCCESS != rc) {
		FUNC_EXIT_RC(rc);
	}

	aws_iot_mqtt_internal_write_char(&ptr, header.byte); /* write header */

	ptr += aws_iot_mqtt_internal_write_len_to_buffer(ptr, len); /* write remaining length */

	// Enable if adding support for more versions
	//if(MQTT_3_1_1 == pConnectParams->MQTTVersion) {
	aws_iot_mqtt_internal_write_utf8_string(&ptr, "MQTT", 4);
	aws_iot_mqtt_internal_write_char(&ptr, (unsigned char) pConnectParams->MQTTVersion);
	//}

	flags.all = 0;
	flags.bits.cleansession = (pConnectParams->isCleanSession) ? 1 : 0;
	flags.bits.will = (pConnectParams->isWillMsgPresent) ? 1 : 0;
	if(flags.bits.will) {
		flags.bits.willQoS = pConnectParams->will.qos;
		flags.bits.willRetain = (pConnectParams->will.isRetained) ? 1 : 0;
	}

	if(pConnectParams->pUsername) {
		flags.bits.username = 1;
	}

	if(pConnectParams->pPassword) {
		flags.bits.password = 1;
	}

	aws_iot_mqtt_internal_write_char(&ptr, flags.all);
	aws_iot_mqtt_internal_write_uint_16(&ptr, pConnectParams->keepAliveIntervalInSec);

	/* If the code have passed the check for incorrect values above, no client id was passed as argument */
	if(NULL == pConnectParams->pClientID) {
		aws_iot_mqtt_internal_write_uint_16(&ptr, 0);
	} else {
		aws_iot_mqtt_internal_write_utf8_string(&ptr, pConnectParams->pClientID, pConnectParams->clientIDLen);
	}

	if(pConnectParams->isWillMsgPresent) {
		aws_iot_mqtt_internal_write_utf8_string(&ptr, pConnectParams->will.pTopicName,
												pConnectParams->will.topicNameLen);
		aws_iot_mqtt_internal_write_utf8_string(&ptr, pConnectParams->will.pMessage, pConnectParams->will.msgLen);
	}

	if(flags.bits.username) {
		aws_iot_mqtt_internal_write_utf8_string(&ptr, pConnectParams->pUsername, pConnectParams->usernameLen);
	}

	if(flags.bits.password) {
		aws_iot_mqtt_internal_write_utf8_string(&ptr, pConnectParams->pPassword, pConnectParams->passwordLen);
	}

	*pSerializedLen = (size_t) (ptr - pTxBuf);

	FUNC_EXIT_RC(SUCCESS);
}