mirror of
https://github.com/eclipse/paho.mqtt-sn.embedded-c.git
synced 2025-12-13 07:26:52 +01:00
Connect and publish packets
This commit is contained in:
124
.cproject
Normal file
124
.cproject
Normal file
@@ -0,0 +1,124 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
|
||||
<storageModule moduleId="org.eclipse.cdt.core.settings">
|
||||
<cconfiguration id="cdt.managedbuild.config.gnu.exe.debug.1685199227">
|
||||
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.debug.1685199227" moduleId="org.eclipse.cdt.core.settings" name="Debug">
|
||||
<externalSettings/>
|
||||
<extensions>
|
||||
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
</extensions>
|
||||
</storageModule>
|
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.debug.1685199227" name="Debug" parent="cdt.managedbuild.config.gnu.exe.debug">
|
||||
<folderInfo id="cdt.managedbuild.config.gnu.exe.debug.1685199227." name="/" resourcePath="">
|
||||
<toolChain id="cdt.managedbuild.toolchain.gnu.exe.debug.102264757" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.debug">
|
||||
<targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.debug.2137160061" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.debug"/>
|
||||
<builder buildPath="${workspace_loc:/MQTTSN-embedded-C}/Debug" id="cdt.managedbuild.target.gnu.builder.exe.debug.767762182" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.exe.debug"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.archiver.base.602829827" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.109068141" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug">
|
||||
<option id="gnu.cpp.compiler.exe.debug.option.optimization.level.1710260957" name="Optimization Level" superClass="gnu.cpp.compiler.exe.debug.option.optimization.level" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/>
|
||||
<option id="gnu.cpp.compiler.exe.debug.option.debugging.level.1258567310" name="Debug Level" superClass="gnu.cpp.compiler.exe.debug.option.debugging.level" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.debug.2017162618" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.debug">
|
||||
<option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.exe.debug.option.optimization.level.1941536725" name="Optimization Level" superClass="gnu.c.compiler.exe.debug.option.optimization.level" valueType="enumerated"/>
|
||||
<option id="gnu.c.compiler.exe.debug.option.debugging.level.1668726974" name="Debug Level" superClass="gnu.c.compiler.exe.debug.option.debugging.level" value="gnu.c.debugging.level.max" valueType="enumerated"/>
|
||||
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.814497727" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.c.linker.exe.debug.1881440001" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.debug">
|
||||
<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.910023243" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
|
||||
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
|
||||
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
|
||||
</inputType>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug.581660133" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.assembler.exe.debug.1531154076" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.debug">
|
||||
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1193873077" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
|
||||
</tool>
|
||||
</toolChain>
|
||||
</folderInfo>
|
||||
<sourceEntries>
|
||||
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="samples"/>
|
||||
<entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="src"/>
|
||||
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="test"/>
|
||||
</sourceEntries>
|
||||
</configuration>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||
</cconfiguration>
|
||||
<cconfiguration id="cdt.managedbuild.config.gnu.exe.release.561557339">
|
||||
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.release.561557339" moduleId="org.eclipse.cdt.core.settings" name="Release">
|
||||
<externalSettings/>
|
||||
<extensions>
|
||||
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
</extensions>
|
||||
</storageModule>
|
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.release.561557339" name="Release" parent="cdt.managedbuild.config.gnu.exe.release">
|
||||
<folderInfo id="cdt.managedbuild.config.gnu.exe.release.561557339." name="/" resourcePath="">
|
||||
<toolChain id="cdt.managedbuild.toolchain.gnu.exe.release.474335535" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.release">
|
||||
<targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.release.338327831" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.release"/>
|
||||
<builder buildPath="${workspace_loc:/MQTTSN-embedded-C}/Release" id="cdt.managedbuild.target.gnu.builder.exe.release.1268563010" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.exe.release"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.archiver.base.1908794347" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.1903732701" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release">
|
||||
<option id="gnu.cpp.compiler.exe.release.option.optimization.level.15425920" name="Optimization Level" superClass="gnu.cpp.compiler.exe.release.option.optimization.level" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/>
|
||||
<option id="gnu.cpp.compiler.exe.release.option.debugging.level.857802503" name="Debug Level" superClass="gnu.cpp.compiler.exe.release.option.debugging.level" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.release.246546722" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.release">
|
||||
<option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.exe.release.option.optimization.level.1094525037" name="Optimization Level" superClass="gnu.c.compiler.exe.release.option.optimization.level" valueType="enumerated"/>
|
||||
<option id="gnu.c.compiler.exe.release.option.debugging.level.162341902" name="Debug Level" superClass="gnu.c.compiler.exe.release.option.debugging.level" value="gnu.c.debugging.level.none" valueType="enumerated"/>
|
||||
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.456127079" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.c.linker.exe.release.2140499460" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.release">
|
||||
<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.46435036" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
|
||||
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
|
||||
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
|
||||
</inputType>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.cpp.linker.exe.release.1623573602" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.release"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.assembler.exe.release.67939689" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.release">
|
||||
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.651929038" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
|
||||
</tool>
|
||||
</toolChain>
|
||||
</folderInfo>
|
||||
<sourceEntries>
|
||||
<entry excluding="samples|test" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
|
||||
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="samples"/>
|
||||
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="test"/>
|
||||
</sourceEntries>
|
||||
</configuration>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||
</cconfiguration>
|
||||
</storageModule>
|
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
<project id="MQTTSN-embedded-C.cdt.managedbuild.target.gnu.exe.317758410" name="Executable" projectType="cdt.managedbuild.target.gnu.exe"/>
|
||||
</storageModule>
|
||||
<storageModule moduleId="scannerConfiguration">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.561557339;cdt.managedbuild.config.gnu.exe.release.561557339.;cdt.managedbuild.tool.gnu.c.compiler.exe.release.246546722;cdt.managedbuild.tool.gnu.c.compiler.input.456127079">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
</scannerConfigBuildInfo>
|
||||
<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.1685199227;cdt.managedbuild.config.gnu.exe.debug.1685199227.;cdt.managedbuild.tool.gnu.c.compiler.exe.debug.2017162618;cdt.managedbuild.tool.gnu.c.compiler.input.814497727">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
</scannerConfigBuildInfo>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
|
||||
<storageModule moduleId="refreshScope" versionNumber="2">
|
||||
<configuration configurationName="Debug">
|
||||
<resource resourceType="PROJECT" workspacePath="/MQTTSN-embedded-C"/>
|
||||
</configuration>
|
||||
<configuration configurationName="Release">
|
||||
<resource resourceType="PROJECT" workspacePath="/MQTTSN-embedded-C"/>
|
||||
</configuration>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
|
||||
</cproject>
|
||||
26
.project
Normal file
26
.project
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>MQTTSN-embedded-C</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
|
||||
<triggers>clean,full,incremental,</triggers>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
|
||||
<triggers>full,incremental,</triggers>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
43
src/MQTTSNConnect.h
Normal file
43
src/MQTTSNConnect.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef MQTTSNCONNECT_H_
|
||||
#define MQTTSNCONNECT_H_
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/** The eyecatcher for this structure. must be MQSC. */
|
||||
char struct_id[4];
|
||||
/** The version number of this structure. Must be 0.
|
||||
*/
|
||||
int struct_version;
|
||||
MQTTString clientID;
|
||||
int duration;
|
||||
int cleansession;
|
||||
int willFlag;
|
||||
} MQTTSNPacket_connectData;
|
||||
|
||||
#define MQTTSNPacket_connectData_initializer { {'M', 'Q', 'S', 'C'}, 0, {NULL, {0, NULL}}, 0, 0, 0 }
|
||||
|
||||
int MQTTSNSerialize_connect(unsigned char* buf, int buflen, MQTTSNPacket_connectData* options);
|
||||
int MQTTSNDeserialize_connect(MQTTSNPacket_connectData* data, unsigned char* buf, int len);
|
||||
|
||||
int MQTTSNSerialize_connack(unsigned char* buf, int buflen, int connack_rc);
|
||||
int MQTTSNDeserialize_connack(int* connack_rc, unsigned char* buf, int buflen);
|
||||
|
||||
int MQTTSNSerialize_disconnect(unsigned char* buf, int buflen, int duration);
|
||||
|
||||
#endif /* MQTTSNCONNECT_H_ */
|
||||
153
src/MQTTSNConnectClient.c
Normal file
153
src/MQTTSNConnectClient.c
Normal file
@@ -0,0 +1,153 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "MQTTSNPacket.h"
|
||||
#include "StackTrace.h"
|
||||
|
||||
#include <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 + MQTTstrlen(options->clientID);
|
||||
FUNC_EXIT_RC(len);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the connect options into the buffer.
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param len the length in bytes of the supplied buffer
|
||||
* @param options the options to be used to build the connect packet
|
||||
* @return serialized length, or error if 0
|
||||
*/
|
||||
int MQTTSNSerialize_connect(unsigned char* buf, int buflen, MQTTSNPacket_connectData* options)
|
||||
{
|
||||
unsigned char *ptr = buf;
|
||||
MQTTSNFlags flags;
|
||||
int len = 0;
|
||||
int rc = -1;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if ((len = MQTTSNPacket_len(MQTTSNSerialize_connectLength(options))) > buflen)
|
||||
{
|
||||
rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
|
||||
goto exit;
|
||||
}
|
||||
ptr += MQTTSNPacket_encode(ptr, len); /* write length */
|
||||
writeChar(&ptr, MQTTSN_CONNECT); /* write message type */
|
||||
|
||||
flags.all = 0;
|
||||
flags.bits.cleanSession = options->cleansession;
|
||||
flags.bits.will = options->willFlag;
|
||||
writeChar(&ptr, flags.all);
|
||||
writeChar(&ptr, 0x01); /* protocol ID */
|
||||
writeInt(&ptr, options->duration);
|
||||
writeMQTTSNString(&ptr, options->clientID);
|
||||
|
||||
rc = ptr - buf;
|
||||
|
||||
exit: FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes the supplied (wire) buffer into connack data - return code
|
||||
* @param connack_rc returned integer value of the connack return code
|
||||
* @param buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param len the length in bytes of the data in the supplied buffer
|
||||
* @return error code. 1 is success, 0 is failure
|
||||
*/
|
||||
int MQTTSNDeserialize_connack(int* connack_rc, unsigned char* buf, int buflen)
|
||||
{
|
||||
unsigned char* curdata = buf;
|
||||
unsigned char* enddata = NULL;
|
||||
int rc = 0;
|
||||
int mylen;
|
||||
|
||||
FUNC_ENTRY;
|
||||
curdata += (rc = MQTTSNPacket_decodeBuf(curdata, &mylen)); /* read length */
|
||||
enddata = buf + mylen;
|
||||
if (enddata - curdata < 2)
|
||||
goto exit;
|
||||
|
||||
if (readChar(&curdata) != MQTTSN_CONNACK)
|
||||
goto exit;
|
||||
|
||||
*connack_rc = readInt(&curdata);
|
||||
|
||||
rc = 1;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines the length of the MQTT disconnect packet (without length field)
|
||||
* @param duration the parameter used for the disconnect
|
||||
* @return the length of buffer needed to contain the serialized version of the packet
|
||||
*/
|
||||
int MQTTSNSerialize_disconnectLength(int duration)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
len = (duration >= 0) ? 3 : 1;
|
||||
FUNC_EXIT_RC(len);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer, to avoid overruns
|
||||
* @param duration optional duration, not added to packet if < 0
|
||||
* @return serialized length, or error if 0
|
||||
*/
|
||||
int MQTTSNSerialize_disconnect(unsigned char* buf, int buflen, int duration)
|
||||
{
|
||||
int rc = -1;
|
||||
unsigned char *ptr = buf;
|
||||
int len = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if ((len = MQTTSNPacket_len(MQTTSNSerialize_disconnectLength(duration))) > buflen)
|
||||
{
|
||||
rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
|
||||
goto exit;
|
||||
}
|
||||
ptr += MQTTSNPacket_encode(ptr, len); /* write length */
|
||||
writeChar(&ptr, MQTTSN_DISCONNECT); /* write message type */
|
||||
|
||||
if (duration >= 0)
|
||||
writeInt(&ptr, duration);
|
||||
|
||||
rc = ptr - buf;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
96
src/MQTTSNConnectServer.c
Normal file
96
src/MQTTSNConnectServer.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "StackTrace.h"
|
||||
#include "MQTTSNPacket.h"
|
||||
#include <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;
|
||||
unsigned char* curdata = buf;
|
||||
unsigned char* enddata = &buf[len];
|
||||
int rc = 0;
|
||||
int version;
|
||||
int mylen = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
curdata += (rc = MQTTSNPacket_decodeBuf(curdata, &mylen)); /* read length */
|
||||
enddata = buf + mylen;
|
||||
if (enddata - curdata < 2)
|
||||
goto exit;
|
||||
|
||||
if (readChar(&curdata) != MQTTSN_CONNECT)
|
||||
goto exit;
|
||||
|
||||
flags.all = readChar(&curdata);
|
||||
data->cleansession = flags.bits.cleanSession;
|
||||
data->willFlag = flags.bits.will;
|
||||
|
||||
if ((version = (int)readChar(&curdata)) != 1) /* Protocol version */
|
||||
goto exit;
|
||||
|
||||
data->duration = readInt(&curdata);
|
||||
|
||||
if (!readMQTTSNString(&data->clientID, &curdata, enddata))
|
||||
goto exit;
|
||||
|
||||
rc = 1;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the connack packet into the supplied buffer.
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer
|
||||
* @param connack_rc the integer connack return code to be used
|
||||
* @return serialized length, or error if 0
|
||||
*/
|
||||
int MQTTSNSerialize_connack(unsigned char* buf, int buflen, int connack_rc)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned char *ptr = buf;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (buflen < 4)
|
||||
{
|
||||
rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ptr += MQTTSNPacket_encode(ptr, 4); /* write length */
|
||||
writeChar(&ptr, MQTTSN_CONNACK);
|
||||
writeInt(&ptr, connack_rc);
|
||||
|
||||
rc = ptr - buf;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
114
src/MQTTSNDeserializePublish.c
Normal file
114
src/MQTTSNDeserializePublish.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "StackTrace.h"
|
||||
#include "MQTTSNPacket.h"
|
||||
#include <string.h>
|
||||
|
||||
#define min(a, b) ((a < b) ? 1 : 0)
|
||||
|
||||
/**
|
||||
* Deserializes the supplied (wire) buffer into publish data
|
||||
* @param dup returned integer - the MQTT dup flag
|
||||
* @param qos returned integer - the MQTT QoS value
|
||||
* @param retained returned integer - the MQTT retained flag
|
||||
* @param packetid returned integer - the MQTT packet identifier
|
||||
* @param topicName returned MQTTString - the MQTT topic in the publish
|
||||
* @param payload returned byte buffer - the MQTT publish payload
|
||||
* @param payloadlen returned integer - the length of the MQTT payload
|
||||
* @param buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param buflen the length in bytes of the data in the supplied buffer
|
||||
* @return error code. 1 is success
|
||||
*/
|
||||
int MQTTSNDeserialize_publish(int* dup, int* qos, int* retained, int* packetid, MQTTSN_topicid* topic,
|
||||
unsigned char** payload, int* payloadlen, unsigned char* buf, int buflen)
|
||||
{
|
||||
MQTTSNFlags flags;
|
||||
unsigned char* curdata = buf;
|
||||
unsigned char* enddata = NULL;
|
||||
int rc = 0;
|
||||
int mylen = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
curdata += (rc = MQTTSNPacket_decodeBuf(curdata, &mylen)); /* read length */
|
||||
enddata = buf + mylen;
|
||||
if (enddata - curdata > buflen)
|
||||
goto exit;
|
||||
|
||||
if (readChar(&curdata) != MQTTSN_PUBLISH)
|
||||
goto exit;
|
||||
|
||||
flags.all = readChar(&curdata);
|
||||
*dup = flags.bits.dup;
|
||||
*qos = flags.bits.QoS;
|
||||
*retained = flags.bits.retain;
|
||||
|
||||
topic->type = flags.bits.topicIdType;
|
||||
if (topic->type == MQTTSN_TOPIC_TYPE_NORMAL || topic->type == MQTTSN_TOPIC_TYPE_PREDEFINED)
|
||||
topic->data.id = readInt(&curdata);
|
||||
else
|
||||
{
|
||||
topic->data.name[0] = readChar(&curdata);
|
||||
topic->data.name[1] = readChar(&curdata);
|
||||
}
|
||||
*packetid = readInt(&curdata);
|
||||
|
||||
*payloadlen = enddata - curdata;
|
||||
*payload = curdata;
|
||||
rc = 1;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
/**
|
||||
* Deserializes the supplied (wire) buffer into an ack
|
||||
* @param type returned integer - the MQTT packet type
|
||||
* @param dup returned integer - the MQTT dup flag
|
||||
* @param packetid returned integer - the MQTT packet identifier
|
||||
* @param buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param buflen the length in bytes of the data in the supplied buffer
|
||||
* @return error code. 1 is success, 0 is failure
|
||||
*/
|
||||
int MQTTDeserialize_ack(int* type, int* dup, int* packetid, char* buf, int buflen)
|
||||
{
|
||||
MQTTHeader header;
|
||||
char* curdata = buf;
|
||||
char* enddata = NULL;
|
||||
int rc = 0;
|
||||
int mylen;
|
||||
|
||||
FUNC_ENTRY;
|
||||
header.byte = readChar(&curdata);
|
||||
*dup = header.bits.dup;
|
||||
*type = header.bits.type;
|
||||
|
||||
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
|
||||
enddata = curdata + mylen;
|
||||
|
||||
if (enddata - curdata < 2)
|
||||
goto exit;
|
||||
*packetid = readInt(&curdata);
|
||||
|
||||
rc = 1;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif
|
||||
291
src/MQTTSNPacket.c
Normal file
291
src/MQTTSNPacket.c
Normal file
@@ -0,0 +1,291 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "StackTrace.h"
|
||||
#include "MQTTSNPacket.h"
|
||||
|
||||
#include <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(int (*getcharfn)(unsigned char*, int), int* value)
|
||||
{
|
||||
unsigned char c;
|
||||
int rc = MQTTSNPACKET_READ_ERROR;
|
||||
int len = MQTTSNPACKET_READ_ERROR;
|
||||
#define MAX_NO_OF_LENGTH_BYTES 3
|
||||
|
||||
FUNC_ENTRY;
|
||||
rc = (*getcharfn)(&c, 1);
|
||||
if (rc != 1)
|
||||
goto exit;
|
||||
|
||||
if (c == 1)
|
||||
{
|
||||
unsigned char buf[2];
|
||||
unsigned char* ptr = buf;
|
||||
|
||||
rc = (*getcharfn)(buf, 2);
|
||||
if (rc != 2)
|
||||
goto exit;
|
||||
*value = readInt(&ptr);
|
||||
len = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
*value = c;
|
||||
len = 1;
|
||||
}
|
||||
exit:
|
||||
FUNC_EXIT_RC(len);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static unsigned char* bufptr;
|
||||
|
||||
int bufchar(unsigned char* c, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
*c = *bufptr++;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
int MQTTSNPacket_decodeBuf(unsigned char* buf, int* value)
|
||||
{
|
||||
bufptr = buf;
|
||||
return MQTTSNPacket_decode(bufchar, value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates an integer from two bytes read from the input buffer
|
||||
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
|
||||
* @return the integer value calculated
|
||||
*/
|
||||
int readInt(unsigned char** pptr)
|
||||
{
|
||||
unsigned char* ptr = *pptr;
|
||||
int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1));
|
||||
*pptr += 2;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads one character from the input buffer.
|
||||
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
|
||||
* @return the character read
|
||||
*/
|
||||
char readChar(unsigned char** pptr)
|
||||
{
|
||||
char c = **pptr;
|
||||
(*pptr)++;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes one character to an output buffer.
|
||||
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
|
||||
* @param c the character to write
|
||||
*/
|
||||
void writeChar(unsigned char** pptr, char c)
|
||||
{
|
||||
**pptr = (unsigned char)c;
|
||||
(*pptr)++;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes an integer as 2 bytes to an output buffer.
|
||||
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
|
||||
* @param anInt the integer to write: 0 to 65535
|
||||
*/
|
||||
void writeInt(unsigned char** pptr, int anInt)
|
||||
{
|
||||
**pptr = (unsigned char)(anInt / 256);
|
||||
(*pptr)++;
|
||||
**pptr = (unsigned char)(anInt % 256);
|
||||
(*pptr)++;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes a "UTF" string to an output buffer. Converts C string to length-delimited.
|
||||
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
|
||||
* @param string the C string to write
|
||||
*/
|
||||
void writeCString(unsigned char** pptr, char* string)
|
||||
{
|
||||
int len = strlen(string);
|
||||
memcpy(*pptr, string, len);
|
||||
*pptr += len;
|
||||
}
|
||||
|
||||
|
||||
int getLenStringLen(char* ptr)
|
||||
{
|
||||
int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1));
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
void writeMQTTSNString(unsigned char** pptr, MQTTString mqttstring)
|
||||
{
|
||||
if (mqttstring.lenstring.len > 0)
|
||||
{
|
||||
memcpy(*pptr, mqttstring.lenstring.data, mqttstring.lenstring.len);
|
||||
*pptr += mqttstring.lenstring.len;
|
||||
}
|
||||
else if (mqttstring.cstring)
|
||||
writeCString(pptr, mqttstring.cstring);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mqttstring the MQTTString structure into which the data is to be read
|
||||
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
|
||||
* @param enddata pointer to the end of the data: do not read beyond
|
||||
* @return 1 if successful, 0 if not
|
||||
*/
|
||||
int readMQTTSNString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
mqttstring->lenstring.len = enddata - *pptr;
|
||||
mqttstring->lenstring.data = (char*)*pptr;
|
||||
*pptr += mqttstring->lenstring.len;
|
||||
rc = 1;
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the length of the MQTTstring - C string if there is one, otherwise the length delimited string
|
||||
* @param mqttstring the string to return the length of
|
||||
* @return the length of the string
|
||||
*/
|
||||
int MQTTstrlen(MQTTString mqttstring)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (mqttstring.cstring)
|
||||
rc = strlen(mqttstring.cstring);
|
||||
else
|
||||
rc = mqttstring.lenstring.len;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function to read packet data from some source into a buffer
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer
|
||||
* @param getfn pointer to a function which will read any number of bytes from the needed source
|
||||
* @return integer MQTT packet type, or MQTTSNPACKET_READ_ERROR on error
|
||||
*/
|
||||
int MQTTSNPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int))
|
||||
{
|
||||
int rc = MQTTSNPACKET_READ_ERROR;
|
||||
int len = 0; /* the length of the whole packet including length field */
|
||||
int lenlen = 0; /* the length of the length field: 1 or 3 */
|
||||
|
||||
/* 1. read the length. This is variable in itself */
|
||||
lenlen = MQTTSNPacket_decode(getfn, &len);
|
||||
if (lenlen <= 0)
|
||||
goto exit; /* there was an error */
|
||||
|
||||
if (MQTTSNPacket_encode(buf, len) != lenlen) /* put the original remaining length back into the buffer */
|
||||
goto exit;
|
||||
|
||||
/* 2. read the rest of the data using a callback */
|
||||
if ((*getfn)(buf + lenlen, len - lenlen) != len - lenlen)
|
||||
goto exit;
|
||||
|
||||
rc = buf[lenlen]; /* return the packet type */
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
146
src/MQTTSNPacket.h
Normal file
146
src/MQTTSNPacket.h
Normal file
@@ -0,0 +1,146 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef MQTTSNPACKET_H_
|
||||
#define MQTTSNPACKET_H_
|
||||
|
||||
#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum errors
|
||||
{
|
||||
MQTTSNPACKET_BUFFER_TOO_SHORT = -2,
|
||||
MQTTSNPACKET_READ_ERROR = -1,
|
||||
MQTTSNPACKET_READ_COMPLETE,
|
||||
};
|
||||
|
||||
#define MQTTSN_PROTOCOL_VERSION 0x01
|
||||
|
||||
enum MQTTSN_connackCodes
|
||||
{
|
||||
MQTTSN_RC_ACCEPTED,
|
||||
MQTTSN_RC_REJECTED_CONGESTED,
|
||||
MQTTSN_RC_REJECTED_INVALID_TOPIC_ID,
|
||||
};
|
||||
|
||||
enum MQTTSN_topicTypes
|
||||
{
|
||||
MQTTSN_TOPIC_TYPE_NORMAL, /* topic id in publish, topic name in subscribe */
|
||||
MQTTSN_TOPIC_TYPE_PREDEFINED,
|
||||
MQTTSN_TOPIC_TYPE_SHORT,
|
||||
};
|
||||
|
||||
|
||||
enum MQTTSN_msgTypes
|
||||
{
|
||||
MQTTSN_ADVERTISE, MQTTSN_SEARCHGW, MQTTSN_GWINFO, MQTTSN_RESERVED1,
|
||||
MQTTSN_CONNECT, MQTTSN_CONNACK,
|
||||
MQTTSN_WILLTOPICREQ, MQTTSN_WILLTOPIC, MQTTSN_WILLMSGREQ, MQTTSN_WILLMSG,
|
||||
MQTTSN_REGISTER, MQTTSN_REGACK,
|
||||
MQTTSN_PUBLISH, MQTTSN_PUBACK, MQTTSN_PUBCOMP, MQTTSN_PUBREC, MQTTSN_PUBREL, MQTTSN_RESERVED2,
|
||||
MQTTSN_SUBSCRIBE, MQTTSN_SUBACK, MQTTSN_UNSUBSCRIBE, MQTTSN_UNSUBACK,
|
||||
MQTTSN_PINGREQ, MQTTSN_PINGRESP,
|
||||
MQTTSN_DISCONNECT, MQTTSN_RESERVED3,
|
||||
MQTTSN_WILLTOPICUPD, MQTTSN_WILLTOPICRESP, MQTTSN_WILLMSGUPD, MQTTSN_WILLMSGRESP,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
enum MQTTSN_topicTypes type;
|
||||
union
|
||||
{
|
||||
unsigned short id;
|
||||
char name[2];
|
||||
} data;
|
||||
} MQTTSN_topicid;
|
||||
|
||||
|
||||
/**
|
||||
* Bitfields for the MQTT-SN flags byte.
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
unsigned char all;
|
||||
#if defined(REVERSED)
|
||||
struct
|
||||
{
|
||||
int dup: 1;
|
||||
unsigned int QoS : 2;
|
||||
unsigned int retain : 1;
|
||||
unsigned int will : 1;
|
||||
unsigned int cleanSession : 1;
|
||||
unsigned int topicIdType : 2;
|
||||
} bits;
|
||||
#else
|
||||
struct
|
||||
{
|
||||
unsigned int topicIdType : 2;
|
||||
unsigned int cleanSession : 1;
|
||||
unsigned int will : 1;
|
||||
unsigned int retain : 1;
|
||||
unsigned int QoS : 2;
|
||||
int dup: 1;
|
||||
} bits;
|
||||
#endif
|
||||
} MQTTSNFlags;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int len;
|
||||
char* data;
|
||||
} MQTTLenString;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char* cstring;
|
||||
MQTTLenString lenstring;
|
||||
} MQTTString;
|
||||
|
||||
#define MQTTString_initializer {NULL, {0, NULL}}
|
||||
|
||||
int MQTTstrlen(MQTTString mqttstring);
|
||||
|
||||
#include "MQTTSNConnect.h"
|
||||
#include "MQTTSNPublish.h"
|
||||
/*#include "MQTTSNSubscribe.h"
|
||||
#include "MQTTSNUnsubscribe.h"
|
||||
*/
|
||||
|
||||
char* MQTTSNPacket_name(int ptype);
|
||||
int MQTTSNPacket_len(int length);
|
||||
|
||||
int MQTTSNPacket_encode(unsigned char* buf, int length);
|
||||
int MQTTSNPacket_decode(int (*getcharfn)(unsigned char*, int), int* value);
|
||||
int MQTTSNPacket_decodeBuf(unsigned char* buf, int* value);
|
||||
|
||||
int readInt(unsigned char** pptr);
|
||||
char readChar(unsigned char** pptr);
|
||||
void writeChar(unsigned char** pptr, char c);
|
||||
void writeInt(unsigned char** pptr, int anInt);
|
||||
int readMQTTSNString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata);
|
||||
void writeCString(unsigned char** pptr, char* string);
|
||||
void writeMQTTSNString(unsigned char** pptr, MQTTString mqttstring);
|
||||
|
||||
int MQTTDeserialize_ack(int* type, int* dup, int* packetid, char* buf, int buflen);
|
||||
|
||||
#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* MQTTSNPACKET_H_ */
|
||||
30
src/MQTTSNPublish.h
Normal file
30
src/MQTTSNPublish.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef MQTTSNPUBLISH_H_
|
||||
#define MQTTSNPUBLISH_H_
|
||||
|
||||
int MQTTSNSerialize_publish(unsigned char* buf, int buflen, int dup, int qos, int retained, int packetid,
|
||||
MQTTSN_topicid topic, unsigned char* payload, int payloadlen);
|
||||
|
||||
int MQTTSNDeserialize_publish(int* dup, int* qos, int* retained, int* packetid,
|
||||
MQTTSN_topicid* topic, unsigned char** payload, int* payloadlen, unsigned char* buf, int len);
|
||||
|
||||
int MQTTSerialize_puback(char* buf, int buflen, unsigned short packetid, unsigned short topicid, unsigned char returncode);
|
||||
int MQTTSerialize_pubrel(char* buf, int buflen, int packetid);
|
||||
int MQTTSerialize_pubcomp(char* buf, int buflen, int packetid);
|
||||
|
||||
#endif /* MQTTSNPUBLISH_H_ */
|
||||
167
src/MQTTSNSerializePublish.c
Normal file
167
src/MQTTSNSerializePublish.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "MQTTSNPacket.h"
|
||||
#include "StackTrace.h"
|
||||
|
||||
#include <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)
|
||||
{
|
||||
return payloadlen + 6;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the supplied publish data into the supplied buffer, ready for sending
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer
|
||||
* @param dup integer - the MQTT dup flag
|
||||
* @param qos integer - the MQTT QoS value
|
||||
* @param retained integer - the MQTT retained flag
|
||||
* @param packetid integer - the MQTT packet identifier
|
||||
* @param topicName MQTTString - the MQTT topic in the publish
|
||||
* @param payload byte buffer - the MQTT publish payload
|
||||
* @param payloadlen integer - the length of the MQTT payload
|
||||
* @return the length of the serialized data. <= 0 indicates error
|
||||
*/
|
||||
int MQTTSNSerialize_publish(unsigned char* buf, int buflen, int dup, int qos, int retained, int packetid,
|
||||
MQTTSN_topicid topic, unsigned char* payload, int payloadlen)
|
||||
{
|
||||
unsigned char *ptr = buf;
|
||||
MQTTSNFlags flags;
|
||||
int len = 0;
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if ((len = MQTTSNPacket_len(MQTTSNSerialize_publishLength(payloadlen))) > buflen)
|
||||
{
|
||||
rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
|
||||
goto exit;
|
||||
}
|
||||
ptr += MQTTSNPacket_encode(ptr, len); /* write length */
|
||||
writeChar(&ptr, MQTTSN_PUBLISH); /* write message type */
|
||||
|
||||
flags.all = 0;
|
||||
flags.bits.dup = dup;
|
||||
flags.bits.QoS = qos;
|
||||
flags.bits.retain = retained;
|
||||
flags.bits.topicIdType = topic.type;
|
||||
writeChar(&ptr, flags.all);
|
||||
|
||||
if (topic.type == MQTTSN_TOPIC_TYPE_NORMAL || topic.type == MQTTSN_TOPIC_TYPE_PREDEFINED)
|
||||
writeInt(&ptr, topic.data.id);
|
||||
else
|
||||
{
|
||||
writeChar(&ptr, topic.data.name[0]);
|
||||
writeChar(&ptr, topic.data.name[1]);
|
||||
}
|
||||
writeInt(&ptr, packetid);
|
||||
memcpy(ptr, payload, payloadlen);
|
||||
ptr += payloadlen;
|
||||
|
||||
rc = ptr - buf;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Serializes the ack packet into the supplied buffer.
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer
|
||||
* @param type integer - the MQTT packet type
|
||||
* @param dup integer - the MQTT dup flag
|
||||
* @param packetid integer - the MQTT packet identifier
|
||||
* @return serialized length, or error if 0
|
||||
*/
|
||||
int MQTTSerialize_ack(char* buf, int buflen, int type, int dup, int packetid)
|
||||
{
|
||||
MQTTHeader header;
|
||||
int rc = 0;
|
||||
char *ptr = buf;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (buflen < 4)
|
||||
{
|
||||
rc = MQTTPACKET_BUFFER_TOO_SHORT;
|
||||
goto exit;
|
||||
}
|
||||
header.bits.type = type;
|
||||
header.bits.dup = dup;
|
||||
header.bits.qos = 0;
|
||||
writeChar(&ptr, header.byte); /* write header */
|
||||
|
||||
ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
|
||||
writeInt(&ptr, packetid);
|
||||
rc = ptr - buf;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes a puback packet into the supplied buffer.
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer
|
||||
* @param packetid integer - the MQTT packet identifier
|
||||
* @return serialized length, or error if 0
|
||||
*/
|
||||
int MQTTSerialize_puback(char* buf, int buflen, int packetid)
|
||||
{
|
||||
return MQTTSerialize_ack(buf, buflen, PUBACK, packetid, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes a pubrel packet into the supplied buffer.
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer
|
||||
* @param dup integer - the MQTT dup flag
|
||||
* @param packetid integer - the MQTT packet identifier
|
||||
* @return serialized length, or error if 0
|
||||
*/
|
||||
int MQTTSerialize_pubrel(char* buf, int buflen, int dup, int packetid)
|
||||
{
|
||||
return MQTTSerialize_ack(buf, buflen, PUBREL, packetid, dup);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes a pubrel packet into the supplied buffer.
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer
|
||||
* @param packetid integer - the MQTT packet identifier
|
||||
* @return serialized length, or error if 0
|
||||
*/
|
||||
int MQTTSerialize_pubcomp(char* buf, int buflen, int packetid)
|
||||
{
|
||||
return MQTTSerialize_ack(buf, buflen, PUBCOMP, packetid, 0);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
1
test/build_test
Normal file
1
test/build_test
Normal file
@@ -0,0 +1 @@
|
||||
gcc -Wall test1.c -I../src ../src/MQTTSNConnectClient.c ../src/MQTTSNConnectServer.c ../src/MQTTSNPacket.c ../src/MQTTSNSerializePublish.c ../src/MQTTSNDeserializePublish.c
|
||||
606
test/test1.c
Normal file
606
test/test1.c
Normal file
@@ -0,0 +1,606 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
#include "MQTTSNPacket.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if !defined(_WINDOWS)
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define MAXHOSTNAMELEN 256
|
||||
#define EAGAIN WSAEWOULDBLOCK
|
||||
#define EINTR WSAEINTR
|
||||
#define EINPROGRESS WSAEINPROGRESS
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#define ENOTCONN WSAENOTCONN
|
||||
#define ECONNRESET WSAECONNRESET
|
||||
#endif
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
struct Options
|
||||
{
|
||||
char* connection; /**< connection to system under test. */
|
||||
char** haconnections;
|
||||
int hacount;
|
||||
int verbose;
|
||||
int test_no;
|
||||
} options =
|
||||
{
|
||||
"tcp://m2m.eclipse.org:1883",
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
void usage()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void getopts(int argc, char** argv)
|
||||
{
|
||||
int count = 1;
|
||||
|
||||
while (count < argc)
|
||||
{
|
||||
if (strcmp(argv[count], "--test_no") == 0)
|
||||
{
|
||||
if (++count < argc)
|
||||
options.test_no = atoi(argv[count]);
|
||||
else
|
||||
usage();
|
||||
}
|
||||
else if (strcmp(argv[count], "--connection") == 0)
|
||||
{
|
||||
if (++count < argc)
|
||||
{
|
||||
options.connection = argv[count];
|
||||
printf("\nSetting connection to %s\n", options.connection);
|
||||
}
|
||||
else
|
||||
usage();
|
||||
}
|
||||
else if (strcmp(argv[count], "--haconnections") == 0)
|
||||
{
|
||||
if (++count < argc)
|
||||
{
|
||||
char* tok = strtok(argv[count], " ");
|
||||
options.hacount = 0;
|
||||
options.haconnections = malloc(sizeof(char*) * 5);
|
||||
while (tok)
|
||||
{
|
||||
options.haconnections[options.hacount] = malloc(strlen(tok) + 1);
|
||||
strcpy(options.haconnections[options.hacount], tok);
|
||||
options.hacount++;
|
||||
tok = strtok(NULL, " ");
|
||||
}
|
||||
}
|
||||
else
|
||||
usage();
|
||||
}
|
||||
else if (strcmp(argv[count], "--verbose") == 0)
|
||||
{
|
||||
options.verbose = 1;
|
||||
printf("\nSetting verbose on\n");
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define LOGA_DEBUG 0
|
||||
#define LOGA_INFO 1
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <sys/timeb.h>
|
||||
void MyLog(int LOGA_level, char* format, ...)
|
||||
{
|
||||
static char msg_buf[256];
|
||||
va_list args;
|
||||
struct timeb ts;
|
||||
|
||||
struct tm *timeinfo;
|
||||
|
||||
if (LOGA_level == LOGA_DEBUG && options.verbose == 0)
|
||||
return;
|
||||
|
||||
ftime(&ts);
|
||||
timeinfo = localtime(&ts.time);
|
||||
strftime(msg_buf, 80, "%Y%m%d %H%M%S", timeinfo);
|
||||
|
||||
sprintf(&msg_buf[strlen(msg_buf)], ".%.3hu ", ts.millitm);
|
||||
|
||||
va_start(args, format);
|
||||
vsnprintf(&msg_buf[strlen(msg_buf)], sizeof(msg_buf) - strlen(msg_buf), format, args);
|
||||
va_end(args);
|
||||
|
||||
printf("%s\n", msg_buf);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
#if defined(WIN32) || defined(_WINDOWS)
|
||||
#define mqsleep(A) Sleep(1000*A)
|
||||
#define START_TIME_TYPE DWORD
|
||||
static DWORD start_time = 0;
|
||||
START_TIME_TYPE start_clock(void)
|
||||
{
|
||||
return GetTickCount();
|
||||
}
|
||||
#elif defined(AIX)
|
||||
#define mqsleep sleep
|
||||
#define START_TIME_TYPE struct timespec
|
||||
START_TIME_TYPE start_clock(void)
|
||||
{
|
||||
static struct timespec start;
|
||||
clock_gettime(CLOCK_REALTIME, &start);
|
||||
return start;
|
||||
}
|
||||
#else
|
||||
#define mqsleep sleep
|
||||
#define START_TIME_TYPE struct timeval
|
||||
/* TODO - unused - remove? static struct timeval start_time; */
|
||||
START_TIME_TYPE start_clock(void)
|
||||
{
|
||||
struct timeval start_time;
|
||||
gettimeofday(&start_time, NULL);
|
||||
return start_time;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(WIN32)
|
||||
long elapsed(START_TIME_TYPE start_time)
|
||||
{
|
||||
return GetTickCount() - start_time;
|
||||
}
|
||||
#elif defined(AIX)
|
||||
#define assert(a)
|
||||
long elapsed(struct timespec start)
|
||||
{
|
||||
struct timespec now, res;
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
ntimersub(now, start, res);
|
||||
return (res.tv_sec)*1000L + (res.tv_nsec)/1000000L;
|
||||
}
|
||||
#else
|
||||
long elapsed(START_TIME_TYPE start_time)
|
||||
{
|
||||
struct timeval now, res;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
timersub(&now, &start_time, &res);
|
||||
return (res.tv_sec)*1000 + (res.tv_usec)/1000;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#define assert(a, b, c, d) myassert(__FILE__, __LINE__, a, b, c, d)
|
||||
#define assert1(a, b, c, d, e) myassert(__FILE__, __LINE__, a, b, c, d, e)
|
||||
|
||||
int tests = 0;
|
||||
int failures = 0;
|
||||
FILE* xml;
|
||||
START_TIME_TYPE global_start_time;
|
||||
char output[3000];
|
||||
char* cur_output = output;
|
||||
|
||||
|
||||
void write_test_result()
|
||||
{
|
||||
long duration = elapsed(global_start_time);
|
||||
|
||||
fprintf(xml, " time=\"%ld.%.3ld\" >\n", duration / 1000, duration % 1000);
|
||||
if (cur_output != output)
|
||||
{
|
||||
fprintf(xml, "%s", output);
|
||||
cur_output = output;
|
||||
}
|
||||
fprintf(xml, "</testcase>\n");
|
||||
}
|
||||
|
||||
|
||||
void myassert(char* filename, int lineno, char* description, int value, char* format, ...)
|
||||
{
|
||||
++tests;
|
||||
if (!value)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
++failures;
|
||||
printf("Assertion failed, file %s, line %d, description: %s\n", filename, lineno, description);
|
||||
|
||||
va_start(args, format);
|
||||
vprintf(format, args);
|
||||
va_end(args);
|
||||
|
||||
cur_output += sprintf(cur_output, "<failure type=\"%s\">file %s, line %d </failure>\n",
|
||||
description, filename, lineno);
|
||||
}
|
||||
else
|
||||
MyLog(LOGA_DEBUG, "Assertion succeeded, file %s, line %d, description: %s", filename, lineno, description);
|
||||
}
|
||||
|
||||
#define min(a, b) ((a < b) ? a : b)
|
||||
|
||||
int checkMQTTStrings(MQTTString a, MQTTString b)
|
||||
{
|
||||
if (!a.lenstring.data)
|
||||
{
|
||||
a.lenstring.data = a.cstring;
|
||||
if (a.cstring)
|
||||
a.lenstring.len = strlen(a.cstring);
|
||||
}
|
||||
if (!b.lenstring.data)
|
||||
{
|
||||
b.lenstring.data = b.cstring;
|
||||
if (b.cstring)
|
||||
b.lenstring.len = strlen(b.cstring);
|
||||
}
|
||||
return memcmp(a.lenstring.data, b.lenstring.data, min(a.lenstring.len, b.lenstring.len)) == 0;
|
||||
}
|
||||
|
||||
int checkMQTTSNTopics(MQTTSN_topicid a, MQTTSN_topicid b)
|
||||
{
|
||||
return a.type == b.type && a.data.id == b.data.id;
|
||||
}
|
||||
|
||||
|
||||
int checkConnectPackets(MQTTSNPacket_connectData* before, MQTTSNPacket_connectData* after)
|
||||
{
|
||||
int rc = 0;
|
||||
int start_failures = failures;
|
||||
|
||||
assert("struct_ids should be the same",
|
||||
memcmp(before->struct_id, after->struct_id, 4) == 0, "struct_ids were different %.4s\n", after->struct_id);
|
||||
|
||||
assert("struct_versions should be the same",
|
||||
before->struct_version == after->struct_version, "struct_versions were different\n", rc);
|
||||
|
||||
assert("ClientIDs should be the same",
|
||||
checkMQTTStrings(before->clientID, after->clientID), "ClientIDs were different\n", rc);
|
||||
|
||||
assert("durations should be the same",
|
||||
before->duration == after->duration, "durations were different\n", rc);
|
||||
|
||||
assert("cleansessions should be the same",
|
||||
before->cleansession == after->cleansession, "cleansessions were different\n", rc);
|
||||
|
||||
assert("willFlags should be the same",
|
||||
before->willFlag == after->willFlag, "willFlags were different\n", rc);
|
||||
|
||||
return failures == start_failures;
|
||||
}
|
||||
|
||||
int test1(struct Options options)
|
||||
{
|
||||
MQTTSNPacket_connectData data = MQTTSNPacket_connectData_initializer;
|
||||
MQTTSNPacket_connectData data_after = MQTTSNPacket_connectData_initializer;
|
||||
int rc = 0;
|
||||
unsigned char buf[100];
|
||||
int buflen = sizeof(buf);
|
||||
|
||||
fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\"");
|
||||
global_start_time = start_clock();
|
||||
failures = 0;
|
||||
MyLog(LOGA_INFO, "Starting test 1 - serialization of connect and back");
|
||||
|
||||
data.clientID.cstring = "me too";
|
||||
|
||||
data.duration = 20;
|
||||
data.cleansession = 1;
|
||||
|
||||
data.willFlag = 1;
|
||||
|
||||
rc = MQTTSNSerialize_connect(buf, buflen, &data);
|
||||
assert("good rc from serialize connect", rc > 0, "rc was %d\n", rc);
|
||||
|
||||
rc = MQTTSNDeserialize_connect(&data_after, buf, buflen);
|
||||
assert("good rc from deserialize connect", rc == 1, "rc was %d\n", rc);
|
||||
|
||||
/* data after should be the same as data before */
|
||||
rc = checkConnectPackets(&data, &data_after);
|
||||
assert("packets should be the same", rc == 1, "packets were different\n", rc);
|
||||
|
||||
/* exit: */
|
||||
MyLog(LOGA_INFO, "TEST1: test %s. %d tests run, %d failures.",
|
||||
(failures == 0) ? "passed" : "failed", tests, failures);
|
||||
write_test_result();
|
||||
return failures;
|
||||
}
|
||||
|
||||
|
||||
int test2(struct Options options)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned char buf[100];
|
||||
int buflen = sizeof(buf);
|
||||
|
||||
int dup = 0;
|
||||
int qos = 2;
|
||||
int retained = 0;
|
||||
int msgid = 23;
|
||||
MQTTSN_topicid topic;
|
||||
unsigned char *payload = (unsigned char*)"kkhkhkjkj jkjjk jk jk ";
|
||||
int payloadlen = strlen((char*)payload);
|
||||
|
||||
int dup2 = 1;
|
||||
int qos2 = 1;
|
||||
int retained2 = 1;
|
||||
int msgid2 = 3243;
|
||||
MQTTSN_topicid topic2;
|
||||
unsigned char *payload2 = NULL;
|
||||
int payloadlen2 = 0;
|
||||
|
||||
fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\"");
|
||||
global_start_time = start_clock();
|
||||
failures = 0;
|
||||
MyLog(LOGA_INFO, "Starting test 2 - serialization of publish and back");
|
||||
|
||||
memset(&topic, 0, sizeof(topic));
|
||||
memset(&topic2, 0, sizeof(topic2));
|
||||
topic.type = MQTTSN_TOPIC_TYPE_SHORT;
|
||||
memcpy(topic.data.name, "my", 2);
|
||||
rc = MQTTSNSerialize_publish(buf, buflen, dup, qos, retained, msgid, topic,
|
||||
payload, payloadlen);
|
||||
assert("good rc from serialize publish", rc > 0, "rc was %d\n", rc);
|
||||
|
||||
rc = MQTTSNDeserialize_publish(&dup2, &qos2, &retained2, &msgid2, &topic2,
|
||||
&payload2, &payloadlen2, buf, buflen);
|
||||
assert("good rc from deserialize publish", rc == 1, "rc was %d\n", rc);
|
||||
|
||||
/* data after should be the same as data before */
|
||||
assert("dups should be the same", dup == dup2, "dups were different %d\n", dup2);
|
||||
assert("qoss should be the same", qos == qos2, "qoss were different %d\n", qos2);
|
||||
assert("retaineds should be the same", retained == retained2, "retaineds were different %d\n", retained2);
|
||||
assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2);
|
||||
|
||||
assert("topics should be the same",
|
||||
checkMQTTSNTopics(topic, topic2), "topics were different %s\n", "");
|
||||
|
||||
assert("payload lengths should be the same",
|
||||
payloadlen == payloadlen2, "payload lengths were different %d\n", payloadlen2);
|
||||
|
||||
assert("payloads should be the same",
|
||||
memcmp(payload, payload2, payloadlen) == 0, "payloads were different %s\n", "");
|
||||
|
||||
/*exit:*/
|
||||
MyLog(LOGA_INFO, "TEST2: test %s. %d tests run, %d failures.",
|
||||
(failures == 0) ? "passed" : "failed", tests, failures);
|
||||
write_test_result();
|
||||
return failures;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
int test3(struct Options options)
|
||||
{
|
||||
int i = 0;
|
||||
int rc = 0;
|
||||
char buf[100];
|
||||
int buflen = sizeof(buf);
|
||||
#define TOPIC_COUNT 2
|
||||
|
||||
int dup = 0;
|
||||
int msgid = 23;
|
||||
int count = TOPIC_COUNT;
|
||||
MQTTString topicStrings[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer };
|
||||
int req_qoss[TOPIC_COUNT] = {2, 1};
|
||||
|
||||
int dup2 = 1;
|
||||
int msgid2 = 2223;
|
||||
int count2 = 0;
|
||||
MQTTString topicStrings2[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer };
|
||||
int req_qoss2[TOPIC_COUNT] = {0, 0};
|
||||
|
||||
fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\"");
|
||||
global_start_time = start_clock();
|
||||
failures = 0;
|
||||
MyLog(LOGA_INFO, "Starting test 2 - serialization of subscribe and back");
|
||||
|
||||
topicStrings[0].cstring = "mytopic";
|
||||
topicStrings[1].cstring = "mytopic2";
|
||||
rc = MQTTSerialize_subscribe(buf, buflen, dup, msgid, count, topicStrings, req_qoss);
|
||||
assert("good rc from serialize subscribe", rc > 0, "rc was %d\n", rc);
|
||||
|
||||
rc = MQTTDeserialize_subscribe(&dup2, &msgid2, 2, &count2, topicStrings2, req_qoss2, buf, buflen);
|
||||
assert("good rc from deserialize subscribe", rc == 1, "rc was %d\n", rc);
|
||||
|
||||
/* data after should be the same as data before */
|
||||
assert("dups should be the same", dup == dup2, "dups were different %d\n", dup2);
|
||||
assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2);
|
||||
|
||||
assert("count should be the same", count == count2, "counts were different %d\n", count2);
|
||||
|
||||
for (i = 0; i < count2; ++i)
|
||||
{
|
||||
assert("topics should be the same",
|
||||
checkMQTTStrings(topicStrings[i], topicStrings2[i]), "topics were different %s\n", "");
|
||||
|
||||
assert("qoss should be the same", req_qoss[i] == req_qoss2[i], "qoss were different %d\n", req_qoss2[i]);
|
||||
}
|
||||
|
||||
/*exit:*/
|
||||
MyLog(LOGA_INFO, "TEST3: test %s. %d tests run, %d failures.",
|
||||
(failures == 0) ? "passed" : "failed", tests, failures);
|
||||
write_test_result();
|
||||
return failures;
|
||||
}
|
||||
|
||||
|
||||
int test4(struct Options options)
|
||||
{
|
||||
int i = 0;
|
||||
int rc = 0;
|
||||
char buf[100];
|
||||
int buflen = sizeof(buf);
|
||||
#define TOPIC_COUNT 2
|
||||
|
||||
int msgid = 23;
|
||||
int count = TOPIC_COUNT;
|
||||
int granted_qoss[TOPIC_COUNT] = {2, 1};
|
||||
;
|
||||
int msgid2 = 2223;
|
||||
int count2 = 0;
|
||||
int granted_qoss2[TOPIC_COUNT] = {0, 0};
|
||||
|
||||
fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\"");
|
||||
global_start_time = start_clock();
|
||||
failures = 0;
|
||||
MyLog(LOGA_INFO, "Starting test 4 - serialization of suback and back");
|
||||
|
||||
rc = MQTTSerialize_suback(buf, buflen, msgid, count, granted_qoss);
|
||||
assert("good rc from serialize suback", rc > 0, "rc was %d\n", rc);
|
||||
|
||||
rc = MQTTDeserialize_suback(&msgid2, 2, &count2, granted_qoss2, buf, buflen);
|
||||
assert("good rc from deserialize suback", rc == 1, "rc was %d\n", rc);
|
||||
|
||||
/* data after should be the same as data before */
|
||||
assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2);
|
||||
|
||||
assert("count should be the same", count == count2, "counts were different %d\n", count2);
|
||||
|
||||
for (i = 0; i < count2; ++i)
|
||||
assert("qoss should be the same", granted_qoss[i] == granted_qoss2[i], "qoss were different %d\n", granted_qoss2[i]);
|
||||
|
||||
/* exit: */
|
||||
MyLog(LOGA_INFO, "TEST4: test %s. %d tests run, %d failures.",
|
||||
(failures == 0) ? "passed" : "failed", tests, failures);
|
||||
write_test_result();
|
||||
return failures;
|
||||
}
|
||||
|
||||
|
||||
int test5(struct Options options)
|
||||
{
|
||||
int i = 0;
|
||||
int rc = 0;
|
||||
char buf[100];
|
||||
int buflen = sizeof(buf);
|
||||
#define TOPIC_COUNT 2
|
||||
|
||||
int dup = 0;
|
||||
int msgid = 23;
|
||||
int count = TOPIC_COUNT;
|
||||
MQTTString topicStrings[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer };
|
||||
|
||||
int dup2 = 1;
|
||||
int msgid2 = 2223;
|
||||
int count2 = 0;
|
||||
MQTTString topicStrings2[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer };
|
||||
|
||||
fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\"");
|
||||
global_start_time = start_clock();
|
||||
failures = 0;
|
||||
MyLog(LOGA_INFO, "Starting test 2 - serialization of unsubscribe and back");
|
||||
|
||||
topicStrings[0].cstring = "mytopic";
|
||||
topicStrings[1].cstring = "mytopic2";
|
||||
rc = MQTTSerialize_unsubscribe(buf, buflen, dup, msgid, count, topicStrings);
|
||||
assert("good rc from serialize unsubscribe", rc > 0, "rc was %d\n", rc);
|
||||
|
||||
rc = MQTTDeserialize_unsubscribe(&dup2, &msgid2, 2, &count2, topicStrings2, buf, buflen);
|
||||
assert("good rc from deserialize unsubscribe", rc == 1, "rc was %d\n", rc);
|
||||
|
||||
/* data after should be the same as data before */
|
||||
assert("dups should be the same", dup == dup2, "dups were different %d\n", dup2);
|
||||
assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2);
|
||||
|
||||
assert("count should be the same", count == count2, "counts were different %d\n", count2);
|
||||
|
||||
for (i = 0; i < count2; ++i)
|
||||
assert("topics should be the same",
|
||||
checkMQTTStrings(topicStrings[i], topicStrings2[i]), "topics were different %s\n", "");
|
||||
|
||||
/* exit: */
|
||||
MyLog(LOGA_INFO, "TEST5: test %s. %d tests run, %d failures.",
|
||||
(failures == 0) ? "passed" : "failed", tests, failures);
|
||||
write_test_result();
|
||||
return failures;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int test6(struct Options options)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned char buf[100];
|
||||
int buflen = sizeof(buf);
|
||||
|
||||
int connack_rc = 77;
|
||||
|
||||
int connack_rc2 = 0;
|
||||
|
||||
fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\"");
|
||||
global_start_time = start_clock();
|
||||
failures = 0;
|
||||
MyLog(LOGA_INFO, "Starting test 2 - serialization of connack and back");
|
||||
|
||||
rc = MQTTSNSerialize_connack(buf, buflen, connack_rc);
|
||||
assert("good rc from serialize connack", rc > 0, "rc was %d\n", rc);
|
||||
|
||||
rc = MQTTSNDeserialize_connack(&connack_rc2, buf, buflen);
|
||||
assert("good rc from deserialize connack", rc == 1, "rc was %d\n", rc);
|
||||
|
||||
/* data after should be the same as data before */
|
||||
assert("dups should be the same", connack_rc == connack_rc2, "dups were different %d\n", connack_rc2);
|
||||
|
||||
/* exit: */
|
||||
MyLog(LOGA_INFO, "TEST6: test %s. %d tests run, %d failures.",
|
||||
(failures == 0) ? "passed" : "failed", tests, failures);
|
||||
write_test_result();
|
||||
return failures;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int rc = 0;
|
||||
int (*tests[])() = {NULL, test1, test2, /*test3, test4, test5,*/ test6};
|
||||
|
||||
xml = fopen("TEST-test1.xml", "w");
|
||||
fprintf(xml, "<testsuite name=\"test1\" tests=\"%d\">\n", (int)(ARRAY_SIZE(tests) - 1));
|
||||
|
||||
getopts(argc, argv);
|
||||
|
||||
if (options.test_no == 0)
|
||||
{ /* run all the tests */
|
||||
for (options.test_no = 1; options.test_no < ARRAY_SIZE(tests); ++options.test_no)
|
||||
rc += tests[options.test_no](options); /* return number of failures. 0 = test succeeded */
|
||||
}
|
||||
else
|
||||
rc = tests[options.test_no](options); /* run just the selected test */
|
||||
|
||||
if (rc == 0)
|
||||
MyLog(LOGA_INFO, "verdict pass");
|
||||
else
|
||||
MyLog(LOGA_INFO, "verdict fail");
|
||||
|
||||
fprintf(xml, "</testsuite>\n");
|
||||
fclose(xml);
|
||||
return rc;
|
||||
}
|
||||
Reference in New Issue
Block a user