My Modify MQTTPacket Packet size 100 -> 400
Fork of MQTTPacket by
Revision 0:7734401cc1b4, committed 2014-02-04
- Comitter:
- icraggs
- Date:
- Tue Feb 04 22:31:32 2014 +0000
- Child:
- 1:069ae45b7070
- Commit message:
- First version of MQTT library
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTConnect.h Tue Feb 04 22:31:32 2014 +0000
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#ifndef MQTTCONNECT_H_
+#define MQTTCONNECT_H_
+
+ typedef union
+ {
+ unsigned char all; /**< all connect flags */
+#if defined(REVERSED)
+ struct
+ {
+ unsigned int username : 1; /**< 3.1 user name */
+ unsigned int password : 1; /**< 3.1 password */
+ unsigned int willRetain : 1; /**< will retain setting */
+ unsigned int willQoS : 2; /**< will QoS value */
+ unsigned int will : 1; /**< will flag */
+ unsigned int cleansession : 1; /**< clean session flag */
+ unsigned int : 1; /**< unused */
+ } bits;
+#else
+ struct
+ {
+ unsigned int : 1; /**< unused */
+ unsigned int cleansession : 1; /**< cleansession flag */
+ unsigned int will : 1; /**< will flag */
+ unsigned int willQoS : 2; /**< will QoS value */
+ unsigned int willRetain : 1; /**< will retain setting */
+ unsigned int password : 1; /**< 3.1 password */
+ unsigned int username : 1; /**< 3.1 user name */
+ } bits;
+#endif
+ } MQTTConnectFlags; /**< connect flags byte */
+
+
+
+/**
+ * Defines the MQTT "Last Will and Testament" (LWT) settings for
+ * the connect packet.
+ */
+typedef struct
+{
+ /** The eyecatcher for this structure. must be MQTW. */
+ char struct_id[4];
+ /** The version number of this structure. Must be 0 */
+ int struct_version;
+ /** The LWT topic to which the LWT message will be published. */
+ MQTTString topicName;
+ /** The LWT payload. */
+ MQTTString message;
+ /**
+ * The retained flag for the LWT message (see MQTTAsync_message.retained).
+ */
+ int retained;
+ /**
+ * The quality of service setting for the LWT message (see
+ * MQTTAsync_message.qos and @ref qos).
+ */
+ int qos;
+} MQTTPacket_willOptions;
+
+
+#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, 0 }
+
+
+typedef struct
+{
+ /** The eyecatcher for this structure. must be MQTC. */
+ char struct_id[4];
+ /** The version number of this structure. Must be 0, 1 or 2.
+ * 0 signifies no SSL options and no serverURIs
+ * 1 signifies no serverURIs
+ */
+ int struct_version;
+ /** Version of MQTT to be used. 3 = 3.1 4 = 3.1.1
+ */
+ int MQTTVersion;
+ MQTTString clientID;
+ int keepAliveInterval;
+ int cleansession;
+ int willFlag;
+ MQTTPacket_willOptions will;
+ MQTTString username;
+ MQTTString password;
+} MQTTPacket_connectData;
+
+#define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'W'}, 0, 3, {NULL, {0, NULL}}, 0, 1, 0, \
+ MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} }
+
+int MQTTSerialize_connect(char* buf, int buflen, MQTTPacket_connectData* options);
+int MQTTDeserialize_connect(MQTTPacket_connectData* data, char* buf, int len);
+
+int MQTTSerialize_connack(char* buf, int buflen, int connack_rc);
+int MQTTDeserialize_connack(int* connack_rc, char* buf, int buflen);
+
+int MQTTSerialize_disconnect(char* buf, int buflen);
+
+#endif /* MQTTCONNECT_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTConnectClient.c Tue Feb 04 22:31:32 2014 +0000
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+/**
+ * Determines the length of the MQTT connect packet that would be produced using the supplied connect options.
+ * @param options the options to be used to build the connect packet
+ * @return the length of buffer needed to contain the serialized version of the packet
+ */
+int MQTTSerialize_connectLength(MQTTPacket_connectData* options)
+{
+ int len = 0;
+
+ FUNC_ENTRY;
+
+ if (options->MQTTVersion == 3)
+ len = 12; /* variable depending on MQTT or MQIsdp */
+ else if (options->MQTTVersion == 4)
+ len = 10;
+
+ len += MQTTstrlen(options->clientID)+2;
+ if (options->willFlag)
+ len += MQTTstrlen(options->will.topicName)+2 + MQTTstrlen(options->will.message)+2;
+ if (options->username.cstring || options->username.lenstring.data)
+ len += MQTTstrlen(options->username)+2;
+ if (options->password.cstring || options->password.lenstring.data)
+ len += MQTTstrlen(options->password)+2;
+
+ FUNC_EXIT_RC(len);
+ return len;
+}
+
+
+/**
+ * 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
+ * @return serialized length, or error if 0
+ */
+int MQTTSerialize_connect(char* buf, int buflen, MQTTPacket_connectData* options)
+{
+ char *ptr = buf;
+ MQTTHeader header;
+ MQTTConnectFlags flags;
+ int len = 0;
+ int rc = -1;
+
+ FUNC_ENTRY;
+ if (MQTTPacket_len(len = MQTTSerialize_connectLength(options)) > buflen)
+ {
+ rc = MQTTPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+
+ header.byte = 0;
+ header.bits.type = CONNECT;
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, len); /* write remaining length */
+
+ if (options->MQTTVersion == 4)
+ {
+ writeCString(&ptr, "MQTT");
+ writeChar(&ptr, (char) 4);
+ }
+ else
+ {
+ writeCString(&ptr, "MQIsdp");
+ writeChar(&ptr, (char) 3);
+ }
+
+ flags.all = 0;
+ flags.bits.cleansession = options->cleansession;
+ flags.bits.will = (options->willFlag) ? 1 : 0;
+ if (flags.bits.will)
+ {
+ flags.bits.willQoS = options->will.qos;
+ flags.bits.willRetain = options->will.retained;
+ }
+
+ if (options->username.cstring || options->username.lenstring.data)
+ flags.bits.username = 1;
+ if (options->password.cstring || options->password.lenstring.data)
+ flags.bits.password = 1;
+
+ writeChar(&ptr, flags.all);
+ writeInt(&ptr, options->keepAliveInterval);
+ writeMQTTString(&ptr, options->clientID);
+ if (options->willFlag)
+ {
+ writeMQTTString(&ptr, options->will.topicName);
+ writeMQTTString(&ptr, options->will.message);
+ }
+ if (flags.bits.username)
+ writeMQTTString(&ptr, options->username);
+ if (flags.bits.password)
+ writeMQTTString(&ptr, options->password);
+
+ rc = ptr - buf;
+
+ exit: FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Deserializes the supplied (wire) buffer into connack data - return code
+ * @param connack_rc returned integer value of the connack return code
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param len the length in bytes of the data in the supplied buffer
+ * @return error code. 1 is success, 0 is failure
+ */
+int MQTTDeserialize_connack(int* connack_rc, char* buf, int buflen)
+{
+ MQTTHeader header;
+ char* curdata = buf;
+ char* enddata = NULL;
+ int rc = 0;
+ int mylen;
+ int compression;
+
+ FUNC_ENTRY;
+ header.byte = readChar(&curdata);
+ if (header.bits.type != CONNACK)
+ goto exit;
+
+ curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+ enddata = curdata + mylen;
+ if (enddata - curdata < 2)
+ goto exit;
+
+ compression = readChar(&curdata);
+ *connack_rc = readChar(&curdata);
+
+ rc = 1;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Serializes a disconnect 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
+ * @return serialized length, or error if 0
+ */
+int MQTTSerialize_disconnect(char* buf, int buflen)
+{
+ MQTTHeader header;
+ int rc = -1;
+ char *ptr = buf;
+
+ FUNC_ENTRY;
+ if (buflen < 2)
+ {
+ rc = MQTTPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+ header.byte = 0;
+ header.bits.type = DISCONNECT;
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, 0); /* write remaining length */
+ rc = ptr - buf;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTConnectServer.c Tue Feb 04 22:31:32 2014 +0000
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "StackTrace.h"
+#include "MQTTPacket.h"
+#include <string.h>
+
+#define min(a, b) ((a < b) ? 1 : 0)
+
+
+/**
+ * Validates MQTT protocol name and version combinations
+ * @param protocol the MQTT protocol name as an MQTTString
+ * @param version the MQTT protocol version number, as in the connect packet
+ * @return correct MQTT combination? 1 is true, 0 is false
+ */
+int MQTTPacket_checkVersion(MQTTString* protocol, int version)
+{
+ int rc = 0;
+
+ if (version == 3 && memcmp(protocol->lenstring.data, "MQIdsp",
+ min(6, protocol->lenstring.len)))
+ rc = 1;
+ else if (version == 3 && memcmp(protocol->lenstring.data, "MQTT",
+ min(4, protocol->lenstring.len)))
+ rc = 1;
+
+ return 1;
+}
+
+
+/**
+ * Deserializes the supplied (wire) buffer into connect data structure
+ * @param data the connect data structure to be filled out
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param len the length in bytes of the data in the supplied buffer
+ * @return error code. 1 is success, 0 is failure
+ */
+int MQTTDeserialize_connect(MQTTPacket_connectData* data, char* buf, int len)
+{
+ MQTTHeader header;
+ MQTTConnectFlags flags;
+ char* curdata = buf;
+ char* enddata = &buf[len];
+ int rc = 0;
+ MQTTString Protocol;
+ int version;
+ int mylen = 0;
+
+ FUNC_ENTRY;
+ header.byte = readChar(&curdata);
+
+ curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+
+ if (!readMQTTLenString(&Protocol, &curdata, enddata) ||
+ enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
+ goto exit;
+
+ version = (int)readChar(&curdata); /* Protocol version */
+ /* If we don't recognize the protocol version, we don't parse the connect packet on the
+ * basis that we don't know what the format will be.
+ */
+ if (MQTTPacket_checkVersion(&Protocol, version))
+ {
+ flags.all = readChar(&curdata);
+ data->cleansession = flags.bits.cleansession;
+ data->keepAliveInterval = readInt(&curdata);
+ if (!readMQTTLenString(&data->clientID, &curdata, enddata))
+ goto exit;
+ if (flags.bits.will)
+ {
+ data->willFlag = 1;
+ data->will.qos = flags.bits.willQoS;
+ data->will.retained = flags.bits.willRetain;
+ if (!readMQTTLenString(&data->will.topicName, &curdata, enddata) ||
+ !readMQTTLenString(&data->will.message, &curdata, enddata))
+ goto exit;
+ }
+ if (flags.bits.username)
+ {
+ if (enddata - curdata < 3 || !readMQTTLenString(&data->username, &curdata, enddata))
+ goto exit; /* username flag set, but no username supplied - invalid */
+ if (flags.bits.password &&
+ (enddata - curdata < 3 || !readMQTTLenString(&data->password, &curdata, enddata)))
+ goto exit; /* password flag set, but no password supplied - invalid */
+ }
+ else if (flags.bits.password)
+ goto exit; /* password flag set without username - invalid */
+ rc = 1;
+ }
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Serializes the connack packet into the supplied buffer.
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param connack_rc the integer connack return code to be used
+ * @return serialized length, or error if 0
+ */
+int MQTTSerialize_connack(char* buf, int buflen, int connack_rc)
+{
+ MQTTHeader header;
+ int rc = 0;
+ char *ptr = buf;
+
+ FUNC_ENTRY;
+ if (buflen < 2)
+ {
+ rc = MQTTPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+ header.byte = 0;
+ header.bits.type = CONNACK;
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
+
+ writeChar(&ptr, 0); /* compression byte - not used */
+ writeChar(&ptr, connack_rc);
+
+ rc = ptr - buf;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTDeserializePublish.c Tue Feb 04 22:31:32 2014 +0000
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "StackTrace.h"
+#include "MQTTPacket.h"
+#include <string.h>
+
+#define min(a, b) ((a < b) ? 1 : 0)
+
+/**
+ * Deserializes the supplied (wire) buffer into publish data
+ * @param dup returned integer - the MQTT dup flag
+ * @param qos returned integer - the MQTT QoS value
+ * @param retained returned integer - the MQTT retained flag
+ * @param packetid returned integer - the MQTT packet identifier
+ * @param topicName returned MQTTString - the MQTT topic in the publish
+ * @param payload returned byte buffer - the MQTT publish payload
+ * @param payloadlen returned integer - the length of the MQTT payload
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @return error code. 1 is success
+ */
+int MQTTDeserialize_publish(int* dup, int* qos, int* retained, int* packetid, MQTTString* topicName,
+ char** payload, int* payloadlen, char* buf, int buflen)
+{
+ MQTTHeader header;
+ char* curdata = buf;
+ char* enddata = NULL;
+ int rc = 0;
+ int mylen = 0;
+
+ FUNC_ENTRY;
+ header.byte = readChar(&curdata);
+ *dup = header.bits.dup;
+ *qos = header.bits.qos;
+ *retained = header.bits.retain;
+
+ curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+ enddata = curdata + mylen;
+
+ if (!readMQTTLenString(topicName, &curdata, enddata) ||
+ enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
+ goto exit;
+
+ if (*qos > 0)
+ *packetid = readInt(&curdata);
+
+ *payloadlen = enddata - curdata;
+ *payload = curdata;
+ rc = 1;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+
+/**
+ * Deserializes the supplied (wire) buffer into an ack
+ * @param type returned integer - the MQTT packet type
+ * @param dup returned integer - the MQTT dup flag
+ * @param packetid returned integer - the MQTT packet identifier
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @return error code. 1 is success, 0 is failure
+ */
+int MQTTDeserialize_ack(int* type, int* dup, int* packetid, char* buf, int buflen)
+{
+ MQTTHeader header;
+ char* curdata = buf;
+ char* enddata = NULL;
+ int rc = 0;
+ int mylen;
+
+ FUNC_ENTRY;
+ header.byte = readChar(&curdata);
+ *dup = header.bits.dup;
+ *type = header.bits.type;
+
+ curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+ enddata = curdata + mylen;
+
+ if (enddata - curdata < 2)
+ goto exit;
+ *packetid = readInt(&curdata);
+
+ rc = 1;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTPacket.c Tue Feb 04 22:31:32 2014 +0000
@@ -0,0 +1,283 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "StackTrace.h"
+#include "MQTTPacket.h"
+
+#include <string.h>
+
+/**
+ * Encodes the message length according to the MQTT algorithm
+ * @param buf the buffer into which the encoded data is written
+ * @param length the length to be encoded
+ * @return the number of bytes written to buffer
+ */
+int MQTTPacket_encode(char* buf, int length)
+{
+ int rc = 0;
+
+ FUNC_ENTRY;
+ do
+ {
+ char d = length % 128;
+ length /= 128;
+ /* if there are more digits to encode, set the top bit of this digit */
+ if (length > 0)
+ d |= 0x80;
+ buf[rc++] = d;
+ } while (length > 0);
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Decodes the message length according to the MQTT algorithm
+ * @param getcharfn pointer to function to read the next character from the data source
+ * @param value the decoded length returned
+ * @return the number of bytes read from the socket
+ */
+int MQTTPacket_decode(int (*getcharfn)(char*, int), int* value)
+{
+ char c;
+ int multiplier = 1;
+ int len = 0;
+#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4
+
+ FUNC_ENTRY;
+ *value = 0;
+ do
+ {
+ int rc = MQTTPACKET_READ_ERROR;
+
+ if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
+ {
+ rc = MQTTPACKET_READ_ERROR; /* bad data */
+ goto exit;
+ }
+ rc = (*getcharfn)(&c, 1);
+ if (rc != 1)
+ goto exit;
+ *value += (c & 127) * multiplier;
+ multiplier *= 128;
+ } while ((c & 128) != 0);
+exit:
+ FUNC_EXIT_RC(len);
+ return len;
+}
+
+
+int MQTTPacket_len(int rem_len)
+{
+ rem_len += 1; /* header byte */
+
+ /* now remaining_length field */
+ if (rem_len < 128)
+ rem_len += 1;
+ else if (rem_len < 16384)
+ rem_len += 2;
+ else if (rem_len < 2097151)
+ rem_len += 3;
+ else
+ rem_len += 4;
+ return rem_len;
+}
+
+
+static char* bufptr;
+
+int bufchar(char* c, int count)
+{
+ int i;
+
+ for (i = 0; i < count; ++i)
+ *c = *bufptr++;
+ return count;
+}
+
+
+int MQTTPacket_decodeBuf(char* buf, int* value)
+{
+ bufptr = buf;
+ return MQTTPacket_decode(bufchar, value);
+}
+
+
+/**
+ * Calculates an integer from two bytes read from the input buffer
+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
+ * @return the integer value calculated
+ */
+int readInt(char** pptr)
+{
+ char* ptr = *pptr;
+ int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1));
+ *pptr += 2;
+ return len;
+}
+
+
+/**
+ * Reads one character from the input buffer.
+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
+ * @return the character read
+ */
+char readChar(char** pptr)
+{
+ char c = **pptr;
+ (*pptr)++;
+ return c;
+}
+
+
+/**
+ * Writes one character to an output buffer.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param c the character to write
+ */
+void writeChar(char** pptr, char c)
+{
+ **pptr = c;
+ (*pptr)++;
+}
+
+
+/**
+ * Writes an integer as 2 bytes to an output buffer.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param anInt the integer to write
+ */
+void writeInt(char** pptr, int anInt)
+{
+ **pptr = (char)(anInt / 256);
+ (*pptr)++;
+ **pptr = (char)(anInt % 256);
+ (*pptr)++;
+}
+
+
+/**
+ * Writes a "UTF" string to an output buffer. Converts C string to length-delimited.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param string the C string to write
+ */
+void writeCString(char** pptr, char* string)
+{
+ int len = strlen(string);
+ writeInt(pptr, len);
+ memcpy(*pptr, string, len);
+ *pptr += len;
+}
+
+
+int getLenStringLen(char* ptr)
+{
+ int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1));
+ return len;
+}
+
+
+void writeMQTTString(char** pptr, MQTTString mqttstring)
+{
+ if (mqttstring.lenstring.len > 0)
+ {
+ writeInt(pptr, mqttstring.lenstring.len);
+ memcpy(*pptr, mqttstring.lenstring.data, mqttstring.lenstring.len);
+ *pptr += mqttstring.lenstring.len;
+ }
+ else if (mqttstring.cstring)
+ writeCString(pptr, mqttstring.cstring);
+}
+
+
+/**
+ * @param mqttstring the MQTTString structure into which the data is to be read
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param enddata pointer to the end of the data: do not read beyond
+ * @return 1 if successful, 0 if not
+ */
+int readMQTTLenString(MQTTString* mqttstring, char** pptr, char* enddata)
+{
+ int rc = 0;
+
+ FUNC_ENTRY;
+ /* the first two bytes are the length of the string */
+ if (enddata - (*pptr) > 1) /* enough length to read the integer? */
+ {
+ mqttstring->lenstring.len = readInt(pptr); /* increments pptr to point past length */
+ if (&(*pptr)[mqttstring->lenstring.len] <= enddata)
+ {
+ mqttstring->lenstring.data = *pptr;
+ *pptr += mqttstring->lenstring.len;
+ rc = 1;
+ }
+ }
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Return the length of the MQTTstring - C string if there is one, otherwise the length delimited string
+ * @param mqttstring the string to return the length of
+ * @return the length of the string
+ */
+int MQTTstrlen(MQTTString mqttstring)
+{
+ int rc = 0;
+
+ if (mqttstring.cstring)
+ rc = strlen(mqttstring.cstring);
+ else
+ rc = mqttstring.lenstring.len;
+ return rc;
+}
+
+
+/**
+ * Helper function to read packet data from some source into a buffer
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param getfn pointer to a function which will read any number of bytes from the needed source
+ * @return integer MQTT packet type, or -1 on error
+ */
+int MQTTPacket_read(char* buf, int buflen, int (*getfn)(char*, int))
+{
+ int rc = -1;
+ MQTTHeader header;
+ int len = 0;
+ int rem_len = 0;
+
+ /* 1. read the header byte. This has the packet type in it */
+ if ((*getfn)(buf, 1) != 1)
+ goto exit;
+
+ len = 1;
+ /* 2. read the remaining length. This is variable in itself */
+ MQTTPacket_decode(getfn, &rem_len);
+ len += MQTTPacket_encode(buf + 1, rem_len); /* put the original remaining length back into the buffer */
+
+ /* 3. read the rest of the buffer using a callback to supply the rest of the data */
+ if ((*getfn)(buf + len, rem_len) != rem_len)
+ goto exit;
+
+ header.byte = buf[0];
+ rc = header.bits.type;
+exit:
+ return rc;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTPacket.h Tue Feb 04 22:31:32 2014 +0000
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#ifndef MQTTPACKET_H_
+#define MQTTPACKET_H_
+
+#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
+extern "C" {
+#endif
+
+enum errors
+{
+ MQTTPACKET_BUFFER_TOO_SHORT = -2,
+ MQTTPACKET_READ_ERROR = -1,
+ MQTTPACKET_READ_COMPLETE,
+};
+
+enum msgTypes
+{
+ CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL,
+ PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK,
+ PINGREQ, PINGRESP, DISCONNECT
+};
+
+/**
+ * Bitfields for the MQTT header byte.
+ */
+typedef union
+{
+ /*unsigned*/ char byte; /**< the whole byte */
+#if defined(REVERSED)
+ struct
+ {
+ unsigned int type : 4; /**< message type nibble */
+ unsigned int dup : 1; /**< DUP flag bit */
+ unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
+ unsigned int retain : 1; /**< retained flag bit */
+ } bits;
+#else
+ struct
+ {
+ unsigned int retain : 1; /**< retained flag bit */
+ unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
+ unsigned int dup : 1; /**< DUP flag bit */
+ unsigned int type : 4; /**< message type nibble */
+ } bits;
+#endif
+} MQTTHeader;
+
+typedef struct
+{
+ int len;
+ char* data;
+} MQTTLenString;
+
+typedef struct
+{
+ char* cstring;
+ MQTTLenString lenstring;
+} MQTTString;
+
+#define MQTTString_initializer {NULL, {0, NULL}}
+
+int MQTTstrlen(MQTTString mqttstring);
+
+#include "MQTTConnect.h"
+#include "MQTTPublish.h"
+#include "MQTTSubscribe.h"
+#include "MQTTUnsubscribe.h"
+
+int MQTTDeserialize_ack(int* type, int* dup, int* packetid, char* buf, int buflen);
+
+int MQTTPacket_len(int rem_len);
+
+int MQTTPacket_encode(char* buf, int length);
+int MQTTPacket_decode(int (*getcharfn)(char*, int), int* value);
+int MQTTPacket_decodeBuf(char* buf, int* value);
+
+int readInt(char** pptr);
+char readChar(char** pptr);
+void writeChar(char** pptr, char c);
+void writeInt(char** pptr, int anInt);
+int readMQTTLenString(MQTTString* mqttstring, char** pptr, char* enddata);
+void writeCString(char** pptr, char* string);
+void writeMQTTString(char** pptr, MQTTString mqttstring);
+
+#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
+}
+#endif
+
+
+#endif /* MQTTPACKET_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTPublish.h Tue Feb 04 22:31:32 2014 +0000 @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#ifndef MQTTPUBLISH_H_ +#define MQTTPUBLISH_H_ + +int MQTTSerialize_publish(char* buf, int buflen, int dup, int qos, int retained, int packetid, MQTTString topicName, + char* payload, int payloadlen); + +int MQTTDeserialize_publish(int* dup, int* qos, int* retained, int* packetid, MQTTString* topicName, + char** payload, int* payloadlen, char* buf, int len); + +int MQTTSerialize_puback(char* buf, int buflen, int packetid); +int MQTTSerialize_pubrel(char* buf, int buflen, int packetid, int dup); +int MQTTSerialize_pubcomp(char* buf, int buflen, int packetid); + +#endif /* MQTTPUBLISH_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSerializePublish.c Tue Feb 04 22:31:32 2014 +0000
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+
+/**
+ * Determines the length of the MQTT publish packet that would be produced using the supplied parameters
+ * @param qos the MQTT QoS of the publish (packetid is omitted for QoS 0)
+ * @param topicName the topic name to be used in the publish
+ * @param payloadlen the length of the payload to be sent
+ * @return the length of buffer needed to contain the serialized version of the packet
+ */
+int MQTTSerialize_publishLength(int qos, MQTTString topicName, int payloadlen)
+{
+ int len = 0;
+
+ len += 2 + MQTTstrlen(topicName) + payloadlen;
+ if (qos > 0)
+ len += 2; /* packetid */
+ return len;
+}
+
+
+/**
+ * Serializes the supplied publish data into the supplied buffer, ready for sending
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param dup integer - the MQTT dup flag
+ * @param qos integer - the MQTT QoS value
+ * @param retained integer - the MQTT retained flag
+ * @param packetid integer - the MQTT packet identifier
+ * @param topicName MQTTString - the MQTT topic in the publish
+ * @param payload byte buffer - the MQTT publish payload
+ * @param payloadlen integer - the length of the MQTT payload
+ * @return the length of the serialized data. <= 0 indicates error
+ */
+int MQTTSerialize_publish(char* buf, int buflen, int dup, int qos, int retained, int packetid, MQTTString topicName,
+ char* payload, int payloadlen)
+{
+ char *ptr = buf;
+ MQTTHeader header;
+ int rem_len = 0;
+ int rc = 0;
+
+ FUNC_ENTRY;
+ if (MQTTPacket_len(rem_len = MQTTSerialize_publishLength(qos, topicName, payloadlen)) > buflen)
+ {
+ rc = MQTTPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+
+ header.bits.type = PUBLISH;
+ header.bits.dup = dup;
+ header.bits.qos = qos;
+ header.bits.retain = retained;
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
+
+ writeMQTTString(&ptr, topicName);
+
+ if (qos > 0)
+ writeInt(&ptr, packetid);
+
+ memcpy(ptr, payload, payloadlen);
+ ptr += payloadlen;
+
+ rc = ptr - buf;
+
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+
+/**
+ * Serializes the ack packet into the supplied buffer.
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param type integer - the MQTT packet type
+ * @param dup integer - the MQTT dup flag
+ * @param packetid integer - the MQTT packet identifier
+ * @return serialized length, or error if 0
+ */
+int MQTTSerialize_ack(char* buf, int buflen, int type, int dup, int packetid)
+{
+ MQTTHeader header;
+ int rc = 0;
+ char *ptr = buf;
+
+ FUNC_ENTRY;
+ if (buflen < 4)
+ {
+ rc = MQTTPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+ header.bits.type = type;
+ header.bits.dup = dup;
+ header.bits.qos = 0;
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
+ writeInt(&ptr, packetid);
+ rc = ptr - buf;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Serializes a puback packet into the supplied buffer.
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param packetid integer - the MQTT packet identifier
+ * @return serialized length, or error if 0
+ */
+int MQTTSerialize_puback(char* buf, int buflen, int packetid)
+{
+ return MQTTSerialize_ack(buf, buflen, PUBACK, packetid, 0);
+}
+
+
+/**
+ * Serializes a pubrel packet into the supplied buffer.
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param dup integer - the MQTT dup flag
+ * @param packetid integer - the MQTT packet identifier
+ * @return serialized length, or error if 0
+ */
+int MQTTSerialize_pubrel(char* buf, int buflen, int dup, int packetid)
+{
+ return MQTTSerialize_ack(buf, buflen, PUBREL, packetid, dup);
+}
+
+
+/**
+ * Serializes a pubrel packet into the supplied buffer.
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param packetid integer - the MQTT packet identifier
+ * @return serialized length, or error if 0
+ */
+int MQTTSerialize_pubcomp(char* buf, int buflen, int packetid)
+{
+ return MQTTSerialize_ack(buf, buflen, PUBCOMP, packetid, 0);
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSubscribe.h Tue Feb 04 22:31:32 2014 +0000 @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#ifndef MQTTSUBSCRIBE_H_ +#define MQTTSUBSCRIBE_H_ + +int MQTTSerialize_subscribe(char* buf, int buflen, int dup, int packetid, int count, MQTTString topicFilters[], int requestedQoSs[]); + +int MQTTDeserialize_subscribe(int* dup, int* packetid, int maxcount, int* count, MQTTString topicFilters[], int requestedQoSs[], char* buf, int len); + +int MQTTSerialize_suback(char* buf, int buflen, int packetid, int count, int* grantedQoSs); + +int MQTTDeserialize_suback(int* packetid, int maxcount, int* count, int grantedQoSs[], char* buf, int len); + + +#endif /* MQTTSUBSCRIBE_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSubscribeClient.c Tue Feb 04 22:31:32 2014 +0000
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+/**
+ * Determines the length of the MQTT subscribe packet that would be produced using the supplied parameters
+ * @param count the number of topic filter strings in topicFilters
+ * @param topicFilters the array of topic filter strings to be used in the publish
+ * @return the length of buffer needed to contain the serialized version of the packet
+ */
+int MQTTSerialize_subscribeLength(int count, MQTTString topicFilters[])
+{
+ int i;
+ int len = 2; /* packetid */
+
+ for (i = 0; i < count; ++i)
+ len += 2 + MQTTstrlen(topicFilters[i]) + 1; /* length + topic + req_qos */
+ return len;
+}
+
+
+/**
+ * Serializes the supplied subscribe data into the supplied buffer, ready for sending
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied bufferr
+ * @param dup integer - the MQTT dup flag
+ * @param packetid integer - the MQTT packet identifier
+ * @param count - number of members in the topicFilters and reqQos arrays
+ * @param topicFilters - array of topic filter names
+ * @param requestedQoSs - array of requested QoS
+ * @return the length of the serialized data. <= 0 indicates error
+ */
+int MQTTSerialize_subscribe(char* buf, int buflen, int dup, int packetid, int count, MQTTString topicFilters[], int requestedQoSs[])
+{
+ char *ptr = buf;
+ MQTTHeader header;
+ int rem_len = 0;
+ int rc = 0;
+ int i = 0;
+
+ FUNC_ENTRY;
+ if (MQTTPacket_len(rem_len = MQTTSerialize_subscribeLength(count, topicFilters)) > buflen)
+ {
+ rc = MQTTPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+
+ header.byte = 0;
+ header.bits.type = SUBSCRIBE;
+ header.bits.dup = dup;
+ header.bits.qos = 1;
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
+
+ writeInt(&ptr, packetid);
+
+ for (i = 0; i < count; ++i)
+ {
+ writeMQTTString(&ptr, topicFilters[i]);
+ writeChar(&ptr, requestedQoSs[i]);
+ }
+
+ rc = ptr - buf;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+
+/**
+ * Deserializes the supplied (wire) buffer into suback data
+ * @param packetid returned integer - the MQTT packet identifier
+ * @param maxcount - the maximum number of members allowed in the grantedQoSs array
+ * @param count returned integer - number of members in the grantedQoSs array
+ * @param grantedQoSs returned array of integers - the granted qualities of service
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @return error code. 1 is success, 0 is failure
+ */
+int MQTTDeserialize_suback(int* packetid, int maxcount, int* count, int grantedQoSs[], char* buf, int buflen)
+{
+ MQTTHeader header;
+ char* curdata = buf;
+ char* enddata = NULL;
+ int rc = 0;
+ int mylen;
+
+ FUNC_ENTRY;
+ header.byte = readChar(&curdata);
+
+ curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+ enddata = curdata + mylen;
+ if (enddata - curdata < 2)
+ goto exit;
+
+ *packetid = readInt(&curdata);
+
+ *count = 0;
+ while (curdata < enddata)
+ {
+ if (*count > maxcount)
+ {
+ rc = -1;
+ goto exit;
+ }
+ grantedQoSs[(*count)++] = readChar(&curdata);
+ }
+
+ rc = 1;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSubscribeServer.c Tue Feb 04 22:31:32 2014 +0000
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+
+/**
+ * Deserializes the supplied (wire) buffer into subscribe data
+ * @param dup integer returned - the MQTT dup flag
+ * @param packetid integer returned - the MQTT packet identifier
+ * @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays
+ * @param count - number of members in the topicFilters and requestedQoSs arrays
+ * @param topicFilters - array of topic filter names
+ * @param requestedQoSs - array of requested QoS
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @return the length of the serialized data. <= 0 indicates error
+ */
+int MQTTDeserialize_subscribe(int* dup, int* packetid, int maxcount, int* count, MQTTString topicFilters[], int requestedQoSs[],
+ char* buf, int buflen)
+{
+ MQTTHeader header;
+ char* curdata = buf;
+ char* enddata = NULL;
+ int rc = -1;
+ int mylen = 0;
+
+ FUNC_ENTRY;
+ header.byte = readChar(&curdata);
+ *dup = header.bits.dup;
+
+ curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+ enddata = curdata + mylen;
+
+ *packetid = readInt(&curdata);
+
+ *count = 0;
+ while (curdata < enddata)
+ {
+ if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))
+ goto exit;
+ if (curdata >= enddata) /* do we have enough data to read the req_qos version byte? */
+ goto exit;
+ requestedQoSs[*count] = readChar(&curdata);
+ (*count)++;
+ }
+
+ rc = 1;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Serializes the supplied suback data into the supplied buffer, ready for sending
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param packetid integer - the MQTT packet identifier
+ * @param count - number of members in the grantedQoSs array
+ * @param grantedQoSs - array of granted QoS
+ * @return the length of the serialized data. <= 0 indicates error
+ */
+int MQTTSerialize_suback(char* buf, int buflen, int packetid, int count, int* grantedQoSs)
+{
+ MQTTHeader header;
+ int rc = -1;
+ char *ptr = buf;
+ int i;
+
+ FUNC_ENTRY;
+ if (buflen < 2 + count)
+ {
+ rc = MQTTPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+ header.byte = 0;
+ header.bits.type = SUBACK;
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, 2 + count); /* write remaining length */
+
+ writeInt(&ptr, packetid);
+
+ for (i = 0; i < count; ++i)
+ writeChar(&ptr, grantedQoSs[i]);
+
+ rc = ptr - buf;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTUnsubscribe.h Tue Feb 04 22:31:32 2014 +0000 @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#ifndef MQTTUNSUBSCRIBE_H_ +#define MQTTUNSUBSCRIBE_H_ + +int MQTTSerialize_unsubscribe(char* buf, int buflen, int dup, int packetid, int count, MQTTString topicFilters[]); + +int MQTTDeserialize_unsubscribe(int* dup, int* packetid, int max_count, int* count, MQTTString topicFilters[], char* buf, int len); + +int MQTTSerialize_unsuback(char* buf, int buflen, int packetid); + +int MQTTDeserialize_unsuback(int* packetid, char* buf, int len); + +#endif /* MQTTUNSUBSCRIBE_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTUnsubscribeClient.c Tue Feb 04 22:31:32 2014 +0000
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+/**
+ * Determines the length of the MQTT unsubscribe packet that would be produced using the supplied parameters
+ * @param count the number of topic filter strings in topicFilters
+ * @param topicFilters the array of topic filter strings to be used in the publish
+ * @return the length of buffer needed to contain the serialized version of the packet
+ */
+int MQTTSerialize_unsubscribeLength(int count, MQTTString topicFilters[])
+{
+ int i;
+ int len = 2; /* packetid */
+
+ for (i = 0; i < count; ++i)
+ len += 2 + MQTTstrlen(topicFilters[i]); /* length + topic*/
+ return len;
+}
+
+
+/**
+ * Serializes the supplied unsubscribe data into the supplied buffer, ready for sending
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @param dup integer - the MQTT dup flag
+ * @param packetid integer - the MQTT packet identifier
+ * @param count - number of members in the topicFilters array
+ * @param topicFilters - array of topic filter names
+ * @return the length of the serialized data. <= 0 indicates error
+ */
+int MQTTSerialize_unsubscribe(char* buf, int buflen, int dup, int packetid, int count, MQTTString topicFilters[])
+{
+ char *ptr = buf;
+ MQTTHeader header;
+ int rem_len = 0;
+ int rc = -1;
+ int i = 0;
+
+ FUNC_ENTRY;
+ if (MQTTPacket_len(rem_len = MQTTSerialize_unsubscribeLength(count, topicFilters)) > buflen)
+ {
+ rc = MQTTPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+
+ header.byte = 0;
+ header.bits.type = SUBSCRIBE;
+ header.bits.dup = dup;
+ header.bits.qos = 1;
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
+
+ writeInt(&ptr, packetid);
+
+ for (i = 0; i < count; ++i)
+ writeMQTTString(&ptr, topicFilters[i]);
+
+ rc = ptr - buf;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Deserializes the supplied (wire) buffer into unsuback data
+ * @param packetid returned integer - the MQTT packet identifier
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @return error code. 1 is success, 0 is failure
+ */
+int MQTTDeserialize_unsuback(int* packetid, char* buf, int buflen)
+{
+ int type = 0;
+ int dup = 0;
+ int rc = 0;
+
+ FUNC_ENTRY;
+ rc = MQTTDeserialize_ack(&type, &dup, packetid, buf, buflen);
+ if (type == UNSUBACK)
+ rc = 1;
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTUnsubscribeServer.c Tue Feb 04 22:31:32 2014 +0000
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+
+/**
+ * Deserializes the supplied (wire) buffer into unsubscribe data
+ * @param dup integer returned - the MQTT dup flag
+ * @param packetid integer returned - the MQTT packet identifier
+ * @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays
+ * @param count - number of members in the topicFilters and requestedQoSs arrays
+ * @param topicFilters - array of topic filter names
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @return the length of the serialized data. <= 0 indicates error
+ */
+int MQTTDeserialize_unsubscribe(int* dup, int* packetid, int maxcount, int* count, MQTTString topicFilters[], char* buf, int len)
+{
+ MQTTHeader header;
+ char* curdata = buf;
+ char* enddata = NULL;
+ int rc = 0;
+ int mylen = 0;
+
+ FUNC_ENTRY;
+ header.byte = readChar(&curdata);
+ *dup = header.bits.dup;
+
+ curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+ enddata = curdata + mylen;
+
+ *packetid = readInt(&curdata);
+
+ *count = 0;
+ while (curdata < enddata)
+ {
+ if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))
+ goto exit;
+ (*count)++;
+ }
+
+ rc = 1;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Serializes the supplied unsuback data into the supplied buffer, ready for sending
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param packetid integer - the MQTT packet identifier
+ * @return the length of the serialized data. <= 0 indicates error
+ */
+int MQTTSerialize_unsuback(char* buf, int buflen, int packetid)
+{
+ MQTTHeader header;
+ int rc = 0;
+ char *ptr = buf;
+
+ FUNC_ENTRY;
+ if (buflen < 2)
+ {
+ rc = MQTTPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+ header.byte = 0;
+ header.bits.type = UNSUBACK;
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
+
+ writeInt(&ptr, packetid);
+
+ rc = ptr - buf;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/StackTrace.h Tue Feb 04 22:31:32 2014 +0000 @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#ifndef STACKTRACE_H_ +#define STACKTRACE_H_ + +#include <stdio.h> +#define NOSTACKTRACE 1 + +#if defined(NOSTACKTRACE) +#define FUNC_ENTRY +#define FUNC_ENTRY_NOLOG +#define FUNC_ENTRY_MED +#define FUNC_ENTRY_MAX +#define FUNC_EXIT +#define FUNC_EXIT_NOLOG +#define FUNC_EXIT_MED +#define FUNC_EXIT_MAX +#define FUNC_EXIT_RC(x) +#define FUNC_EXIT_MED_RC(x) +#define FUNC_EXIT_MAX_RC(x) +#else +#if defined(WIN32) +#define inline __inline +#define FUNC_ENTRY StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MINIMUM) +#define FUNC_ENTRY_NOLOG StackTrace_entry(__FUNCTION__, __LINE__, -1) +#define FUNC_ENTRY_MED StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MEDIUM) +#define FUNC_ENTRY_MAX StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MAXIMUM) +#define FUNC_EXIT StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MINIMUM) +#define FUNC_EXIT_NOLOG StackTrace_exit(__FUNCTION__, __LINE__, -1) +#define FUNC_EXIT_MED StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MEDIUM) +#define FUNC_EXIT_MAX StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MAXIMUM) +#define FUNC_EXIT_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MINIMUM) +#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MEDIUM) +#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MAXIMUM) +#else +#define FUNC_ENTRY StackTrace_entry(__func__, __LINE__, TRACE_MINIMUM) +#define FUNC_ENTRY_NOLOG StackTrace_entry(__func__, __LINE__, -1) +#define FUNC_ENTRY_MED StackTrace_entry(__func__, __LINE__, TRACE_MEDIUM) +#define FUNC_ENTRY_MAX StackTrace_entry(__func__, __LINE__, TRACE_MAXIMUM) +#define FUNC_EXIT StackTrace_exit(__func__, __LINE__, NULL, TRACE_MINIMUM) +#define FUNC_EXIT_NOLOG StackTrace_exit(__func__, __LINE__, NULL, -1) +#define FUNC_EXIT_MED StackTrace_exit(__func__, __LINE__, NULL, TRACE_MEDIUM) +#define FUNC_EXIT_MAX StackTrace_exit(__func__, __LINE__, NULL, TRACE_MAXIMUM) +#define FUNC_EXIT_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MINIMUM) +#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MEDIUM) +#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MAXIMUM) +#endif +#endif + +void StackTrace_entry(const char* name, int line, int trace); +void StackTrace_exit(const char* name, int line, void* return_value, int trace); + +void StackTrace_printStack(FILE* dest); +char* StackTrace_get(unsigned long); + + +#endif /* STACKTRACE_H_ */
