diff --git a/.cproject b/.cproject
new file mode 100644
index 0000000..439b340
--- /dev/null
+++ b/.cproject
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.project b/.project
new file mode 100644
index 0000000..09b1b50
--- /dev/null
+++ b/.project
@@ -0,0 +1,26 @@
+
+
+ MQTTSN-embedded-C
+
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+
+
diff --git a/src/MQTTSNConnect.h b/src/MQTTSNConnect.h
new file mode 100644
index 0000000..c84a17d
--- /dev/null
+++ b/src/MQTTSNConnect.h
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * 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 MQTTSNCONNECT_H_
+#define MQTTSNCONNECT_H_
+
+typedef struct
+{
+ /** The eyecatcher for this structure. must be MQSC. */
+ char struct_id[4];
+ /** The version number of this structure. Must be 0.
+ */
+ int struct_version;
+ MQTTString clientID;
+ int duration;
+ int cleansession;
+ int willFlag;
+} MQTTSNPacket_connectData;
+
+#define MQTTSNPacket_connectData_initializer { {'M', 'Q', 'S', 'C'}, 0, {NULL, {0, NULL}}, 0, 0, 0 }
+
+int MQTTSNSerialize_connect(unsigned char* buf, int buflen, MQTTSNPacket_connectData* options);
+int MQTTSNDeserialize_connect(MQTTSNPacket_connectData* data, unsigned char* buf, int len);
+
+int MQTTSNSerialize_connack(unsigned char* buf, int buflen, int connack_rc);
+int MQTTSNDeserialize_connack(int* connack_rc, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_disconnect(unsigned char* buf, int buflen, int duration);
+
+#endif /* MQTTSNCONNECT_H_ */
diff --git a/src/MQTTSNConnectClient.c b/src/MQTTSNConnectClient.c
new file mode 100644
index 0000000..7f182ed
--- /dev/null
+++ b/src/MQTTSNConnectClient.c
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * 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 "MQTTSNPacket.h"
+#include "StackTrace.h"
+
+#include
+
+/**
+ * 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 MQTTSNSerialize_connectLength(MQTTSNPacket_connectData* options)
+{
+ int len = 0;
+
+ FUNC_ENTRY;
+ len = 5 + MQTTstrlen(options->clientID);
+ 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 MQTTSNSerialize_connect(unsigned char* buf, int buflen, MQTTSNPacket_connectData* options)
+{
+ unsigned char *ptr = buf;
+ MQTTSNFlags flags;
+ int len = 0;
+ int rc = -1;
+
+ FUNC_ENTRY;
+ if ((len = MQTTSNPacket_len(MQTTSNSerialize_connectLength(options))) > buflen)
+ {
+ rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+ ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+ writeChar(&ptr, MQTTSN_CONNECT); /* write message type */
+
+ flags.all = 0;
+ flags.bits.cleanSession = options->cleansession;
+ flags.bits.will = options->willFlag;
+ writeChar(&ptr, flags.all);
+ writeChar(&ptr, 0x01); /* protocol ID */
+ writeInt(&ptr, options->duration);
+ writeMQTTSNString(&ptr, options->clientID);
+
+ 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 MQTTSNDeserialize_connack(int* connack_rc, unsigned char* buf, int buflen)
+{
+ unsigned char* curdata = buf;
+ unsigned char* enddata = NULL;
+ int rc = 0;
+ int mylen;
+
+ FUNC_ENTRY;
+ curdata += (rc = MQTTSNPacket_decodeBuf(curdata, &mylen)); /* read length */
+ enddata = buf + mylen;
+ if (enddata - curdata < 2)
+ goto exit;
+
+ if (readChar(&curdata) != MQTTSN_CONNACK)
+ goto exit;
+
+ *connack_rc = readInt(&curdata);
+
+ rc = 1;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Determines the length of the MQTT disconnect packet (without length field)
+ * @param duration the parameter used for the disconnect
+ * @return the length of buffer needed to contain the serialized version of the packet
+ */
+int MQTTSNSerialize_disconnectLength(int duration)
+{
+ int len = 0;
+
+ FUNC_ENTRY;
+ len = (duration >= 0) ? 3 : 1;
+ FUNC_EXIT_RC(len);
+ return len;
+}
+
+
+/**
+ * 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
+ * @param duration optional duration, not added to packet if < 0
+ * @return serialized length, or error if 0
+ */
+int MQTTSNSerialize_disconnect(unsigned char* buf, int buflen, int duration)
+{
+ int rc = -1;
+ unsigned char *ptr = buf;
+ int len = 0;
+
+ FUNC_ENTRY;
+ if ((len = MQTTSNPacket_len(MQTTSNSerialize_disconnectLength(duration))) > buflen)
+ {
+ rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+ ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+ writeChar(&ptr, MQTTSN_DISCONNECT); /* write message type */
+
+ if (duration >= 0)
+ writeInt(&ptr, duration);
+
+ rc = ptr - buf;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
diff --git a/src/MQTTSNConnectServer.c b/src/MQTTSNConnectServer.c
new file mode 100644
index 0000000..7ebf8d1
--- /dev/null
+++ b/src/MQTTSNConnectServer.c
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * 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 "MQTTSNPacket.h"
+#include
+
+#define min(a, b) ((a < b) ? 1 : 0)
+
+
+/**
+ * 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 MQTTSNDeserialize_connect(MQTTSNPacket_connectData* data, unsigned char* buf, int len)
+{
+ MQTTSNFlags flags;
+ unsigned char* curdata = buf;
+ unsigned char* enddata = &buf[len];
+ int rc = 0;
+ int version;
+ int mylen = 0;
+
+ FUNC_ENTRY;
+ curdata += (rc = MQTTSNPacket_decodeBuf(curdata, &mylen)); /* read length */
+ enddata = buf + mylen;
+ if (enddata - curdata < 2)
+ goto exit;
+
+ if (readChar(&curdata) != MQTTSN_CONNECT)
+ goto exit;
+
+ flags.all = readChar(&curdata);
+ data->cleansession = flags.bits.cleanSession;
+ data->willFlag = flags.bits.will;
+
+ if ((version = (int)readChar(&curdata)) != 1) /* Protocol version */
+ goto exit;
+
+ data->duration = readInt(&curdata);
+
+ if (!readMQTTSNString(&data->clientID, &curdata, enddata))
+ goto exit;
+
+ 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 MQTTSNSerialize_connack(unsigned char* buf, int buflen, int connack_rc)
+{
+ int rc = 0;
+ unsigned char *ptr = buf;
+
+ FUNC_ENTRY;
+ if (buflen < 4)
+ {
+ rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+
+ ptr += MQTTSNPacket_encode(ptr, 4); /* write length */
+ writeChar(&ptr, MQTTSN_CONNACK);
+ writeInt(&ptr, connack_rc);
+
+ rc = ptr - buf;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
diff --git a/src/MQTTSNDeserializePublish.c b/src/MQTTSNDeserializePublish.c
new file mode 100644
index 0000000..7371189
--- /dev/null
+++ b/src/MQTTSNDeserializePublish.c
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * 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 "MQTTSNPacket.h"
+#include
+
+#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 MQTTSNDeserialize_publish(int* dup, int* qos, int* retained, int* packetid, MQTTSN_topicid* topic,
+ unsigned char** payload, int* payloadlen, unsigned char* buf, int buflen)
+{
+ MQTTSNFlags flags;
+ unsigned char* curdata = buf;
+ unsigned char* enddata = NULL;
+ int rc = 0;
+ int mylen = 0;
+
+ FUNC_ENTRY;
+ curdata += (rc = MQTTSNPacket_decodeBuf(curdata, &mylen)); /* read length */
+ enddata = buf + mylen;
+ if (enddata - curdata > buflen)
+ goto exit;
+
+ if (readChar(&curdata) != MQTTSN_PUBLISH)
+ goto exit;
+
+ flags.all = readChar(&curdata);
+ *dup = flags.bits.dup;
+ *qos = flags.bits.QoS;
+ *retained = flags.bits.retain;
+
+ topic->type = flags.bits.topicIdType;
+ if (topic->type == MQTTSN_TOPIC_TYPE_NORMAL || topic->type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+ topic->data.id = readInt(&curdata);
+ else
+ {
+ topic->data.name[0] = readChar(&curdata);
+ topic->data.name[1] = readChar(&curdata);
+ }
+ *packetid = readInt(&curdata);
+
+ *payloadlen = enddata - curdata;
+ *payload = curdata;
+ rc = 1;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+#if 0
+
+/**
+ * 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;
+}
+
+#endif
diff --git a/src/MQTTSNPacket.c b/src/MQTTSNPacket.c
new file mode 100644
index 0000000..748a6e8
--- /dev/null
+++ b/src/MQTTSNPacket.c
@@ -0,0 +1,291 @@
+/*******************************************************************************
+ * 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 "MQTTSNPacket.h"
+
+#include
+
+static char* packet_names[] =
+{
+ "ADVERTISE", "SEARCHGW", "GWINFO", "RESERVED", "CONNECT", "CONNACK",
+ "WILLTOPICREQ", "WILLTOPIC", "WILLMSGREQ", "WILLMSG", "REGISTER", "REGACK",
+ "PUBLISH", "PUBACK", "PUBCOMP", "PUBREC", "PUBREL", "RESERVED",
+ "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK", "PINGREQ", "PINGRESP",
+ "DISCONNECT", "RESERVED", "WILLTOPICUPD", "WILLTOPICRESP", "WILLMSGUPD",
+ "WILLMSGRESP"
+};
+
+
+/**
+ * Returns a character string representing the packet name given a MsgType code
+ * @param code MsgType code
+ * @return the corresponding packet name
+ */
+char* MQTTSNPacket_name(int code)
+{
+ return (code >= 0 && code <= MQTTSN_WILLMSGRESP) ? packet_names[code] : "UNKNOWN";
+}
+
+
+/**
+ * Calculates the full packet length including length field
+ * @param length the length of the MQTT-SN packet without the length field
+ * @return the total length of the MQTT-SN packet including the length field
+ */
+int MQTTSNPacket_len(int length)
+{
+ return (length > 255) ? length + 3 : length + 1;
+}
+
+
+/**
+ * Encodes the MQTT-SN message length
+ * @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 the buffer
+ */
+int MQTTSNPacket_encode(unsigned char* buf, int length)
+{
+ int rc = 0;
+
+ FUNC_ENTRY;
+ if (length > 255)
+ {
+ buf[rc++] = 0x01;
+ writeInt(&buf, length);
+ rc += 2;
+ }
+ else
+ buf[rc++] = length;
+
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Obtains the MQTT-SN packet length from received data
+ * @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 MQTTSNPacket_decode(int (*getcharfn)(unsigned char*, int), int* value)
+{
+ unsigned char c;
+ int rc = MQTTSNPACKET_READ_ERROR;
+ int len = MQTTSNPACKET_READ_ERROR;
+#define MAX_NO_OF_LENGTH_BYTES 3
+
+ FUNC_ENTRY;
+ rc = (*getcharfn)(&c, 1);
+ if (rc != 1)
+ goto exit;
+
+ if (c == 1)
+ {
+ unsigned char buf[2];
+ unsigned char* ptr = buf;
+
+ rc = (*getcharfn)(buf, 2);
+ if (rc != 2)
+ goto exit;
+ *value = readInt(&ptr);
+ len = 3;
+ }
+ else
+ {
+ *value = c;
+ len = 1;
+ }
+exit:
+ FUNC_EXIT_RC(len);
+ return len;
+}
+
+
+static unsigned char* bufptr;
+
+int bufchar(unsigned char* c, int count)
+{
+ int i;
+
+ for (i = 0; i < count; ++i)
+ *c = *bufptr++;
+ return count;
+}
+
+
+int MQTTSNPacket_decodeBuf(unsigned char* buf, int* value)
+{
+ bufptr = buf;
+ return MQTTSNPacket_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(unsigned char** pptr)
+{
+ unsigned 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(unsigned 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(unsigned char** pptr, char c)
+{
+ **pptr = (unsigned char)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: 0 to 65535
+ */
+void writeInt(unsigned char** pptr, int anInt)
+{
+ **pptr = (unsigned char)(anInt / 256);
+ (*pptr)++;
+ **pptr = (unsigned 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(unsigned char** pptr, char* string)
+{
+ int len = strlen(string);
+ memcpy(*pptr, string, len);
+ *pptr += len;
+}
+
+
+int getLenStringLen(char* ptr)
+{
+ int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1));
+ return len;
+}
+
+
+void writeMQTTSNString(unsigned char** pptr, MQTTString mqttstring)
+{
+ if (mqttstring.lenstring.len > 0)
+ {
+ 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 readMQTTSNString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata)
+{
+ int rc = 0;
+
+ FUNC_ENTRY;
+ mqttstring->lenstring.len = enddata - *pptr;
+ mqttstring->lenstring.data = (char*)*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 MQTTSNPACKET_READ_ERROR on error
+ */
+int MQTTSNPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int))
+{
+ int rc = MQTTSNPACKET_READ_ERROR;
+ int len = 0; /* the length of the whole packet including length field */
+ int lenlen = 0; /* the length of the length field: 1 or 3 */
+
+ /* 1. read the length. This is variable in itself */
+ lenlen = MQTTSNPacket_decode(getfn, &len);
+ if (lenlen <= 0)
+ goto exit; /* there was an error */
+
+ if (MQTTSNPacket_encode(buf, len) != lenlen) /* put the original remaining length back into the buffer */
+ goto exit;
+
+ /* 2. read the rest of the data using a callback */
+ if ((*getfn)(buf + lenlen, len - lenlen) != len - lenlen)
+ goto exit;
+
+ rc = buf[lenlen]; /* return the packet type */
+exit:
+ return rc;
+}
+
+
diff --git a/src/MQTTSNPacket.h b/src/MQTTSNPacket.h
new file mode 100644
index 0000000..05a7782
--- /dev/null
+++ b/src/MQTTSNPacket.h
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * 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 MQTTSNPACKET_H_
+#define MQTTSNPACKET_H_
+
+#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
+extern "C" {
+#endif
+
+enum errors
+{
+ MQTTSNPACKET_BUFFER_TOO_SHORT = -2,
+ MQTTSNPACKET_READ_ERROR = -1,
+ MQTTSNPACKET_READ_COMPLETE,
+};
+
+#define MQTTSN_PROTOCOL_VERSION 0x01
+
+enum MQTTSN_connackCodes
+{
+ MQTTSN_RC_ACCEPTED,
+ MQTTSN_RC_REJECTED_CONGESTED,
+ MQTTSN_RC_REJECTED_INVALID_TOPIC_ID,
+};
+
+enum MQTTSN_topicTypes
+{
+ MQTTSN_TOPIC_TYPE_NORMAL, /* topic id in publish, topic name in subscribe */
+ MQTTSN_TOPIC_TYPE_PREDEFINED,
+ MQTTSN_TOPIC_TYPE_SHORT,
+};
+
+
+enum MQTTSN_msgTypes
+{
+ MQTTSN_ADVERTISE, MQTTSN_SEARCHGW, MQTTSN_GWINFO, MQTTSN_RESERVED1,
+ MQTTSN_CONNECT, MQTTSN_CONNACK,
+ MQTTSN_WILLTOPICREQ, MQTTSN_WILLTOPIC, MQTTSN_WILLMSGREQ, MQTTSN_WILLMSG,
+ MQTTSN_REGISTER, MQTTSN_REGACK,
+ MQTTSN_PUBLISH, MQTTSN_PUBACK, MQTTSN_PUBCOMP, MQTTSN_PUBREC, MQTTSN_PUBREL, MQTTSN_RESERVED2,
+ MQTTSN_SUBSCRIBE, MQTTSN_SUBACK, MQTTSN_UNSUBSCRIBE, MQTTSN_UNSUBACK,
+ MQTTSN_PINGREQ, MQTTSN_PINGRESP,
+ MQTTSN_DISCONNECT, MQTTSN_RESERVED3,
+ MQTTSN_WILLTOPICUPD, MQTTSN_WILLTOPICRESP, MQTTSN_WILLMSGUPD, MQTTSN_WILLMSGRESP,
+};
+
+typedef struct
+{
+ enum MQTTSN_topicTypes type;
+ union
+ {
+ unsigned short id;
+ char name[2];
+ } data;
+} MQTTSN_topicid;
+
+
+/**
+ * Bitfields for the MQTT-SN flags byte.
+ */
+typedef union
+{
+ unsigned char all;
+#if defined(REVERSED)
+ struct
+ {
+ int dup: 1;
+ unsigned int QoS : 2;
+ unsigned int retain : 1;
+ unsigned int will : 1;
+ unsigned int cleanSession : 1;
+ unsigned int topicIdType : 2;
+ } bits;
+#else
+ struct
+ {
+ unsigned int topicIdType : 2;
+ unsigned int cleanSession : 1;
+ unsigned int will : 1;
+ unsigned int retain : 1;
+ unsigned int QoS : 2;
+ int dup: 1;
+ } bits;
+#endif
+} MQTTSNFlags;
+
+
+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 "MQTTSNConnect.h"
+#include "MQTTSNPublish.h"
+/*#include "MQTTSNSubscribe.h"
+#include "MQTTSNUnsubscribe.h"
+*/
+
+char* MQTTSNPacket_name(int ptype);
+int MQTTSNPacket_len(int length);
+
+int MQTTSNPacket_encode(unsigned char* buf, int length);
+int MQTTSNPacket_decode(int (*getcharfn)(unsigned char*, int), int* value);
+int MQTTSNPacket_decodeBuf(unsigned char* buf, int* value);
+
+int readInt(unsigned char** pptr);
+char readChar(unsigned char** pptr);
+void writeChar(unsigned char** pptr, char c);
+void writeInt(unsigned char** pptr, int anInt);
+int readMQTTSNString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata);
+void writeCString(unsigned char** pptr, char* string);
+void writeMQTTSNString(unsigned char** pptr, MQTTString mqttstring);
+
+int MQTTDeserialize_ack(int* type, int* dup, int* packetid, char* buf, int buflen);
+
+#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
+}
+#endif
+
+
+#endif /* MQTTSNPACKET_H_ */
diff --git a/src/MQTTSNPublish.h b/src/MQTTSNPublish.h
new file mode 100644
index 0000000..5c690ce
--- /dev/null
+++ b/src/MQTTSNPublish.h
@@ -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 MQTTSNPUBLISH_H_
+#define MQTTSNPUBLISH_H_
+
+int MQTTSNSerialize_publish(unsigned char* buf, int buflen, int dup, int qos, int retained, int packetid,
+ MQTTSN_topicid topic, unsigned char* payload, int payloadlen);
+
+int MQTTSNDeserialize_publish(int* dup, int* qos, int* retained, int* packetid,
+ MQTTSN_topicid* topic, unsigned char** payload, int* payloadlen, unsigned char* buf, int len);
+
+int MQTTSerialize_puback(char* buf, int buflen, unsigned short packetid, unsigned short topicid, unsigned char returncode);
+int MQTTSerialize_pubrel(char* buf, int buflen, int packetid);
+int MQTTSerialize_pubcomp(char* buf, int buflen, int packetid);
+
+#endif /* MQTTSNPUBLISH_H_ */
diff --git a/src/MQTTSNSerializePublish.c b/src/MQTTSNSerializePublish.c
new file mode 100644
index 0000000..c56250f
--- /dev/null
+++ b/src/MQTTSNSerializePublish.c
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * 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 "MQTTSNPacket.h"
+#include "StackTrace.h"
+
+#include
+
+
+/**
+ * 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 MQTTSNSerialize_publishLength(int payloadlen)
+{
+ return payloadlen + 6;
+}
+
+
+/**
+ * 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 MQTTSNSerialize_publish(unsigned char* buf, int buflen, int dup, int qos, int retained, int packetid,
+ MQTTSN_topicid topic, unsigned char* payload, int payloadlen)
+{
+ unsigned char *ptr = buf;
+ MQTTSNFlags flags;
+ int len = 0;
+ int rc = 0;
+
+ FUNC_ENTRY;
+ if ((len = MQTTSNPacket_len(MQTTSNSerialize_publishLength(payloadlen))) > buflen)
+ {
+ rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+ ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+ writeChar(&ptr, MQTTSN_PUBLISH); /* write message type */
+
+ flags.all = 0;
+ flags.bits.dup = dup;
+ flags.bits.QoS = qos;
+ flags.bits.retain = retained;
+ flags.bits.topicIdType = topic.type;
+ writeChar(&ptr, flags.all);
+
+ if (topic.type == MQTTSN_TOPIC_TYPE_NORMAL || topic.type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+ writeInt(&ptr, topic.data.id);
+ else
+ {
+ writeChar(&ptr, topic.data.name[0]);
+ writeChar(&ptr, topic.data.name[1]);
+ }
+ writeInt(&ptr, packetid);
+ memcpy(ptr, payload, payloadlen);
+ ptr += payloadlen;
+
+ rc = ptr - buf;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+#if 0
+/**
+ * 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);
+}
+
+
+#endif
diff --git a/test/build_test b/test/build_test
new file mode 100644
index 0000000..9ef86cd
--- /dev/null
+++ b/test/build_test
@@ -0,0 +1 @@
+gcc -Wall test1.c -I../src ../src/MQTTSNConnectClient.c ../src/MQTTSNConnectServer.c ../src/MQTTSNPacket.c ../src/MQTTSNSerializePublish.c ../src/MQTTSNDeserializePublish.c
diff --git a/test/test1.c b/test/test1.c
new file mode 100644
index 0000000..5659820
--- /dev/null
+++ b/test/test1.c
@@ -0,0 +1,606 @@
+/*******************************************************************************
+ * 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 "MQTTSNPacket.h"
+#include
+#include
+#include
+
+#if !defined(_WINDOWS)
+ #include
+ #include
+ #include
+ #include
+#else
+#include
+#include
+#define MAXHOSTNAMELEN 256
+#define EAGAIN WSAEWOULDBLOCK
+#define EINTR WSAEINTR
+#define EINPROGRESS WSAEINPROGRESS
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define ENOTCONN WSAENOTCONN
+#define ECONNRESET WSAECONNRESET
+#endif
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+struct Options
+{
+ char* connection; /**< connection to system under test. */
+ char** haconnections;
+ int hacount;
+ int verbose;
+ int test_no;
+} options =
+{
+ "tcp://m2m.eclipse.org:1883",
+ NULL,
+ 0,
+ 0,
+ 0,
+};
+
+void usage()
+{
+
+}
+
+void getopts(int argc, char** argv)
+{
+ int count = 1;
+
+ while (count < argc)
+ {
+ if (strcmp(argv[count], "--test_no") == 0)
+ {
+ if (++count < argc)
+ options.test_no = atoi(argv[count]);
+ else
+ usage();
+ }
+ else if (strcmp(argv[count], "--connection") == 0)
+ {
+ if (++count < argc)
+ {
+ options.connection = argv[count];
+ printf("\nSetting connection to %s\n", options.connection);
+ }
+ else
+ usage();
+ }
+ else if (strcmp(argv[count], "--haconnections") == 0)
+ {
+ if (++count < argc)
+ {
+ char* tok = strtok(argv[count], " ");
+ options.hacount = 0;
+ options.haconnections = malloc(sizeof(char*) * 5);
+ while (tok)
+ {
+ options.haconnections[options.hacount] = malloc(strlen(tok) + 1);
+ strcpy(options.haconnections[options.hacount], tok);
+ options.hacount++;
+ tok = strtok(NULL, " ");
+ }
+ }
+ else
+ usage();
+ }
+ else if (strcmp(argv[count], "--verbose") == 0)
+ {
+ options.verbose = 1;
+ printf("\nSetting verbose on\n");
+ }
+ count++;
+ }
+}
+
+
+#define LOGA_DEBUG 0
+#define LOGA_INFO 1
+#include
+#include
+#include
+void MyLog(int LOGA_level, char* format, ...)
+{
+ static char msg_buf[256];
+ va_list args;
+ struct timeb ts;
+
+ struct tm *timeinfo;
+
+ if (LOGA_level == LOGA_DEBUG && options.verbose == 0)
+ return;
+
+ ftime(&ts);
+ timeinfo = localtime(&ts.time);
+ strftime(msg_buf, 80, "%Y%m%d %H%M%S", timeinfo);
+
+ sprintf(&msg_buf[strlen(msg_buf)], ".%.3hu ", ts.millitm);
+
+ va_start(args, format);
+ vsnprintf(&msg_buf[strlen(msg_buf)], sizeof(msg_buf) - strlen(msg_buf), format, args);
+ va_end(args);
+
+ printf("%s\n", msg_buf);
+ fflush(stdout);
+}
+
+
+#if defined(WIN32) || defined(_WINDOWS)
+#define mqsleep(A) Sleep(1000*A)
+#define START_TIME_TYPE DWORD
+static DWORD start_time = 0;
+START_TIME_TYPE start_clock(void)
+{
+ return GetTickCount();
+}
+#elif defined(AIX)
+#define mqsleep sleep
+#define START_TIME_TYPE struct timespec
+START_TIME_TYPE start_clock(void)
+{
+ static struct timespec start;
+ clock_gettime(CLOCK_REALTIME, &start);
+ return start;
+}
+#else
+#define mqsleep sleep
+#define START_TIME_TYPE struct timeval
+/* TODO - unused - remove? static struct timeval start_time; */
+START_TIME_TYPE start_clock(void)
+{
+ struct timeval start_time;
+ gettimeofday(&start_time, NULL);
+ return start_time;
+}
+#endif
+
+
+#if defined(WIN32)
+long elapsed(START_TIME_TYPE start_time)
+{
+ return GetTickCount() - start_time;
+}
+#elif defined(AIX)
+#define assert(a)
+long elapsed(struct timespec start)
+{
+ struct timespec now, res;
+
+ clock_gettime(CLOCK_REALTIME, &now);
+ ntimersub(now, start, res);
+ return (res.tv_sec)*1000L + (res.tv_nsec)/1000000L;
+}
+#else
+long elapsed(START_TIME_TYPE start_time)
+{
+ struct timeval now, res;
+
+ gettimeofday(&now, NULL);
+ timersub(&now, &start_time, &res);
+ return (res.tv_sec)*1000 + (res.tv_usec)/1000;
+}
+#endif
+
+
+#define assert(a, b, c, d) myassert(__FILE__, __LINE__, a, b, c, d)
+#define assert1(a, b, c, d, e) myassert(__FILE__, __LINE__, a, b, c, d, e)
+
+int tests = 0;
+int failures = 0;
+FILE* xml;
+START_TIME_TYPE global_start_time;
+char output[3000];
+char* cur_output = output;
+
+
+void write_test_result()
+{
+ long duration = elapsed(global_start_time);
+
+ fprintf(xml, " time=\"%ld.%.3ld\" >\n", duration / 1000, duration % 1000);
+ if (cur_output != output)
+ {
+ fprintf(xml, "%s", output);
+ cur_output = output;
+ }
+ fprintf(xml, "\n");
+}
+
+
+void myassert(char* filename, int lineno, char* description, int value, char* format, ...)
+{
+ ++tests;
+ if (!value)
+ {
+ va_list args;
+
+ ++failures;
+ printf("Assertion failed, file %s, line %d, description: %s\n", filename, lineno, description);
+
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+
+ cur_output += sprintf(cur_output, "file %s, line %d \n",
+ description, filename, lineno);
+ }
+ else
+ MyLog(LOGA_DEBUG, "Assertion succeeded, file %s, line %d, description: %s", filename, lineno, description);
+}
+
+#define min(a, b) ((a < b) ? a : b)
+
+int checkMQTTStrings(MQTTString a, MQTTString b)
+{
+ if (!a.lenstring.data)
+ {
+ a.lenstring.data = a.cstring;
+ if (a.cstring)
+ a.lenstring.len = strlen(a.cstring);
+ }
+ if (!b.lenstring.data)
+ {
+ b.lenstring.data = b.cstring;
+ if (b.cstring)
+ b.lenstring.len = strlen(b.cstring);
+ }
+ return memcmp(a.lenstring.data, b.lenstring.data, min(a.lenstring.len, b.lenstring.len)) == 0;
+}
+
+int checkMQTTSNTopics(MQTTSN_topicid a, MQTTSN_topicid b)
+{
+ return a.type == b.type && a.data.id == b.data.id;
+}
+
+
+int checkConnectPackets(MQTTSNPacket_connectData* before, MQTTSNPacket_connectData* after)
+{
+ int rc = 0;
+ int start_failures = failures;
+
+ assert("struct_ids should be the same",
+ memcmp(before->struct_id, after->struct_id, 4) == 0, "struct_ids were different %.4s\n", after->struct_id);
+
+ assert("struct_versions should be the same",
+ before->struct_version == after->struct_version, "struct_versions were different\n", rc);
+
+ assert("ClientIDs should be the same",
+ checkMQTTStrings(before->clientID, after->clientID), "ClientIDs were different\n", rc);
+
+ assert("durations should be the same",
+ before->duration == after->duration, "durations were different\n", rc);
+
+ assert("cleansessions should be the same",
+ before->cleansession == after->cleansession, "cleansessions were different\n", rc);
+
+ assert("willFlags should be the same",
+ before->willFlag == after->willFlag, "willFlags were different\n", rc);
+
+ return failures == start_failures;
+}
+
+int test1(struct Options options)
+{
+ MQTTSNPacket_connectData data = MQTTSNPacket_connectData_initializer;
+ MQTTSNPacket_connectData data_after = MQTTSNPacket_connectData_initializer;
+ int rc = 0;
+ unsigned char buf[100];
+ int buflen = sizeof(buf);
+
+ fprintf(xml, " 0, "rc was %d\n", rc);
+
+ rc = MQTTSNDeserialize_connect(&data_after, buf, buflen);
+ assert("good rc from deserialize connect", rc == 1, "rc was %d\n", rc);
+
+ /* data after should be the same as data before */
+ rc = checkConnectPackets(&data, &data_after);
+ assert("packets should be the same", rc == 1, "packets were different\n", rc);
+
+/* exit: */
+ MyLog(LOGA_INFO, "TEST1: test %s. %d tests run, %d failures.",
+ (failures == 0) ? "passed" : "failed", tests, failures);
+ write_test_result();
+ return failures;
+}
+
+
+int test2(struct Options options)
+{
+ int rc = 0;
+ unsigned char buf[100];
+ int buflen = sizeof(buf);
+
+ int dup = 0;
+ int qos = 2;
+ int retained = 0;
+ int msgid = 23;
+ MQTTSN_topicid topic;
+ unsigned char *payload = (unsigned char*)"kkhkhkjkj jkjjk jk jk ";
+ int payloadlen = strlen((char*)payload);
+
+ int dup2 = 1;
+ int qos2 = 1;
+ int retained2 = 1;
+ int msgid2 = 3243;
+ MQTTSN_topicid topic2;
+ unsigned char *payload2 = NULL;
+ int payloadlen2 = 0;
+
+ fprintf(xml, " 0, "rc was %d\n", rc);
+
+ rc = MQTTSNDeserialize_publish(&dup2, &qos2, &retained2, &msgid2, &topic2,
+ &payload2, &payloadlen2, buf, buflen);
+ assert("good rc from deserialize publish", rc == 1, "rc was %d\n", rc);
+
+ /* data after should be the same as data before */
+ assert("dups should be the same", dup == dup2, "dups were different %d\n", dup2);
+ assert("qoss should be the same", qos == qos2, "qoss were different %d\n", qos2);
+ assert("retaineds should be the same", retained == retained2, "retaineds were different %d\n", retained2);
+ assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2);
+
+ assert("topics should be the same",
+ checkMQTTSNTopics(topic, topic2), "topics were different %s\n", "");
+
+ assert("payload lengths should be the same",
+ payloadlen == payloadlen2, "payload lengths were different %d\n", payloadlen2);
+
+ assert("payloads should be the same",
+ memcmp(payload, payload2, payloadlen) == 0, "payloads were different %s\n", "");
+
+/*exit:*/
+ MyLog(LOGA_INFO, "TEST2: test %s. %d tests run, %d failures.",
+ (failures == 0) ? "passed" : "failed", tests, failures);
+ write_test_result();
+ return failures;
+}
+
+
+#if 0
+int test3(struct Options options)
+{
+ int i = 0;
+ int rc = 0;
+ char buf[100];
+ int buflen = sizeof(buf);
+#define TOPIC_COUNT 2
+
+ int dup = 0;
+ int msgid = 23;
+ int count = TOPIC_COUNT;
+ MQTTString topicStrings[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer };
+ int req_qoss[TOPIC_COUNT] = {2, 1};
+
+ int dup2 = 1;
+ int msgid2 = 2223;
+ int count2 = 0;
+ MQTTString topicStrings2[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer };
+ int req_qoss2[TOPIC_COUNT] = {0, 0};
+
+ fprintf(xml, " 0, "rc was %d\n", rc);
+
+ rc = MQTTDeserialize_subscribe(&dup2, &msgid2, 2, &count2, topicStrings2, req_qoss2, buf, buflen);
+ assert("good rc from deserialize subscribe", rc == 1, "rc was %d\n", rc);
+
+ /* data after should be the same as data before */
+ assert("dups should be the same", dup == dup2, "dups were different %d\n", dup2);
+ assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2);
+
+ assert("count should be the same", count == count2, "counts were different %d\n", count2);
+
+ for (i = 0; i < count2; ++i)
+ {
+ assert("topics should be the same",
+ checkMQTTStrings(topicStrings[i], topicStrings2[i]), "topics were different %s\n", "");
+
+ assert("qoss should be the same", req_qoss[i] == req_qoss2[i], "qoss were different %d\n", req_qoss2[i]);
+ }
+
+/*exit:*/
+ MyLog(LOGA_INFO, "TEST3: test %s. %d tests run, %d failures.",
+ (failures == 0) ? "passed" : "failed", tests, failures);
+ write_test_result();
+ return failures;
+}
+
+
+int test4(struct Options options)
+{
+ int i = 0;
+ int rc = 0;
+ char buf[100];
+ int buflen = sizeof(buf);
+#define TOPIC_COUNT 2
+
+ int msgid = 23;
+ int count = TOPIC_COUNT;
+ int granted_qoss[TOPIC_COUNT] = {2, 1};
+;
+ int msgid2 = 2223;
+ int count2 = 0;
+ int granted_qoss2[TOPIC_COUNT] = {0, 0};
+
+ fprintf(xml, " 0, "rc was %d\n", rc);
+
+ rc = MQTTDeserialize_suback(&msgid2, 2, &count2, granted_qoss2, buf, buflen);
+ assert("good rc from deserialize suback", rc == 1, "rc was %d\n", rc);
+
+ /* data after should be the same as data before */
+ assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2);
+
+ assert("count should be the same", count == count2, "counts were different %d\n", count2);
+
+ for (i = 0; i < count2; ++i)
+ assert("qoss should be the same", granted_qoss[i] == granted_qoss2[i], "qoss were different %d\n", granted_qoss2[i]);
+
+/* exit: */
+ MyLog(LOGA_INFO, "TEST4: test %s. %d tests run, %d failures.",
+ (failures == 0) ? "passed" : "failed", tests, failures);
+ write_test_result();
+ return failures;
+}
+
+
+int test5(struct Options options)
+{
+ int i = 0;
+ int rc = 0;
+ char buf[100];
+ int buflen = sizeof(buf);
+#define TOPIC_COUNT 2
+
+ int dup = 0;
+ int msgid = 23;
+ int count = TOPIC_COUNT;
+ MQTTString topicStrings[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer };
+
+ int dup2 = 1;
+ int msgid2 = 2223;
+ int count2 = 0;
+ MQTTString topicStrings2[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer };
+
+ fprintf(xml, " 0, "rc was %d\n", rc);
+
+ rc = MQTTDeserialize_unsubscribe(&dup2, &msgid2, 2, &count2, topicStrings2, buf, buflen);
+ assert("good rc from deserialize unsubscribe", rc == 1, "rc was %d\n", rc);
+
+ /* data after should be the same as data before */
+ assert("dups should be the same", dup == dup2, "dups were different %d\n", dup2);
+ assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2);
+
+ assert("count should be the same", count == count2, "counts were different %d\n", count2);
+
+ for (i = 0; i < count2; ++i)
+ assert("topics should be the same",
+ checkMQTTStrings(topicStrings[i], topicStrings2[i]), "topics were different %s\n", "");
+
+/* exit: */
+ MyLog(LOGA_INFO, "TEST5: test %s. %d tests run, %d failures.",
+ (failures == 0) ? "passed" : "failed", tests, failures);
+ write_test_result();
+ return failures;
+}
+#endif
+
+
+int test6(struct Options options)
+{
+ int rc = 0;
+ unsigned char buf[100];
+ int buflen = sizeof(buf);
+
+ int connack_rc = 77;
+
+ int connack_rc2 = 0;
+
+ fprintf(xml, " 0, "rc was %d\n", rc);
+
+ rc = MQTTSNDeserialize_connack(&connack_rc2, buf, buflen);
+ assert("good rc from deserialize connack", rc == 1, "rc was %d\n", rc);
+
+ /* data after should be the same as data before */
+ assert("dups should be the same", connack_rc == connack_rc2, "dups were different %d\n", connack_rc2);
+
+/* exit: */
+ MyLog(LOGA_INFO, "TEST6: test %s. %d tests run, %d failures.",
+ (failures == 0) ? "passed" : "failed", tests, failures);
+ write_test_result();
+ return failures;
+}
+
+
+int main(int argc, char** argv)
+{
+ int rc = 0;
+ int (*tests[])() = {NULL, test1, test2, /*test3, test4, test5,*/ test6};
+
+ xml = fopen("TEST-test1.xml", "w");
+ fprintf(xml, "\n", (int)(ARRAY_SIZE(tests) - 1));
+
+ getopts(argc, argv);
+
+ if (options.test_no == 0)
+ { /* run all the tests */
+ for (options.test_no = 1; options.test_no < ARRAY_SIZE(tests); ++options.test_no)
+ rc += tests[options.test_no](options); /* return number of failures. 0 = test succeeded */
+ }
+ else
+ rc = tests[options.test_no](options); /* run just the selected test */
+
+ if (rc == 0)
+ MyLog(LOGA_INFO, "verdict pass");
+ else
+ MyLog(LOGA_INFO, "verdict fail");
+
+ fprintf(xml, "\n");
+ fclose(xml);
+ return rc;
+}