Low level MQTTSN packet library, part of the Eclipse Paho project: http://eclipse.org/paho

Dependents:   MQTTSN sara-n200-hello-mqtt-sn MQTTSN_2

The master source for this project is held at: https://github.com/eclipse/paho.mqtt-sn.embedded-c

Files at this revision

API Documentation at this revision

Comitter:
icraggs
Date:
Thu Feb 26 15:59:36 2015 +0000
Child:
1:7fa362fa563f
Commit message:
First version that works nicely :-)

Changed in this revision

MQTTSNConnect.h Show annotated file Show diff for this revision Revisions of this file
MQTTSNConnectClient.c Show annotated file Show diff for this revision Revisions of this file
MQTTSNConnectServer.c Show annotated file Show diff for this revision Revisions of this file
MQTTSNDeserializePublish.c Show annotated file Show diff for this revision Revisions of this file
MQTTSNPacket.c Show annotated file Show diff for this revision Revisions of this file
MQTTSNPacket.h Show annotated file Show diff for this revision Revisions of this file
MQTTSNPublish.h Show annotated file Show diff for this revision Revisions of this file
MQTTSNSearch.h Show annotated file Show diff for this revision Revisions of this file
MQTTSNSearchClient.c Show annotated file Show diff for this revision Revisions of this file
MQTTSNSearchServer.c Show annotated file Show diff for this revision Revisions of this file
MQTTSNSerializePublish.c Show annotated file Show diff for this revision Revisions of this file
MQTTSNSubscribe.h Show annotated file Show diff for this revision Revisions of this file
MQTTSNSubscribeClient.c Show annotated file Show diff for this revision Revisions of this file
MQTTSNSubscribeServer.c Show annotated file Show diff for this revision Revisions of this file
MQTTSNUnsubscribe.h Show annotated file Show diff for this revision Revisions of this file
MQTTSNUnsubscribeClient.c Show annotated file Show diff for this revision Revisions of this file
MQTTSNUnsubscribeServer.c Show annotated file Show diff for this revision Revisions of this file
StackTrace.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSNConnect.h	Thu Feb 26 15:59:36 2015 +0000
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * 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;
+	MQTTSNString clientID;
+	unsigned short duration;
+	unsigned char cleansession;
+	unsigned char willFlag;
+} MQTTSNPacket_connectData;
+
+#define MQTTSNPacket_connectData_initializer { {'M', 'Q', 'S', 'C'}, 0, {NULL, {0, NULL}}, 10, 1, 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);
+int MQTTSNDeserialize_disconnect(int* duration, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_pingreq(unsigned char* buf, int buflen, MQTTSNString clientid);
+int MQTTSNDeserialize_pingreq(MQTTSNString* clientID, unsigned char* buf, int len);
+
+int MQTTSNSerialize_pingresp(unsigned char* buf, int buflen);
+int MQTTSNDeserialize_pingresp(unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_willmsg(unsigned char* buf, int buflen, MQTTSNString willMsg);
+int MQTTSNDeserialize_willmsg(MQTTSNString* willMsg, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_willmsgreq(unsigned char* buf, int buflen);
+int MQTTSNDeserialize_willmsgreq(unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_willmsgupd(unsigned char* buf, int buflen, MQTTSNString willMsg);
+int MQTTSNDeserialize_willmsgupd(MQTTSNString* willMsg, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_willmsgresp(unsigned char* buf, int buflen, int resp_rc);
+int MQTTSNDeserialize_willmsgresp(int* resp_rc, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_willtopic(unsigned char* buf, int buflen, int willQoS, unsigned char willRetain, MQTTSNString willTopic);
+int MQTTSNDeserialize_willtopic(int* willQoS, unsigned char* willRetain, MQTTSNString* willTopic, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_willtopicreq(unsigned char* buf, int buflen);
+int MQTTSNDeserialize_willtopicreq(unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_willtopicupd(unsigned char* buf, int buflen, int willQoS, unsigned char willRetain, MQTTSNString willTopic);
+int MQTTSNDeserialize_willtopicupd(int *willQoS, unsigned char *willRetain, MQTTSNString* willTopic, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_willtopicresp(unsigned char* buf, int buflen, int resp_rc);
+int MQTTSNDeserialize_willtopicresp(int* resp_rc, unsigned char* buf, int buflen);
+
+#endif /* MQTTSNCONNECT_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSNConnectClient.c	Thu Feb 26 15:59:36 2015 +0000
@@ -0,0 +1,479 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2015 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
+ *    Nicholas Humfrey - Reformatting to make more consistent; bug 453862
+ *******************************************************************************/
+
+#include "MQTTSNPacket.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 MQTTSNSerialize_connectLength(MQTTSNPacket_connectData* options)
+{
+	int len = 0;
+
+	FUNC_ENTRY;
+	len = 5 + MQTTSNstrlen(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 = {0};
+	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_decode(curdata, buflen, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata - buf < 3)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_CONNACK)
+		goto exit;
+
+	*connack_rc = readChar(&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;
+}
+
+
+/**
+  * 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 clientid optional string, not added to packet string == NULL
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_pingreq(unsigned char* buf, int buflen, MQTTSNString clientid)
+{
+	int rc = -1;
+	unsigned char *ptr = buf;
+	int len = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(MQTTSNstrlen(clientid) + 1)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+	writeChar(&ptr, MQTTSN_PINGREQ);      /* write message type */
+
+	writeMQTTSNString(&ptr, clientid);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer
+  * @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_pingresp(unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen;
+
+	FUNC_ENTRY;
+	curdata += (rc = MQTTSNPacket_decode(curdata, buflen, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata < 2)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_PINGRESP)
+		goto exit;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a willtopic or willtopicupd packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param len the length in bytes of the supplied buffer
+  * @param willQoS the qos of the will message
+  * @param willRetain the retained flag of the will message
+  * @param willTopic the topic of the will message
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willtopic1(unsigned char* buf, int buflen, int willQoS, unsigned char willRetain, MQTTSNString willTopic,
+		enum MQTTSN_msgTypes packet_type)
+{
+	unsigned char *ptr = buf;
+	MQTTSNFlags flags = {0};
+	int len = 0;
+	int rc = -1;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(MQTTSNstrlen(willTopic) + 2)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+	writeChar(&ptr, packet_type);      /* write message type */
+
+	flags.all = 0;
+	flags.bits.QoS = willQoS;
+	flags.bits.retain = willRetain;
+	writeChar(&ptr, flags.all);
+
+	writeMQTTSNString(&ptr, willTopic);
+
+	rc = ptr - buf;
+
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a willtopicupd packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param len the length in bytes of the supplied buffer
+  * @param willQoS the qos of the will message
+  * @param willRetain the retained flag of the will message
+  * @param willTopic the topic of the will message
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willtopicupd(unsigned char* buf, int buflen, int willQoS, unsigned char willRetain, MQTTSNString willTopic)
+{
+	return MQTTSNSerialize_willtopic1(buf, buflen, willQoS, willRetain, willTopic, MQTTSN_WILLTOPICUPD);
+}
+
+
+/**
+  * Serializes a willtopic packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param len the length in bytes of the supplied buffer
+  * @param willQoS the qos of the will message
+  * @param willRetain the retained flag of the will message
+  * @param willTopic the topic of the will message
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willtopic(unsigned char* buf, int buflen, int willQoS, unsigned char willRetain, MQTTSNString willTopic)
+{
+	return MQTTSNSerialize_willtopic1(buf, buflen, willQoS, willRetain, willTopic, MQTTSN_WILLTOPIC);
+}
+
+
+/**
+  * Serializes a willmsg or willmsgupd 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 willMsg the will message
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willmsg1(unsigned char* buf, int buflen, MQTTSNString willMsg, enum MQTTSN_msgTypes packet_type)
+{
+	unsigned char *ptr = buf;
+	int len = 0;
+	int rc = -1;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(MQTTSNstrlen(willMsg) + 1)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+	writeChar(&ptr, packet_type);      /* write message type */
+
+	writeMQTTSNString(&ptr, willMsg);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a willmsg packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param len the length in bytes of the supplied buffersage
+  * @param willMsg the will message
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willmsg(unsigned char* buf, int buflen, MQTTSNString willMsg)
+{
+	return MQTTSNSerialize_willmsg1(buf, buflen, willMsg, MQTTSN_WILLMSG);
+}
+
+
+/**
+  * Serializes a willmsgupd packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param len the length in bytes of the supplied buffersage
+  * @param willMsg the will message
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willmsgupd(unsigned char* buf, int buflen, MQTTSNString willMsg)
+{
+	return MQTTSNSerialize_willmsg1(buf, buflen, willMsg, MQTTSN_WILLMSGUPD);
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer
+  * @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_willtopicreq(unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = -1;
+	int mylen;
+
+	FUNC_ENTRY;
+	if (MQTTSNPacket_decode(curdata++, buflen, &mylen) != 1) /* read length */
+		goto exit;
+	if (mylen > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	enddata = buf + mylen;
+	if (enddata - curdata < 1)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_WILLTOPICREQ)
+		goto exit;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer
+  * @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_willmsgreq(unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = -1;
+	int mylen;
+
+	FUNC_ENTRY;
+	if (MQTTSNPacket_decode(curdata++, buflen, &mylen) != 1) /* read length */
+		goto exit;
+	if (mylen > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	enddata = buf + mylen;
+	if (enddata - curdata < 1)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_WILLMSGREQ)
+		goto exit;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into willtopicresp data - return code
+  * @param connack_rc returned integer value of the 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_willtopicresp(int* resp_rc, unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen;
+
+	FUNC_ENTRY;
+	curdata += (rc = MQTTSNPacket_decode(curdata, buflen, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata - buf < 3)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_WILLTOPICRESP)
+		goto exit;
+
+	*resp_rc = readChar(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into willmsgresp data - return code
+  * @param connack_rc returned integer value of the 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_willmsgresp(int* resp_rc, unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen;
+
+	FUNC_ENTRY;
+	curdata += (rc = MQTTSNPacket_decode(curdata, buflen, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata - buf < 3)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_WILLMSGRESP)
+		goto exit;
+
+	*resp_rc = readChar(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSNConnectServer.c	Thu Feb 26 15:59:36 2015 +0000
@@ -0,0 +1,431 @@
+/*******************************************************************************
+ * 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 <string.h>
+
+#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 = {0};
+	unsigned char* curdata = buf;
+	unsigned char* enddata = &buf[len];
+	int rc = 0;
+	int version = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += (rc = MQTTSNPacket_decode(curdata, len, &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 < 3)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	ptr += MQTTSNPacket_encode(ptr, 3); /* write length */
+	writeChar(&ptr, MQTTSN_CONNACK);
+	writeChar(&ptr, connack_rc);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into disconnect data - optional duration
+  * @param duration returned integer value of the duration field, -1 if no duration was specified
+  * @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_disconnect(int* duration, unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = -1;
+	int mylen;
+
+	FUNC_ENTRY;
+	curdata += (rc = MQTTSNPacket_decode(curdata, buflen, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata < 1)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_DISCONNECT)
+		goto exit;
+
+	if (enddata - curdata == 2)
+		*duration = readInt(&curdata);
+	else if (enddata != curdata)
+		goto exit;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a willtopicreq 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
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willtopicreq(unsigned char* buf, int buflen)
+{
+	int rc = 0;
+	unsigned char *ptr = buf;
+
+	FUNC_ENTRY;
+	if (buflen < 2)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	ptr += MQTTSNPacket_encode(ptr, 2); /* write length */
+	writeChar(&ptr, MQTTSN_WILLTOPICREQ);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a willmsgreq 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
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willmsgreq(unsigned char* buf, int buflen)
+{
+	int rc = 0;
+	unsigned char *ptr = buf;
+
+	FUNC_ENTRY;
+	if (buflen < 2)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	ptr += MQTTSNPacket_encode(ptr, 2); /* write length */
+	writeChar(&ptr, MQTTSN_WILLMSGREQ);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+
+/**
+  * Deserializes the supplied (wire) buffer into pingreq data
+  * @param clientID 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_pingreq(MQTTSNString* clientID, unsigned char* buf, int len)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = &buf[len];
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += (rc = MQTTSNPacket_decode(curdata, len, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata < 1)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_PINGREQ)
+		goto exit;
+
+	if (!readMQTTSNString(clientID, &curdata, enddata))
+		goto exit;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a pingresp 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
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_pingresp(unsigned char* buf, int buflen)
+{
+	int rc = 0;
+	unsigned char *ptr = buf;
+
+	FUNC_ENTRY;
+	if (buflen < 2)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	ptr += MQTTSNPacket_encode(ptr, 2); /* write length */
+	writeChar(&ptr, MQTTSN_PINGRESP);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into willtopic or willtopicupd 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_willtopic1(int *willQoS, unsigned char *willRetain, MQTTSNString* willTopic, unsigned char* buf, int len,
+		enum MQTTSN_msgTypes packet_type)
+{
+	MQTTSNFlags flags = {0};
+	unsigned char* curdata = buf;
+	unsigned char* enddata = &buf[len];
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += (rc = MQTTSNPacket_decode(curdata, len, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata > buf + len)
+		goto exit;
+
+	if (readChar(&curdata) != packet_type)
+		goto exit;
+
+	flags.all = readChar(&curdata);
+	*willQoS = flags.bits.QoS;
+	*willRetain = flags.bits.retain;
+
+	if (!readMQTTSNString(willTopic, &curdata, enddata))
+		goto exit;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into willtopic 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_willtopic(int *willQoS, unsigned char *willRetain, MQTTSNString* willTopic, unsigned char* buf, int len)
+{
+	return MQTTSNDeserialize_willtopic1(willQoS, willRetain, willTopic, buf, len, MQTTSN_WILLTOPIC);
+}
+
+/**
+  * Deserializes the supplied (wire) buffer into willtopic 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_willtopicupd(int *willQoS, unsigned char *willRetain, MQTTSNString* willTopic, unsigned char* buf, int len)
+{
+	return MQTTSNDeserialize_willtopic1(willQoS, willRetain, willTopic, buf, len, MQTTSN_WILLTOPICUPD);
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into willmsg or willmsgupd data
+  * @param willMsg the will message to be retrieved
+  * @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_willmsg1(MQTTSNString* willMsg, unsigned char* buf, int len, enum MQTTSN_msgTypes packet_type)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = &buf[len];
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += (rc = MQTTSNPacket_decode(curdata, len, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata > buf + len)
+		goto exit;
+
+	if (readChar(&curdata) != packet_type)
+		goto exit;
+
+	if (!readMQTTSNString(willMsg, &curdata, enddata))
+		goto exit;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into willmsg data
+  * @param willMsg the will message to be retrieved
+  * @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_willmsg(MQTTSNString* willMsg, unsigned char* buf, int len)
+{
+	return MQTTSNDeserialize_willmsg1(willMsg, buf, len, MQTTSN_WILLMSG);
+}
+
+/**
+  * Deserializes the supplied (wire) buffer into willmsgupd data
+  * @param willMsg the will message to be retrieved
+  * @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_willmsgupd(MQTTSNString* willMsg, unsigned char* buf, int len)
+{
+	return MQTTSNDeserialize_willmsg1(willMsg, buf, len, MQTTSN_WILLMSGUPD);
+}
+
+
+/**
+  * Serializes the willtopicresp 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 rc the integer return code to be used
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willtopicresp(unsigned char* buf, int buflen, int resp_rc)
+{
+	int rc = 0;
+	unsigned char *ptr = buf;
+
+	FUNC_ENTRY;
+	if (buflen < 3)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	ptr += MQTTSNPacket_encode(ptr, 3); /* write length */
+	writeChar(&ptr, MQTTSN_WILLTOPICRESP);
+	writeChar(&ptr, resp_rc);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes the willmsgresp 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 rc the integer return code to be used
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willmsgresp(unsigned char* buf, int buflen, int resp_rc)
+{
+	int rc = 0;
+	unsigned char *ptr = buf;
+
+	FUNC_ENTRY;
+	if (buflen < 3)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	ptr += MQTTSNPacket_encode(ptr, 3); /* write length */
+	writeChar(&ptr, MQTTSN_WILLMSGRESP);
+	writeChar(&ptr, resp_rc);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSNDeserializePublish.c	Thu Feb 26 15:59:36 2015 +0000
@@ -0,0 +1,226 @@
+/*******************************************************************************
+ * 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 <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 MQTTSNString - 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(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* 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_decode(curdata, buflen, &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 && *qos == 3)
+	{
+		/* special arrangement for long topic names in QoS -1 publishes.  The length of the topic is in the topicid field */
+		topic->data.long_.len = readInt(&curdata);
+	}
+	else if (topic->type == MQTTSN_TOPIC_TYPE_NORMAL || topic->type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+		topic->data.id = readInt(&curdata);
+	else
+	{
+		topic->data.short_name[0] = readChar(&curdata);
+		topic->data.short_name[1] = readChar(&curdata);
+	}
+	*packetid = readInt(&curdata);
+
+	if (topic->type == MQTTSN_TOPIC_TYPE_NORMAL && *qos == 3)
+	{
+		topic->data.long_.name = (char*)curdata;
+		curdata += topic->data.long_.len;
+	}
+
+	*payloadlen = enddata - curdata;
+	*payload = curdata;
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+int MQTTSNDeserialize_puback(unsigned short* topicid, unsigned short* packetid,
+		unsigned char* returncode, unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += (rc = MQTTSNPacket_decode(curdata, buflen, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_PUBACK)
+		goto exit;
+
+	*topicid = readInt(&curdata);
+	*packetid = readInt(&curdata);
+	*returncode = readChar(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into an ack
+  * @param packettype returned integer - the MQTT packet type
+  * @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 MQTTSNDeserialize_ack(unsigned char* type, unsigned short* packetid, unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += (rc = MQTTSNPacket_decode(curdata, buflen, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	*type = readChar(&curdata);
+	if (*type != MQTTSN_PUBREL && *type != MQTTSN_PUBREC && *type != MQTTSN_PUBCOMP)
+		goto exit;
+
+	*packetid = readInt(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into register data
+  * @param topicid returned topic id
+  * @param packetid returned integer - the MQTT packet identifier
+  * @param topicName returned MQTTSNString - the MQTT topic in the register
+  * @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_register(unsigned short* topicid, unsigned short* packetid, MQTTSNString* topicname,
+		unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += (rc = MQTTSNPacket_decode(curdata, buflen, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_REGISTER)
+		goto exit;
+
+	*topicid = readInt(&curdata);
+	*packetid = readInt(&curdata);
+
+	topicname->lenstring.data = (char*)curdata;
+	topicname->lenstring.len = enddata - curdata;
+	topicname->cstring = NULL;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into register data
+  * @param topicid returned topic id
+  * @param packetid returned integer - the MQTT packet identifier
+  * @param return_code returned integer return code
+  * @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_regack(unsigned short* topicid, unsigned short* packetid, unsigned char* return_code,
+		unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += (rc = MQTTSNPacket_decode(curdata, buflen, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_REGACK)
+		goto exit;
+
+	*topicid = readInt(&curdata);
+	*packetid = readInt(&curdata);
+	*return_code = readChar(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSNPacket.c	Thu Feb 26 15:59:36 2015 +0000
@@ -0,0 +1,272 @@
+/*******************************************************************************
+ * 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 <string.h>
+
+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(unsigned char* buf, int buflen, int* value)
+{
+	int len = MQTTSNPACKET_READ_ERROR;
+#define MAX_NO_OF_LENGTH_BYTES 3
+
+	FUNC_ENTRY;
+	if (buflen <= 0)
+		goto exit;
+
+	if (buf[0] == 1)
+	{
+		unsigned char* bufptr = &buf[1];
+		if (buflen < 3)
+			goto exit;
+		*value = readInt(&bufptr);
+		len = 3;
+	}
+	else
+	{
+		*value = buf[0];
+		len = 1;
+	}
+exit:
+	FUNC_EXIT_RC(len);
+	return len;
+}
+
+
+/**
+ * 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, MQTTSNString MQTTSNString)
+{
+	if (MQTTSNString.lenstring.len > 0)
+	{
+		memcpy(*pptr, MQTTSNString.lenstring.data, MQTTSNString.lenstring.len);
+		*pptr += MQTTSNString.lenstring.len;
+	}
+	else if (MQTTSNString.cstring)
+		writeCString(pptr, MQTTSNString.cstring);
+}
+
+
+/**
+ * @param MQTTSNString the MQTTSNString 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(MQTTSNString* MQTTSNString, unsigned char** pptr, unsigned char* enddata)
+{
+	int rc = 0;
+
+	FUNC_ENTRY;
+	MQTTSNString->lenstring.len = enddata - *pptr;
+	if (MQTTSNString->lenstring.len > 0)
+	{
+		MQTTSNString->lenstring.data = (char*)*pptr;
+		*pptr += MQTTSNString->lenstring.len;
+	}
+	else
+		MQTTSNString->lenstring.data = NULL;
+	MQTTSNString->cstring = NULL;
+	rc = 1;
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+ * Return the length of the MQTTSNString - C string if there is one, otherwise the length delimited string
+ * @param MQTTSNString the string to return the length of
+ * @return the length of the string
+ */
+int MQTTSNstrlen(MQTTSNString MQTTSNString)
+{
+	int rc = 0;
+
+	if (MQTTSNString.cstring)
+		rc = strlen(MQTTSNString.cstring);
+	else
+		rc = MQTTSNString.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;
+	const int MQTTSN_MIN_PACKET_LENGTH = 3;
+	int len = 0;  /* the length of the whole packet including length field */
+	int lenlen = 0;
+	int datalen = 0;
+
+	/* 1. read a packet - UDP style */
+	if ((len = (*getfn)(buf, buflen)) < MQTTSN_MIN_PACKET_LENGTH)
+		goto exit;
+
+	/* 2. read the length.  This is variable in itself */
+	lenlen = MQTTSNPacket_decode(buf, len, &datalen);
+	if (datalen != len)
+		goto exit; /* there was an error */
+
+	rc = buf[lenlen]; /* return the packet type */
+exit:
+	return rc;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSNPacket.h	Thu Feb 26 15:59:36 2015 +0000
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * 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 short_name[2];
+		struct
+		{
+			char* name;
+			int len;
+		} long_;
+	} 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;
+} MQTTSNLenString;
+
+typedef struct
+{
+	char* cstring;
+	MQTTSNLenString lenstring;
+} MQTTSNString;
+
+#define MQTTSNString_initializer {NULL, {0, NULL}}
+
+int MQTTSNstrlen(MQTTSNString mqttsnstring);
+
+#include "MQTTSNConnect.h"
+#include "MQTTSNPublish.h"
+#include "MQTTSNSubscribe.h"
+#include "MQTTSNUnsubscribe.h"
+#include "MQTTSNSearch.h"
+
+char* MQTTSNPacket_name(int ptype);
+int MQTTSNPacket_len(int length);
+
+int MQTTSNPacket_encode(unsigned char* buf, int length);
+int MQTTSNPacket_decode(unsigned char* buf, int buflen, 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(MQTTSNString* mqttstring, unsigned char** pptr, unsigned char* enddata);
+void writeCString(unsigned char** pptr, char* string);
+void writeMQTTSNString(unsigned char** pptr, MQTTSNString mqttstring);
+
+int MQTTSNPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int));
+
+#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
+}
+#endif
+
+
+#endif /* MQTTSNPACKET_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSNPublish.h	Thu Feb 26 15:59:36 2015 +0000
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+
+#if !defined(MQTTSNPUBLISH_H_)
+#define MQTTSNPUBLISH_H_
+
+int MQTTSNSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
+		MQTTSN_topicid topic, unsigned char* payload, int payloadlen);
+int MQTTSNDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid,
+		MQTTSN_topicid* topic, unsigned char** payload, int* payloadlen, unsigned char* buf, int len);
+
+int MQTTSNSerialize_puback(unsigned char* buf, int buflen, unsigned short topicid, unsigned short packetid,
+		unsigned char returncode);
+int MQTTSNDeserialize_puback(unsigned short* topicid, unsigned short* packetid,
+		unsigned char* returncode, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_pubrec(unsigned char* buf, int buflen, unsigned short packetid);
+int MQTTSNSerialize_pubrel(unsigned char* buf, int buflen, unsigned short packetid);
+int MQTTSNSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid);
+
+int MQTTSNDeserialize_ack(unsigned char* packettype, unsigned short* packetid, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_register(unsigned char* buf, int buflen, unsigned short topicid, unsigned short packetid,
+		MQTTSNString* topicname);
+int MQTTSNDeserialize_register(unsigned short* topicid, unsigned short* packetid, MQTTSNString* topicname,
+		unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_regack(unsigned char* buf, int buflen, unsigned short topicid, unsigned short packetid,
+		unsigned char return_code);
+int MQTTSNDeserialize_regack(unsigned short* topicid, unsigned short* packetid, unsigned char* return_code,
+		unsigned char* buf, int buflen);
+
+#endif /* MQTTSNPUBLISH_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSNSearch.h	Thu Feb 26 15:59:36 2015 +0000
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+
+#if !defined(MQTTSNSEARCH_H_)
+#define MQTTSNSEARCH_H_
+
+int MQTTSNSerialize_advertise(unsigned char* buf, int buflen, unsigned char gatewayid, unsigned short duration);
+int MQTTSNDeserialize_advertise(unsigned char* gatewayid, unsigned short* duration, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_searchgw(unsigned char* buf, int buflen, unsigned char radius);
+int MQTTSNDeserialize_searchgw(unsigned char* radius, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_gwinfo(unsigned char* buf, int buflen, unsigned char gatewayid, unsigned short gatewayaddress_len,
+		unsigned char* gatewayaddress);
+int MQTTSNDeserialize_gwinfo(unsigned char* gatewayid, unsigned short* gatewayaddress_len, unsigned char** gatewayaddress,
+		unsigned char* buf, int buflen);
+
+#endif /* MQTTSNSEARCH_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSNSearchClient.c	Thu Feb 26 15:59:36 2015 +0000
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * 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 <string.h>
+
+
+/**
+  * Deserializes the supplied (wire) buffer into advertise data
+  * @param gatewayid the returned gateway id
+  * @param duration the returned duration - the time interval until the next advertise will be sent
+  * @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_advertise(unsigned char* gatewayid, unsigned short* duration,	unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += (rc = MQTTSNPacket_decode(curdata, buflen, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_ADVERTISE)
+		goto exit;
+
+	*gatewayid = readChar(&curdata);
+	*duration = readInt(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+
+/**
+  * Serializes the supplied searchgw 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 radius the broadcast radius of this message
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSNSerialize_searchgw(unsigned char* buf, int buflen, unsigned char radius)
+{
+	unsigned char *ptr = buf;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(2)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len);   /* write length */
+	writeChar(&ptr, MQTTSN_SEARCHGW);      /* write message type */
+
+	writeChar(&ptr, radius);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into gwinfo data
+  * @param gatewayid the returned gateway id
+  * @param gatewayaddress_len the optional returned length of the gateway address (0 if none)
+  * @param gatewayaddress the optional returned gateway address (set to NULL if none)
+  * @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_gwinfo(unsigned char* gatewayid, unsigned short* gatewayaddress_len,
+		unsigned char** gatewayaddress, unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += (rc = MQTTSNPacket_decode(curdata, buflen, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_GWINFO)
+		goto exit;
+
+	*gatewayid = readChar(&curdata);
+
+	*gatewayaddress_len = enddata - curdata;
+	*gatewayaddress = (gatewayaddress_len > 0) ? curdata : NULL;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSNSearchServer.c	Thu Feb 26 15:59:36 2015 +0000
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * 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 <string.h>
+
+
+/**
+  * Serializes the supplied advertise 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 radius the broadcast radius of this message
+  * @param duration - the time interval until the next advertise will be sent
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSNSerialize_advertise(unsigned char* buf, int buflen, unsigned char gatewayid, unsigned short duration)
+{
+	unsigned char *ptr = buf;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(4)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len);   /* write length */
+	writeChar(&ptr, MQTTSN_ADVERTISE);      /* write message type */
+
+	writeChar(&ptr, gatewayid);
+	writeInt(&ptr, duration);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into searchgw data
+  * @param radius the returned broadcast radius of this message
+  * @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_searchgw(unsigned char* radius, unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += (rc = MQTTSNPacket_decode(curdata, buflen, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_SEARCHGW)
+		goto exit;
+
+	*radius = readChar(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes the supplied gwinfo 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 gatewayid the gateway id
+  * @param gatewayaddress_len the optional length of the gateway address (0 if none)
+  * @param gatewayaddress the optional gateway address (NULL if none)
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSNSerialize_gwinfo(unsigned char* buf, int buflen, unsigned char gatewayid, unsigned short gatewayaddress_len,
+		unsigned char* gatewayaddress)
+{
+	unsigned char *ptr = buf;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(2 + gatewayaddress_len)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len);   /* write length */
+	writeChar(&ptr, MQTTSN_GWINFO);      /* write message type */
+
+	writeChar(&ptr, gatewayid);
+	if (gatewayaddress_len > 0 && gatewayaddress != NULL)
+	{
+		memcpy(ptr, gatewayaddress, gatewayaddress_len);
+		ptr += gatewayaddress_len;
+	}
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSNSerializePublish.c	Thu Feb 26 15:59:36 2015 +0000
@@ -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 "MQTTSNPacket.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 MQTTSNSerialize_publishLength(int payloadlen, MQTTSN_topicid topic, int qos)
+{
+	int len = 6;
+
+	if (topic.type == MQTTSN_TOPIC_TYPE_NORMAL && qos == 3)
+		len += topic.data.long_.len;
+
+	return payloadlen + 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 topic MQTTSN_topicid - 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, unsigned char dup, int qos, unsigned char retained, unsigned short 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, topic, qos))) > 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 && qos == 3)
+	{
+		/* special arrangement for long topic names in QoS -1 publishes.  The length of the topic is in the topicid field */
+		writeInt(&ptr, topic.data.long_.len); /* topic length */
+	}
+	else if (topic.type == MQTTSN_TOPIC_TYPE_NORMAL || topic.type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+		writeInt(&ptr, topic.data.id);
+	else
+	{
+		writeChar(&ptr, topic.data.short_name[0]);
+		writeChar(&ptr, topic.data.short_name[1]);
+	}
+	writeInt(&ptr, packetid);
+	if (topic.type == MQTTSN_TOPIC_TYPE_NORMAL && qos == 3)
+	{
+		memcpy(ptr, topic.data.long_.name, topic.data.long_.len);
+		ptr += topic.data.long_.len;
+	}
+	memcpy(ptr, payload, payloadlen);
+	ptr += payloadlen;
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+int MQTTSNSerialize_puback(unsigned char* buf, int buflen, unsigned short topicid, unsigned short packetid,
+		unsigned char returncode)
+{
+	unsigned char *ptr = buf;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(6)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+	writeChar(&ptr, MQTTSN_PUBACK);      /* write message type */
+
+	writeInt(&ptr, topicid);
+	writeInt(&ptr, packetid);
+	writeChar(&ptr, returncode);
+
+	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 the MQTT-SN packet type
+  * @param packetid the MQTT-SN packet identifier
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_ack(unsigned char* buf, int buflen, unsigned short packet_type, unsigned short packetid)
+{
+	int rc = 0;
+	unsigned char *ptr = buf;
+	int len = 4; /* ack packet length */
+
+	FUNC_ENTRY;
+	if (len > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+	writeChar(&ptr, packet_type);      /* write packet type */
+
+	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 MQTTSNSerialize_pubrec(unsigned char* buf, int buflen, unsigned short packetid)
+{
+	return MQTTSNSerialize_ack(buf, buflen, MQTTSN_PUBREC, packetid);
+}
+
+
+/**
+  * 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 MQTTSNSerialize_pubrel(unsigned char* buf, int buflen, unsigned short packetid)
+{
+	return MQTTSNSerialize_ack(buf, buflen, MQTTSN_PUBREL, packetid);
+}
+
+
+/**
+  * 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 MQTTSNSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid)
+{
+	return MQTTSNSerialize_ack(buf, buflen, MQTTSN_PUBCOMP, packetid);
+}
+
+
+/**
+  * Determines the length of the MQTT register packet that would be produced using the supplied parameters
+  * @param topicnamelen the length of the topic name to be used in the register
+  * @return the length of buffer needed to contain the serialized version of the packet
+  */
+int MQTTSNSerialize_registerLength(int topicnamelen)
+{
+	return topicnamelen + 5;
+}
+
+/**
+  * Serializes the supplied register 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 topicid if sent by a gateway, contains the id for the topicname, otherwise 0
+  * @param packetid integer - the MQTT packet identifier
+  * @param topicname null-terminated topic name string
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSNSerialize_register(unsigned char* buf, int buflen, unsigned short topicid, unsigned short packetid,
+		MQTTSNString* topicname)
+{
+	unsigned char *ptr = buf;
+	int len = 0;
+	int rc = 0;
+	int topicnamelen = 0;
+
+	FUNC_ENTRY;
+	topicnamelen = (topicname->cstring) ? strlen(topicname->cstring) : topicname->lenstring.len;
+	if ((len = MQTTSNPacket_len(MQTTSNSerialize_registerLength(topicnamelen))) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len);  /* write length */
+	writeChar(&ptr, MQTTSN_REGISTER);      /* write message type */
+
+	writeInt(&ptr, topicid);
+	writeInt(&ptr, packetid);
+
+	memcpy(ptr, (topicname->cstring) ? topicname->cstring : topicname->lenstring.data, topicnamelen);
+	ptr += topicnamelen;
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes the supplied register 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 topicid if sent by a gateway, contains the id for the topicname, otherwise 0
+  * @param packetid integer - the MQTT packet identifier
+  * @param return_code integer return code
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSNSerialize_regack(unsigned char* buf, int buflen, unsigned short topicid, unsigned short packetid,
+		unsigned char return_code)
+{
+	unsigned char *ptr = buf;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(6)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len);  /* write length */
+	writeChar(&ptr, MQTTSN_REGACK);      /* write message type */
+
+	writeInt(&ptr, topicid);
+	writeInt(&ptr, packetid);
+	writeChar(&ptr, return_code);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSNSubscribe.h	Thu Feb 26 15:59:36 2015 +0000
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+
+#if !defined(MQTTSNSUBSCRIBE_H_)
+#define MQTTSNSUBSCRIBE_H_
+
+int MQTTSNSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned short packetid,
+        MQTTSN_topicid* topicFilter);
+int MQTTSNDeserialize_subscribe(unsigned char* dup, int* qos, unsigned short* packetid,
+        MQTTSN_topicid* topicFilter, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_suback(unsigned char* buf, int buflen, int qos, unsigned short topicid, unsigned short packetid,
+		unsigned char returncode);
+int MQTTSNDeserialize_suback(int* qos, unsigned short* topicid, unsigned short* packetid,
+		unsigned char* returncode, unsigned char* buf, int buflen);
+
+#endif /* MQTTSNSUBSCRIBE_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSNSubscribeClient.c	Thu Feb 26 15:59:36 2015 +0000
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * 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 <string.h>
+
+/**
+  * Determines the length of the MQTTSN subscribe packet that would be produced using the supplied parameters, 
+  * excluding length
+  * @param topicName the topic name to be used in the publish  
+  * @return the length of buffer needed to contain the serialized version of the packet
+  */
+int MQTTSNSerialize_subscribeLength(MQTTSN_topicid* topicFilter)
+{
+	int len = 4;
+
+	if (topicFilter->type == MQTTSN_TOPIC_TYPE_NORMAL)
+		len += topicFilter->data.long_.len;
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_SHORT || topicFilter->type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+		len += 2;
+
+	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 buffer
+  * @param dup integer - the MQTT-SN dup flag
+  * @param qos integer - the MQTT-SN QoS value
+  * @param packetid integer - the MQTT-SN packet identifier
+  * @param topic MQTTSN_topicid - the MQTT-SN topic in the subscribe
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSNSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned short packetid,
+		MQTTSN_topicid* topicFilter)
+{
+	unsigned char *ptr = buf;
+	MQTTSNFlags flags;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(MQTTSNSerialize_subscribeLength(topicFilter))) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len);   /* write length */
+	writeChar(&ptr, MQTTSN_SUBSCRIBE);      /* write message type */
+
+	flags.all = 0;
+	flags.bits.dup = dup;
+	flags.bits.QoS = qos;
+	flags.bits.topicIdType = topicFilter->type;
+	writeChar(&ptr, flags.all);
+
+	writeInt(&ptr, packetid);
+
+	/* now the topic id or name */
+	if (topicFilter->type == MQTTSN_TOPIC_TYPE_NORMAL) /* means long topic name */
+	{
+		memcpy(ptr, topicFilter->data.long_.name, topicFilter->data.long_.len);
+		ptr += topicFilter->data.long_.len;
+	}
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+		writeInt(&ptr, topicFilter->data.id);
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_SHORT)
+	{
+		writeChar(&ptr, topicFilter->data.short_name[0]);
+		writeChar(&ptr, topicFilter->data.short_name[1]);
+	}
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into suback data
+  * @param qos the returned qos
+  * @param topicid returned if "accepted" the value which will be used by the gateway in subsequent PUBLISH packets
+  * @param packetid returned - the same value as the one contained in the corresponding SUBSCRIBE
+  * @param returncode returned - "accepted" or rejection reason
+  * @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_suback(int* qos, unsigned short* topicid, unsigned short* packetid,
+		unsigned char* returncode, 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_decode(curdata, buflen, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_SUBACK)
+		goto exit;
+
+	flags.all = readChar(&curdata);
+	*qos = flags.bits.QoS;
+
+	*topicid = readInt(&curdata);
+	*packetid = readInt(&curdata);
+	*returncode = readChar(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSNSubscribeServer.c	Thu Feb 26 15:59:36 2015 +0000
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * 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 <string.h>
+
+
+/**
+  * Deserializes the supplied (wire) buffer into subscribe data
+  * @param dup the returned MQTT-SN dup flag
+  * @param qos the returned qos
+  * @param packetid returned - the same value as the one contained in the corresponding SUBSCRIBE
+  * @param topicFilter returned - the topic filter - normal, predefined or short
+  * @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_subscribe(unsigned char* dup, int* qos, unsigned short* packetid,
+        MQTTSN_topicid* topicFilter, unsigned char* buf, int buflen)
+{
+	MQTTSNFlags flags = {0};
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += (rc = MQTTSNPacket_decode(curdata, buflen, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_SUBSCRIBE)
+		goto exit;
+
+	flags.all = readChar(&curdata);
+	*dup = flags.bits.dup;
+	*qos = flags.bits.QoS;
+
+	*packetid = readInt(&curdata);
+
+	topicFilter->type = flags.bits.topicIdType;
+
+	if (topicFilter->type == MQTTSN_TOPIC_TYPE_NORMAL)
+	{
+		topicFilter->data.long_.len = enddata - curdata;
+		topicFilter->data.long_.name = (char*)curdata;
+	}
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+		topicFilter->data.id = readInt(&curdata);
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_SHORT)
+	{
+		topicFilter->data.short_name[0] = readChar(&curdata);
+		topicFilter->data.short_name[1] = readChar(&curdata);
+	}
+
+	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 qos integer - the MQTT-SN QoS value
+  * @param topicid if "accepted" the value which will be used by the gateway in subsequent PUBLISH packets
+  * @param packetid integer - the MQTT-SN packet identifier
+  * @param returncode returned - "accepted" or rejection reason
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSNSerialize_suback(unsigned char* buf, int buflen, int qos, unsigned short topicid, unsigned short packetid,
+		unsigned char returncode)
+{
+	MQTTSNFlags flags = {0};
+	unsigned char *ptr = buf;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(7)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+	writeChar(&ptr, MQTTSN_SUBACK);      /* write message type */
+
+	flags.all = 0;
+	flags.bits.QoS = qos;
+	writeChar(&ptr, flags.all);
+
+	writeInt(&ptr, topicid);
+	writeInt(&ptr, packetid);
+	writeChar(&ptr, returncode);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSNUnsubscribe.h	Thu Feb 26 15:59:36 2015 +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
+ *******************************************************************************/
+
+#if !defined(MQTTSNUNSUBSCRIBE_H_)
+#define MQTTSNUNSUBSCRIBE_H_
+
+int MQTTSNSerialize_unsubscribe(unsigned char* buf, int buflen,
+		unsigned short packetid, MQTTSN_topicid* topicFilter);
+int MQTTSNDeserialize_unsubscribe(unsigned short* packetid, MQTTSN_topicid* topicFilter,
+		unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid);
+int MQTTSNDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int buflen);
+
+#endif /* MQTTSNUNSUBSCRIBE_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTTSNUnsubscribeClient.c	Thu Feb 26 15:59:36 2015 +0000
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * 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 <string.h>
+
+/**
+  * Determines the length of the MQTTSN subscribe packet that would be produced using the supplied parameters, 
+  * excluding length
+  * @param topicName the topic name to be used in the publish  
+  * @return the length of buffer needed to contain the serialized version of the packet
+  */
+int MQTTSNSerialize_unsubscribeLength(MQTTSN_topicid* topicFilter)
+{
+	int len = 4;
+
+	if (topicFilter->type == MQTTSN_TOPIC_TYPE_NORMAL)
+		len += topicFilter->data.long_.len;
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_SHORT || topicFilter->type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+		len += 2;
+
+	return len;
+}
+
+
+int MQTTSNSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned short packetid, MQTTSN_topicid* topicFilter)
+{
+	unsigned char *ptr = buf;
+	MQTTSNFlags flags;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(MQTTSNSerialize_unsubscribeLength(topicFilter))) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len);   /* write length */
+	writeChar(&ptr, MQTTSN_UNSUBSCRIBE);      /* write message type */
+
+	flags.all = 0;
+	flags.bits.topicIdType = topicFilter->type;
+	writeChar(&ptr, flags.all);
+
+	writeInt(&ptr, packetid);
+
+	/* now the topic id or name */
+	if (topicFilter->type == MQTTSN_TOPIC_TYPE_NORMAL) /* means long topic name */
+	{
+		memcpy(ptr, topicFilter->data.long_.name, topicFilter->data.long_.len);
+		ptr += topicFilter->data.long_.len;
+	}
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+		writeInt(&ptr, topicFilter->data.id);
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_SHORT)
+	{
+		writeChar(&ptr, topicFilter->data.short_name[0]);
+		writeChar(&ptr, topicFilter->data.short_name[1]);
+	}
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into unsuback data
+  * @param packetid returned - the same value as the one contained in the corresponding SUBSCRIBE
+  * @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_unsuback(unsigned short* packetid, unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += (rc = MQTTSNPacket_decode(curdata, buflen, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_UNSUBACK)
+		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/MQTTSNUnsubscribeServer.c	Thu Feb 26 15:59:36 2015 +0000
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * 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"
+
+int MQTTSNDeserialize_unsubscribe(unsigned short* packetid, MQTTSN_topicid* topicFilter,
+		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_decode(curdata, buflen, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_UNSUBSCRIBE)
+		goto exit;
+
+	flags.all = readChar(&curdata);
+	*packetid = readInt(&curdata);
+
+	topicFilter->type = flags.bits.topicIdType;
+	if (topicFilter->type == MQTTSN_TOPIC_TYPE_NORMAL)
+	{
+		topicFilter->data.long_.len = enddata - curdata;
+		topicFilter->data.long_.name = (char*)curdata;
+	}
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+		topicFilter->data.id = readInt(&curdata);
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_SHORT)
+	{
+		topicFilter->data.short_name[0] = readChar(&curdata);
+		topicFilter->data.short_name[1] = readChar(&curdata);
+	}
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+int MQTTSNSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid)
+{
+	unsigned char *ptr = buf;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(7)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+	writeChar(&ptr, MQTTSN_UNSUBACK);      /* write message type */
+
+	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	Thu Feb 26 15:59:36 2015 +0000
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * 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_ */
+