From 649fac47495992f73bb6d4f6ffffb29cdb264000 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 13 May 2014 22:45:12 +0100 Subject: [PATCH] Latest updates - qos1 publish sample --- samples/build | 1 + samples/qos1pub.c | 195 ++++++++++++++++++++++++++++++ src/MQTTSNConnect.h | 13 ++ src/MQTTSNConnectClient.c | 211 ++++++++++++++++++++++++++++++++- src/MQTTSNConnectServer.c | 154 +++++++++++++++++++++++- src/MQTTSNDeserializePublish.c | 6 +- src/MQTTSNPacket.c | 72 ++++------- src/MQTTSNPacket.h | 7 +- src/MQTTSNSubscribeClient.c | 28 +++++ test/test1.c | 92 +++++++++++++- 10 files changed, 723 insertions(+), 56 deletions(-) create mode 100644 samples/qos1pub.c create mode 100644 src/MQTTSNSubscribeClient.c diff --git a/samples/build b/samples/build index 82f8e8a..e397cad 100644 --- a/samples/build +++ b/samples/build @@ -1,2 +1,3 @@ gcc -Wall qos0pub.c -I ../src ../src/MQTTSNSerializePublish.c ../src/MQTTSNPacket.c ../src/MQTTSNConnectClient.c -o qos0pub -Os -s gcc -Wall qos-1pub.c -I ../src ../src/MQTTSNSerializePublish.c ../src/MQTTSNPacket.c -o qos-1pub -Os -s +gcc -Wall qos1pub.c -I ../src ../src/MQTTSNSerializePublish.c ../src/MQTTSNDeserializePublish.c ../src/MQTTSNPacket.c ../src/MQTTSNConnectClient.c -o qos1pub -Os -s diff --git a/samples/qos1pub.c b/samples/qos1pub.c new file mode 100644 index 0000000..6d66707 --- /dev/null +++ b/samples/qos1pub.c @@ -0,0 +1,195 @@ +/******************************************************************************* + * 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 + +#if !defined(SOCKET_ERROR) + /** error in socket operation */ + #define SOCKET_ERROR -1 +#endif + +#if defined(WIN32) +/* default on Windows is 64 - increase to make Linux and Windows the same */ +#define FD_SETSIZE 1024 +#include +#include +#define MAXHOSTNAMELEN 256 +#define EAGAIN WSAEWOULDBLOCK +#define EINTR WSAEINTR +#define EINVAL WSAEINVAL +#define EINPROGRESS WSAEINPROGRESS +#define EWOULDBLOCK WSAEWOULDBLOCK +#define ENOTCONN WSAENOTCONN +#define ECONNRESET WSAECONNRESET +#define ioctl ioctlsocket +#define socklen_t int +#else +#define INVALID_SOCKET SOCKET_ERROR +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#if defined(WIN32) +#include +#else +#include +#include +#endif + + +int Socket_error(char* aString, int sock) +{ +#if defined(WIN32) + int errno; +#endif + +#if defined(WIN32) + errno = WSAGetLastError(); +#endif + if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS && errno != EWOULDBLOCK) + { + if (strcmp(aString, "shutdown") != 0 || (errno != ENOTCONN && errno != ECONNRESET)) + { + int orig_errno = errno; + char* errmsg = strerror(errno); + + printf("Socket error %d (%s) in %s for socket %d\n", orig_errno, errmsg, aString, sock); + } + } + return errno; +} + + +int sendPacketBuffer(int asocket, char* host, int port, unsigned char* buf, int buflen) +{ + struct sockaddr_in cliaddr; + int rc = 0; + + memset(&cliaddr, 0, sizeof(cliaddr)); + cliaddr.sin_family = AF_INET; + cliaddr.sin_addr.s_addr = inet_addr(host); + cliaddr.sin_port = htons(port); + + if ((rc = sendto(asocket, buf, buflen, 0, (const struct sockaddr*)&cliaddr, sizeof(cliaddr))) == SOCKET_ERROR) + Socket_error("sendto", asocket); + else + rc = 0; + return rc; +} + + +int mysock = 0; +char *host = "127.0.0.1"; +int port = 1884; + +int getdata(unsigned char* buf, size_t count) +{ + int rc = recvfrom(mysock, buf, count, 0, NULL, NULL); + //printf("received %d bytes count %d\n", rc, (int)count); + return rc; +} + + +int main(int argc, char** argv) +{ + int rc = 0; + unsigned char buf[200]; + int buflen = sizeof(buf); + MQTTSN_topicid topic; + unsigned char* payload = (unsigned char*)"mypayload"; + int payloadlen = strlen((char*)payload); + int len = 0; + int dup = 0; + int qos = 1; + int retained = 0, packetid = 1; + char *topicname = "a long topic name"; + MQTTSNPacket_connectData options = MQTTSNPacket_connectData_initializer; + + if (argc > 1) + host = argv[1]; + + if (argc > 2) + port = atoi(argv[2]); + + printf("Sending to hostname %s port %d\n", host, port); + + mysock = socket(AF_INET, SOCK_DGRAM, 0); + if (mysock == INVALID_SOCKET) + rc = Socket_error("socket", mysock); + + options.clientID.cstring = "myclientid"; + len = MQTTSNSerialize_connect(buf, buflen, &options); + rc = sendPacketBuffer(mysock, host, port, buf, len); + + /* wait for connack */ + if (MQTTSNPacket_read(buf, buflen, getdata) == MQTTSN_CONNACK) + { + int connack_rc = -1; + + if (MQTTSNDeserialize_connack(&connack_rc, buf, buflen) != 1 || connack_rc != 0) + { + printf("Unable to connect, return code %d\n", connack_rc); + goto exit; + } + else + printf("connected rc %d\n", connack_rc); + } + else + goto exit; + + /* publish with short name */ + topic.type = MQTTSN_TOPIC_TYPE_SHORT; + memcpy(topic.data.name, "tt", 2); + len = MQTTSNSerialize_publish(buf, buflen - len, dup, qos, retained, packetid, + topic, payload, payloadlen); + rc = sendPacketBuffer(mysock, host, port, buf, len); + + /* wait for puback */ + if (MQTTSNPacket_read(buf, buflen, getdata) == MQTTSN_PUBACK) + { + unsigned short packet_id, topic_id; + unsigned char returncode; + + if (MQTTSNDeserialize_puback(&topic_id, &packet_id, &returncode, buf, buflen) != 1 || returncode != MQTTSN_RC_ACCEPTED) + printf("Unable to publish, return code %d\n", returncode); + else + printf("puback received, id %d\n", packet_id); + } + else + goto exit; + + len = MQTTSNSerialize_disconnect(buf, buflen, 0); + rc = sendPacketBuffer(mysock, host, port, buf, len); + +exit: + rc = shutdown(mysock, SHUT_WR); + rc = close(mysock); + + return 0; +} diff --git a/src/MQTTSNConnect.h b/src/MQTTSNConnect.h index 67a3ca6..82ab961 100644 --- a/src/MQTTSNConnect.h +++ b/src/MQTTSNConnect.h @@ -39,5 +39,18 @@ 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, MQTTString clientid); +int MQTTSNDeserialize_pingreq(MQTTString* clientID, unsigned char* buf, int len); + +int MQTTSNSerialize_pingresp(unsigned char* buf, int buflen); +int MQTTSNDeserialize_pingresp(unsigned char* buf, int buflen); + +int MQTTSNSerialize_willtopicreq(unsigned char* buf, int buflen); +int MQTTSNDeserialize_willtopicreq(unsigned char* buf, int buflen); + +int MQTTSNSerialize_willmsgreq(unsigned char* buf, int buflen); +int MQTTSNDeserialize_willmsgreq(unsigned char* buf, int buflen); #endif /* MQTTSNCONNECT_H_ */ diff --git a/src/MQTTSNConnectClient.c b/src/MQTTSNConnectClient.c index 7f182ed..38f4ed6 100644 --- a/src/MQTTSNConnectClient.c +++ b/src/MQTTSNConnectClient.c @@ -88,15 +88,15 @@ int MQTTSNDeserialize_connack(int* connack_rc, unsigned char* buf, int buflen) int mylen; FUNC_ENTRY; - curdata += (rc = MQTTSNPacket_decodeBuf(curdata, &mylen)); /* read length */ + curdata += (rc = MQTTSNPacket_decode(curdata, buflen, &mylen)); /* read length */ enddata = buf + mylen; - if (enddata - curdata < 2) + if (enddata - buf < 3) goto exit; if (readChar(&curdata) != MQTTSN_CONNACK) goto exit; - *connack_rc = readInt(&curdata); + *connack_rc = readChar(&curdata); rc = 1; exit: @@ -151,3 +151,208 @@ 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, MQTTString clientid) +{ + int rc = -1; + unsigned char *ptr = buf; + int len = 0; + + FUNC_ENTRY; + if ((len = MQTTSNPacket_len(MQTTstrlen(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 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, int willRetain, MQTTString willTopic) +{ + unsigned char *ptr = buf; + MQTTSNFlags flags; + int len = 0; + int rc = -1; + + FUNC_ENTRY; + if ((len = MQTTSNPacket_len(MQTTstrlen(willTopic) + 2)) > buflen) + { + rc = MQTTSNPACKET_BUFFER_TOO_SHORT; + goto exit; + } + ptr += MQTTSNPacket_encode(ptr, len); /* write length */ + writeChar(&ptr, MQTTSN_WILLTOPICUPD); /* 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 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, MQTTString willMsg) +{ + unsigned char *ptr = buf; + int len = 0; + int rc = -1; + + FUNC_ENTRY; + if ((len = MQTTSNPacket_len(MQTTstrlen(willMsg) + 1)) > buflen) + { + rc = MQTTSNPACKET_BUFFER_TOO_SHORT; + goto exit; + } + ptr += MQTTSNPacket_encode(ptr, len); /* write length */ + writeChar(&ptr, MQTTSN_WILLMSGUPD); /* write message type */ + + writeMQTTSNString(&ptr, willMsg); + + 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_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; +} + + + + diff --git a/src/MQTTSNConnectServer.c b/src/MQTTSNConnectServer.c index 7ebf8d1..d6ae337 100644 --- a/src/MQTTSNConnectServer.c +++ b/src/MQTTSNConnectServer.c @@ -38,7 +38,7 @@ int MQTTSNDeserialize_connect(MQTTSNPacket_connectData* data, unsigned char* buf int mylen = 0; FUNC_ENTRY; - curdata += (rc = MQTTSNPacket_decodeBuf(curdata, &mylen)); /* read length */ + curdata += (rc = MQTTSNPacket_decode(curdata, len, &mylen)); /* read length */ enddata = buf + mylen; if (enddata - curdata < 2) goto exit; @@ -94,3 +94,155 @@ exit: 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(MQTTString* 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; +} diff --git a/src/MQTTSNDeserializePublish.c b/src/MQTTSNDeserializePublish.c index e9e9943..7593bbd 100644 --- a/src/MQTTSNDeserializePublish.c +++ b/src/MQTTSNDeserializePublish.c @@ -43,7 +43,7 @@ int MQTTSNDeserialize_publish(int* dup, int* qos, int* retained, unsigned short* int mylen = 0; FUNC_ENTRY; - curdata += (rc = MQTTSNPacket_decodeBuf(curdata, &mylen)); /* read length */ + curdata += (rc = MQTTSNPacket_decode(curdata, buflen, &mylen)); /* read length */ enddata = buf + mylen; if (enddata - curdata > buflen) goto exit; @@ -95,7 +95,7 @@ int MQTTSNDeserialize_puback(unsigned short* topicid, unsigned short* packetid, int mylen = 0; FUNC_ENTRY; - curdata += (rc = MQTTSNPacket_decodeBuf(curdata, &mylen)); /* read length */ + curdata += (rc = MQTTSNPacket_decode(curdata, buflen, &mylen)); /* read length */ enddata = buf + mylen; if (enddata - curdata > buflen) goto exit; @@ -130,7 +130,7 @@ int MQTTSNDeserialize_ack(unsigned char* type, unsigned short* packetid, unsigne int mylen = 0; FUNC_ENTRY; - curdata += (rc = MQTTSNPacket_decodeBuf(curdata, &mylen)); /* read length */ + curdata += (rc = MQTTSNPacket_decode(curdata, buflen, &mylen)); /* read length */ enddata = buf + mylen; if (enddata - curdata > buflen) goto exit; diff --git a/src/MQTTSNPacket.c b/src/MQTTSNPacket.c index 748a6e8..aad7d70 100644 --- a/src/MQTTSNPacket.c +++ b/src/MQTTSNPacket.c @@ -83,32 +83,26 @@ int MQTTSNPacket_encode(unsigned char* buf, int length) * @param value the decoded length returned * @return the number of bytes read from the socket */ -int MQTTSNPacket_decode(int (*getcharfn)(unsigned char*, int), int* value) +int MQTTSNPacket_decode(unsigned char* buf, size_t buflen, int* value) { - unsigned char c; - int rc = MQTTSNPACKET_READ_ERROR; int len = MQTTSNPACKET_READ_ERROR; #define MAX_NO_OF_LENGTH_BYTES 3 FUNC_ENTRY; - rc = (*getcharfn)(&c, 1); - if (rc != 1) + if (buflen <= 0) goto exit; - if (c == 1) + if (buf[0] == 1) { - unsigned char buf[2]; - unsigned char* ptr = buf; - - rc = (*getcharfn)(buf, 2); - if (rc != 2) + unsigned char* bufptr = &buf[1]; + if (buflen < 3) goto exit; - *value = readInt(&ptr); + *value = readInt(&bufptr); len = 3; } else { - *value = c; + *value = buf[0]; len = 1; } exit: @@ -117,25 +111,6 @@ exit: } -static unsigned char* bufptr; - -int bufchar(unsigned char* c, int count) -{ - int i; - - for (i = 0; i < count; ++i) - *c = *bufptr++; - return count; -} - - -int MQTTSNPacket_decodeBuf(unsigned char* buf, int* value) -{ - bufptr = buf; - return MQTTSNPacket_decode(bufchar, value); -} - - /** * Calculates an integer from two bytes read from the input buffer * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned @@ -233,8 +208,14 @@ int readMQTTSNString(MQTTString* mqttstring, unsigned char** pptr, unsigned char FUNC_ENTRY; mqttstring->lenstring.len = enddata - *pptr; - mqttstring->lenstring.data = (char*)*pptr; - *pptr += mqttstring->lenstring.len; + if (mqttstring->lenstring.len > 0) + { + mqttstring->lenstring.data = (char*)*pptr; + *pptr += mqttstring->lenstring.len; + } + else + mqttstring->lenstring.data = NULL; + mqttstring->cstring = NULL; rc = 1; FUNC_EXIT_RC(rc); return rc; @@ -265,24 +246,23 @@ int MQTTstrlen(MQTTString mqttstring) * @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 MQTTSNPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, size_t)) { 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; /* the length of the length field: 1 or 3 */ + int lenlen = 0; + int datalen = 0; - /* 1. read the length. This is variable in itself */ - lenlen = MQTTSNPacket_decode(getfn, &len); - if (lenlen <= 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 */ - if (MQTTSNPacket_encode(buf, len) != lenlen) /* put the original remaining length back into the buffer */ - goto exit; - - /* 2. read the rest of the data using a callback */ - if ((*getfn)(buf + lenlen, len - lenlen) != len - lenlen) - goto exit; - rc = buf[lenlen]; /* return the packet type */ exit: return rc; diff --git a/src/MQTTSNPacket.h b/src/MQTTSNPacket.h index 64e6e69..abb9512 100644 --- a/src/MQTTSNPacket.h +++ b/src/MQTTSNPacket.h @@ -126,12 +126,13 @@ int MQTTstrlen(MQTTString mqttstring); #include "MQTTSNUnsubscribe.h" */ +#include + char* MQTTSNPacket_name(int ptype); int MQTTSNPacket_len(int length); int MQTTSNPacket_encode(unsigned char* buf, int length); -int MQTTSNPacket_decode(int (*getcharfn)(unsigned char*, int), int* value); -int MQTTSNPacket_decodeBuf(unsigned char* buf, int* value); +int MQTTSNPacket_decode(unsigned char* buf, size_t buflen, int* value); int readInt(unsigned char** pptr); char readChar(unsigned char** pptr); @@ -143,6 +144,8 @@ void writeMQTTSNString(unsigned char** pptr, MQTTString mqttstring); int MQTTDeserialize_ack(int* type, int* dup, int* packetid, char* buf, int buflen); +int MQTTSNPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, size_t)); + #ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ } #endif diff --git a/src/MQTTSNSubscribeClient.c b/src/MQTTSNSubscribeClient.c new file mode 100644 index 0000000..1153f97 --- /dev/null +++ b/src/MQTTSNSubscribeClient.c @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + + + +int MQTTDeserialize_subscribe(int* dup, int* packetid, int maxcount, int* count, MQTTString topicFilters[], int requestedQoSs[], + char* buf, int buflen) +{ + +} + + +int MQTTSerialize_suback(char* buf, int buflen, int packetid, int count, int* grantedQoSs) +{ + diff --git a/test/test1.c b/test/test1.c index 1bbab32..d1a2500 100644 --- a/test/test1.c +++ b/test/test1.c @@ -303,6 +303,8 @@ int test1(struct Options options) int rc = 0; unsigned char buf[100]; int buflen = sizeof(buf); + MQTTString clientid = MQTTString_initializer, clientid_after = MQTTString_initializer; + int duration_after = -1; fprintf(xml, " 0, "rc was %d\n", rc); + + rc = MQTTSNDeserialize_pingreq(&clientid_after, buf, buflen); + assert("good rc from deserialize pingreq", rc == 1, "rc was %d\n", rc); + + /* data after should be the same as data before */ + assert("ClientIDs should be the same", + checkMQTTStrings(clientid, clientid_after), "ClientIDs were different\n", rc); + + /* Pingreq with clientid */ + clientid.cstring = "this is me"; + rc = MQTTSNSerialize_pingreq(buf, buflen, clientid); + assert("good rc from serialize pingreq", rc > 0, "rc was %d\n", rc); + + rc = MQTTSNDeserialize_pingreq(&clientid_after, buf, buflen); + assert("good rc from deserialize pingreq", rc == 1, "rc was %d\n", rc); + + /* data after should be the same as data before */ + assert("ClientIDs should be the same", + checkMQTTStrings(clientid, clientid_after), "ClientIDs were different\n", rc); + + rc = MQTTSNSerialize_pingresp(buf, buflen); + assert("good rc from serialize pingresp", rc > 0, "rc was %d\n", rc); + + rc = MQTTSNDeserialize_pingresp(buf, buflen); + assert("good rc from deserialize pingresp", rc == 1, "rc was %d\n", rc); + + /* Disconnect without duration */ + rc = MQTTSNSerialize_disconnect(buf, buflen, 0); + assert("good rc from serialize disconnect", rc > 0, "rc was %d\n", rc); + + rc = MQTTSNDeserialize_disconnect(&duration_after, buf, buflen); + assert("good rc from deserialize disconnect", rc == 1, "rc was %d\n", rc); + + /* data after should be the same as data before */ + assert("durations should be the same", 0 == duration_after, "durations were different\n", rc); + + /* Disconnect with duration */ + rc = MQTTSNSerialize_disconnect(buf, buflen, 33); + assert("good rc from serialize disconnect", rc > 0, "rc was %d\n", rc); + + rc = MQTTSNDeserialize_disconnect(&duration_after, buf, buflen); + assert("good rc from deserialize disconnect", rc == 1, "rc was %d\n", rc); + + /* data after should be the same as data before */ + assert("durations should be the same", 33 == duration_after, "durations were different\n", rc); + + /* Pingreq with clientid */ + clientid.cstring = "this is me"; + rc = MQTTSNSerialize_pingreq(buf, buflen, clientid); + assert("good rc from serialize pingreq", rc > 0, "rc was %d\n", rc); + + rc = MQTTSNDeserialize_pingreq(&clientid_after, buf, buflen); + assert("good rc from deserialize pingreq", rc == 1, "rc was %d\n", rc); + /* exit: */ MyLog(LOGA_INFO, "TEST1: test %s. %d tests run, %d failures.", (failures == 0) ? "passed" : "failed", tests, failures); @@ -415,6 +474,37 @@ int test2(struct Options options) } +int test3(struct Options options) +{ + int rc = 0; + unsigned char buf[100]; + int buflen = sizeof(buf); + + fprintf(xml, " 0, "rc was %d\n", rc); + + rc = MQTTSNDeserialize_willtopicreq(buf, buflen); + assert("good rc from deserialize willtopicreq", rc == 1, "rc was %d\n", rc); + + rc = MQTTSNSerialize_willmsgreq(buf, buflen); + assert("good rc from serialize willmsgreq", rc > 0, "rc was %d\n", rc); + + rc = MQTTSNDeserialize_willmsgreq(buf, rc); + assert("good rc from deserialize willmsgreq", rc == 1, "rc was %d\n", rc); + +/* exit: */ + MyLog(LOGA_INFO, "TEST1: test %s. %d tests run, %d failures.", + (failures == 0) ? "passed" : "failed", tests, failures); + write_test_result(); + return failures; +} + + #if 0 int test3(struct Options options) { @@ -599,7 +689,7 @@ int test6(struct Options options) int main(int argc, char** argv) { int rc = 0; - int (*tests[])() = {NULL, test1, test2, /*test3, test4, test5,*/ test6}; + int (*tests[])() = {NULL, test1, test2, test3, /*test4, test5,*/ test6}; xml = fopen("TEST-test1.xml", "w"); fprintf(xml, "\n", (int)(ARRAY_SIZE(tests) - 1));