Update revision to use TI's mqtt and Freertos.

Dependencies:   mbed client server

Fork of cc3100_Test_mqtt_CM3 by David Fletcher

mqtt_V1/common/mqtt_common.h

Committer:
dflet
Date:
2015-09-03
Revision:
3:a8c249046181

File content as of revision 3:a8c249046181:

/******************************************************************************
*
*   Copyright (C) 2014 Texas Instruments Incorporated
*
*   All rights reserved. Property of Texas Instruments Incorporated.
*   Restricted rights to use, duplicate or disclose this code are
*   granted through contract.
*
*   The program may not be used without the written permission of
*   Texas Instruments Incorporated or against the terms and conditions
*   stipulated in the agreement under which this program has been supplied,
*   and under no circumstances can it be used with non-TI connectivity device.
*
******************************************************************************/

/*
  mqtt_common.h

  This module outlines the interfaces that are common to both client amd
  server components. The applications are not expected to utilize the
  services outlined in this module.
*/

#ifndef __MQTT_COMMON_H__
#define __MQTT_COMMON_H__

/** @file mqtt_common.h 
    This file incorporates constructs that are common to both client and server
    implementation. 

    The applications are not expected to utlize the routines made available in
    this module module. 

    @note the routines in this module do not check for availability and 
    correctness of the input parameters

    @warning The module is expected to under-go changes whilst incorporating
    support for the server. Therefore, it is suggested that applications do
    not rely on the services provided in this module.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#include "platform.h"

#ifdef __cplusplus
extern "C"
{
#endif

namespace mbed_mqtt {

#define MQTT_COMMON_VERSTR "1.1.1" /**< Version of Common LIB */

#define MIN(a, b) ((a > b)? b : a)

/** MQTT Message Types */
#define MQTT_CONNECT      0x01
#define MQTT_CONNACK      0x02
#define MQTT_PUBLISH      0x03
#define MQTT_PUBACK       0x04
#define MQTT_PUBREC       0x05
#define MQTT_PUBREL       0x06
#define MQTT_PUBCOMP      0x07
#define MQTT_SUBSCRIBE    0x08
#define MQTT_SUBACK       0x09
#define MQTT_UNSUBSCRIBE  0x0A
#define MQTT_UNSUBACK     0x0B
#define MQTT_PINGREQ      0x0C
#define MQTT_PINGRSP      0x0D
#define MQTT_DISCONNECT   0x0E

#define MAX_FH_LEN        0x05    /**< MAX Length of Fixed Header */

/** Max number of bytes in remaining length field */
#define MAX_REMLEN_BYTES  (MAX_FH_LEN - 1)  

#define MAKE_FH_BYTE1(msg_type,  flags) (uint8_t)((msg_type << 4) | flags)

#define MAKE_FH_FLAGS(bool_dup, enum_qos, bool_retain)                  \
        (uint8_t)(((bool_dup << 3) | (enum_qos << 1) | bool_retain) & 0xF)

#define QID_VMASK           0x3
#define QOS_VALUE(enum_qos) (uint8_t)(enum_qos & QID_VMASK)
#define QFL_VALUE           0x80  /**< QOS Failure value (SUBACK) */

#define DUP_FLAG_VAL(bool_val) (uint8_t)(bool_val << 3)

#define BOOL_RETAIN(fh_byte1)  ((fh_byte1 & 0x1)? true : false)
#define BOOL_DUP(fh_byte1)     ((fh_byte1 & 0x8)? true : false)
#define ENUM_QOS(fh_byte1)     (enum mqtt_qos)((fh_byte1 & 0x6) >> 1)

#define MSG_TYPE(fh_byte1)  (uint8_t)((fh_byte1 & 0xf0) >> 4)

static inline uint32_t buf_wr_nbytes(uint8_t *dst, const uint8_t *src, uint32_t n)
{
//        printf("buf_wr_nbytes\r\n");
        uint32_t c = n; 
        while(c--)
                *dst++ = *src++;

        return n;
}

static inline uint32_t buf_set(uint8_t *dst, uint8_t val, uint32_t n)
{
        uint32_t c = n; 
        while(c--)
                *dst++ = val;

        return n;
}

/** Writing 2 bytes entity in network byte order */
static inline uint32_t buf_wr_nbo_2B(uint8_t *buf, uint16_t val)
{
        buf[0] = (uint8_t)((val >> 8) & 0xFF); /* MSB */
        buf[1] = (uint8_t)((val)      & 0xFF); /* LSB */
        return 2;
}

/** Reading 2 bytes entity in network byte order */
static inline uint32_t buf_rd_nbo_2B(const uint8_t *buf, uint16_t *val)
{
        *val = (uint16_t)((buf[0] << 8) | (buf[1]));
        return 2;
}

/** @defgroup mqp_group MQTT Packet (MQP) Buffer structure
    The core construct to encapsulate, construct and process a message

    @{
*/
struct mqtt_packet {

        uint8_t                     msg_type;   /**< MQTT  Message  Type */
        uint8_t                     fh_byte1;   /**< Fixed Header: Byte1 */

        uint16_t                    msg_id;     /**< Msg transaction  ID */

        uint8_t                     n_refs;     /**< # users of this msg */
        uint8_t                     pad[3];

        uint8_t                     offset;     /**< Start of data index */
        uint8_t                     fh_len;     /**< Fix Header Length   */
        uint16_t                    vh_len;     /**< Var Header Length   */
        uint32_t                    pl_len;     /**< Pay Load   Length   */

        uint32_t                    private_;

        uint32_t                    maxlen;     /**< Maximum buffer size */
        uint8_t                    *buffer;     /**< The attached buffer */

        /** Method to free this packet to a particular pool */
        void                  (*free)(struct mqtt_packet *mqp);

        struct mqtt_packet    *next;
};

/** @} */

#define MQP_FHEADER_BUF(mqp)  (mqp->buffer + mqp->offset)
#define MQP_VHEADER_BUF(mqp)  (MQP_FHEADER_BUF(mqp) + mqp->fh_len)
#define MQP_PAYLOAD_BUF(mqp)  (MQP_VHEADER_BUF(mqp) + mqp->vh_len)

#define MQP_CONTENT_LEN(mqp)  (mqp->fh_len + mqp->vh_len + mqp->pl_len)
#define MQP_FREEBUF_LEN(mqp)  (mqp->maxlen - mqp->offset -      \
                               MQP_CONTENT_LEN(mqp))

#define MQP_FHEADER_VAL(mqp)  (mqp->fh_byte1)
#define MQP_FHEADER_MSG(mqp)  (MSG_TYPE(MQP_FHEADER_VAL(mqp)))
#define MQP_FHEADER_FLG(mqp)  (MSG_FLAGS(MQP_FHEADER_VAL(mqp)))

#define DEFINE_MQP_VEC(num_mqp, mqp_vec)                \
        static struct mqtt_packet mqp_vec[num_mqp];

#define DEFINE_MQP_BUF_VEC(num_mqp, mqp_vec, buf_len, buf_vec)        \
        DEFINE_MQP_VEC(num_mqp, mqp_vec);                             \
        static uint8_t buf_vec[num_mqp][buf_len];

/*---------------------------------------------------------------------
 * Heleper MACROS for PUBLISH-RX Message Processing
 *---------------------------------------------------------------------
 */

/** @defgroup rxpub_help_group Helper Macros for RX PUBLISH
    @{
*/

/** Yields pointer to topic content */
#define MQP_PUB_TOP_BUF(mqp) (MQP_VHEADER_BUF(mqp) + 2)

/** Length or size of topic content */
#define MQP_PUB_TOP_LEN(mqp) (mqp->vh_len - 2 - (mqp->msg_id? 2 : 0))

/** Yields pointer to payload data */
#define MQP_PUB_PAY_BUF(mqp) (mqp->pl_len? MQP_PAYLOAD_BUF(mqp) : NULL)

/** Length or size of payload data */
#define MQP_PUB_PAY_LEN(mqp) (mqp->pl_len)

/** @} */

/** @cond
    CONNECT Message Flags, as outined in the MQTT Specification
*/
#define WILL_RETAIN_VAL 0x20
#define WILL_CONFIG_VAL 0x04
#define CLEAN_START_VAL 0x02
#define USER_NAME_OPVAL 0x80
#define PASS_WORD_OPVAL 0x40
/**
    @endcond
*/

/** @cond
    CONNACK 8bit Return Code, as outlined in the MQTT Specification
*/
#define CONNACK_RC_REQ_ACCEPT   0x00
#define CONNACK_RC_BAD_PROTOV   0x01
#define CONNACK_RC_CLI_REJECT   0x02
#define CONNACK_RC_SVR_UNAVBL   0x03
#define CONNACK_RC_BAD_USRPWD   0x04
#define CONNACK_RC_NOT_AUTHED   0x05
/**
   @endcond
*/

/** @defgroup lib_err_group LIBRARY Generated Error Codes
    Library provides these codes as return values in several routines

    @{
*/
#define MQP_ERR_NETWORK   (-1)  /**< Problem in network (sock err) */
#define MQP_ERR_TIMEOUT   (-2)  /**< Net transaction has timed out */
#define MQP_ERR_NET_OPS   (-3)  /**< Platform Net Ops un-available */
#define MQP_ERR_FNPARAM   (-4)  /**< Invalid parameter(s) provided */
#define MQP_ERR_PKT_AVL   (-5)  /**< No pkts are available in pool */
#define MQP_ERR_PKT_LEN   (-6)  /**< Inadequate free buffer in pkt */
#define MQP_ERR_NOTCONN   (-7)  /**< Lib isn't CONNECTED to server */
#define MQP_ERR_BADCALL   (-8)  /**< Irrelevant call for LIB state */
#define MQP_ERR_CONTENT   (-9)  /**< MSG / Data content has errors */
#define MQP_ERR_LIBQUIT  (-10)  /**< Needs reboot library has quit */


#define MQP_ERR_NOT_DEF  (-32)  /**< Value other than defined ones */

/** @} */

/*---------------------------------------------------------------------
 * Common Operations
 *---------------------------------------------------------------------
 */

/** Free a MQTT Packet Buffer 
    Puts back the packet buffer in to the appropriate pool.
    
    @param[in] mqp packet buffer to be freed
    @return none
*/
void mqp_free(struct mqtt_packet *mqp);

/** Resets the attributes of MQTT Packet Holder to its init state
    Not all fields are reset - entities such as offset, n_refs in addition
    to buffer information are not updated.

    @param[in] mqp packet buffer to be reset
    @return none

    @see mqp_init
*/
void mqp_reset(struct mqtt_packet *mqp);

/** Initializes attributes of the MQTT Packet Holder.
    This routine sets number of users of the MQTT Packet Holder to 1. However,
    it leaves, if already provisioned, the reference to buffer and its size
    un-altered.

    @param[in] mqp packet buffer to be initialized
    @param[in] offset index in buffer to indicate start of the contents
    @return none
*/
void mqp_init(struct mqtt_packet *mqp, uint8_t offset);

/** Initialize MQTT Packet Holder and attach the buffer */
static 
inline void mqp_buffer_attach(struct mqtt_packet *mqp, uint8_t *buffer, uint32_t length,
                              uint8_t offset)
{
        mqp_init(mqp, offset);

        mqp->buffer = buffer;
        mqp->maxlen = length;
        mqp->free   = NULL;

        return;
}

/** Description of UTF8 information as used by MQTT Library. */
struct utf8_string {
        
        const char *buffer;   /**< Refers to UTF8 content */
        uint16_t       length;   /**< Length of UTF8 content */
};

/** Write UTF8 information into the buffer. 
    The UTF8 information includes content and its length.

    @warning The routine does not check for correctness of the paramters.

    @param[in] buf refers to memory to write UTF8 information into
    @param[in] utf8 contains UTF8 information to be written
    @return on success, number of bytes written, otherwise -1 on error.
*/
int32_t mqp_buf_wr_utf8(uint8_t *buf, const struct utf8_string *utf8);

/** Write the MQTT construct 'Remaining Length' into trailing end of buffer.
    The 'remaining length' is written in the format as outlined in the MQTT
    specification. 

    The implementation assumes availability of at-least 4 bytes in the buffer.
    Depending on the value of 'Remaining Length' appropriate trailing bytes in
    the buffer would be used.
    
    @param[in] buf refers to memory to tail-write 'Remaining Length' into
    @param[in] remlen The 'Remaining Length' value
    @return in success, number of trailing bytes used, otherwise -1 on error
*/
int32_t mqp_buf_tail_wr_remlen(uint8_t *buf, uint32_t remlen);

/** Read MQTT construct 'Remaining Length' from leading bytes of the buffer.
    The 'remaining length' is written in the format as outlined in the MQTT
    specification.
     
    @param[in] buf refers to memory to head-read 'Remaining Length' from
    @param[in] remlen place-holder for The 'Remaining Length' value
    @return in success, number of header bytes read, otherwise -1 on error
*/   
int32_t mqp_buf_rd_remlen(uint8_t *buf, uint32_t *remlen);

/** Include variable header Topic as part of PUB Message construction.
    Inclusion of a Topic also encompasses incorporation of the message ID.

    The topic refers to the subject for which data will be published by
    the client or the server. The topic entity must be appended into the
    packet buffer prior to the inclusion of the payload (data).

    @warning This routine does not check for correctness of the input
    parameters.

    @param[in] mqp packet buffer in which topic must be included.
    @param[in] topic UTF8 information
    @param[in] msg_id Message or Packet transaction ID
    @return on success, number of bytes appended, otherwise -1 on error.

    @note A 'topic' must be appended prior to inclusion of pulished data.
*/
int32_t 
mqp_pub_append_topic(struct mqtt_packet *mqp, const struct utf8_string *topic,
                     uint16_t msg_id);

/** Include payload data for publishing
    The payload data is associated with a topic.
    
    @warning This routine does not check for correctness of the input
    parameters.

    @param[in] mqp packet buffer in which payload data must be included.
    @param[in] data_buf data to be included in the packet buffer
    @param[in] data_len length of the data to be included in the packet.
    @return on success, number of bytes appended, otherwise -1 on error.

    @note A 'topic' must be appended prior to inclusion of pulished data.
*/
int32_t mqp_pub_append_data(struct mqtt_packet *mqp, const uint8_t *data_buf,
                        uint32_t data_len);

/** Construct a packet for Message ID enabled ACK received from network
    Process the raw ACK message information to update the packet holder.
   
    @warning This routine does not check for correctness of the input
    parameters.
       
    @param[in] mqp_raw holds a raw buffer from the network
    @param[in] has_payload asserted, if ACK message should have a payload
    @return on success, true, otherwise false
*/
bool mqp_proc_msg_id_ack_rx(struct mqtt_packet *mqp_raw, bool has_payload);

/** Construct a packet for PUBLISH message received from the network
    Process the raw PUB message information to update the packet holder.

    @warning This routine does not check for correctness of the input
    parameters.

    @param[in] mqp_raw holds a raw buffer from the network
    @return on success, true, other wise false
*/
bool mqp_proc_pub_rx(struct mqtt_packet *mqp_raw);

/*
   Wait-List of MQTT Messages for which acknoledge is pending from remote node.
*/
struct mqtt_ack_wlist {
        
        struct mqtt_packet *head;  /* Points to head of single linked-list. */
        struct mqtt_packet *tail;  /* Points to tail of single linked-list. */
};

static inline bool mqp_ack_wlist_is_empty(struct mqtt_ack_wlist *list)
{
        return (NULL == list->head) ? true : false;
}

/*
   Add specified element into trailing end of list.

   Returns, on success, true, otherwise false.
*/
bool mqp_ack_wlist_append(struct mqtt_ack_wlist *list,
                          struct mqtt_packet    *elem);

/*
   Removes element that has specified msg_id from list. 

   Returns, on success, pointer to removed element, otherwise NULL.
*/
struct mqtt_packet *mqp_ack_wlist_remove(struct mqtt_ack_wlist *list,
                                          uint16_t msg_id);
/* 
   Removes and frees all elements in list. 
*/
void mqp_ack_wlist_purge(struct mqtt_ack_wlist *list);

static inline bool is_wlist_empty(const struct mqtt_ack_wlist *list)
{
        return list->head? false : true;
}

/** Prepare the Fixed-Header of the MQTT Packet (before being sent to network)
    Based on the contents of the mqtt packet and the combination of DUP, QoS
    and Retain flags as outlined the MQTT specification, the routine updates,
    among others, significant internal fields such as 'remaining length' and
    'fixed header length' in the packet construct and embeds the fixed header,
    so created, in the packet buffer.
    
    This service must be utilized on a packet that has been already populated
    with all the payload data, topics and other contents. The fixed header
    must be the final step in the compostion of MQTT packet prior to its
    dispatch to the server.
    
    Returns size, in bytes, of the fixed-header, otherwise -1 on error.
*/
int32_t mqp_prep_fh(struct mqtt_packet *mqp, uint8_t flags);

/** MQTT Quality of Service */
enum mqtt_qos {
        
        MQTT_QOS0,  /**< QoS Level 0 */
        MQTT_QOS1,  /**< QoS Level 1 */
        MQTT_QOS2   /**< QoS Level 2 */
};

/** Construct to create Topic to SUBSCRIBE */
struct utf8_strqos {

        const char       *buffer;  /**< Refers to UTF8 content */
        uint16_t             length;  /**< Length of UTF8 content */
        enum mqtt_qos   qosreq;  /**< QoS Level  for content */
};


/** @defgroup mqtt_netsec_grp Information to establish a secure connection.
    This is implementation specific and is targeted for the network services.

    Specifically, the MQTT implementation makes no assumption or use of this
    construct. The client library merely passes information from the app to
    the network service layer.
    Note: value of n_file can vary from 1 to 4, with corresponding pointers to
    the files in files field. Value of 1(n_file) will assume the corresponding
    pointer is for CA File Name. Any other value of n_file expects the files to
    be in following order:
    1.  Private Key File
    2.  Certificate File Name
    3.  CA File Name
    4.  DH Key File Name

example: 
If you want to provide only CA File Name, following are the two way of doing it:
for n_file = 1
char *security_file_list[] = {"/cert/testcacert.der"};
for n_file = 4
char *security_file_list[] = {NULL, NULL, "/cert/testcacert.der", NULL};

where files = security_file_list
    @{
*/
struct secure_conn {
        
        void *method;  /**< Reference to information about protocol or methods */
        void *cipher;  /**< Reference to information about cryptograph ciphers */
        uint32_t   n_file;  /**< Count of secure connection related files, certs... */
        char   **files;  /**< Reference to array of file-names used for security */
};

/** @} */

/* Initialize the struct secure_conn data */
void secure_conn_struct_init(struct secure_conn *nw_security);

/** @defgroup net_ops_group Abstraction of Network Services on a platform
    Services to enable the MQTT Client-Server communication over network
   
    These services are invoked by the MQTT Library.
    
    @{
*/ 
struct device_net_services {

       /** @defgroup dev_netconn_opt_grp Options for platform to configure network
           @{
        */
#define DEV_NETCONN_OPT_TCP  0x01  /**< Assert to indicate TCP net connection  */
#define DEV_NETCONN_OPT_UDP  0x02  /**< Assert to create a local UDP port bind */
#define DEV_NETCONN_OPT_IP6  0x04  /**< Assert for IPv6, otherwise it is IPv4  */
#define DEV_NETCONN_OPT_URL  0x08  /**< Assert if the network address is a URL */
#define DEV_NETCONN_OPT_SEC  0x10  /**< Assert to indicate a secure connection */
        /** @} */

        /** Set up a communication channel with a server or set up a local port.
            This routine opens up either a "connection oriented" communication
            channel with the specified server or set up a local configuration for
            "connectionless" transactions.

            @param[in] nwconn_opts Implementation specific construct to enumerate
            server address and / or connection related details
            @param[in] server_addr URL or IP address (string) or other server
            reference. For setting up a local (UDP) port, set it to NULL.
            @param[in] port_number Network port number, typically, 1883 or 8883
            for remote severs. For setting up a local (UDP) port, use an intended
            port number.
            @param[in] nw_security Information to establish a secure connection
            with server. Set it to NULL, if not used. @ref mqtt_netsec_grp
            @return a valid handle to connection, otherwise NULL
        */
        int32_t (*open)(uint32_t nwconn_opts, const char *server_addr, uint16_t port_number,
                    const struct secure_conn *nw_security);

        /** Send data onto the "connection oriented" network.
            The routine blocks till the time, the data has been copied into the
            network stack for dispatch on to the "connection oriented" network.

            @param[in] comm handle to network connection as returned by open().
            @param[in] buf refers to the data that is intended to be sent
            @param[in] len length of the data
            @param[in] ctx reference to the MQTT connection context
            @return on success, the number of bytes sent, 0 on connection reset,
            otherwise -1
        */
        int32_t   (*send)(int32_t comm, const uint8_t *buf, uint32_t len, void *ctx);

        /** Receive data from the "connection oriented" channel.
            The routine blocks till the time, there is either a data that has
            been received from the server or the time to await data from the
            server has expired.

            @param[in] comm Handle to network connection as returned by
            accept().
            @param[out] buf place-holder to which data from network should be
            written into.
            @param[in] len maximum length of 'buf'
            @param[in] wait_secs maximum time to await data from network. If
            exceeded, the routine returns error with the err_timeo flag set
            as true.
            @param[out] err_timeo if set, indicates that error is due to
            timeout.
            @param[in] ctx reference to the MQTT connection context
            @return on success, number of bytes received, 0 on connection reset,
            otherwise -1 on error. In case, error (-1) is due to the time-out,
            then the implementation should set flag err_timeo as true.
        */
        int32_t   (*recv)(int32_t comm, uint8_t *buf, uint32_t len, uint32_t wait_secs,
                      bool *err_timeo, void *ctx);

        /** Send data to particular port on the specified network element.
            The routine blocks till the time, the data has been copied into the
            network stack for dispatch to the "specified" network entity.

            @param[in] comm handle to network connection as returned by open().
            @param[in] buf refers to data that is intended to be sent
            @param[in] len length of the data
            @param[in] dest_port network port to which data is to be sent.
            @param[in] dest_ip IP address of the entity to which data is to be
            sent.
            @param[in] ip_len length of the destination IP address.
            @return on success, the number of bytes sent, 0 on connection reset,
            otherwise -1.
        */
        int32_t   (*send_dest)(int32_t comm, const uint8_t *buf, uint32_t len, uint16_t dest_port,
                           const uint8_t *dest_ip, uint32_t ip_len);

        /** Receive data on a local port sent by any network element.
            The routine blocks till the time, data has been received on the local
            port from any remote network element.

            @param[in] comm handle to network connection as return by open().
            @param[in] buf place-holder to which data from network should be
            written into.
            @param[in] len maximum lengh of 'buf'
            @param[out] from_port place-holder for the port of the sender network
            entity
            @param[out] from_ip place-holder to retrieve the IP address of the
            sender network entity. The memory space must be provisioned to store
            atleast 16 bytes.
            @param[in, out] ip_len length of IP address. It is provided by
            the caller to declare the length of the place holder and updated by
            routine to indicate the length of the remote network entity's IP
            address.
            @return on success, number of bytes received, 0 on connection reset,
            otherwise -1 on errir. 
        */
        int32_t   (*recv_from)(int32_t comm, uint8_t *buf, uint32_t len, uint16_t *from_port,
                           uint8_t *from_ip, uint32_t *ip_len);

        /** Close communication connection */
        int32_t   (*close)(int32_t comm);

        /** Listen to incoming connection from clients.
            This routine prepares the system to listen on the specified port
            for the incoming network connections from the remote clients.

            @param[in] nwconn_opts Implementation specific construct to
            enumerate server address and / or connection related details
            @param[in] port_number Network port number, typically, 1883 or 8883
            @param[in] nw_security Information to establish a secure connection
            with client. Set it to NULL, if not used. @ref mqtt_netsec_grp
            @return a valid handle to listening contruct, otherwise NULL
        */
        int32_t (*listen)(uint32_t nwconn_opts, uint16_t port_number,
                      const struct secure_conn *nw_security);

        /** Accept an incominng connection.
            This routine creates a new communication channel for the (remote)
            requesting client.

            @param[in] listen handle to listen for the incoming connection
            requests from the remote clients
            @param[out] client_ip IP address of the connected client. This value
            is valid only on successful return of the routine. The place holder
            must provide memory to store atleast 16 bytes.
            @param[in, out] ip_length Length of IP address. It is provided by
            the caller to declare the length of the place holder and updated by
            routine to indicate the length of the connected client's IP address.
            @return on success, a valid handle to the new connection, otherwise
            NULL
        */
        int32_t (*accept)(int32_t listen, uint8_t *client_ip, uint32_t *ip_length);

        /** Monitor activity on communication handles.
            The routine blocks for the specified period of time to monitor
            activity, if any, on each of the communication handle that has
            been provided in one or more vector sets. At the expiry of the
            wait time, this function must identify the handles, on which,
            acitvities were observed.

            A particular collection of communication handles are packed as
            an array or in a vector and is passed to the routine. A NULL
            handle in the vector indicates the termination of the vector
            and can effectively used to account for the size of the vector.

            Similarly, at end the end of the wait period, the routine must
            provide a vector of the handles for which activity was observed.

            @param[in, out] recv_hvec a vector of handles which must be
            monitored for receive activities. 
            @param[in, out] send_hvec a vector of handles which must be
            monitored for send activities.
            @param[in, out] rsvd_hvec reserved for future use.
            @param[in] wait_secs time to wait and monitor activity on
            communication handles provided in one or more sets. If set 
            to 0, the routine returns immediately.
            @return on success, the total number of handles for which activity
            was observed. This number can be 0, if no activity was observed on
            any of the provided handle in the specified time. Otherwise, -1 on
            error.
        */
        int32_t   (*io_mon)(int32_t *recv_cvec, int32_t *send_cvec,
                        int32_t *rsvd_cvec,  uint32_t wait_secs);

        /** Get Time (in seconds).
            Provides a monotonically incrementing value of a time  service in
            unit of seconds. The implementation should ensure that associated
            timer hardware or the clock module remains active through the low
            power states of the system. Such an arrangement ensures that MQTT
            Library is able to track the Keep-Alive time across the cycles of
            low power states. It would be typical of battery operated systems
            to transition to low power states during the period of inactivity
            or otherwise to conserve battery. 

            In the absence of a sustained time reference across the low power
            states, if the system transitions away from the active state, the
            MQTT Library, then may not be able to effectively monitor the Keep
            Alive duration.

            It is the responsbililty of the implementation to manage the roll-
            over problem of the hardware and ensure the integrity of the time
            value is maintained.

           @return time in seconds
        */
        uint32_t   (*time)(void);
};

/** @} */ /* device_net_services */

/* Receive data from the specified network and read into the 'mqp' */
int32_t mqp_recv(int32_t  net,     const struct device_net_services *net_ops,
             struct mqtt_packet *mqp, uint32_t wait_secs, bool *timed_out,
             void *ctx);

/*-----------------------------------------------------------------------------
 * Data structure for managing the QoS2 PUB RX packets and follow-ups
 *---------------------------------------------------------------------------*/

#define MAX_PUBREL_INFLT 8 /* Must be kept as a value of 2^n */

struct pub_qos2_cq { /* Circular Queue CQ to track QOS2 PUB RX messages */

        uint16_t id_vec[MAX_PUBREL_INFLT];  /* Vector to store RX Message-IDs */
        uint8_t  n_free;                    /* Num of free elements in vector */
        uint8_t  rd_idx;                    /* Index to Read  next Message-ID */
        uint8_t  wr_idx;                    /* Index to Write next Message-ID */
};

/* Reset the specified Circular Queue (CQ) */
void qos2_pub_cq_reset(struct pub_qos2_cq *cq);

/* Append the message-id into the CQ tail. Return true on success, else false */
bool qos2_pub_cq_logup(struct pub_qos2_cq *cq, uint16_t msg_id);

/* Remove the message-id from the CQ head. Return true on success, else false */
bool qos2_pub_cq_unlog(struct pub_qos2_cq *cq, uint16_t msg_id);

/* Is the message-id available in the CQ ? Return true on success, else false */
bool qos2_pub_cq_check(struct pub_qos2_cq *cq, uint16_t msg_id);

/* Get the count of message-ID(s) availalbe in the CQ */
static inline int32_t qos2_pub_cq_count(struct pub_qos2_cq *cq)
{
        return MAX_PUBREL_INFLT - cq->n_free;
}

struct client_ctx {

        void        *usr;  /* Client Usr */
        int32_t          net;  /* Socket HND */

        uint8_t           remote_ip[16];
        uint32_t          ip_length;

        uint32_t          timeout;
        uint16_t          ka_secs;

        uint32_t          flags;

        struct client_ctx *next;
};

void cl_ctx_reset(struct client_ctx *cl_ctx);
void cl_ctx_timeout_insert(struct client_ctx **head,
                           struct client_ctx *elem);

void cl_ctx_remove(struct client_ctx **head,
                   struct client_ctx *elem);

#define KA_TIMEOUT_NONE 0xffffffff  /* Different than KA SECS = 0 */
void cl_ctx_timeout_update(struct client_ctx *cl_ctx, uint32_t now_secs);

}//namespace mbed_mqtt 

#ifdef __cplusplus  
}
#endif 

#endif