mirror of
https://github.com/eclipse/paho.mqtt-sn.embedded-c.git
synced 2025-12-13 07:26:52 +01:00
Merge pull request #10 from ty4tw/gateway
First Commit of MQTT-SN Gateway
This commit is contained in:
83
.cproject
83
.cproject
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<?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">
|
||||
@@ -22,6 +23,16 @@
|
||||
<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"/>
|
||||
<option id="gnu.cpp.compiler.option.dialect.std.1678347248" name="Language standard" superClass="gnu.cpp.compiler.option.dialect.std" value="gnu.cpp.compiler.dialect.default" valueType="enumerated"/>
|
||||
<option id="gnu.cpp.compiler.option.dialect.flags.1711182709" name="Other dialect flags" superClass="gnu.cpp.compiler.option.dialect.flags" value="-std=c++11" valueType="string"/>
|
||||
<option id="gnu.cpp.compiler.option.include.paths.1361987608" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
|
||||
<listOptionValue builtIn="false" value="/home/tomoaki/git/paho.mqtt-sn.embedded-c/MQTTSNGateway/src"/>
|
||||
<listOptionValue builtIn="false" value="/home/tomoaki/git/paho.mqtt-sn.embedded-c/MQTTSNGateway/src/linux"/>
|
||||
<listOptionValue builtIn="false" value="/home/tomoaki/git/paho.mqtt-sn.embedded-c/MQTTSNPacket/src"/>
|
||||
<listOptionValue builtIn="false" value="/home/tomoaki/git/paho.mqtt-sn.embedded-c/MQTTSNClient/src"/>
|
||||
<listOptionValue builtIn="false" value="/home/tomoaki/git/paho.mqtt-sn.embedded-c/MQTTSNGateway/src/linux/udp"/>
|
||||
</option>
|
||||
<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1626802967" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
|
||||
</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"/>
|
||||
@@ -34,14 +45,24 @@
|
||||
<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.cpp.linker.exe.debug.581660133" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug">
|
||||
<option id="gnu.cpp.link.option.libs.1848275182" name="Libraries (-l)" superClass="gnu.cpp.link.option.libs" valueType="libs">
|
||||
<listOptionValue builtIn="false" srcPrefixMapping="" srcRootPath="" value="pthread"/>
|
||||
<listOptionValue builtIn="false" srcPrefixMapping="" srcRootPath="" value="ssl"/>
|
||||
<listOptionValue builtIn="false" srcPrefixMapping="" srcRootPath="" value="crypto"/>
|
||||
</option>
|
||||
<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.98211496" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
|
||||
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
|
||||
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
|
||||
</inputType>
|
||||
</tool>
|
||||
<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=""/>
|
||||
<entry excluding="MQTTSNGateway/src/linux/xbee|MQTTSNGateway/src/mainLogmonitor.cpp|MQTTSNPacket/test|MQTTSNPacket/samples" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
|
||||
</sourceEntries>
|
||||
</configuration>
|
||||
</storageModule>
|
||||
@@ -69,6 +90,15 @@
|
||||
<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"/>
|
||||
<option id="gnu.cpp.compiler.option.dialect.flags.1078302249" name="Other dialect flags" superClass="gnu.cpp.compiler.option.dialect.flags" value="-std=c++11" valueType="string"/>
|
||||
<option id="gnu.cpp.compiler.option.include.paths.2114194326" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
|
||||
<listOptionValue builtIn="false" value="/home/tomoaki/git/paho.mqtt-sn.embedded-c/MQTTSNGateway/src/linux/udp"/>
|
||||
<listOptionValue builtIn="false" value="/home/tomoaki/git/paho.mqtt-sn.embedded-c/MQTTSNGateway/src"/>
|
||||
<listOptionValue builtIn="false" value="/home/tomoaki/git/paho.mqtt-sn.embedded-c/MQTTSNGateway/src/linux"/>
|
||||
<listOptionValue builtIn="false" value="/home/tomoaki/git/paho.mqtt-sn.embedded-c/MQTTSNPacket/src"/>
|
||||
</option>
|
||||
<option id="gnu.cpp.compiler.option.dialect.std.216116103" name="Language standard" superClass="gnu.cpp.compiler.option.dialect.std" value="gnu.cpp.compiler.dialect.default" valueType="enumerated"/>
|
||||
<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1606625536" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
|
||||
</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"/>
|
||||
@@ -81,14 +111,27 @@
|
||||
<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.cpp.linker.exe.release.1623573602" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.release">
|
||||
<option id="gnu.cpp.link.option.libs.68366124" name="Libraries (-l)" superClass="gnu.cpp.link.option.libs" valueType="libs">
|
||||
<listOptionValue builtIn="false" srcPrefixMapping="" srcRootPath="" value="pthread"/>
|
||||
<listOptionValue builtIn="false" srcPrefixMapping="" srcRootPath="" value="ssl"/>
|
||||
<listOptionValue builtIn="false" srcPrefixMapping="" srcRootPath="" value="crypto"/>
|
||||
</option>
|
||||
<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.2044523925" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
|
||||
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
|
||||
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
|
||||
</inputType>
|
||||
</tool>
|
||||
<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 excluding="MQTTSNPacket/src|MQTTSNGateway/src|MQTTSNGateway/src/linux|MQTTSNGateway/src/linux/udp|MQTTSNGateway/src/mainLogmonitor.cpp|MQTTSNGateway/src/linux/xbee|MQTTSNPacket/test|MQTTSNPacket/samples" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
|
||||
<entry excluding="mainLogmonitor.cpp|linux|linux/udp" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="MQTTSNGateway/src"/>
|
||||
<entry excluding="xbee" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="MQTTSNGateway/src/linux"/>
|
||||
<entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="MQTTSNPacket/src"/>
|
||||
</sourceEntries>
|
||||
</configuration>
|
||||
</storageModule>
|
||||
@@ -98,23 +141,29 @@
|
||||
<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="org.eclipse.cdt.core.LanguageSettingsProviders"/>
|
||||
<storageModule moduleId="refreshScope" versionNumber="2">
|
||||
<configuration configurationName="Release">
|
||||
<resource resourceType="PROJECT" workspacePath="/MQTTSN-embedded-C"/>
|
||||
</configuration>
|
||||
<configuration configurationName="Debug">
|
||||
<resource resourceType="PROJECT" workspacePath="/MQTTSN-embedded-C"/>
|
||||
</configuration>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
|
||||
<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">
|
||||
<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.561557339;cdt.managedbuild.config.gnu.exe.release.561557339.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.1903732701;cdt.managedbuild.tool.gnu.cpp.compiler.input.1606625536">
|
||||
<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>
|
||||
<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.1685199227;cdt.managedbuild.config.gnu.exe.debug.1685199227.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.109068141;cdt.managedbuild.tool.gnu.cpp.compiler.input.1626802967">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
</scannerConfigBuildInfo>
|
||||
<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>
|
||||
</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>
|
||||
</cproject>
|
||||
|
||||
1
.project
1
.project
@@ -20,6 +20,7 @@
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||
<nature>org.eclipse.cdt.core.ccnature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||
</natures>
|
||||
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
rc = errno;
|
||||
}
|
||||
//}
|
||||
return errno;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int connect(const char* hostname, int port)
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
mysock = socket(family, type, 0);
|
||||
if (mysock != -1)
|
||||
{
|
||||
int opt = 1;
|
||||
//int opt = 1;
|
||||
|
||||
//if (setsockopt(mysock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&opt, sizeof(opt)) != 0)
|
||||
// printf("Could not set SO_NOSIGPIPE for socket %d", mysock);
|
||||
|
||||
@@ -1,559 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014, 2016 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(MQTTCONNECTION_H)
|
||||
#define MQTTCONNECTION_H
|
||||
|
||||
#include "FP.h"
|
||||
#include "MQTTPacket.h"
|
||||
#include "stdio.h"
|
||||
#include "MQTTLogging.h"
|
||||
|
||||
#if !defined(MQTTCLIENT_QOS1)
|
||||
#define MQTTCLIENT_QOS1 1
|
||||
#endif
|
||||
#if !defined(MQTTCLIENT_QOS2)
|
||||
#define MQTTCLIENT_QOS2 0
|
||||
#endif
|
||||
|
||||
namespace MQTT
|
||||
{
|
||||
|
||||
|
||||
enum QoS { QOS0, QOS1, QOS2 };
|
||||
|
||||
// all failure return codes must be negative
|
||||
enum returnCode { BUFFER_OVERFLOW = -2, FAILURE = -1, SUCCESS = 0 };
|
||||
|
||||
|
||||
struct Message
|
||||
{
|
||||
enum QoS qos;
|
||||
bool retained;
|
||||
bool dup;
|
||||
unsigned short id;
|
||||
void *payload;
|
||||
size_t payloadlen;
|
||||
};
|
||||
|
||||
|
||||
class PacketId
|
||||
{
|
||||
public:
|
||||
PacketId()
|
||||
{
|
||||
next = 0;
|
||||
}
|
||||
|
||||
int getNext()
|
||||
{
|
||||
return next = (next == MAX_PACKET_ID) ? 1 : ++next;
|
||||
}
|
||||
|
||||
private:
|
||||
static const int MAX_PACKET_ID = 65535;
|
||||
int next;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @class Client
|
||||
* @brief blocking, non-threaded MQTT client API
|
||||
*
|
||||
* This version of the API blocks on all method calls, until they are complete. This means that only one
|
||||
* MQTT request can be in process at any one time.
|
||||
* @param Network a network class which supports send, receive
|
||||
* @param Timer a timer class with the methods:
|
||||
*/
|
||||
template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE = 100, int MAX_MESSAGE_HANDLERS = 5>
|
||||
class Connection
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/** Construct the client
|
||||
* @param network - pointer to an instance of the Network class - must be connected to the endpoint
|
||||
* before calling MQTT connect
|
||||
* @param limits an instance of the Limit class - to alter limits as required
|
||||
*/
|
||||
Connection(unsigned int command_timeout_ms = 30000);
|
||||
|
||||
|
||||
static void run(void const* arg);
|
||||
|
||||
|
||||
/** MQTT Disconnect - send an MQTT disconnect packet, and clean up any state
|
||||
* @return success code -
|
||||
*/
|
||||
int disconnect();
|
||||
|
||||
/** Is the client connected?
|
||||
* @return flag - is the client connected or not?
|
||||
*/
|
||||
bool isConnected()
|
||||
{
|
||||
return isconnected;
|
||||
}
|
||||
|
||||
int sendPacket(int length, Timer& timer);
|
||||
unsigned char sendbuf[MAX_MQTT_PACKET_SIZE];
|
||||
|
||||
private:
|
||||
|
||||
int connect(MQTTPacket_connectData&);
|
||||
int connect();
|
||||
|
||||
void cleanSession();
|
||||
int cycle(Timer& timer);
|
||||
int waitfor(int packet_type, Timer& timer);
|
||||
int keepalive();
|
||||
int publish(int len, Timer& timer, enum QoS qos);
|
||||
|
||||
int decodePacket(int* value, int timeout);
|
||||
int readPacket(Timer& timer);
|
||||
|
||||
Network ipstack;
|
||||
unsigned long command_timeout_ms;
|
||||
unsigned char readbuf[MAX_MQTT_PACKET_SIZE];
|
||||
|
||||
Timer last_sent, last_received;
|
||||
unsigned int keepAliveInterval;
|
||||
bool ping_outstanding;
|
||||
bool cleansession;
|
||||
|
||||
PacketId packetid;
|
||||
|
||||
bool isconnected;
|
||||
|
||||
#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
|
||||
unsigned char pubbuf[MAX_MQTT_PACKET_SIZE]; // store the last publish for sending on reconnect
|
||||
int inflightLen;
|
||||
unsigned short inflightMsgid;
|
||||
enum QoS inflightQoS;
|
||||
#endif
|
||||
|
||||
#if MQTTCLIENT_QOS2
|
||||
bool pubrel;
|
||||
#if !defined(MAX_INCOMING_QOS2_MESSAGES)
|
||||
#define MAX_INCOMING_QOS2_MESSAGES 10
|
||||
#endif
|
||||
unsigned short incomingQoS2messages[MAX_INCOMING_QOS2_MESSAGES];
|
||||
bool isQoS2msgidFree(unsigned short id);
|
||||
bool useQoS2msgid(unsigned short id);
|
||||
void freeQoS2msgid(unsigned short id);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<class Network, class Timer, int a, int MAX_MESSAGE_HANDLERS>
|
||||
void MQTT::Connection<Network, Timer, a, MAX_MESSAGE_HANDLERS>::run(void const* arg)
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<class Network, class Timer, int a, int MAX_MESSAGE_HANDLERS>
|
||||
void MQTT::Connection<Network, Timer, a, MAX_MESSAGE_HANDLERS>::cleanSession()
|
||||
{
|
||||
ping_outstanding = false;
|
||||
isconnected = false;
|
||||
|
||||
#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
|
||||
inflightMsgid = 0;
|
||||
inflightQoS = QOS0;
|
||||
#endif
|
||||
|
||||
#if MQTTCLIENT_QOS2
|
||||
pubrel = false;
|
||||
for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i)
|
||||
incomingQoS2messages[i] = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
template<class Network, class Timer, int a, int MAX_MESSAGE_HANDLERS>
|
||||
MQTT::Connection<Network, Timer, a, MAX_MESSAGE_HANDLERS>::Connection(unsigned int command_timeout_ms) : packetid()
|
||||
{
|
||||
last_sent = Timer();
|
||||
last_received = Timer();
|
||||
this->command_timeout_ms = command_timeout_ms;
|
||||
cleanSession();
|
||||
}
|
||||
|
||||
|
||||
#if MQTTCLIENT_QOS2
|
||||
template<class Network, class Timer, int a, int b>
|
||||
bool MQTT::Connection<Network, Timer, a, b>::isQoS2msgidFree(unsigned short id)
|
||||
{
|
||||
for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i)
|
||||
{
|
||||
if (incomingQoS2messages[i] == id)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template<class Network, class Timer, int a, int b>
|
||||
bool MQTT::Connection<Network, Timer, a, b>::useQoS2msgid(unsigned short id)
|
||||
{
|
||||
for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i)
|
||||
{
|
||||
if (incomingQoS2messages[i] == 0)
|
||||
{
|
||||
incomingQoS2messages[i] = id;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template<class Network, class Timer, int a, int b>
|
||||
void MQTT::Connection<Network, Timer, a, b>::freeQoS2msgid(unsigned short id)
|
||||
{
|
||||
for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i)
|
||||
{
|
||||
if (incomingQoS2messages[i] == id)
|
||||
{
|
||||
incomingQoS2messages[i] = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
template<class Network, class Timer, int a, int b>
|
||||
int MQTT::Connection<Network, Timer, a, b>::sendPacket(int length, Timer& timer)
|
||||
{
|
||||
int rc = FAILURE,
|
||||
sent = 0;
|
||||
|
||||
while (sent < length && !timer.expired())
|
||||
{
|
||||
rc = ipstack.write(&sendbuf[sent], length - sent, timer.left_ms());
|
||||
if (rc < 0) // there was an error writing the data
|
||||
break;
|
||||
sent += rc;
|
||||
}
|
||||
if (sent == length)
|
||||
{
|
||||
if (this->keepAliveInterval > 0)
|
||||
last_sent.countdown(this->keepAliveInterval); // record the fact that we have successfully sent the packet
|
||||
rc = SUCCESS;
|
||||
}
|
||||
else
|
||||
rc = FAILURE;
|
||||
|
||||
#if defined(MQTT_DEBUG)
|
||||
char printbuf[150];
|
||||
DEBUG("Rc %d from sending packet %s\n", rc, MQTTFormat_toServerString(printbuf, sizeof(printbuf), sendbuf, length));
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
template<class Network, class Timer, int a, int b>
|
||||
int MQTT::Connection<Network, Timer, a, b>::decodePacket(int* value, int timeout)
|
||||
{
|
||||
unsigned char c;
|
||||
int multiplier = 1;
|
||||
int len = 0;
|
||||
const int MAX_NO_OF_REMAINING_LENGTH_BYTES = 4;
|
||||
|
||||
*value = 0;
|
||||
do
|
||||
{
|
||||
int rc = MQTTPACKET_READ_ERROR;
|
||||
|
||||
if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
|
||||
{
|
||||
rc = MQTTPACKET_READ_ERROR; /* bad data */
|
||||
goto exit;
|
||||
}
|
||||
rc = ipstack.read(&c, 1, timeout);
|
||||
if (rc != 1)
|
||||
goto exit;
|
||||
*value += (c & 127) * multiplier;
|
||||
multiplier *= 128;
|
||||
} while ((c & 128) != 0);
|
||||
exit:
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If any read fails in this method, then we should disconnect from the network, as on reconnect
|
||||
* the packets can be retried.
|
||||
* @param timeout the max time to wait for the packet read to complete, in milliseconds
|
||||
* @return the MQTT packet type, or -1 if none
|
||||
*/
|
||||
template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
|
||||
int MQTT::Connection<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::readPacket(Timer& timer)
|
||||
{
|
||||
int rc = FAILURE;
|
||||
MQTTHeader header = {0};
|
||||
int len = 0;
|
||||
int rem_len = 0;
|
||||
|
||||
/* 1. read the header byte. This has the packet type in it */
|
||||
if (ipstack.read(readbuf, 1, timer.left_ms()) != 1)
|
||||
goto exit;
|
||||
|
||||
len = 1;
|
||||
/* 2. read the remaining length. This is variable in itself */
|
||||
decodePacket(&rem_len, timer.left_ms());
|
||||
len += MQTTPacket_encode(readbuf + 1, rem_len); /* put the original remaining length into the buffer */
|
||||
|
||||
if (rem_len > (MAX_MQTT_PACKET_SIZE - len))
|
||||
{
|
||||
rc = BUFFER_OVERFLOW;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* 3. read the rest of the buffer using a callback to supply the rest of the data */
|
||||
if (rem_len > 0 && (ipstack.read(readbuf + len, rem_len, timer.left_ms()) != rem_len))
|
||||
goto exit;
|
||||
|
||||
header.byte = readbuf[0];
|
||||
rc = header.bits.type;
|
||||
if (this->keepAliveInterval > 0)
|
||||
last_received.countdown(this->keepAliveInterval); // record the fact that we have successfully received a packet
|
||||
exit:
|
||||
|
||||
#if defined(MQTT_DEBUG)
|
||||
if (rc >= 0)
|
||||
{
|
||||
char printbuf[50];
|
||||
DEBUG("Rc %d from receiving packet %s\n", rc, MQTTFormat_toClientString(printbuf, sizeof(printbuf), readbuf, len));
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
|
||||
int MQTT::Connection<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::cycle(Timer& timer)
|
||||
{
|
||||
/* get one piece of work off the wire and one pass through */
|
||||
|
||||
// read the socket, see what work is due
|
||||
int packet_type = readPacket(timer);
|
||||
|
||||
int len = 0,
|
||||
rc = SUCCESS;
|
||||
|
||||
switch (packet_type)
|
||||
{
|
||||
case FAILURE:
|
||||
case BUFFER_OVERFLOW:
|
||||
rc = packet_type;
|
||||
break;
|
||||
case CONNACK:
|
||||
case PUBACK:
|
||||
case SUBACK:
|
||||
break;
|
||||
case PUBLISH:
|
||||
{
|
||||
MQTTString topicName = MQTTString_initializer;
|
||||
Message msg;
|
||||
int intQoS;
|
||||
if (MQTTDeserialize_publish((unsigned char*)&msg.dup, &intQoS, (unsigned char*)&msg.retained, (unsigned short*)&msg.id, &topicName,
|
||||
(unsigned char**)&msg.payload, (int*)&msg.payloadlen, readbuf, MAX_MQTT_PACKET_SIZE) != 1)
|
||||
goto exit;
|
||||
msg.qos = (enum QoS)intQoS;
|
||||
#if MQTTCLIENT_QOS2
|
||||
if (msg.qos != QOS2)
|
||||
#endif
|
||||
; //deliverMessage(topicName, msg);
|
||||
#if MQTTCLIENT_QOS2
|
||||
else if (isQoS2msgidFree(msg.id))
|
||||
{
|
||||
if (useQoS2msgid(msg.id))
|
||||
; //deliverMessage(topicName, msg);
|
||||
else
|
||||
WARN("Maximum number of incoming QoS2 messages exceeded");
|
||||
}
|
||||
#endif
|
||||
#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
|
||||
if (msg.qos != QOS0)
|
||||
{
|
||||
if (msg.qos == QOS1)
|
||||
len = MQTTSerialize_ack(sendbuf, MAX_MQTT_PACKET_SIZE, PUBACK, 0, msg.id);
|
||||
else if (msg.qos == QOS2)
|
||||
len = MQTTSerialize_ack(sendbuf, MAX_MQTT_PACKET_SIZE, PUBREC, 0, msg.id);
|
||||
if (len <= 0)
|
||||
rc = FAILURE;
|
||||
else
|
||||
rc = sendPacket(len, timer);
|
||||
if (rc == FAILURE)
|
||||
goto exit; // there was a problem
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
#if MQTTCLIENT_QOS2
|
||||
case PUBREC:
|
||||
case PUBREL:
|
||||
unsigned short mypacketid;
|
||||
unsigned char dup, type;
|
||||
if (MQTTDeserialize_ack(&type, &dup, &mypacketid, readbuf, MAX_MQTT_PACKET_SIZE) != 1)
|
||||
rc = FAILURE;
|
||||
else if ((len = MQTTSerialize_ack(sendbuf, MAX_MQTT_PACKET_SIZE,
|
||||
(packet_type == PUBREC) ? PUBREL : PUBCOMP, 0, mypacketid)) <= 0)
|
||||
rc = FAILURE;
|
||||
else if ((rc = sendPacket(len, timer)) != SUCCESS) // send the PUBREL packet
|
||||
rc = FAILURE; // there was a problem
|
||||
if (rc == FAILURE)
|
||||
goto exit; // there was a problem
|
||||
if (packet_type == PUBREL)
|
||||
freeQoS2msgid(mypacketid);
|
||||
break;
|
||||
|
||||
case PUBCOMP:
|
||||
break;
|
||||
#endif
|
||||
case PINGRESP:
|
||||
ping_outstanding = false;
|
||||
break;
|
||||
}
|
||||
keepalive();
|
||||
exit:
|
||||
if (rc == SUCCESS)
|
||||
rc = packet_type;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
|
||||
int MQTT::Connection<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::keepalive()
|
||||
{
|
||||
int rc = FAILURE;
|
||||
|
||||
if (keepAliveInterval == 0)
|
||||
{
|
||||
rc = SUCCESS;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (last_sent.expired() || last_received.expired())
|
||||
{
|
||||
if (!ping_outstanding)
|
||||
{
|
||||
Timer timer(1000);
|
||||
int len = MQTTSerialize_pingreq(sendbuf, MAX_MQTT_PACKET_SIZE);
|
||||
if (len > 0 && (rc = sendPacket(len, timer)) == SUCCESS) // send the ping packet
|
||||
ping_outstanding = true;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
|
||||
int MQTT::Connection<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::connect(MQTTPacket_connectData& options)
|
||||
{
|
||||
Timer connect_timer(command_timeout_ms);
|
||||
int rc = FAILURE;
|
||||
int len = 0;
|
||||
|
||||
if (isconnected) // don't send connect packet again if we are already connected
|
||||
goto exit;
|
||||
|
||||
this->keepAliveInterval = options.keepAliveInterval;
|
||||
this->cleansession = options.cleansession;
|
||||
if ((len = MQTTSerialize_connect(sendbuf, MAX_MQTT_PACKET_SIZE, &options)) <= 0)
|
||||
goto exit;
|
||||
if ((rc = sendPacket(len, connect_timer)) != SUCCESS) // send the connect packet
|
||||
goto exit; // there was a problem
|
||||
|
||||
if (this->keepAliveInterval > 0)
|
||||
last_received.countdown(this->keepAliveInterval);
|
||||
// this will be a blocking call, wait for the connack
|
||||
if (waitfor(CONNACK, connect_timer) == CONNACK)
|
||||
{
|
||||
unsigned char connack_rc = 255;
|
||||
bool sessionPresent = false;
|
||||
if (MQTTDeserialize_connack((unsigned char*)&sessionPresent, &connack_rc, readbuf, MAX_MQTT_PACKET_SIZE) == 1)
|
||||
rc = connack_rc;
|
||||
else
|
||||
rc = FAILURE;
|
||||
}
|
||||
else
|
||||
rc = FAILURE;
|
||||
|
||||
#if MQTTCLIENT_QOS2
|
||||
// resend any inflight publish
|
||||
if (inflightMsgid > 0 && inflightQoS == QOS2 && pubrel)
|
||||
{
|
||||
if ((len = MQTTSerialize_ack(sendbuf, MAX_MQTT_PACKET_SIZE, PUBREL, 0, inflightMsgid)) <= 0)
|
||||
rc = FAILURE;
|
||||
else
|
||||
rc = publish(len, connect_timer, inflightQoS);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
|
||||
if (inflightMsgid > 0)
|
||||
{
|
||||
memcpy(sendbuf, pubbuf, MAX_MQTT_PACKET_SIZE);
|
||||
rc = publish(inflightLen, connect_timer, inflightQoS);
|
||||
}
|
||||
#endif
|
||||
|
||||
exit:
|
||||
if (rc == SUCCESS)
|
||||
isconnected = true;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
|
||||
int MQTT::Connection<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::connect()
|
||||
{
|
||||
MQTTPacket_connectData default_options = MQTTPacket_connectData_initializer;
|
||||
return connect(default_options);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
|
||||
int MQTT::Connection<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::disconnect()
|
||||
{
|
||||
int rc = FAILURE;
|
||||
Timer timer(command_timeout_ms); // we might wait for incomplete incoming publishes to complete
|
||||
int len = MQTTSerialize_disconnect(sendbuf, MAX_MQTT_PACKET_SIZE);
|
||||
if (len > 0)
|
||||
rc = sendPacket(len, timer); // send the disconnect packet
|
||||
|
||||
if (cleansession)
|
||||
cleanSession();
|
||||
else
|
||||
isconnected = false;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
106
MQTTSNGateway/src/MQTTGWConnectionHandler.cpp
Normal file
106
MQTTSNGateway/src/MQTTGWConnectionHandler.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include "MQTTGWConnectionHandler.h"
|
||||
#include "MQTTGWPacket.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
MQTTGWConnectionHandler::MQTTGWConnectionHandler(Gateway* gateway)
|
||||
{
|
||||
_gateway = gateway;
|
||||
}
|
||||
|
||||
MQTTGWConnectionHandler::~MQTTGWConnectionHandler()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void MQTTGWConnectionHandler::handleConnack(Client* client, MQTTGWPacket* packet)
|
||||
{
|
||||
uint8_t rc = MQTT_SERVER_UNAVAILABLE;
|
||||
Connack resp;
|
||||
packet->getCONNACK(&resp);
|
||||
|
||||
/* convert MQTT ReturnCode to MQTT-SN one */
|
||||
if (resp.rc == MQTT_CONNECTION_ACCEPTED)
|
||||
{
|
||||
rc = MQTTSN_RC_ACCEPTED;
|
||||
}
|
||||
else if (resp.rc == MQTT_UNACCEPTABLE_PROTOCOL_VERSION)
|
||||
{
|
||||
rc = MQTTSN_RC_NOT_SUPPORTED;
|
||||
WRITELOG(" ClientID : %s Requested Protocol version is not supported.\n", client->getClientId());
|
||||
}
|
||||
else if (resp.rc == MQTT_IDENTIFIER_REJECTED)
|
||||
{
|
||||
rc = MQTTSN_RC_NOT_SUPPORTED;
|
||||
WRITELOG(" ClientID : %s ClientID is collect UTF-8 but not allowed by the Server.\n",
|
||||
client->getClientId());
|
||||
}
|
||||
else if (resp.rc == MQTT_SERVER_UNAVAILABLE)
|
||||
{
|
||||
rc = MQTTSN_RC_REJECTED_CONGESTED;
|
||||
WRITELOG(" ClientID : %s The Network Connection has been made but the MQTT service is unavailable.\n",
|
||||
client->getClientId());
|
||||
}
|
||||
else if (resp.rc == MQTT_BAD_USERNAME_OR_PASSWORD)
|
||||
{
|
||||
rc = MQTTSN_RC_NOT_SUPPORTED;
|
||||
WRITELOG(" Gateway Configuration Error: The data in the user name or password is malformed.\n");
|
||||
}
|
||||
else if (resp.rc == MQTT_NOT_AUTHORIZED)
|
||||
{
|
||||
rc = MQTTSN_RC_NOT_SUPPORTED;
|
||||
WRITELOG(" Gateway Configuration Error: The Client is not authorized to connect.\n");
|
||||
}
|
||||
|
||||
MQTTSNPacket* snPacket = new MQTTSNPacket();
|
||||
snPacket->setCONNACK(rc);
|
||||
|
||||
Event* ev1 = new Event();
|
||||
ev1->setClientSendEvent(client, snPacket);
|
||||
client->connackSended(rc); // update the client's status
|
||||
_gateway->getClientSendQue()->post(ev1);
|
||||
|
||||
MQTTSNPacket* sleepPacket = 0;
|
||||
while ( (sleepPacket = client->getClientSleepPacket()) )
|
||||
{
|
||||
Event* ev1 = new Event();
|
||||
ev1->setClientSendEvent(client, sleepPacket);
|
||||
_gateway->getClientSendQue()->post(ev1);
|
||||
}
|
||||
}
|
||||
|
||||
void MQTTGWConnectionHandler::handlePingresp(Client* client, MQTTGWPacket* packet)
|
||||
{
|
||||
MQTTSNPacket* snPacket = new MQTTSNPacket();
|
||||
snPacket->setPINGRESP();
|
||||
Event* ev1 = new Event();
|
||||
ev1->setClientSendEvent(client, snPacket);
|
||||
_gateway->getClientSendQue()->post(ev1);
|
||||
}
|
||||
|
||||
void MQTTGWConnectionHandler::handleDisconnect(Client* client, MQTTGWPacket* packet)
|
||||
{
|
||||
MQTTSNPacket* snPacket = new MQTTSNPacket();
|
||||
snPacket->setDISCONNECT(0);
|
||||
client->disconnected();
|
||||
Event* ev1 = new Event();
|
||||
ev1->setClientSendEvent(client, snPacket);
|
||||
}
|
||||
|
||||
42
MQTTSNGateway/src/MQTTGWConnectionHandler.h
Normal file
42
MQTTSNGateway/src/MQTTGWConnectionHandler.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
#ifndef MQTTGWCONNECTIONHANDLER_H_
|
||||
#define MQTTGWCONNECTIONHANDLER_H_
|
||||
|
||||
#include "MQTTSNGWDefines.h"
|
||||
#include "MQTTSNGWPacket.h"
|
||||
#include "MQTTSNGateway.h"
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
|
||||
class MQTTGWConnectionHandler
|
||||
{
|
||||
public:
|
||||
MQTTGWConnectionHandler(Gateway* gateway);
|
||||
~MQTTGWConnectionHandler();
|
||||
void handleConnack(Client* client, MQTTGWPacket* packet);
|
||||
void handlePingresp(Client* client, MQTTGWPacket* packet);
|
||||
void handleDisconnect(Client* client, MQTTGWPacket* packet);
|
||||
|
||||
private:
|
||||
Gateway* _gateway;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* MQTTGWCONNECTIONHANDLER_H_ */
|
||||
530
MQTTSNGateway/src/MQTTGWPacket.cpp
Normal file
530
MQTTSNGateway/src/MQTTGWPacket.cpp
Normal file
@@ -0,0 +1,530 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2009, 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
|
||||
* Tomoaki Yamaguchi - modify codes for MATT-SN Gateway
|
||||
**************************************************************************************/
|
||||
|
||||
#include "MQTTGWPacket.h"
|
||||
#include <string>
|
||||
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
#define MAX_NO_OF_REMAINING_LENGTH_BYTES 3
|
||||
/**
|
||||
* List of the predefined MQTT v3 packet names.
|
||||
*/
|
||||
static const char* mqtt_packet_names[] =
|
||||
{ "RESERVED", "CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL", "PUBCOMP", "SUBSCRIBE", "SUBACK",
|
||||
"UNSUBSCRIBE", "UNSUBACK", "PINGREQ", "PINGRESP", "DISCONNECT" };
|
||||
|
||||
/**
|
||||
* Encodes the message length according to the MQTT algorithm
|
||||
* @param buf the buffer into which the encoded data is written
|
||||
* @param length the length to be encoded
|
||||
* @return the number of bytes written to buffer
|
||||
*/
|
||||
int MQTTPacket_encode(char* buf, int length)
|
||||
{
|
||||
int rc = 0;
|
||||
do
|
||||
{
|
||||
char d = length % 128;
|
||||
length /= 128;
|
||||
/* if there are more digits to encode, set the top bit of this digit */
|
||||
if (length > 0)
|
||||
d |= 0x80;
|
||||
buf[rc++] = d;
|
||||
} while (length > 0);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates an integer from two bytes read from the input buffer
|
||||
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
|
||||
* @return the integer value calculated
|
||||
*/
|
||||
int readInt(char** pptr)
|
||||
{
|
||||
char* ptr = *pptr;
|
||||
int len = 256 * ((unsigned char) (*ptr)) + (unsigned char) (*(ptr + 1));
|
||||
*pptr += 2;
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a "UTF" string from the input buffer. UTF as in the MQTT v3 spec which really means
|
||||
* a length delimited string. So it reads the two byte length then the data according to
|
||||
* that length. The end of the buffer is provided too, so we can prevent buffer overruns caused
|
||||
* by an incorrect length.
|
||||
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
|
||||
* @param enddata pointer to the end of the buffer not to be read beyond
|
||||
* @param len returns the calculcated value of the length bytes read
|
||||
* @return an allocated C string holding the characters read, or NULL if the length read would
|
||||
* have caused an overrun.
|
||||
*
|
||||
*/
|
||||
char* readUTFlen(char** pptr, char* enddata, int* len)
|
||||
{
|
||||
char* string = NULL;
|
||||
|
||||
if (enddata - (*pptr) > 1) /* enough length to read the integer? */
|
||||
{
|
||||
*len = readInt(pptr);
|
||||
if (&(*pptr)[*len] <= enddata)
|
||||
{
|
||||
string = (char*)calloc(*len + 1, 1);
|
||||
memcpy(string, *pptr, (size_t)*len);
|
||||
string[*len] = '\0';
|
||||
*pptr += *len;
|
||||
}
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a "UTF" string from the input buffer. UTF as in the MQTT v3 spec which really means
|
||||
* a length delimited string. So it reads the two byte length then the data according to
|
||||
* that length. The end of the buffer is provided too, so we can prevent buffer overruns caused
|
||||
* by an incorrect length.
|
||||
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
|
||||
* @param enddata pointer to the end of the buffer not to be read beyond
|
||||
* @return an allocated C string holding the characters read, or NULL if the length read would
|
||||
* have caused an overrun.
|
||||
*/
|
||||
char* readUTF(char** pptr, char* enddata)
|
||||
{
|
||||
int len;
|
||||
return readUTFlen(pptr, enddata, &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
|
||||
*/
|
||||
unsigned char readChar(char** pptr)
|
||||
{
|
||||
unsigned 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 = c;
|
||||
(*pptr)++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an integer as 2 bytes to an output buffer.
|
||||
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
|
||||
* @param anInt the integer to write
|
||||
*/
|
||||
void writeInt(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 writeUTF(unsigned char** pptr, const char* string)
|
||||
{
|
||||
int len = (int)strlen(string);
|
||||
writeInt(pptr, len);
|
||||
memcpy(*pptr, string, (size_t)len);
|
||||
*pptr += len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lapper class of MQTTPacket
|
||||
*
|
||||
*/
|
||||
MQTTGWPacket::MQTTGWPacket()
|
||||
{
|
||||
_data = 0;
|
||||
_header.byte = 0;
|
||||
_remainingLength = 0;
|
||||
}
|
||||
|
||||
MQTTGWPacket::~MQTTGWPacket()
|
||||
{
|
||||
if (_data)
|
||||
{
|
||||
free(_data);
|
||||
}
|
||||
}
|
||||
|
||||
int MQTTGWPacket::recv(Network* network)
|
||||
{
|
||||
int len = 0;
|
||||
int multiplier = 1;
|
||||
unsigned char c;
|
||||
|
||||
/* read First Byte of Packet */
|
||||
if (network->recv((unsigned char*)&_header.byte, 1) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
/* read RemainingLength */
|
||||
do
|
||||
{
|
||||
if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
if (network->recv(&c, 1) == -1)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
_remainingLength += (c & 127) * multiplier;
|
||||
multiplier *= 128;
|
||||
} while ((c & 128) != 0);
|
||||
|
||||
/* allocate buffer */
|
||||
_data = (unsigned char*)calloc(_remainingLength, 1);
|
||||
if ( !_data )
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* read Payload */
|
||||
int remlen = network->recv(_data, _remainingLength);
|
||||
|
||||
if (remlen == -1 || remlen != _remainingLength )
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
return 1 + len + _remainingLength;
|
||||
}
|
||||
|
||||
int MQTTGWPacket::send(Network* network)
|
||||
{
|
||||
unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE];
|
||||
memset(buf, 0, MQTTSNGW_MAX_PACKET_SIZE);
|
||||
int len = getPacketData(buf);
|
||||
return network->send(buf, len);
|
||||
|
||||
}
|
||||
|
||||
int MQTTGWPacket::getAck(Ack* ack)
|
||||
{
|
||||
if (PUBACK != _header.bits.type && PUBREC != _header.bits.type && PUBREL != _header.bits.type
|
||||
&& PUBCOMP != _header.bits.type && UNSUBACK != _header.bits.type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
char* ptr = (char*) _data;
|
||||
ack->header.byte = _header.byte;
|
||||
ack->msgId = readInt((char**) &ptr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int MQTTGWPacket::getCONNACK(Connack* resp)
|
||||
{
|
||||
if (_header.bits.type != CONNACK)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
char* ptr = (char*) _data;
|
||||
resp->header.byte = _header.byte;
|
||||
resp->flags.all = *ptr++;
|
||||
resp->rc = readChar(&ptr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int MQTTGWPacket::getSUBACK(unsigned short* msgId, unsigned char* rc)
|
||||
{
|
||||
if (_header.bits.type != SUBACK)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
char *ptr = (char*) _data;
|
||||
*msgId = readInt((char**) &ptr);
|
||||
*rc = readChar(&ptr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int MQTTGWPacket::getPUBLISH(Publish* pub)
|
||||
{
|
||||
if (_header.bits.type != PUBLISH)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
char* ptr = (char*) _data;
|
||||
pub->header = _header;
|
||||
pub->topiclen = readInt((char**) &ptr);
|
||||
pub->topic = (char*) _data + 2;
|
||||
ptr += pub->topiclen;
|
||||
pub->msgId = readInt(&ptr);
|
||||
pub->payload = ptr;
|
||||
pub->payloadlen = _remainingLength - pub->topiclen - 4;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int MQTTGWPacket::setCONNECT(Connect* connect, unsigned char* username, unsigned char* password)
|
||||
{
|
||||
clearData();
|
||||
_header = connect->header;
|
||||
|
||||
_remainingLength = ((connect->version == 3) ? 12 : 10) + (int)strlen(connect->clientID) + 2;
|
||||
if (connect->flags.bits.will)
|
||||
{
|
||||
_remainingLength += (int)strlen(connect->willTopic) + 2 + (int)strlen(connect->willMsg) + 2;
|
||||
}
|
||||
if ( connect->flags.bits.username )
|
||||
{
|
||||
_remainingLength += (int)strlen((char*) username) + 2;
|
||||
}
|
||||
if (connect->flags.bits.password)
|
||||
{
|
||||
_remainingLength += (int)strlen((char*) password) + 2;
|
||||
}
|
||||
|
||||
_data = (unsigned char*)calloc(_remainingLength, 1);
|
||||
unsigned char* ptr = _data;
|
||||
|
||||
if (connect->version == 3)
|
||||
{
|
||||
writeUTF(&ptr, "MQIsdp");
|
||||
writeChar(&ptr, (char) 3);
|
||||
}
|
||||
else if (connect->version == 4)
|
||||
{
|
||||
writeUTF(&ptr, "MQTT");
|
||||
writeChar(&ptr, (char) 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
writeChar(&ptr, connect->flags.all);
|
||||
writeInt(&ptr, connect->keepAliveTimer);
|
||||
writeUTF(&ptr, connect->clientID);
|
||||
if (connect->flags.bits.will)
|
||||
{
|
||||
writeUTF(&ptr, connect->willTopic);
|
||||
writeUTF(&ptr, connect->willMsg);
|
||||
}
|
||||
|
||||
if (connect->flags.bits.username)
|
||||
{
|
||||
writeUTF(&ptr, (const char*) username);
|
||||
}
|
||||
if (connect->flags.bits.password)
|
||||
{
|
||||
writeUTF(&ptr, (const char*) password);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int MQTTGWPacket::setSUBSCRIBE(const char* topic, unsigned char qos, unsigned short msgId)
|
||||
{
|
||||
clearData();
|
||||
_header.byte = 0;
|
||||
_header.bits.type = SUBSCRIBE;
|
||||
_header.bits.qos = 1; // Reserved
|
||||
_remainingLength = (int)strlen(topic) + 5;
|
||||
_data = (unsigned char*)calloc(_remainingLength, 1);
|
||||
if (_data)
|
||||
{
|
||||
unsigned char* ptr = _data;
|
||||
writeInt(&ptr, msgId);
|
||||
writeUTF(&ptr, topic);
|
||||
writeChar(&ptr, (char) qos);
|
||||
return 1;
|
||||
}
|
||||
clearData();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MQTTGWPacket::setUNSUBSCRIBE(const char* topic, unsigned short msgid)
|
||||
{
|
||||
clearData();
|
||||
_header.byte = 0;
|
||||
_header.bits.type = UNSUBSCRIBE;
|
||||
_header.bits.qos = 1;
|
||||
_remainingLength = (int)strlen(topic) + 4;
|
||||
_data = (unsigned char*)calloc(_remainingLength, 1);
|
||||
if (_data)
|
||||
{
|
||||
unsigned char* ptr = _data;
|
||||
writeInt(&ptr, msgid);
|
||||
writeUTF(&ptr, topic);
|
||||
return 1;
|
||||
}
|
||||
clearData();
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int MQTTGWPacket::setPUBLISH(Publish* pub)
|
||||
{
|
||||
clearData();
|
||||
_header.byte = pub->header.byte;
|
||||
_header.bits.type = PUBLISH;
|
||||
_remainingLength = 4 + pub->topiclen + pub->payloadlen;
|
||||
_data = (unsigned char*)calloc(_remainingLength, 1);
|
||||
if (_data)
|
||||
{
|
||||
unsigned char* ptr = _data;
|
||||
writeInt(&ptr, pub->topiclen);
|
||||
memcpy(ptr, pub->topic, pub->topiclen);
|
||||
ptr += pub->topiclen;
|
||||
writeInt(&ptr, pub->msgId);
|
||||
memcpy(ptr, pub->payload, pub->payloadlen);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
clearData();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int MQTTGWPacket::setAck(unsigned char msgType, unsigned short msgid)
|
||||
{
|
||||
clearData();
|
||||
_remainingLength = 2;
|
||||
_header.bits.type = msgType;
|
||||
_header.bits.qos = (msgType == PUBREL) ? 1 : 0;
|
||||
|
||||
_data = (unsigned char*)calloc(_remainingLength, 1);
|
||||
if (_data)
|
||||
{
|
||||
unsigned char* data = _data;
|
||||
writeInt(&data, msgid);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MQTTGWPacket::setHeader(unsigned char msgType)
|
||||
{
|
||||
clearData();
|
||||
if (msgType < CONNECT || msgType > DISCONNECT)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
_header.bits.type = msgType;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MQTTGWPacket::getType(void)
|
||||
{
|
||||
return _header.bits.type;
|
||||
}
|
||||
|
||||
const char* MQTTGWPacket::getName(void)
|
||||
{
|
||||
return getType() > DISCONNECT ? "UNKNOWN" : mqtt_packet_names[getType()];
|
||||
}
|
||||
|
||||
int MQTTGWPacket::getPacketData(unsigned char* buf)
|
||||
{
|
||||
unsigned char* ptr = buf;
|
||||
*ptr++ = _header.byte;
|
||||
int len = MQTTPacket_encode((char*)ptr, _remainingLength);
|
||||
ptr += len;
|
||||
memcpy(ptr, _data, _remainingLength);
|
||||
return 1 + len + _remainingLength;
|
||||
}
|
||||
|
||||
int MQTTGWPacket::getPacketLength(void)
|
||||
{
|
||||
char buf[4];
|
||||
return 1 + MQTTPacket_encode(buf, _remainingLength) + _remainingLength;
|
||||
}
|
||||
|
||||
void MQTTGWPacket::clearData(void)
|
||||
{
|
||||
if (_data)
|
||||
{
|
||||
free(_data);
|
||||
}
|
||||
_header.byte = 0;
|
||||
_remainingLength = 0;
|
||||
}
|
||||
|
||||
char* MQTTGWPacket::getMsgId(char* pbuf)
|
||||
{
|
||||
int type = getType();
|
||||
|
||||
switch ( type )
|
||||
{
|
||||
case PUBLISH:
|
||||
Publish pub;
|
||||
getPUBLISH(&pub);
|
||||
if ( _header.bits.dup )
|
||||
{
|
||||
sprintf(pbuf, "+%04X", pub.msgId);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(pbuf, " %04X", pub.msgId);
|
||||
}
|
||||
break;
|
||||
case PUBACK:
|
||||
case PUBREC:
|
||||
case PUBREL:
|
||||
case PUBCOMP:
|
||||
case SUBSCRIBE:
|
||||
case UNSUBSCRIBE:
|
||||
case SUBACK:
|
||||
case UNSUBACK:
|
||||
sprintf(pbuf, " %02X%02X", _data[0], _data[1]);
|
||||
break;
|
||||
default:
|
||||
sprintf(pbuf, " ");
|
||||
break;
|
||||
}
|
||||
return pbuf;
|
||||
}
|
||||
|
||||
char* MQTTGWPacket::print(char* pbuf)
|
||||
{
|
||||
char* ptr = pbuf;
|
||||
char** pptr = &pbuf;
|
||||
char digit[4];
|
||||
|
||||
sprintf(*pptr, " %02X",(const unsigned char)_header.byte);
|
||||
*pptr += 3;
|
||||
int len = MQTTPacket_encode((char*) digit, _remainingLength);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
sprintf(*pptr, " %02X", digit[i]);
|
||||
*pptr += 3;
|
||||
}
|
||||
|
||||
int size = _remainingLength > SIZEOF_LOG_PACKET ? SIZEOF_LOG_PACKET : _remainingLength;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
sprintf(*pptr, " %02X", *(_data + i));
|
||||
*pptr += 3;
|
||||
}
|
||||
**pptr = 0;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
218
MQTTSNGateway/src/MQTTGWPacket.h
Normal file
218
MQTTSNGateway/src/MQTTGWPacket.h
Normal file
@@ -0,0 +1,218 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 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
|
||||
* Ian Craggs, Allan Stockdill-Mander - SSL updates
|
||||
* Ian Craggs - MQTT 3.1.1 support
|
||||
* Tomoaki Yamaguchi - modify codes for MATT-SN Gateway
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef MQTTGWPACKET_H_
|
||||
#define MQTTGWPACKET_H_
|
||||
|
||||
#include "Network.h"
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
|
||||
typedef void* (*pf)(unsigned char, char*, size_t);
|
||||
|
||||
#define BAD_MQTT_PACKET -4
|
||||
|
||||
enum msgTypes
|
||||
{
|
||||
CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL,
|
||||
PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK,
|
||||
PINGREQ, PINGRESP, DISCONNECT
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Bitfields for the MQTT header byte.
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
/*unsigned*/ char byte; /**< the whole byte */
|
||||
#if defined(REVERSED)
|
||||
struct
|
||||
{
|
||||
unsigned int type : 4; /**< message type nibble */
|
||||
bool dup : 1; /**< DUP flag bit */
|
||||
unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
|
||||
bool retain : 1; /**< retained flag bit */
|
||||
} bits;
|
||||
#else
|
||||
struct
|
||||
{
|
||||
bool retain : 1; /**< retained flag bit */
|
||||
unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
|
||||
bool dup : 1; /**< DUP flag bit */
|
||||
unsigned int type : 4; /**< message type nibble */
|
||||
} bits;
|
||||
#endif
|
||||
} Header;
|
||||
|
||||
|
||||
/**
|
||||
* Data for a connect packet.
|
||||
*/
|
||||
|
||||
enum MQTT_connackCodes{
|
||||
MQTT_CONNECTION_ACCEPTED ,
|
||||
MQTT_UNACCEPTABLE_PROTOCOL_VERSION,
|
||||
MQTT_IDENTIFIER_REJECTED,
|
||||
MQTT_SERVER_UNAVAILABLE,
|
||||
MQTT_BAD_USERNAME_OR_PASSWORD,
|
||||
MQTT_NOT_AUTHORIZED
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Header header; /**< MQTT header byte */
|
||||
union
|
||||
{
|
||||
unsigned char all; /**< all connect flags */
|
||||
#if defined(REVERSED)
|
||||
struct
|
||||
{
|
||||
bool username : 1; /**< 3.1 user name */
|
||||
bool password : 1; /**< 3.1 password */
|
||||
bool willRetain : 1; /**< will retain setting */
|
||||
unsigned int willQoS : 2; /**< will QoS value */
|
||||
bool will : 1; /**< will flag */
|
||||
bool cleanstart : 1; /**< cleansession flag */
|
||||
int : 1; /**< unused */
|
||||
} bits;
|
||||
#else
|
||||
struct
|
||||
{
|
||||
int : 1; /**< unused */
|
||||
bool cleanstart : 1; /**< cleansession flag */
|
||||
bool will : 1; /**< will flag */
|
||||
unsigned int willQoS : 2; /**< will QoS value */
|
||||
bool willRetain : 1; /**< will retain setting */
|
||||
bool password : 1; /**< 3.1 password */
|
||||
bool username : 1; /**< 3.1 user name */
|
||||
} bits;
|
||||
#endif
|
||||
} flags; /**< connect flags byte */
|
||||
|
||||
char *Protocol, /**< MQTT protocol name */
|
||||
*clientID, /**< string client id */
|
||||
*willTopic, /**< will topic */
|
||||
*willMsg; /**< will payload */
|
||||
|
||||
int keepAliveTimer; /**< keepalive timeout value in seconds */
|
||||
unsigned char version; /**< MQTT version number */
|
||||
} Connect;
|
||||
|
||||
/**
|
||||
* Data for a willMessage.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char* topic;
|
||||
char* msg;
|
||||
int retained;
|
||||
int qos;
|
||||
}willMessages;
|
||||
|
||||
/**
|
||||
* Data for a connack packet.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
Header header; /**< MQTT header byte */
|
||||
union
|
||||
{
|
||||
unsigned char all; /**< all connack flags */
|
||||
#if defined(REVERSED)
|
||||
struct
|
||||
{
|
||||
unsigned int reserved : 7; /**< message type nibble */
|
||||
bool sessionPresent : 1; /**< was a session found on the server? */
|
||||
} bits;
|
||||
#else
|
||||
struct
|
||||
{
|
||||
bool sessionPresent : 1; /**< was a session found on the server? */
|
||||
unsigned int reserved : 7; /**< message type nibble */
|
||||
} bits;
|
||||
#endif
|
||||
} flags; /**< connack flags byte */
|
||||
char rc; /**< connack return code */
|
||||
} Connack;
|
||||
|
||||
|
||||
/**
|
||||
* Data for a publish packet.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
Header header; /**< MQTT header byte */
|
||||
char* topic; /**< topic string */
|
||||
int topiclen;
|
||||
int msgId; /**< MQTT message id */
|
||||
char* payload; /**< binary payload, length delimited */
|
||||
int payloadlen; /**< payload length */
|
||||
} Publish;
|
||||
|
||||
|
||||
/**
|
||||
* Data for one of the ack packets.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
Header header; /**< MQTT header byte */
|
||||
int msgId; /**< MQTT message id */
|
||||
} Ack;
|
||||
|
||||
/**
|
||||
* Class MQTT Packet
|
||||
*/
|
||||
class MQTTGWPacket
|
||||
{
|
||||
public:
|
||||
MQTTGWPacket();
|
||||
~MQTTGWPacket();
|
||||
int recv(Network* network);
|
||||
int send(Network* network);
|
||||
int getType(void);
|
||||
int getPacketData(unsigned char* buf);
|
||||
int getPacketLength(void);
|
||||
const char* getName(void);
|
||||
|
||||
int getAck(Ack* ack);
|
||||
int getCONNACK(Connack* resp);
|
||||
int getSUBACK(unsigned short* msgId, unsigned char* rc);
|
||||
int getPUBLISH(Publish* pub);
|
||||
|
||||
int setCONNECT(Connect* conect, unsigned char* username, unsigned char* password);
|
||||
int setPUBLISH(Publish* pub);
|
||||
int setAck(unsigned char msgType, unsigned short msgid);
|
||||
int setHeader(unsigned char msgType);
|
||||
int setSUBSCRIBE(const char* topic, unsigned char qos, unsigned short msgId);
|
||||
int setUNSUBSCRIBE(const char* topics, unsigned short msgid);
|
||||
char* getMsgId(char* buf);
|
||||
char* print(char* buf);
|
||||
|
||||
private:
|
||||
void clearData(void);
|
||||
Header _header;
|
||||
int _remainingLength;
|
||||
unsigned char* _data;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* MQTTGWPACKET_H_ */
|
||||
217
MQTTSNGateway/src/MQTTGWPublishHandler.cpp
Normal file
217
MQTTSNGateway/src/MQTTGWPublishHandler.cpp
Normal file
@@ -0,0 +1,217 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include "MQTTGWPublishHandler.h"
|
||||
#include "MQTTSNGateway.h"
|
||||
#include "MQTTSNPacket.h"
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
char* currentDateTime(void);
|
||||
|
||||
MQTTGWPublishHandler::MQTTGWPublishHandler(Gateway* gateway)
|
||||
{
|
||||
_gateway = gateway;
|
||||
}
|
||||
|
||||
MQTTGWPublishHandler::~MQTTGWPublishHandler()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void MQTTGWPublishHandler::handlePublish(Client* client, MQTTGWPacket* packet)
|
||||
{
|
||||
if ( !client->isActive() && !client->isSleep() )
|
||||
{
|
||||
WRITELOG(" The client is neither active nor sleep %s\n", client->getStatus());
|
||||
return;
|
||||
}
|
||||
|
||||
Publish pub;
|
||||
packet->getPUBLISH(&pub);
|
||||
|
||||
MQTTSNPacket* snPacket = new MQTTSNPacket();
|
||||
|
||||
/* create MQTTSN_topicid */
|
||||
MQTTSN_topicid topicId;
|
||||
|
||||
if (pub.topiclen == 2)
|
||||
{
|
||||
topicId.type = MQTTSN_TOPIC_TYPE_SHORT;
|
||||
*(topicId.data.short_name) = *pub.topic;
|
||||
*(topicId.data.short_name + 1) = *(pub.topic + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
topicId.type = MQTTSN_TOPIC_TYPE_NORMAL;
|
||||
topicId.data.long_.len = pub.topiclen;
|
||||
topicId.data.long_.name = pub.topic;
|
||||
unsigned short id = client->getTopics()->getTopicId(&topicId);
|
||||
topicId.data.id = id;
|
||||
}
|
||||
|
||||
if (topicId.data.id == 0)
|
||||
{
|
||||
/* This message might be subscribed with wild card. */
|
||||
Topic* topic = client->getTopics()->match(&topicId);
|
||||
if (topic == 0)
|
||||
{
|
||||
WRITELOG(" Invalid Topic. PUBLISH message is canceled.\n");
|
||||
if (pub.header.bits.qos == 1)
|
||||
{
|
||||
replyACK(client, &pub, PUBACK);
|
||||
}
|
||||
else if ( pub.header.bits.qos == 2 )
|
||||
{
|
||||
replyACK(client, &pub, PUBREC);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* add the Topic and get a TopicId */
|
||||
topic = client->getTopics()->add(&topicId);
|
||||
uint16_t id = topic->getTopicId();
|
||||
|
||||
if (id > 0)
|
||||
{
|
||||
/* create REGACK */
|
||||
MQTTSNPacket* regPacket = new MQTTSNPacket();
|
||||
|
||||
MQTTSNString topicName;
|
||||
topicName.lenstring.len = topicId.data.long_.len;
|
||||
topicName.lenstring.data = topicId.data.long_.name;
|
||||
|
||||
uint16_t regackMsgId = client->getNextSnMsgId();
|
||||
regPacket->setREGISTER(id, regackMsgId, &topicName);
|
||||
|
||||
if (client->isSleep())
|
||||
{
|
||||
client->setClientSleepPacket(regPacket);
|
||||
WRITELOG(FORMAT_BL_NL, currentDateTime(), regPacket->getName(),
|
||||
RIGHTARROW, client->getClientId(), "is sleeping. REGISTER was saved.");
|
||||
}
|
||||
else if (client->isActive())
|
||||
{
|
||||
/* send REGISTER */
|
||||
Event* evrg = new Event();
|
||||
evrg->setClientSendEvent(client, regPacket);
|
||||
_gateway->getClientSendQue()->post(evrg);
|
||||
}
|
||||
|
||||
/* send PUBLISH */
|
||||
topicId.data.id = id;
|
||||
snPacket->setPUBLISH((uint8_t) pub.header.bits.dup, (int) pub.header.bits.qos,
|
||||
(uint8_t) pub.header.bits.retain, (uint16_t) pub.msgId, topicId, (uint8_t*) pub.payload,
|
||||
pub.payloadlen);
|
||||
client->getWaitREGACKPacketList()->setPacket(snPacket, regackMsgId);
|
||||
}
|
||||
else
|
||||
{
|
||||
WRITELOG("\x1b[0m\x1b[31mMQTTGWPublishHandler Can't create a Topic.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* TopicId was aquired. */
|
||||
if (client->isSleep())
|
||||
{
|
||||
/* client is sleeping. save PUBLISH */
|
||||
client->setClientSleepPacket(snPacket);
|
||||
WRITELOG(FORMAT_YE_NL, currentDateTime(), packet->getName(),
|
||||
RIGHTARROW, client->getClientId(), "is sleeping. a message was saved.");
|
||||
int type = 0;
|
||||
if (pub.header.bits.qos == 1)
|
||||
{
|
||||
type = PUBACK;
|
||||
}
|
||||
else if ( pub.header.bits.qos == 2)
|
||||
{
|
||||
WRITELOG(" While Client is sleeping, QoS2 is not supported.\n");
|
||||
type = PUBREC;
|
||||
}
|
||||
replyACK(client, &pub, type);
|
||||
pub.header.bits.qos = 0;
|
||||
replyACK(client, &pub, PUBACK);
|
||||
pub.msgId = 0;
|
||||
snPacket->setPUBLISH((uint8_t) pub.header.bits.dup, (int) pub.header.bits.qos,
|
||||
(uint8_t) pub.header.bits.retain, (uint16_t) pub.msgId, topicId, (uint8_t*) pub.payload,
|
||||
pub.payloadlen);
|
||||
client->setClientSleepPacket(snPacket);
|
||||
}
|
||||
else if (client->isActive())
|
||||
{
|
||||
snPacket->setPUBLISH((uint8_t) pub.header.bits.dup, (int) pub.header.bits.qos, (uint8_t) pub.header.bits.retain,
|
||||
(uint16_t) pub.msgId, topicId, (uint8_t*) pub.payload, pub.payloadlen);
|
||||
Event* ev1 = new Event();
|
||||
ev1->setClientSendEvent(client, snPacket);
|
||||
_gateway->getClientSendQue()->post(ev1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MQTTGWPublishHandler::replyACK(Client* client, Publish* pub, int type)
|
||||
{
|
||||
MQTTGWPacket* pubAck = new MQTTGWPacket();
|
||||
pubAck->setAck(type, (uint16_t)pub->msgId);
|
||||
Event* ev1 = new Event();
|
||||
ev1->setBrokerSendEvent(client, pubAck);
|
||||
_gateway->getBrokerSendQue()->post(ev1);
|
||||
}
|
||||
|
||||
void MQTTGWPublishHandler::handlePuback(Client* client, MQTTGWPacket* packet)
|
||||
{
|
||||
Ack ack;
|
||||
packet->getAck(&ack);
|
||||
uint16_t topicId = client->getWaitedPubTopicId((uint16_t)ack.msgId);
|
||||
if (topicId)
|
||||
{
|
||||
MQTTSNPacket* mqttsnPacket = new MQTTSNPacket();
|
||||
mqttsnPacket->setPUBACK(topicId, (uint16_t)ack.msgId, 0);
|
||||
|
||||
client->eraseWaitedPubTopicId((uint16_t)ack.msgId);
|
||||
Event* ev1 = new Event();
|
||||
ev1->setClientSendEvent(client, mqttsnPacket);
|
||||
_gateway->getClientSendQue()->post(ev1);
|
||||
return;
|
||||
}
|
||||
WRITELOG(" PUBACK from the Broker is invalid. PacketID : %04X ClientID : %s \n", (uint16_t)ack.msgId, client->getClientId());
|
||||
}
|
||||
|
||||
void MQTTGWPublishHandler::handleAck(Client* client, MQTTGWPacket* packet, int type)
|
||||
{
|
||||
Ack ack;
|
||||
packet->getAck(&ack);
|
||||
MQTTSNPacket* mqttsnPacket = new MQTTSNPacket();
|
||||
if (type == PUBREC)
|
||||
{
|
||||
mqttsnPacket->setPUBREC((uint16_t) ack.msgId);
|
||||
}
|
||||
else if (type == PUBREL)
|
||||
{
|
||||
mqttsnPacket->setPUBREL((uint16_t) ack.msgId);
|
||||
}
|
||||
else if (type == PUBCOMP)
|
||||
{
|
||||
mqttsnPacket->setPUBCOMP((uint16_t) ack.msgId);
|
||||
}
|
||||
|
||||
Event* ev1 = new Event();
|
||||
ev1->setClientSendEvent(client, mqttsnPacket);
|
||||
_gateway->getClientSendQue()->post(ev1);
|
||||
}
|
||||
|
||||
45
MQTTSNGateway/src/MQTTGWPublishHandler.h
Normal file
45
MQTTSNGateway/src/MQTTGWPublishHandler.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
#ifndef MQTTGWPUBLISHHANDLER_H_
|
||||
#define MQTTGWPUBLISHHANDLER_H_
|
||||
|
||||
#include "MQTTSNGWDefines.h"
|
||||
#include "MQTTSNGWPacket.h"
|
||||
#include "MQTTSNGateway.h"
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
|
||||
class MQTTGWPublishHandler
|
||||
{
|
||||
public:
|
||||
MQTTGWPublishHandler(Gateway* gateway);
|
||||
~MQTTGWPublishHandler();
|
||||
void handlePublish(Client* client, MQTTGWPacket* packet);
|
||||
void handlePuback(Client* client, MQTTGWPacket* packet);
|
||||
void handleAck(Client* client, MQTTGWPacket* packet, int type);
|
||||
|
||||
private:
|
||||
void replyACK(Client* client, Publish* pub, int type);
|
||||
|
||||
Gateway* _gateway;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* MQTTGWPUBLISHHANDLER_H_ */
|
||||
74
MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp
Normal file
74
MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include "MQTTGWSubscribeHandler.h"
|
||||
#include "MQTTGWPacket.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
MQTTGWSubscribeHandler::MQTTGWSubscribeHandler(Gateway* gateway)
|
||||
{
|
||||
_gateway = gateway;
|
||||
}
|
||||
|
||||
MQTTGWSubscribeHandler::~MQTTGWSubscribeHandler()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void MQTTGWSubscribeHandler::handleSuback(Client* client, MQTTGWPacket* packet)
|
||||
{
|
||||
uint16_t msgId;
|
||||
uint8_t rc;
|
||||
uint8_t returnCode;
|
||||
int qos = 0;
|
||||
|
||||
packet->getSUBACK(&msgId, &rc);
|
||||
uint16_t topicId = client->getWaitedSubTopicId(msgId);
|
||||
|
||||
if (topicId)
|
||||
{
|
||||
MQTTSNPacket* snPacket = new MQTTSNPacket();
|
||||
client->eraseWaitedSubTopicId(msgId);
|
||||
|
||||
if (rc == 0x80)
|
||||
{
|
||||
returnCode = MQTTSN_RC_REJECTED_INVALID_TOPIC_ID;
|
||||
}
|
||||
else
|
||||
{
|
||||
returnCode = MQTTSN_RC_ACCEPTED;
|
||||
qos = rc;
|
||||
}
|
||||
snPacket->setSUBACK(qos, topicId, msgId, returnCode);
|
||||
Event* ev1 = new Event();
|
||||
ev1->setClientSendEvent(client, snPacket);
|
||||
_gateway->getClientSendQue()->post(ev1);
|
||||
}
|
||||
}
|
||||
|
||||
void MQTTGWSubscribeHandler::handleUnsuback(Client* client, MQTTGWPacket* packet)
|
||||
{
|
||||
Ack ack;
|
||||
packet->getAck(&ack);
|
||||
MQTTSNPacket* snPacket = new MQTTSNPacket();
|
||||
snPacket->setUNSUBACK(ack.msgId);
|
||||
Event* ev1 = new Event();
|
||||
ev1->setClientSendEvent(client, snPacket);
|
||||
_gateway->getClientSendQue()->post(ev1);
|
||||
}
|
||||
|
||||
41
MQTTSNGateway/src/MQTTGWSubscribeHandler.h
Normal file
41
MQTTSNGateway/src/MQTTGWSubscribeHandler.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
#ifndef MQTTGWSUBSCRIBEHANDLER_H_
|
||||
#define MQTTGWSUBSCRIBEHANDLER_H_
|
||||
|
||||
#include "MQTTSNGWDefines.h"
|
||||
#include "MQTTGWPacket.h"
|
||||
#include "MQTTSNGateway.h"
|
||||
#include "MQTTSNGWClient.h"
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
|
||||
class MQTTGWSubscribeHandler
|
||||
{
|
||||
public:
|
||||
MQTTGWSubscribeHandler(Gateway* gateway);
|
||||
~MQTTGWSubscribeHandler();
|
||||
void handleSuback(Client* clnode, MQTTGWPacket* packet);
|
||||
void handleUnsuback(Client* clnode, MQTTGWPacket* packet);
|
||||
|
||||
private:
|
||||
Gateway* _gateway;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* MQTTGWSUBSCRIBEHANDLER_H_ */
|
||||
195
MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp
Normal file
195
MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include "MQTTSNGWBrokerRecvTask.h"
|
||||
#include "MQTTSNGWClient.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
char* currentDateTime(void);
|
||||
|
||||
/*=====================================
|
||||
Class BrokerRecvTask
|
||||
=====================================*/
|
||||
BrokerRecvTask::BrokerRecvTask(Gateway* gateway)
|
||||
{
|
||||
_gateway = gateway;
|
||||
_gateway->attach((Thread*)this);
|
||||
_light = 0;
|
||||
}
|
||||
|
||||
BrokerRecvTask::~BrokerRecvTask()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize attributs of this class
|
||||
*/
|
||||
void BrokerRecvTask::initialize(int argc, char** argv)
|
||||
{
|
||||
_light = _gateway->getLightIndicator();
|
||||
}
|
||||
|
||||
/**
|
||||
* receive a MQTT messge from the broker and post a event.
|
||||
*/
|
||||
void BrokerRecvTask::run(void)
|
||||
{
|
||||
struct timeval timeout;
|
||||
MQTTGWPacket* packet = 0;
|
||||
int rc;
|
||||
Event* ev = 0;
|
||||
fd_set rset;
|
||||
fd_set wset;
|
||||
|
||||
while (true)
|
||||
{
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 500000; // 500 msec
|
||||
FD_ZERO(&rset);
|
||||
FD_ZERO(&wset);
|
||||
int maxSock = 0;
|
||||
int sockfd = 0;
|
||||
|
||||
/* Prepare sockets list to read */
|
||||
Client* client = _gateway->getClientList()->getClient();
|
||||
_light->blueLight(false);
|
||||
|
||||
while (client > 0)
|
||||
{
|
||||
if (client->getNetwork()->isValid())
|
||||
{
|
||||
sockfd = client->getNetwork()->getSock();
|
||||
FD_SET(sockfd, &rset);
|
||||
FD_SET(sockfd, &wset);
|
||||
if (sockfd > maxSock)
|
||||
{
|
||||
maxSock = sockfd;
|
||||
}
|
||||
}
|
||||
client = client->getNextClient();
|
||||
}
|
||||
|
||||
if (maxSock > 0)
|
||||
{
|
||||
/* Check sockets is ready to read */
|
||||
int activity = select(maxSock + 1, &rset, 0, 0, &timeout);
|
||||
|
||||
if (activity > 0)
|
||||
{
|
||||
client = _gateway->getClientList()->getClient();
|
||||
|
||||
while (client > 0)
|
||||
{
|
||||
_light->blueLight(false);
|
||||
if (client->getNetwork()->isValid())
|
||||
{
|
||||
int sockfd = client->getNetwork()->getSock();
|
||||
if (FD_ISSET(sockfd, &rset))
|
||||
{
|
||||
packet = new MQTTGWPacket();
|
||||
rc = 0;
|
||||
/* read sockets */
|
||||
_light->blueLight(true);
|
||||
rc = packet->recv(client->getNetwork());
|
||||
if ( rc > 0 )
|
||||
{
|
||||
log(client, packet);
|
||||
|
||||
/* post a BrokerRecvEvent */
|
||||
ev = new Event();
|
||||
ev->setBrokerRecvEvent(client, packet);
|
||||
_gateway->getPacketEventQue()->post(ev);
|
||||
}
|
||||
else
|
||||
{
|
||||
_light->blueLight(false);
|
||||
if ( rc == 0 )
|
||||
{
|
||||
delete packet;
|
||||
continue;
|
||||
}
|
||||
else if (rc == -1)
|
||||
{
|
||||
WRITELOG("%s BrokerRecvTask can't receive a packet from the broker errno=%d %s%s\n", ERRMSG_HEADER, errno, client->getClientId(), ERRMSG_FOOTER);
|
||||
}
|
||||
else if ( rc == -2 )
|
||||
{
|
||||
WRITELOG("%s BrokerRecvTask receive invalid length of packet from the broker. DISCONNECT %s %s\n", ERRMSG_HEADER, client->getClientId(),ERRMSG_FOOTER);
|
||||
}
|
||||
else if ( rc == -3 )
|
||||
{
|
||||
WRITELOG("%s BrokerRecvTask can't create the packet %s%s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER);
|
||||
}
|
||||
|
||||
/* disconnect the client */
|
||||
client->disconnected();
|
||||
client->getNetwork()->disconnect();
|
||||
rc = 0;
|
||||
delete packet;
|
||||
}
|
||||
}
|
||||
}
|
||||
client = client->getNextClient();
|
||||
}
|
||||
_light->blueLight(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_light->greenLight(false);
|
||||
}
|
||||
maxSock = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write message content into stdout or Ringbuffer
|
||||
*/
|
||||
void BrokerRecvTask::log(Client* client, MQTTGWPacket* packet)
|
||||
{
|
||||
char pbuf[SIZEOF_LOG_PACKET * 3];
|
||||
char msgId[6];
|
||||
|
||||
switch (packet->getType())
|
||||
{
|
||||
case CONNACK:
|
||||
case DISCONNECT:
|
||||
WRITELOG(FORMAT_YE_GR_MSGID, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROW, client->getClientId(), packet->print(pbuf));
|
||||
break;
|
||||
case PUBLISH:
|
||||
WRITELOG(FORMAT_GR_MSGID_NL, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROW, client->getClientId(), packet->print(pbuf));
|
||||
break;
|
||||
case PUBACK:
|
||||
case PUBREC:
|
||||
case PUBREL:
|
||||
case PUBCOMP:
|
||||
WRITELOG(FORMAT_GR_MSGID, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROW, client->getClientId(), packet->print(pbuf));
|
||||
break;
|
||||
case SUBACK:
|
||||
case UNSUBACK:
|
||||
WRITELOG(FORMAT_YE_GR_MSGID, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROW, client->getClientId(), packet->print(pbuf));
|
||||
break;
|
||||
case PINGRESP:
|
||||
WRITELOG(FORMAT_GR_NL, currentDateTime(), packet->getName(), LEFTARROW, client->getClientId(), packet->print(pbuf));
|
||||
break;
|
||||
default:
|
||||
WRITELOG(FORMAT_GR_NL, currentDateTime(), "UNKOWN_TYPE", LEFTARROW, client->getClientId(), packet->print(pbuf));
|
||||
break;
|
||||
}
|
||||
}
|
||||
49
MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.h
Normal file
49
MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
#ifndef MQTTSNGWBROKERRECVTASK_H_
|
||||
#define MQTTSNGWBROKERRECVTASK_H_
|
||||
|
||||
#include "MQTTSNGWDefines.h"
|
||||
#include "MQTTSNGateway.h"
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
|
||||
#define ERRNO_APL_03 13 // Task Initialize Error
|
||||
/*=====================================
|
||||
Class BrokerRecvTask
|
||||
=====================================*/
|
||||
class BrokerRecvTask: public Thread
|
||||
{
|
||||
MAGIC_WORD_FOR_THREAD;
|
||||
;
|
||||
public:
|
||||
BrokerRecvTask(Gateway* gateway);
|
||||
~BrokerRecvTask();
|
||||
void initialize(int argc, char** argv);
|
||||
void run(void);
|
||||
|
||||
private:
|
||||
void log(Client*, MQTTGWPacket*);
|
||||
|
||||
Gateway* _gateway;
|
||||
LightIndicator* _light;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* MQTTSNGWBROKERRECVTASK_H_ */
|
||||
162
MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp
Normal file
162
MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include "MQTTSNGWBrokerSendTask.h"
|
||||
#include "MQTTSNGWDefines.h"
|
||||
#include "MQTTSNGateway.h"
|
||||
#include "MQTTSNGWClient.h"
|
||||
#include "MQTTGWPacket.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
char* currentDateTime();
|
||||
#define ERRMSG_FORMAT "\n%s \x1b[0m\x1b[31merror:\x1b[0m\x1b[37m Can't Xmit to the Broker. errno=%d\n"
|
||||
|
||||
/*=====================================
|
||||
Class BrokerSendTask
|
||||
=====================================*/
|
||||
BrokerSendTask::BrokerSendTask(Gateway* gateway)
|
||||
{
|
||||
_gateway = gateway;
|
||||
_gateway->attach((Thread*)this);
|
||||
_host = 0;
|
||||
_service = 0;
|
||||
_light = 0;
|
||||
}
|
||||
|
||||
BrokerSendTask::~BrokerSendTask()
|
||||
{
|
||||
if (_host)
|
||||
{
|
||||
free(_host);
|
||||
}
|
||||
if (_service)
|
||||
{
|
||||
free(_service);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize attributs of this class
|
||||
*/
|
||||
void BrokerSendTask::initialize(int argc, char** argv)
|
||||
{
|
||||
char param[MQTTSNGW_PARAM_MAX];
|
||||
|
||||
if (_gateway->getParam("BrokerName", param) == 0)
|
||||
{
|
||||
_host = strdup(param);
|
||||
}
|
||||
if (_gateway->getParam("BrokerPortNo", param) == 0)
|
||||
{
|
||||
_service = strdup(param);
|
||||
}
|
||||
_light = _gateway->getLightIndicator();
|
||||
}
|
||||
|
||||
/**
|
||||
* connect to the broker and send MQTT messges
|
||||
*/
|
||||
void BrokerSendTask::run()
|
||||
{
|
||||
Event* ev = 0;
|
||||
MQTTGWPacket* packet = 0;
|
||||
Client* client = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
int rc = 0;
|
||||
ev = _gateway->getBrokerSendQue()->wait();
|
||||
client = ev->getClient();
|
||||
packet = ev->getMQTTGWPacket();
|
||||
|
||||
if ( !client->getNetwork()->isValid() )
|
||||
{
|
||||
/* connect to the broker and send a packet */
|
||||
if ( !client->getNetwork()->connect(_host, _service) )
|
||||
{
|
||||
/* disconnect the broker and chage the client's status */
|
||||
WRITELOG("%s BrokerSendTask can't open the socket. errno=%d %s%s\n",
|
||||
ERRMSG_HEADER, rc == -1 ? errno : 0, client->getClientId(), ERRMSG_FOOTER);
|
||||
client->disconnected();
|
||||
client->getNetwork()->disconnect();
|
||||
delete ev;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* send a packet */
|
||||
_light->blueLight(true);
|
||||
if ( (rc = packet->send(client->getNetwork())) > 0 )
|
||||
{
|
||||
if ( packet->getType() == CONNECT )
|
||||
{
|
||||
client->setWaitWillMsgFlg(false);
|
||||
client->connectSended();
|
||||
}
|
||||
log(client, packet);
|
||||
}
|
||||
else
|
||||
{
|
||||
WRITELOG("%s BrokerSendTask can't send a packet. errno=%d %s%s\n",
|
||||
ERRMSG_HEADER, rc == -1 ? errno : 0, client->getClientId(), ERRMSG_FOOTER);
|
||||
WRITELOG("%s BrokerSendTask can't send a packet to the broker errno=%d %s%s\n",
|
||||
ERRMSG_HEADER, rc == -1 ? errno : 0, client->getClientId(), ERRMSG_FOOTER);
|
||||
client->disconnected();
|
||||
client->getNetwork()->disconnect();
|
||||
}
|
||||
|
||||
_light->blueLight(false);
|
||||
delete ev;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* write message content into stdout or Ringbuffer
|
||||
*/
|
||||
void BrokerSendTask::log(Client* client, MQTTGWPacket* packet)
|
||||
{
|
||||
char pbuf[SIZEOF_LOG_PACKET * 3];
|
||||
char msgId[6];
|
||||
|
||||
switch (packet->getType())
|
||||
{
|
||||
case CONNECT:
|
||||
WRITELOG(FORMAT_YE_GR, currentDateTime(), packet->getName(), RIGHTARROW, client->getClientId(), packet->print(pbuf));
|
||||
break;
|
||||
case PUBLISH:
|
||||
WRITELOG(FORMAT_WH_GR_MSGID_NL, currentDateTime(), packet->getName(), packet->getMsgId(msgId), RIGHTARROW, client->getClientId(), packet->print(pbuf));
|
||||
break;
|
||||
case SUBSCRIBE:
|
||||
case UNSUBSCRIBE:
|
||||
case PUBACK:
|
||||
case PUBREC:
|
||||
case PUBREL:
|
||||
case PUBCOMP:
|
||||
WRITELOG(FORMAT_WH_GR_MSGID, currentDateTime(), packet->getName(), packet->getMsgId(msgId), RIGHTARROW, client->getClientId(), packet->print(pbuf));
|
||||
break;
|
||||
case PINGREQ:
|
||||
WRITELOG(FORMAT_YE, currentDateTime(), packet->getName(), RIGHTARROW, client->getClientId(), packet->print(pbuf));
|
||||
break;
|
||||
case DISCONNECT:
|
||||
WRITELOG(FORMAT_YE, currentDateTime(), packet->getName(), RIGHTARROW, client->getClientId(), packet->print(pbuf));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
47
MQTTSNGateway/src/MQTTSNGWBrokerSendTask.h
Normal file
47
MQTTSNGateway/src/MQTTSNGWBrokerSendTask.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
#ifndef MQTTSNGWBROKERSENDTASK_H_
|
||||
#define MQTTSNGWBROKERSENDTASK_H_
|
||||
|
||||
#include "MQTTSNGWDefines.h"
|
||||
#include "MQTTSNGateway.h"
|
||||
#include "MQTTSNGWClient.h"
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
#define ERRNO_APL_04 14 // Task Initialize Error
|
||||
/*=====================================
|
||||
Class BrokerSendTask
|
||||
=====================================*/
|
||||
class BrokerSendTask : public Thread
|
||||
{
|
||||
MAGIC_WORD_FOR_THREAD;
|
||||
public:
|
||||
BrokerSendTask(Gateway* gateway);
|
||||
~BrokerSendTask();
|
||||
void initialize(int argc, char** argv);
|
||||
void run();
|
||||
private:
|
||||
void log(Client*, MQTTGWPacket*);
|
||||
|
||||
Gateway* _gateway;
|
||||
char* _host;
|
||||
char* _service;
|
||||
LightIndicator* _light;
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* MQTTSNGWBROKERSENDTASK_H_ */
|
||||
1142
MQTTSNGateway/src/MQTTSNGWClient.cpp
Normal file
1142
MQTTSNGateway/src/MQTTSNGWClient.cpp
Normal file
File diff suppressed because it is too large
Load Diff
347
MQTTSNGateway/src/MQTTSNGWClient.h
Normal file
347
MQTTSNGateway/src/MQTTSNGWClient.h
Normal file
@@ -0,0 +1,347 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#ifndef MQTTSNGWCLIENT_H_
|
||||
#define MQTTSNGWCLIENT_H_
|
||||
|
||||
#include <Timer.h> // Timer class
|
||||
#include "MQTTSNGWProcess.h"
|
||||
#include "MQTTGWPacket.h"
|
||||
#include "MQTTSNGWPacket.h"
|
||||
#include "MQTTSNPacket.h"
|
||||
#include "Network.h"
|
||||
#include "SensorNetwork.h"
|
||||
#include "MQTTSNPacket.h"
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
|
||||
#define MQTTSN_TOPIC_MULTI_WILDCARD '#'
|
||||
#define MQTTSN_TOPIC_SINGLE_WILDCARD '+'
|
||||
|
||||
/*=====================================
|
||||
Class PacketQue
|
||||
=====================================*/
|
||||
template<class T> class PacketQue
|
||||
{
|
||||
public:
|
||||
PacketQue()
|
||||
{
|
||||
_que = new Que<T>;
|
||||
}
|
||||
|
||||
~PacketQue()
|
||||
{
|
||||
clear();
|
||||
delete _que;
|
||||
}
|
||||
|
||||
T* getPacket()
|
||||
{
|
||||
T* packet;
|
||||
if (_que->size() > 0)
|
||||
{
|
||||
_mutex.lock();
|
||||
packet = _que->front();
|
||||
_mutex.unlock();
|
||||
return packet;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void post(T* packet)
|
||||
{
|
||||
_mutex.lock();
|
||||
_que->post(packet);
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
void pop()
|
||||
{
|
||||
if (_que->size() > 0)
|
||||
{
|
||||
_mutex.lock();
|
||||
_que->pop();
|
||||
_mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
_mutex.lock();
|
||||
while (_que->size() > 0)
|
||||
{
|
||||
delete _que->front();
|
||||
_que->pop();
|
||||
}
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
Que<T>* _que;
|
||||
Mutex _mutex;
|
||||
};
|
||||
|
||||
|
||||
/*=====================================
|
||||
Class Topic
|
||||
======================================*/
|
||||
class Topic
|
||||
{
|
||||
friend class Topics;
|
||||
public:
|
||||
Topic();
|
||||
Topic(string* topic);
|
||||
~Topic();
|
||||
|
||||
string* getTopicName(void);
|
||||
uint16_t getTopicId(void);
|
||||
int hasWildCard(unsigned int* pos);
|
||||
bool isMatch(string* topicName);
|
||||
|
||||
private:
|
||||
uint16_t _topicId;
|
||||
string* _topicName;
|
||||
Topic* _next;
|
||||
};
|
||||
|
||||
/*=====================================
|
||||
Class Topics
|
||||
======================================*/
|
||||
class Topics
|
||||
{
|
||||
public:
|
||||
Topics();
|
||||
~Topics();
|
||||
Topic* add(MQTTSN_topicid* topicid);
|
||||
Topic* add(string* topic);
|
||||
uint16_t getTopicId(MQTTSN_topicid* topic);
|
||||
uint16_t getNextTopicId();
|
||||
Topic* getTopic(uint16_t topicId);
|
||||
Topic* getTopic(MQTTSN_topicid* topicid);
|
||||
Topic* match(MQTTSN_topicid* topicid);
|
||||
|
||||
private:
|
||||
uint16_t _nextTopicId;
|
||||
Topic* _first;
|
||||
|
||||
};
|
||||
|
||||
/*=====================================
|
||||
Class TopicIdMap
|
||||
=====================================*/
|
||||
class TopicIdMapelement
|
||||
{
|
||||
friend class TopicIdMap;
|
||||
public:
|
||||
TopicIdMapelement(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type);
|
||||
~TopicIdMapelement();
|
||||
|
||||
private:
|
||||
uint16_t _msgId;
|
||||
uint16_t _topicId;
|
||||
MQTTSN_topicTypes _type;
|
||||
TopicIdMapelement* _next;
|
||||
TopicIdMapelement* _prev;
|
||||
};
|
||||
|
||||
class TopicIdMap
|
||||
{
|
||||
public:
|
||||
TopicIdMap();
|
||||
~TopicIdMap();
|
||||
uint16_t getTopicId(uint16_t msgId, MQTTSN_topicTypes* type);
|
||||
Topic* getTopic(MQTTSN_topicTypes type);
|
||||
int add(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type);
|
||||
void erase(uint16_t msgId);
|
||||
void clear(void);
|
||||
private:
|
||||
int find(uint16_t msgId);
|
||||
uint16_t* _msgIds;
|
||||
TopicIdMapelement* _first;
|
||||
TopicIdMapelement* _end;
|
||||
int _cnt;
|
||||
int _maxInflight;
|
||||
};
|
||||
|
||||
/*=====================================
|
||||
Class WaitREGACKPacket
|
||||
=====================================*/
|
||||
class waitREGACKPacket
|
||||
{
|
||||
friend class WaitREGACKPacketList;
|
||||
public:
|
||||
waitREGACKPacket(MQTTSNPacket* packet, uint16_t REGACKMsgId);
|
||||
~waitREGACKPacket();
|
||||
|
||||
private:
|
||||
uint16_t _msgId;
|
||||
MQTTSNPacket* _packet;
|
||||
waitREGACKPacket* _next;
|
||||
waitREGACKPacket* _prev;
|
||||
};
|
||||
|
||||
/*=====================================
|
||||
Class WaitREGACKPacketList
|
||||
=====================================*/
|
||||
class WaitREGACKPacketList
|
||||
{
|
||||
public:
|
||||
WaitREGACKPacketList();
|
||||
~WaitREGACKPacketList();
|
||||
int setPacket(MQTTSNPacket* packet, uint16_t REGACKMsgId);
|
||||
MQTTSNPacket* getPacket(uint16_t REGACKMsgId);
|
||||
void erase(uint16_t REGACKMsgId);
|
||||
|
||||
private:
|
||||
waitREGACKPacket* _first;
|
||||
waitREGACKPacket* _end;
|
||||
};
|
||||
|
||||
/*=====================================
|
||||
Class Client
|
||||
=====================================*/
|
||||
#define MQTTSN_CLIENTID_LENGTH 23
|
||||
|
||||
typedef enum
|
||||
{
|
||||
Cstat_Disconnected = 0, Cstat_TryConnecting, Cstat_Connecting, Cstat_Active, Cstat_Asleep, Cstat_Awake, Cstat_Lost
|
||||
} ClientStatus;
|
||||
|
||||
|
||||
class Client
|
||||
{
|
||||
friend class ClientList;
|
||||
public:
|
||||
Client(bool secure = false);
|
||||
Client(uint8_t maxInflightMessages, bool secure);
|
||||
~Client();
|
||||
|
||||
Connect* getConnectData(void);
|
||||
uint16_t getWaitedPubTopicId(uint16_t msgId);
|
||||
uint16_t getWaitedSubTopicId(uint16_t msgId);
|
||||
MQTTSNPacket* getClientSleepPacket();
|
||||
WaitREGACKPacketList* getWaitREGACKPacketList(void);
|
||||
|
||||
void eraseWaitedPubTopicId(uint16_t msgId);
|
||||
void eraseWaitedSubTopicId(uint16_t msgId);
|
||||
void clearWaitedPubTopicId(void);
|
||||
void clearWaitedSubTopicId(void);
|
||||
|
||||
void setClientSleepPacket(MQTTSNPacket*);
|
||||
void setWaitedPubTopicId(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type);
|
||||
void setWaitedSubTopicId(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type);
|
||||
|
||||
void checkTimeover(void);
|
||||
void updateStatus(MQTTSNPacket*);
|
||||
void updateStatus(ClientStatus);
|
||||
void connectSended(void);
|
||||
void connackSended(int rc);
|
||||
void disconnected(void);
|
||||
bool isConnectSendable(void);
|
||||
|
||||
uint16_t getNextPacketId(void);
|
||||
uint8_t getNextSnMsgId(void);
|
||||
Topics* getTopics(void);
|
||||
void setTopics(Topics* topics);
|
||||
void setKeepAlive(MQTTSNPacket* packet);
|
||||
|
||||
SensorNetAddress* getSensorNetAddress(void);
|
||||
Network* getNetwork(void);
|
||||
void setClientAddress(SensorNetAddress* sensorNetAddr);
|
||||
void setSensorNetType(bool stable);
|
||||
|
||||
void setClientId(MQTTSNString id);
|
||||
void setWillTopic(MQTTSNString willTopic);
|
||||
void setWillMsg(MQTTSNString willmsg);
|
||||
char* getClientId(void);
|
||||
char* getWillTopic(void);
|
||||
char* getWillMsg(void);
|
||||
const char* getStatus(void);
|
||||
void setWaitWillMsgFlg(bool);
|
||||
|
||||
bool isDisconnect(void);
|
||||
bool isActive(void);
|
||||
bool isSleep(void);
|
||||
bool isSecureNetwork(void);
|
||||
bool isSensorNetStable(void);
|
||||
bool isWaitWillMsg(void);
|
||||
|
||||
Client* getNextClient(void);
|
||||
|
||||
private:
|
||||
PacketQue<MQTTSNPacket> _clientSleepPacketQue;
|
||||
WaitREGACKPacketList _waitREGACKList;
|
||||
|
||||
Topics* _topics;
|
||||
TopicIdMap _waitedPubTopicIdMap;
|
||||
TopicIdMap _waitedSubTopicIdMap;
|
||||
|
||||
Connect _connectData;
|
||||
MQTTSNPacket* _connAck;
|
||||
|
||||
char* _clientId;
|
||||
char* _willTopic;
|
||||
char* _willMsg;
|
||||
|
||||
Timer _keepAliveTimer;
|
||||
uint32_t _keepAliveMsec;
|
||||
|
||||
ClientStatus _status;
|
||||
bool _waitWillMsgFlg;
|
||||
|
||||
uint16_t _packetId;
|
||||
uint8_t _snMsgId;
|
||||
|
||||
Network* _network; // Broker
|
||||
bool _secureNetwork; // SSL
|
||||
bool _sensorNetype; // false: unstable network like a G3
|
||||
SensorNetAddress _sensorNetAddr;
|
||||
|
||||
Client* _nextClient;
|
||||
Client* _prevClient;
|
||||
|
||||
};
|
||||
|
||||
/*=====================================
|
||||
Class ClientList
|
||||
=====================================*/
|
||||
class ClientList
|
||||
{
|
||||
public:
|
||||
ClientList();
|
||||
~ClientList();
|
||||
bool authorize(const char* fileName);
|
||||
void erase(Client*);
|
||||
Client* getClient(SensorNetAddress* addr);
|
||||
Client* createClient(SensorNetAddress* addr, MQTTSNString* clientId, bool unstableLine,
|
||||
bool secure);
|
||||
uint16_t getClientCount(void);
|
||||
Client* getClient(void);
|
||||
bool isAuthorized();
|
||||
private:
|
||||
Client* _firstClient;
|
||||
Client* _endClient;
|
||||
Mutex _mutex;
|
||||
uint16_t _clientCnt;
|
||||
bool _authorize;
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* MQTTSNGWCLIENT_H_ */
|
||||
172
MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp
Normal file
172
MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include "MQTTSNGWClientRecvTask.h"
|
||||
#include "MQTTSNGateway.h"
|
||||
char* currentDateTime(void);
|
||||
/*=====================================
|
||||
Class ClientRecvTask
|
||||
=====================================*/
|
||||
ClientRecvTask::ClientRecvTask(Gateway* gateway)
|
||||
{
|
||||
_gateway = gateway;
|
||||
_gateway->attach((Thread*)this);
|
||||
_sensorNetwork = _gateway->getSensorNetwork();
|
||||
}
|
||||
|
||||
ClientRecvTask::~ClientRecvTask()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize SensorNetwork
|
||||
*/
|
||||
void ClientRecvTask::initialize(int argc, char** argv)
|
||||
{
|
||||
if ( _sensorNetwork->initialize() < 0 )
|
||||
{
|
||||
throw Exception(" Can't open the sensor network.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive a packet from clients via sensor netwwork
|
||||
* and generate a event to execute the packet handling procedure
|
||||
* of MQTTSNPacketHandlingTask.
|
||||
*/
|
||||
void ClientRecvTask::run()
|
||||
{
|
||||
Event* ev = 0;
|
||||
Client* client = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
MQTTSNPacket* packet = new MQTTSNPacket();
|
||||
int packetLen = packet->recv(_sensorNetwork);
|
||||
|
||||
if (packetLen < 3 )
|
||||
{
|
||||
delete packet;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( packet->getType() <= MQTTSN_ADVERTISE || packet->getType() == MQTTSN_GWINFO )
|
||||
{
|
||||
delete packet;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( packet->getType() == MQTTSN_SEARCHGW )
|
||||
{
|
||||
/* write log and post Event */
|
||||
log(0, packet);
|
||||
ev = new Event();
|
||||
ev->setBrodcastEvent(packet);
|
||||
_gateway->getPacketEventQue()->post(ev);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* get client from the ClientList of Gateway by sensorNetAddress. */
|
||||
client = _gateway->getClientList()->getClient(_sensorNetwork->getSenderAddress());
|
||||
|
||||
if ( client )
|
||||
{
|
||||
/* write log and post Event */
|
||||
log(client, packet);
|
||||
ev = new Event();
|
||||
ev->setClientRecvEvent(client,packet);
|
||||
_gateway->getPacketEventQue()->post(ev);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* new client */
|
||||
if (packet->getType() == MQTTSN_CONNECT)
|
||||
{
|
||||
MQTTSNPacket_connectData data;
|
||||
memset(&data, 0, sizeof(MQTTSNPacket_connectData));
|
||||
packet->getCONNECT(&data);
|
||||
|
||||
/* create a client */
|
||||
client = _gateway->getClientList()->createClient(_sensorNetwork->getSenderAddress(), &data.clientID, false, false);
|
||||
|
||||
if (!client)
|
||||
{
|
||||
WRITELOG("%s Can't create a Client. CONNECT message has been discarded.%s\n", ERRMSG_HEADER, ERRMSG_FOOTER);
|
||||
delete packet;
|
||||
continue;
|
||||
}
|
||||
|
||||
log(client, packet);
|
||||
|
||||
/* set sensorNetAddress & post Event */
|
||||
client->setClientAddress(_sensorNetwork->getSenderAddress());
|
||||
ev = new Event();
|
||||
ev->setClientRecvEvent(client, packet);
|
||||
_gateway->getPacketEventQue()->post(ev);
|
||||
}
|
||||
else
|
||||
{
|
||||
log(client, packet);
|
||||
delete packet;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientRecvTask::log(Client* client, MQTTSNPacket* packet)
|
||||
{
|
||||
char pbuf[SIZEOF_LOG_PACKET * 3];
|
||||
char msgId[6];
|
||||
const char* clientId = client ? (const char*)client->getClientId() :"Non Active Client !" ;
|
||||
|
||||
switch (packet->getType())
|
||||
{
|
||||
case MQTTSN_SEARCHGW:
|
||||
WRITELOG(FORMAT_CY_NL, currentDateTime(), packet->getName(), LEFTARROW, CLIENT, packet->print(pbuf));
|
||||
break;
|
||||
case MQTTSN_CONNECT:
|
||||
WRITELOG(FORMAT_YE_WH_NL, currentDateTime(), packet->getName(), LEFTARROW, clientId, packet->print(pbuf));
|
||||
break;
|
||||
case MQTTSN_WILLTOPIC:
|
||||
case MQTTSN_WILLMSG:
|
||||
case MQTTSN_DISCONNECT:
|
||||
case MQTTSN_WILLTOPICUPD:
|
||||
case MQTTSN_WILLMSGUPD:
|
||||
WRITELOG(FORMAT_WHITE_NL, currentDateTime(), packet->getName(), LEFTARROW, clientId, packet->print(pbuf));
|
||||
break;
|
||||
case MQTTSN_PUBLISH:
|
||||
case MQTTSN_REGISTER:
|
||||
case MQTTSN_SUBSCRIBE:
|
||||
case MQTTSN_UNSUBSCRIBE:
|
||||
WRITELOG(FORMAT_WH_MSGID_NL, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROW, clientId, packet->print(pbuf));
|
||||
break;
|
||||
case MQTTSN_REGACK:
|
||||
case MQTTSN_PUBACK:
|
||||
case MQTTSN_PUBREC:
|
||||
case MQTTSN_PUBREL:
|
||||
case MQTTSN_PUBCOMP:
|
||||
WRITELOG(FORMAT_WH_MSGID, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROW, clientId, packet->print(pbuf));
|
||||
break;
|
||||
case MQTTSN_PINGREQ:
|
||||
WRITELOG(FORMAT_WH_NL, currentDateTime(), packet->getName(), LEFTARROW, clientId, packet->print(pbuf));
|
||||
break;
|
||||
default:
|
||||
WRITELOG(FORMAT_WH_NL, currentDateTime(), packet->getName(), LEFTARROW, clientId, packet->print(pbuf));
|
||||
break;
|
||||
}
|
||||
}
|
||||
46
MQTTSNGateway/src/MQTTSNGWClientRecvTask.h
Normal file
46
MQTTSNGateway/src/MQTTSNGWClientRecvTask.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
#ifndef MQTTSNGWCLIENTRECVTASK_H_
|
||||
#define MQTTSNGWCLIENTRECVTASK_H_
|
||||
|
||||
#include "SensorNetwork.h"
|
||||
#include "MQTTSNGateway.h"
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
|
||||
/*=====================================
|
||||
Class ClientRecvTask
|
||||
=====================================*/
|
||||
class ClientRecvTask:public Thread
|
||||
{
|
||||
MAGIC_WORD_FOR_THREAD;
|
||||
public:
|
||||
ClientRecvTask(Gateway*);
|
||||
~ClientRecvTask();
|
||||
virtual void initialize(int argc, char** argv);
|
||||
void run();
|
||||
|
||||
private:
|
||||
void log(Client*, MQTTSNPacket*);
|
||||
|
||||
Gateway* _gateway;
|
||||
SensorNetwork* _sensorNetwork;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* MQTTSNGWCLIENTRECVTASK_H_ */
|
||||
105
MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp
Normal file
105
MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
#include "MQTTSNGWClientSendTask.h"
|
||||
#include "MQTTSNGWPacket.h"
|
||||
#include "MQTTSNGWPacket.h"
|
||||
#include "MQTTSNGateway.h"
|
||||
|
||||
using namespace MQTTSNGW;
|
||||
using namespace std;
|
||||
char* currentDateTime(void);
|
||||
/*=====================================
|
||||
Class ClientSendTask
|
||||
=====================================*/
|
||||
ClientSendTask::ClientSendTask(Gateway* gateway)
|
||||
{
|
||||
_gateway = gateway;
|
||||
_gateway->attach((Thread*)this);
|
||||
_sensorNetwork = _gateway->getSensorNetwork();
|
||||
}
|
||||
|
||||
ClientSendTask::~ClientSendTask()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ClientSendTask::run()
|
||||
{
|
||||
Client* client = 0;
|
||||
MQTTSNPacket* packet = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
Event* ev = _gateway->getClientSendQue()->wait();
|
||||
|
||||
if (ev->getEventType() == EtClientSend)
|
||||
{
|
||||
client = ev->getClient();
|
||||
packet = ev->getMQTTSNPacket();
|
||||
packet->unicast(_sensorNetwork, client->getSensorNetAddress());
|
||||
}
|
||||
else if (ev->getEventType() == EtBroadcast)
|
||||
{
|
||||
packet = ev->getMQTTSNPacket();
|
||||
packet->broadcast(_sensorNetwork);
|
||||
}
|
||||
|
||||
log(client, packet);
|
||||
delete ev;
|
||||
}
|
||||
}
|
||||
|
||||
void ClientSendTask::log(Client* client, MQTTSNPacket* packet)
|
||||
{
|
||||
char pbuf[SIZEOF_LOG_PACKET * 3];
|
||||
char msgId[6];
|
||||
|
||||
switch (packet->getType())
|
||||
{
|
||||
case MQTTSN_ADVERTISE:
|
||||
case MQTTSN_GWINFO:
|
||||
WRITELOG(FORMAT_CY_NL, currentDateTime(), packet->getName(), RIGHTARROW, CLIENTS, packet->print(pbuf));
|
||||
break;
|
||||
case MQTTSN_CONNACK:
|
||||
case MQTTSN_DISCONNECT:
|
||||
WRITELOG(FORMAT_YE_WH, currentDateTime(), packet->getName(), RIGHTARROW, client->getClientId(), packet->print(pbuf));
|
||||
break;
|
||||
case MQTTSN_WILLTOPICREQ:
|
||||
case MQTTSN_WILLMSGREQ:
|
||||
case MQTTSN_WILLTOPICRESP:
|
||||
case MQTTSN_WILLMSGRESP:
|
||||
WRITELOG(FORMAT_GR, currentDateTime(), packet->getName(), RIGHTARROW, client->getClientId(), packet->print(pbuf));
|
||||
break;
|
||||
case MQTTSN_REGISTER:
|
||||
case MQTTSN_PUBLISH:
|
||||
WRITELOG(FORMAT_GR_WH_MSGID_NL, currentDateTime(), packet->getName(), packet->getMsgId(msgId), RIGHTARROW, client->getClientId(), packet->print(pbuf));
|
||||
break;
|
||||
case MQTTSN_REGACK:
|
||||
case MQTTSN_PUBACK:
|
||||
case MQTTSN_PUBREC:
|
||||
case MQTTSN_PUBREL:
|
||||
case MQTTSN_PUBCOMP:
|
||||
case MQTTSN_SUBACK:
|
||||
case MQTTSN_UNSUBACK:
|
||||
WRITELOG(FORMAT_GR_WH_MSGID, currentDateTime(), packet->getName(), packet->getMsgId(msgId), RIGHTARROW, client->getClientId(), packet->print(pbuf));
|
||||
break;
|
||||
case MQTTSN_PINGRESP:
|
||||
WRITELOG(FORMAT_CY, currentDateTime(), packet->getName(), RIGHTARROW, client->getClientId(), packet->print(pbuf));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
45
MQTTSNGateway/src/MQTTSNGWClientSendTask.h
Normal file
45
MQTTSNGateway/src/MQTTSNGWClientSendTask.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
#ifndef MQTTSNGWCLIENTSENDTASK_H_
|
||||
#define MQTTSNGWCLIENTSENDTASK_H_
|
||||
|
||||
#include "MQTTSNGateway.h"
|
||||
#include "SensorNetwork.h"
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
|
||||
/*=====================================
|
||||
Class ClientSendTask
|
||||
=====================================*/
|
||||
class ClientSendTask: public Thread
|
||||
{
|
||||
MAGIC_WORD_FOR_THREAD;
|
||||
public:
|
||||
ClientSendTask(Gateway* gateway);
|
||||
~ClientSendTask();
|
||||
void run();
|
||||
|
||||
private:
|
||||
void log(Client*, MQTTSNPacket*);
|
||||
|
||||
Gateway* _gateway;
|
||||
SensorNetwork* _sensorNetwork;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* MQTTSNGWCLIENTSENDTASK_H_ */
|
||||
251
MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp
Normal file
251
MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp
Normal file
@@ -0,0 +1,251 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include "MQTTSNGWConnectionHandler.h"
|
||||
#include "MQTTSNGateway.h"
|
||||
#include "MQTTSNGWPacket.h"
|
||||
#include "MQTTGWPacket.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
/*=====================================
|
||||
Class MQTTSNConnectionHandler
|
||||
=====================================*/
|
||||
MQTTSNConnectionHandler::MQTTSNConnectionHandler(Gateway* gateway)
|
||||
{
|
||||
_gateway = gateway;
|
||||
}
|
||||
|
||||
MQTTSNConnectionHandler::~MQTTSNConnectionHandler()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* ADVERTISE
|
||||
*/
|
||||
void MQTTSNConnectionHandler::sendADVERTISE()
|
||||
{
|
||||
MQTTSNPacket* adv = new MQTTSNPacket();
|
||||
adv->setADVERTISE(_gateway->getGWParams()->gatewayId, _gateway->getGWParams()->keepAlive);
|
||||
Event* ev1 = new Event();
|
||||
ev1->setBrodcastEvent(adv); //broadcast
|
||||
_gateway->getClientSendQue()->post(ev1);
|
||||
}
|
||||
|
||||
/*
|
||||
* SEARCHGW
|
||||
*/
|
||||
void MQTTSNConnectionHandler::handleSearchgw(MQTTSNPacket* packet)
|
||||
{
|
||||
if (packet->getType() == MQTTSN_SEARCHGW)
|
||||
{
|
||||
if (_gateway->getClientList()->getClientCount() < DEFAULT_MAX_CLIENTS)
|
||||
{
|
||||
MQTTSNPacket* gwinfo = new MQTTSNPacket();
|
||||
gwinfo->setGWINFO(_gateway->getGWParams()->gatewayId);
|
||||
Event* ev1 = new Event();
|
||||
ev1->setBrodcastEvent(gwinfo);
|
||||
_gateway->getClientSendQue()->post(ev1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* CONNECT
|
||||
*/
|
||||
void MQTTSNConnectionHandler::handleConnect(Client* client, MQTTSNPacket* packet)
|
||||
{
|
||||
MQTTSNPacket_connectData data;
|
||||
packet->getCONNECT(&data);
|
||||
|
||||
/* clear ConnectData of Client */
|
||||
Connect* connectData = client->getConnectData();
|
||||
memset(connectData, 0, sizeof(Connect));
|
||||
client->disconnected();
|
||||
|
||||
Topics* topics = client->getTopics();
|
||||
|
||||
/* CONNECT was not sent yet. prepare Connect data */
|
||||
connectData->header.bits.type = CONNECT;
|
||||
connectData->clientID = client->getClientId();
|
||||
connectData->version = _gateway->getGWParams()->mqttVersion;
|
||||
connectData->keepAliveTimer = data.duration;
|
||||
connectData->flags.bits.will = data.willFlag;
|
||||
|
||||
if ((const char*) _gateway->getGWParams()->loginId != 0 && (const char*) _gateway->getGWParams()->password != 0)
|
||||
{
|
||||
connectData->flags.bits.password = 1;
|
||||
connectData->flags.bits.username = 1;
|
||||
}
|
||||
|
||||
if (data.cleansession)
|
||||
{
|
||||
connectData->flags.bits.cleanstart = 1;
|
||||
/* reset the table of msgNo and TopicId pare */
|
||||
client->clearWaitedPubTopicId();
|
||||
client->clearWaitedSubTopicId();
|
||||
|
||||
/* renew the TopicList */
|
||||
if (topics)
|
||||
{
|
||||
delete topics;
|
||||
}
|
||||
topics = new Topics();
|
||||
client->setTopics(topics);
|
||||
}
|
||||
|
||||
if (data.willFlag)
|
||||
{
|
||||
/* create & send WILLTOPICREQ message to the client */
|
||||
MQTTSNPacket* reqTopic = new MQTTSNPacket();
|
||||
reqTopic->setWILLTOPICREQ();
|
||||
Event* evwr = new Event();
|
||||
evwr->setClientSendEvent(client, reqTopic);
|
||||
|
||||
/* Send WILLTOPICREQ to the client */
|
||||
_gateway->getClientSendQue()->post(evwr);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* CONNECT message was not qued in.
|
||||
* create CONNECT message & send it to the broker */
|
||||
MQTTGWPacket* mqMsg = new MQTTGWPacket();
|
||||
mqMsg->setCONNECT(client->getConnectData(), (unsigned char*)_gateway->getGWParams()->loginId, (unsigned char*)_gateway->getGWParams()->password);
|
||||
Event* ev1 = new Event();
|
||||
ev1->setBrokerSendEvent(client, mqMsg);
|
||||
_gateway->getBrokerSendQue()->post(ev1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* WILLTOPIC
|
||||
*/
|
||||
void MQTTSNConnectionHandler::handleWilltopic(Client* client, MQTTSNPacket* packet)
|
||||
{
|
||||
int willQos;
|
||||
uint8_t willRetain;
|
||||
MQTTSNString willTopic;
|
||||
|
||||
packet->getWILLTOPIC(&willQos, &willRetain, &willTopic);
|
||||
client->setWillTopic(willTopic);
|
||||
Connect* connectData = client->getConnectData();
|
||||
|
||||
/* add the connectData for MQTT CONNECT message */
|
||||
connectData->willTopic = client->getWillTopic();
|
||||
connectData->flags.bits.willQoS = willQos;
|
||||
connectData->flags.bits.willRetain = willRetain;
|
||||
|
||||
/* Send WILLMSGREQ to the client */
|
||||
client->setWaitWillMsgFlg(true);
|
||||
MQTTSNPacket* reqMsg = new MQTTSNPacket();
|
||||
reqMsg->setWILLMSGREQ();
|
||||
Event* evt = new Event();
|
||||
evt->setClientSendEvent(client, reqMsg);
|
||||
_gateway->getClientSendQue()->post(evt);
|
||||
}
|
||||
|
||||
/*
|
||||
* WILLMSG
|
||||
*/
|
||||
void MQTTSNConnectionHandler::handleWillmsg(Client* client, MQTTSNPacket* packet)
|
||||
{
|
||||
if ( !client->isWaitWillMsg() )
|
||||
{
|
||||
DEBUGLOG(" MQTTSNConnectionHandler::handleWillmsg WaitWillMsgFlg is off.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
MQTTSNString willmsg;
|
||||
Connect* connectData = client->getConnectData();
|
||||
|
||||
if( client->isConnectSendable() )
|
||||
{
|
||||
/* save WillMsg in the client */
|
||||
packet->getWILLMSG(&willmsg);
|
||||
client->setWillMsg(willmsg);
|
||||
|
||||
/* create CONNECT message */
|
||||
MQTTGWPacket* mqttPacket = new MQTTGWPacket();
|
||||
connectData->willMsg = client->getWillMsg();
|
||||
mqttPacket->setCONNECT(connectData, (unsigned char*)_gateway->getGWParams()->loginId, (unsigned char*)_gateway->getGWParams()->password);
|
||||
|
||||
/* Send CONNECT to the broker */
|
||||
Event* ev1 = new Event();
|
||||
ev1->setBrokerSendEvent(client, mqttPacket);
|
||||
_gateway->getBrokerSendQue()->post(ev1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* DISCONNECT
|
||||
*/
|
||||
void MQTTSNConnectionHandler::handleDisconnect(Client* client, MQTTSNPacket* packet)
|
||||
{
|
||||
MQTTGWPacket* mqMsg = new MQTTGWPacket();
|
||||
MQTTSNPacket* snMsg = new MQTTSNPacket();
|
||||
|
||||
mqMsg->setHeader(DISCONNECT);
|
||||
snMsg->setDISCONNECT(0);
|
||||
|
||||
Event* ev1 = new Event();
|
||||
ev1->setClientSendEvent(client, snMsg);
|
||||
_gateway->getClientSendQue()->post(ev1);
|
||||
|
||||
ev1 = new Event();
|
||||
ev1->setBrokerSendEvent(client, mqMsg);
|
||||
_gateway->getBrokerSendQue()->post(ev1);
|
||||
}
|
||||
|
||||
/*
|
||||
* WILLTOPICUPD
|
||||
*/
|
||||
void MQTTSNConnectionHandler::handleWilltopicupd(Client* client, MQTTSNPacket* packet)
|
||||
{
|
||||
/* send NOT_SUPPORTED responce to the client */
|
||||
MQTTSNPacket* respMsg = new MQTTSNPacket();
|
||||
respMsg->setWILLTOPICRESP(MQTTSN_RC_NOT_SUPPORTED);
|
||||
Event* evt = new Event();
|
||||
evt->setClientSendEvent(client, respMsg);
|
||||
_gateway->getClientSendQue()->post(evt);
|
||||
}
|
||||
|
||||
/*
|
||||
* WILLMSGUPD
|
||||
*/
|
||||
void MQTTSNConnectionHandler::handleWillmsgupd(Client* client, MQTTSNPacket* packet)
|
||||
{
|
||||
/* send NOT_SUPPORTED responce to the client */
|
||||
MQTTSNPacket* respMsg = new MQTTSNPacket();
|
||||
respMsg->setWILLMSGRESP(MQTTSN_RC_NOT_SUPPORTED);
|
||||
Event* evt = new Event();
|
||||
evt->setClientSendEvent(client, respMsg);
|
||||
_gateway->getClientSendQue()->post(evt);
|
||||
}
|
||||
|
||||
/*
|
||||
* PINGREQ
|
||||
*/
|
||||
void MQTTSNConnectionHandler::handlePingreq(Client* client, MQTTSNPacket* packet)
|
||||
{
|
||||
/* send PINGREQ to the broker */
|
||||
MQTTGWPacket* pingreq = new MQTTGWPacket();
|
||||
pingreq->setHeader(PINGREQ);
|
||||
Event* ev1 = new Event();
|
||||
ev1->setBrokerSendEvent(client, pingreq);
|
||||
}
|
||||
46
MQTTSNGateway/src/MQTTSNGWConnectionHandler.h
Normal file
46
MQTTSNGateway/src/MQTTSNGWConnectionHandler.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
#ifndef MQTTSNGWCONNECTIONHANDLER_H_
|
||||
#define MQTTSNGWCONNECTIONHANDLER_H_
|
||||
|
||||
#include "MQTTSNGateway.h"
|
||||
#include "MQTTSNGWPacket.h"
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
|
||||
class MQTTSNConnectionHandler
|
||||
{
|
||||
public:
|
||||
MQTTSNConnectionHandler(Gateway* gateway);
|
||||
~MQTTSNConnectionHandler();
|
||||
void sendADVERTISE(void);
|
||||
void handleSearchgw(MQTTSNPacket* packet);
|
||||
void handleConnect(Client* client, MQTTSNPacket* packet);
|
||||
void handleWilltopic(Client* client, MQTTSNPacket* packet);
|
||||
void handleWillmsg(Client* client, MQTTSNPacket* packet);
|
||||
void handleDisconnect(Client* client, MQTTSNPacket* packet);
|
||||
void handleWilltopicupd(Client* client, MQTTSNPacket* packet);
|
||||
void handleWillmsgupd(Client* client, MQTTSNPacket* packet);
|
||||
void handlePingreq(Client* client, MQTTSNPacket* packet);
|
||||
private:
|
||||
char _pbuf[MQTTSNGW_MAX_PACKET_SIZE * 3];
|
||||
Gateway* _gateway;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* MQTTSNGWCONNECTIONHANDLER_H_ */
|
||||
62
MQTTSNGateway/src/MQTTSNGWDefines.h
Normal file
62
MQTTSNGateway/src/MQTTSNGWDefines.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#ifndef MQTTSNGWDEFINES_H_
|
||||
#define MQTTSNGWDEFINES_H_
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
|
||||
/*=================================
|
||||
* Starting prompt
|
||||
==================================*/
|
||||
#define GATEWAY_VERSION "(Ver 0.1.1)"
|
||||
|
||||
/*=================================
|
||||
* Log controls
|
||||
==================================*/
|
||||
//#define DEBUG // print out log for debug
|
||||
//#define RINGBUFFER // print out Packets log into shared memory
|
||||
|
||||
/*=================================
|
||||
* Parametrs
|
||||
==================================*/
|
||||
#define MQTTSNGW_MAX_PACKET_SIZE (1024) // Max Packet size
|
||||
#define SIZEOF_LOG_PACKET (128) // Length of the packet log in bytes
|
||||
|
||||
#define MQTTSNGW_CONFIG_FILE "/usr/local/etc/mqttsnGateway/config/param.conf"
|
||||
#define MQTTSNGW_CLIENT_LIST "/usr/local/etc/mqttsnGateway/config/clientList.conf"
|
||||
#define MQTTSNGW_TLS_CA_DIR "/etc/ssl/certs"
|
||||
|
||||
/*=================================
|
||||
* Data Type
|
||||
==================================*/
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
|
||||
/*=================================
|
||||
* Macros
|
||||
==================================*/
|
||||
#ifdef DEBUG
|
||||
#define DEBUGLOG(...) printf(__VA_ARGS__)
|
||||
#undef RINGBUFFER
|
||||
#else
|
||||
#define DEBUGLOG(...)
|
||||
#endif
|
||||
|
||||
}
|
||||
#endif /* MQTTSNGWDEFINES_H_ */
|
||||
50
MQTTSNGateway/src/MQTTSNGWLogmonitor.cpp
Normal file
50
MQTTSNGateway/src/MQTTSNGWLogmonitor.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
#define RINGBUFFER
|
||||
|
||||
#include "MQTTSNGWProcess.h"
|
||||
#include "MQTTSNGWLogmonitor.h"
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
Logmonitor::Logmonitor()
|
||||
{
|
||||
theProcess = this;
|
||||
}
|
||||
|
||||
Logmonitor::~Logmonitor()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Logmonitor::run()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
const char* data = getLog();
|
||||
if ( *data == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s", data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
33
MQTTSNGateway/src/MQTTSNGWLogmonitor.h
Normal file
33
MQTTSNGateway/src/MQTTSNGWLogmonitor.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
#ifndef MQTTSNGWLOGMONITOR_H_
|
||||
#define MQTTSNGWLOGMONITOR_H_
|
||||
|
||||
#include "MQTTSNGWProcess.h"
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
class Logmonitor: public Process
|
||||
{
|
||||
public:
|
||||
Logmonitor();
|
||||
~Logmonitor();
|
||||
void run();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* MQTTSNGWLOGMONITOR_H_ */
|
||||
410
MQTTSNGateway/src/MQTTSNGWPacket.cpp
Normal file
410
MQTTSNGateway/src/MQTTSNGWPacket.cpp
Normal file
@@ -0,0 +1,410 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include "MQTTSNGateway.h"
|
||||
#include "MQTTSNGWPacket.h"
|
||||
#include "MQTTSNPacket.h"
|
||||
#include "SensorNetwork.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
MQTTSNPacket::MQTTSNPacket()
|
||||
{
|
||||
_buf = 0;
|
||||
_bufLen = 0;
|
||||
}
|
||||
MQTTSNPacket::~MQTTSNPacket()
|
||||
{
|
||||
if (_buf)
|
||||
{
|
||||
free(_buf);
|
||||
}
|
||||
}
|
||||
|
||||
int MQTTSNPacket::unicast(SensorNetwork* network, SensorNetAddress* sendTo)
|
||||
{
|
||||
return network->unicast(_buf, _bufLen, sendTo);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::broadcast(SensorNetwork* network)
|
||||
{
|
||||
return network->broadcast(_buf, _bufLen);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::serialize(uint8_t* buf)
|
||||
{
|
||||
buf = _buf;
|
||||
return _bufLen;
|
||||
}
|
||||
|
||||
int MQTTSNPacket::desirialize(unsigned char* buf, unsigned short len)
|
||||
{
|
||||
if ( _buf )
|
||||
{
|
||||
free(_buf);
|
||||
}
|
||||
|
||||
_buf = (unsigned char*)calloc(len, sizeof(unsigned char));
|
||||
if ( _buf )
|
||||
{
|
||||
memcpy(_buf, buf, len);
|
||||
_bufLen = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
_bufLen = 0;
|
||||
}
|
||||
return _bufLen;
|
||||
}
|
||||
|
||||
int MQTTSNPacket::recv(SensorNetwork* network)
|
||||
{
|
||||
uint8_t buf[MQTTSNGW_MAX_PACKET_SIZE];
|
||||
int len = network->read((uint8_t*) buf, MQTTSNGW_MAX_PACKET_SIZE);
|
||||
if (len >= 3)
|
||||
{
|
||||
len = desirialize(buf, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
len = 0;
|
||||
}
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
int MQTTSNPacket::getType(void)
|
||||
{
|
||||
if ( _bufLen == 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int value = 0;
|
||||
int p = MQTTSNPacket_decode(_buf, _bufLen, &value);
|
||||
return _buf[p];
|
||||
}
|
||||
|
||||
unsigned char* MQTTSNPacket::getPacketData(void)
|
||||
{
|
||||
return _buf;
|
||||
}
|
||||
|
||||
int MQTTSNPacket::getPacketLength(void)
|
||||
{
|
||||
return _bufLen;
|
||||
}
|
||||
|
||||
const char* MQTTSNPacket::getName()
|
||||
{
|
||||
return MQTTSNPacket_name(getType());
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setADVERTISE(uint8_t gatewayid, uint16_t duration)
|
||||
{
|
||||
unsigned char buf[5];
|
||||
int len = MQTTSNSerialize_advertise(buf, 5, (unsigned char) gatewayid,
|
||||
(unsigned short) duration);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setGWINFO(uint8_t gatewayId)
|
||||
{
|
||||
unsigned char buf[3];
|
||||
int len = MQTTSNSerialize_gwinfo(buf, 3, (unsigned char) gatewayId, 0, 0);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setConnect(void)
|
||||
{
|
||||
unsigned char buf[40];
|
||||
MQTTSNPacket_connectData data;
|
||||
data.clientID.cstring = (char*)"client01";
|
||||
int len = MQTTSNSerialize_connect(buf, 40, &data);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setCONNACK(uint8_t returnCode)
|
||||
{
|
||||
unsigned char buf[3];
|
||||
int len = MQTTSNSerialize_connack(buf, 3, (int) returnCode);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setWILLTOPICREQ(void)
|
||||
{
|
||||
unsigned char buf[2];
|
||||
int len = MQTTSNSerialize_willtopicreq(buf, 2);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setWILLMSGREQ(void)
|
||||
{
|
||||
unsigned char buf[2];
|
||||
int len = MQTTSNSerialize_willmsgreq(buf, 2);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setREGISTER(uint16_t topicId, uint16_t msgId, MQTTSNString* topicName)
|
||||
{
|
||||
unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE];
|
||||
int len = MQTTSNSerialize_register(buf, MQTTSNGW_MAX_PACKET_SIZE, (unsigned short) topicId, (unsigned short) msgId,
|
||||
topicName);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setREGACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode)
|
||||
{
|
||||
unsigned char buf[7];
|
||||
int len = MQTTSNSerialize_regack(buf, 7, (unsigned short) topicId, (unsigned short) msgId,
|
||||
(unsigned char) returnCode);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setPUBLISH(uint8_t dup, int qos, uint8_t retained, uint16_t msgId, MQTTSN_topicid topic,
|
||||
uint8_t* payload, uint16_t payloadlen)
|
||||
{
|
||||
unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE];
|
||||
int len = MQTTSNSerialize_publish(buf, MQTTSNGW_MAX_PACKET_SIZE, (unsigned char) dup, qos, (unsigned char) retained,
|
||||
(unsigned short) msgId, topic, (unsigned char*) payload, (int) payloadlen);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setPUBACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode)
|
||||
{
|
||||
unsigned char buf[7];
|
||||
int len = MQTTSNSerialize_puback(buf, 7, (unsigned short) topicId, (unsigned short) msgId,
|
||||
(unsigned char) returnCode);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setPUBREC(uint16_t msgId)
|
||||
{
|
||||
unsigned char buf[4];
|
||||
int len = MQTTSNSerialize_pubrec(buf, 4, (unsigned short) msgId);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setPUBREL(uint16_t msgId)
|
||||
{
|
||||
unsigned char buf[4];
|
||||
int len = MQTTSNSerialize_pubrel(buf, 4, (unsigned short) msgId);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setPUBCOMP(uint16_t msgId)
|
||||
{
|
||||
unsigned char buf[4];
|
||||
int len = MQTTSNSerialize_pubcomp(buf, 4, (unsigned short) msgId);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setSUBACK(int qos, uint16_t topicId, uint16_t msgId, uint8_t returnCode)
|
||||
{
|
||||
unsigned char buf[8];
|
||||
int len = MQTTSNSerialize_suback(buf, 8, qos, (unsigned short) topicId,
|
||||
(unsigned short) msgId, (unsigned char) returnCode);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setUNSUBACK(uint16_t msgId)
|
||||
{
|
||||
unsigned char buf[4];
|
||||
int len = MQTTSNSerialize_unsuback(buf, 4, (unsigned short) msgId);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setPINGRESP(void)
|
||||
{
|
||||
unsigned char buf[32];
|
||||
int len = MQTTSNSerialize_pingresp(buf, 32);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setDISCONNECT(uint16_t duration)
|
||||
{
|
||||
unsigned char buf[4];
|
||||
int len = MQTTSNSerialize_disconnect(buf, 4, (int) duration);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setWILLTOPICRESP(uint8_t returnCode)
|
||||
{
|
||||
unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE];
|
||||
int len = MQTTSNSerialize_willtopicresp(buf, MQTTSNGW_MAX_PACKET_SIZE, (int) returnCode);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::setWILLMSGRESP(uint8_t returnCode)
|
||||
{
|
||||
unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE];
|
||||
int len = MQTTSNSerialize_willmsgresp(buf, MQTTSNGW_MAX_PACKET_SIZE, (int) returnCode);
|
||||
return desirialize(buf, len);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::getSERCHGW(uint8_t* radius)
|
||||
{
|
||||
return MQTTSNDeserialize_searchgw((unsigned char*) radius, (unsigned char*) _buf, _bufLen);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::getCONNECT(MQTTSNPacket_connectData* data)
|
||||
{
|
||||
return MQTTSNDeserialize_connect(data, _buf, _bufLen);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::getCONNACK(uint8_t* returnCode)
|
||||
{
|
||||
return MQTTSNSerialize_connack(_buf, _bufLen, (int) *returnCode);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::getWILLTOPIC(int* willQoS, uint8_t* willRetain, MQTTSNString* willTopic)
|
||||
{
|
||||
return MQTTSNDeserialize_willtopic((int*) willQoS, (unsigned char*) willRetain, willTopic, _buf, _bufLen);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::getWILLMSG(MQTTSNString* willmsg)
|
||||
{
|
||||
return MQTTSNDeserialize_willmsg(willmsg, _buf, _bufLen);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::getREGISTER(uint16_t* topicId, uint16_t* msgId, MQTTSNString* topicName)
|
||||
{
|
||||
return MQTTSNDeserialize_register((unsigned short*) topicId, (unsigned short*) msgId, topicName,
|
||||
_buf, _bufLen);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::getREGACK(uint16_t* topicId, uint16_t* msgId, uint8_t* returnCode)
|
||||
{
|
||||
return MQTTSNDeserialize_regack((unsigned short*) topicId, (unsigned short*) msgId, (unsigned char*) returnCode, _buf, _bufLen);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::getPUBLISH(uint8_t* dup, int* qos, uint8_t* retained, uint16_t* msgId, MQTTSN_topicid* topic,
|
||||
uint8_t** payload, int* payloadlen)
|
||||
{
|
||||
return MQTTSNDeserialize_publish((unsigned char*) dup, qos, (unsigned char*) retained, (unsigned short*) msgId,
|
||||
topic, (unsigned char**) payload, (int*) payloadlen, _buf, _bufLen);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::getPUBACK(uint16_t* topicId, uint16_t* msgId, uint8_t* returnCode)
|
||||
{
|
||||
return MQTTSNDeserialize_puback((unsigned short*) topicId, (unsigned short*) msgId, (unsigned char*) returnCode,
|
||||
_buf, _bufLen);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::getACK(uint16_t* msgId)
|
||||
{
|
||||
unsigned char type;
|
||||
return MQTTSNDeserialize_ack(&type, (unsigned short*) msgId, _buf, _bufLen);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::getSUBSCRIBE(uint8_t* dup, int* qos, uint16_t* msgId, MQTTSN_topicid* topicFilter)
|
||||
{
|
||||
return MQTTSNDeserialize_subscribe((unsigned char*) dup, qos, (unsigned short*) msgId, topicFilter, _buf, _bufLen);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::getUNSUBSCRIBE(uint16_t* msgId, MQTTSN_topicid* topicFilter)
|
||||
{
|
||||
return MQTTSNDeserialize_unsubscribe((unsigned short*) msgId, topicFilter, _buf, _bufLen);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::getPINGREQ(void)
|
||||
{
|
||||
if (getType() == MQTTSN_PINGRESP && _bufLen > 2 )
|
||||
{
|
||||
return _bufLen - 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MQTTSNPacket::getDISCONNECT(uint16_t* duration)
|
||||
{
|
||||
return MQTTSNDeserialize_disconnect((int*) duration, _buf, _bufLen);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::getWILLTOPICUPD(uint8_t* willQoS, uint8_t* willRetain, MQTTSNString* willTopic)
|
||||
{
|
||||
return MQTTSNDeserialize_willtopicupd((int*) willQoS, (unsigned char*) willRetain, willTopic, _buf, _bufLen);
|
||||
}
|
||||
|
||||
int MQTTSNPacket::getWILLMSGUPD(MQTTSNString* willMsg)
|
||||
{
|
||||
return MQTTSNDeserialize_willmsgupd(willMsg, _buf, _bufLen);
|
||||
}
|
||||
|
||||
char* MQTTSNPacket::print(char* pbuf)
|
||||
{
|
||||
char* ptr = pbuf;
|
||||
char** pptr = &pbuf;
|
||||
int value = 0;
|
||||
|
||||
int i = MQTTSNPacket_decode(_buf, _bufLen, &value);
|
||||
int size = _bufLen > SIZEOF_LOG_PACKET ? SIZEOF_LOG_PACKET : _bufLen;
|
||||
|
||||
for (; i < size; i++)
|
||||
{
|
||||
sprintf(*pptr, " %02X", *(_buf + i));
|
||||
*pptr += 3;
|
||||
}
|
||||
**pptr = 0;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char* MQTTSNPacket::getMsgId(char* pbuf)
|
||||
{
|
||||
int value = 0;
|
||||
int p = 0;
|
||||
|
||||
switch ( getType() )
|
||||
{
|
||||
case MQTTSN_PUBLISH:
|
||||
p = MQTTSNPacket_decode(_buf, _bufLen, &value);
|
||||
if ( _buf[p + 1] & 0x80 )
|
||||
{
|
||||
sprintf(pbuf, "+%02X%02X", _buf[p + 4], _buf[p + 5]);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(pbuf, " %02X%02X", _buf[p + 4], _buf[p + 5]);
|
||||
}
|
||||
break;
|
||||
case MQTTSN_PUBACK:
|
||||
case MQTTSN_REGISTER:
|
||||
case MQTTSN_REGACK:
|
||||
sprintf(pbuf, " %02X%02X", _buf[4], _buf[5]);
|
||||
break;
|
||||
case MQTTSN_PUBREC:
|
||||
case MQTTSN_PUBREL:
|
||||
case MQTTSN_PUBCOMP:
|
||||
sprintf(pbuf, " %02X%02X", _buf[2], _buf[3]);
|
||||
break;
|
||||
case MQTTSN_SUBSCRIBE:
|
||||
case MQTTSN_UNSUBSCRIBE:
|
||||
p = MQTTSNPacket_decode(_buf, _bufLen, &value);
|
||||
sprintf(pbuf, " %02X%02X", _buf[p + 2], _buf[p + 3]);
|
||||
break;
|
||||
case MQTTSN_SUBACK:
|
||||
case MQTTSN_UNSUBACK:
|
||||
sprintf(pbuf, " %02X%02X", _buf[5], _buf[6]);
|
||||
break;
|
||||
default:
|
||||
sprintf(pbuf, " ");
|
||||
break;
|
||||
}
|
||||
return pbuf;
|
||||
}
|
||||
88
MQTTSNGateway/src/MQTTSNGWPacket.h
Normal file
88
MQTTSNGateway/src/MQTTSNGWPacket.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
#ifndef MQTTSNGWPACKET_H_
|
||||
#define MQTTSNGWPACKET_H_
|
||||
|
||||
#include "MQTTSNGWDefines.h"
|
||||
#include "MQTTSNPacket.h"
|
||||
#include "SensorNetwork.h"
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
|
||||
class MQTTSNPacket
|
||||
{
|
||||
public:
|
||||
MQTTSNPacket();
|
||||
~MQTTSNPacket();
|
||||
int unicast(SensorNetwork* network, SensorNetAddress* sendTo);
|
||||
int broadcast(SensorNetwork* network);
|
||||
int recv(SensorNetwork* network);
|
||||
int serialize(uint8_t* buf);
|
||||
int desirialize(unsigned char* buf, unsigned short len);
|
||||
int getType(void);
|
||||
unsigned char* getPacketData(void);
|
||||
int getPacketLength(void);
|
||||
const char* getName();
|
||||
|
||||
int setConnect(void); // Debug
|
||||
int setADVERTISE(uint8_t gatewayid, uint16_t duration);
|
||||
int setGWINFO(uint8_t gatewayId);
|
||||
int setCONNACK(uint8_t returnCode);
|
||||
int setWILLTOPICREQ(void);
|
||||
int setWILLMSGREQ(void);
|
||||
int setREGISTER(uint16_t topicId, uint16_t msgId, MQTTSNString* TopicName);
|
||||
int setREGACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode);
|
||||
int setPUBLISH(uint8_t dup, int qos, uint8_t retained, uint16_t msgId,
|
||||
MQTTSN_topicid topic, uint8_t* payload, uint16_t payloadlen);
|
||||
int setPUBACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode);
|
||||
int setPUBREC(uint16_t msgId);
|
||||
int setPUBREL(uint16_t msgId);
|
||||
int setPUBCOMP(uint16_t msgId);
|
||||
int setSUBACK(int qos, uint16_t topicId, uint16_t msgId, uint8_t returnCode);
|
||||
int setUNSUBACK(uint16_t msgId);
|
||||
int setPINGRESP(void);
|
||||
int setDISCONNECT(uint16_t duration);
|
||||
int setWILLTOPICRESP(uint8_t returnCode);
|
||||
int setWILLMSGRESP(uint8_t returnCode);
|
||||
|
||||
int getSERCHGW(uint8_t* radius);
|
||||
int getCONNECT(MQTTSNPacket_connectData* option);
|
||||
int getCONNACK(uint8_t* returnCode);
|
||||
int getWILLTOPIC(int* willQoS, uint8_t* willRetain, MQTTSNString* willTopic);
|
||||
int getWILLMSG(MQTTSNString* willmsg);
|
||||
int getREGISTER(uint16_t* topicId, uint16_t* msgId, MQTTSNString* topicName);
|
||||
int getREGACK(uint16_t* topicId, uint16_t* msgId, uint8_t* returnCode);
|
||||
int getPUBLISH(uint8_t* dup, int* qos, uint8_t* retained, uint16_t* msgId,
|
||||
MQTTSN_topicid* topic, unsigned char** payload, int* payloadlen);
|
||||
int getPUBACK(uint16_t* topicId, uint16_t* msgId, uint8_t* returnCode);
|
||||
int getACK(uint16_t* msgId);
|
||||
int getSUBSCRIBE(uint8_t* dup, int* qos, uint16_t* msgId, MQTTSN_topicid* topicFilter);
|
||||
int getUNSUBSCRIBE(uint16_t* msgId, MQTTSN_topicid* topicFilter);
|
||||
int getPINGREQ(void);
|
||||
int getDISCONNECT(uint16_t* duration);
|
||||
int getWILLTOPICUPD(uint8_t* willQoS, uint8_t* willRetain, MQTTSNString* willTopic);
|
||||
int getWILLMSGUPD(MQTTSNString* willMsg);
|
||||
char* getMsgId(char* buf);
|
||||
char* print(char* buf);
|
||||
|
||||
private:
|
||||
unsigned char* _buf; // Ptr to a packet data
|
||||
int _bufLen; // length of the packet data
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* MQTTSNGWPACKET_H_ */
|
||||
236
MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp
Normal file
236
MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include "MQTTSNGWDefines.h"
|
||||
#include "MQTTSNGWPacketHandleTask.h"
|
||||
#include "MQTTSNGWProcess.h"
|
||||
#include "MQTTGWPacket.h"
|
||||
#include "MQTTSNGWClient.h"
|
||||
#include "MQTTSNGWProcess.h"
|
||||
#include "MQTTGWConnectionHandler.h"
|
||||
#include "MQTTGWPublishHandler.h"
|
||||
#include "MQTTGWSubscribeHandler.h"
|
||||
#include "MQTTSNGWConnectionHandler.h"
|
||||
#include "MQTTSNGWPublishHandler.h"
|
||||
#include "MQTTSNGWSubscribeHandler.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
#define EVENT_QUE_TIME_OUT 2000 // 2000 msecs
|
||||
|
||||
/*=====================================
|
||||
Class PacketHandleTask
|
||||
=====================================*/
|
||||
|
||||
PacketHandleTask::PacketHandleTask(Gateway* gateway)
|
||||
{
|
||||
_gateway = gateway;
|
||||
_gateway->attach((Thread*)this);
|
||||
_mqttConnection = new MQTTGWConnectionHandler(_gateway);
|
||||
_mqttPublish = new MQTTGWPublishHandler(_gateway);
|
||||
_mqttSubscribe = new MQTTGWSubscribeHandler(_gateway);
|
||||
_mqttsnConnection = new MQTTSNConnectionHandler(_gateway);
|
||||
_mqttsnPublish = new MQTTSNPublishHandler(_gateway);
|
||||
_mqttsnSubscribe = new MQTTSNSubscribeHandler(_gateway);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor is called by Gateway's destructor indirectly.
|
||||
*/
|
||||
PacketHandleTask::~PacketHandleTask()
|
||||
{
|
||||
if ( _mqttConnection )
|
||||
{
|
||||
delete _mqttConnection;
|
||||
}
|
||||
if ( _mqttPublish )
|
||||
{
|
||||
delete _mqttPublish;
|
||||
}
|
||||
if ( _mqttSubscribe )
|
||||
{
|
||||
delete _mqttSubscribe;
|
||||
}
|
||||
if ( _mqttsnConnection )
|
||||
{
|
||||
delete _mqttsnConnection;
|
||||
}
|
||||
if ( _mqttsnPublish )
|
||||
{
|
||||
delete _mqttsnPublish;
|
||||
}
|
||||
if ( _mqttsnSubscribe )
|
||||
{
|
||||
delete _mqttsnSubscribe;
|
||||
}
|
||||
}
|
||||
|
||||
void PacketHandleTask::run()
|
||||
{
|
||||
Event* ev = 0;
|
||||
EventQue* eventQue = _gateway->getPacketEventQue();
|
||||
ClientList* clist = _gateway->getClientList();
|
||||
Client* client = 0;
|
||||
MQTTSNPacket* snPacket = 0;
|
||||
MQTTGWPacket* brPacket = 0;
|
||||
char msgId[6];
|
||||
memset(msgId, 0, 6);
|
||||
|
||||
_advertiseTimer.start(_gateway->getGWParams()->keepAlive * 1000UL);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (theProcess->checkSignal() == SIGINT)
|
||||
{
|
||||
throw Exception("Terminated by CTL-C");
|
||||
}
|
||||
|
||||
/* wait Event */
|
||||
ev = eventQue->timedwait(EVENT_QUE_TIME_OUT);
|
||||
|
||||
if (ev->getEventType() == EtTimeout)
|
||||
{
|
||||
/*------ Is Client Lost ? ---------*/
|
||||
client = clist->getClient();
|
||||
while (client > 0)
|
||||
{
|
||||
client->checkTimeover();
|
||||
client = client->getNextClient();
|
||||
}
|
||||
/*------ Check Keep Alive Timer & send Advertise ------*/
|
||||
if (_advertiseTimer.isTimeup())
|
||||
{
|
||||
_mqttsnConnection->sendADVERTISE();
|
||||
_advertiseTimer.start(_gateway->getGWParams()->keepAlive * 1000UL);
|
||||
}
|
||||
}
|
||||
|
||||
/*------ Handle SEARCHGW Message ---------*/
|
||||
else if (ev->getEventType() == EtBroadcast)
|
||||
{
|
||||
snPacket = ev->getMQTTSNPacket();
|
||||
_mqttsnConnection->handleSearchgw(snPacket);
|
||||
}
|
||||
|
||||
/*------ Handle Messages form Clients ---------*/
|
||||
else if (ev->getEventType() == EtClientRecv)
|
||||
{
|
||||
client = ev->getClient();
|
||||
snPacket = ev->getMQTTSNPacket();
|
||||
|
||||
DEBUGLOG(" PacketHandleTask gets %s %s from the client.\n", snPacket->getName(), snPacket->getMsgId(msgId));
|
||||
|
||||
switch (snPacket->getType())
|
||||
{
|
||||
case MQTTSN_CONNECT:
|
||||
_mqttsnConnection->handleConnect(client, snPacket);
|
||||
break;
|
||||
case MQTTSN_WILLTOPIC:
|
||||
_mqttsnConnection->handleWilltopic(client, snPacket);
|
||||
break;
|
||||
case MQTTSN_WILLMSG:
|
||||
_mqttsnConnection->handleWillmsg(client, snPacket);
|
||||
break;
|
||||
case MQTTSN_DISCONNECT:
|
||||
_mqttsnConnection->handleDisconnect(client, snPacket);
|
||||
break;
|
||||
case MQTTSN_WILLMSGUPD:
|
||||
_mqttsnConnection->handleWillmsgupd(client, snPacket);
|
||||
break;
|
||||
case MQTTSN_PINGREQ:
|
||||
_mqttsnConnection->handlePingreq(client, snPacket);
|
||||
break;
|
||||
case MQTTSN_PUBLISH:
|
||||
_mqttsnPublish->handlePublish(client, snPacket);
|
||||
break;
|
||||
case MQTTSN_PUBACK:
|
||||
_mqttsnPublish->handlePuback(client, snPacket);
|
||||
break;
|
||||
_mqttsnPublish->handleAck(client, snPacket, PUBREC);
|
||||
break;
|
||||
case MQTTSN_PUBREL:
|
||||
_mqttsnPublish->handleAck(client, snPacket, PUBREL);
|
||||
break;
|
||||
case MQTTSN_PUBCOMP:
|
||||
_mqttsnPublish->handleAck(client, snPacket, PUBCOMP);
|
||||
break;
|
||||
case MQTTSN_REGISTER:
|
||||
_mqttsnPublish->handleRegister(client, snPacket);
|
||||
break;
|
||||
case MQTTSN_REGACK:
|
||||
// NOP
|
||||
break;
|
||||
case MQTTSN_SUBSCRIBE:
|
||||
_mqttsnSubscribe->handleSubscribe(client, snPacket);
|
||||
break;
|
||||
case MQTTSN_UNSUBSCRIBE:
|
||||
_mqttsnSubscribe->handleUnsubscribe(client, snPacket);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Reset the Timer for PINGREQ. */
|
||||
client->updateStatus(snPacket);
|
||||
}
|
||||
|
||||
/*------ Handle Messages form Broker ---------*/
|
||||
else if (ev->getEventType() == EtBrokerRecv)
|
||||
{
|
||||
client = ev->getClient();
|
||||
brPacket = ev->getMQTTGWPacket();
|
||||
DEBUGLOG(" PacketHandleTask gets %s %s from the broker.\n", brPacket->getName(), brPacket->getMsgId(msgId));
|
||||
switch (brPacket->getType())
|
||||
{
|
||||
case CONNACK:
|
||||
_mqttConnection->handleConnack(client, brPacket);
|
||||
break;
|
||||
case DISCONNECT:
|
||||
_mqttConnection->handleDisconnect(client, brPacket);
|
||||
break;
|
||||
case PINGRESP:
|
||||
_mqttConnection->handlePingresp(client, brPacket);
|
||||
break;
|
||||
case PUBLISH:
|
||||
_mqttPublish->handlePublish(client, brPacket);
|
||||
break;
|
||||
case PUBACK:
|
||||
_mqttPublish->handlePuback(client, brPacket);
|
||||
break;
|
||||
case PUBREC:
|
||||
_mqttPublish->handleAck(client, brPacket, PUBREC);
|
||||
break;
|
||||
case PUBREL:
|
||||
_mqttPublish->handleAck(client, brPacket, PUBREL);
|
||||
break;
|
||||
case PUBCOMP:
|
||||
_mqttPublish->handleAck(client, brPacket, PUBCOMP);
|
||||
break;
|
||||
case SUBACK:
|
||||
_mqttSubscribe->handleSuback(client, brPacket);
|
||||
break;
|
||||
case UNSUBACK:
|
||||
_mqttSubscribe->handleUnsuback(client, brPacket);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete ev;
|
||||
}
|
||||
}
|
||||
|
||||
65
MQTTSNGateway/src/MQTTSNGWPacketHandleTask.h
Normal file
65
MQTTSNGateway/src/MQTTSNGWPacketHandleTask.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#ifndef MQTTSNGWPACKETHANDLETASK_H_
|
||||
#define MQTTSNGWPACKETHANDLETASK_H_
|
||||
|
||||
#include <Timer.h>
|
||||
#include "MQTTSNGWDefines.h"
|
||||
#include "MQTTSNGateway.h"
|
||||
#include "MQTTSNGWClient.h"
|
||||
#include "MQTTSNGWPacket.h"
|
||||
#include "MQTTGWPacket.h"
|
||||
#include "MQTTGWConnectionHandler.h"
|
||||
#include "MQTTGWPublishHandler.h"
|
||||
#include "MQTTGWSubscribeHandler.h"
|
||||
#include "MQTTSNGWConnectionHandler.h"
|
||||
#include "MQTTSNGWPublishHandler.h"
|
||||
#include "MQTTSNGWSubscribeHandler.h"
|
||||
#include "SensorNetwork.h"
|
||||
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
|
||||
#define ERRNO_APL_01 11 // Task Initialize Error
|
||||
|
||||
/*=====================================
|
||||
Class PacketHandleTask
|
||||
=====================================*/
|
||||
class PacketHandleTask : public Thread
|
||||
{
|
||||
MAGIC_WORD_FOR_THREAD;
|
||||
public:
|
||||
PacketHandleTask(Gateway* gateway);
|
||||
~PacketHandleTask();
|
||||
void run();
|
||||
private:
|
||||
Gateway* _gateway;
|
||||
Timer _advertiseTimer;
|
||||
Timer _sendUnixTimer;
|
||||
MQTTGWConnectionHandler* _mqttConnection;
|
||||
MQTTGWPublishHandler* _mqttPublish;
|
||||
MQTTGWSubscribeHandler* _mqttSubscribe;
|
||||
MQTTSNConnectionHandler* _mqttsnConnection;
|
||||
MQTTSNPublishHandler* _mqttsnPublish;
|
||||
MQTTSNSubscribeHandler* _mqttsnSubscribe;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif /* MQTTSNGWPACKETHANDLETASK_H_ */
|
||||
333
MQTTSNGateway/src/MQTTSNGWProcess.cpp
Normal file
333
MQTTSNGateway/src/MQTTSNGWProcess.cpp
Normal file
@@ -0,0 +1,333 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
#include <Timer.h>
|
||||
#include <exception>
|
||||
#include "MQTTSNGWProcess.h"
|
||||
#include "Threading.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
char* currentDateTime(void);
|
||||
|
||||
/*=====================================
|
||||
Global Variables & Functions
|
||||
======================================*/
|
||||
Process* MQTTSNGW::theProcess = 0;
|
||||
MultiTaskProcess* MQTTSNGW::theMultiTaskProcess = 0;
|
||||
|
||||
/*
|
||||
* Save the type of signal
|
||||
*/
|
||||
volatile int theSignaled = 0;
|
||||
|
||||
static void signalHandler(int sig)
|
||||
{
|
||||
theSignaled = sig;
|
||||
}
|
||||
|
||||
/*=====================================
|
||||
Class Process
|
||||
====================================*/
|
||||
Process::Process()
|
||||
{
|
||||
_argc = 0;
|
||||
_argv = 0;
|
||||
_rbsem = new Semaphore(MQTTSNGW_RB_SEMAPHOR_NAME, 0);
|
||||
_rb = new RingBuffer();
|
||||
}
|
||||
|
||||
Process::~Process()
|
||||
{
|
||||
delete _rb;
|
||||
delete _rbsem;
|
||||
}
|
||||
|
||||
void Process::run()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Process::initialize(int argc, char** argv)
|
||||
{
|
||||
_argc = argc;
|
||||
_argv = argv;
|
||||
signal(SIGINT, signalHandler);
|
||||
signal(SIGTERM, signalHandler);
|
||||
signal(SIGHUP, signalHandler);
|
||||
}
|
||||
|
||||
int Process::getArgc()
|
||||
{
|
||||
return _argc;
|
||||
}
|
||||
|
||||
char** Process::getArgv()
|
||||
{
|
||||
return _argv;
|
||||
}
|
||||
|
||||
int Process::getParam(const char* parameter, char* value)
|
||||
{
|
||||
char str[MQTTSNGW_PARAM_MAX];
|
||||
char param[MQTTSNGW_PARAM_MAX];
|
||||
FILE *fp;
|
||||
int i = 0, j = 0;
|
||||
|
||||
if ((fp = fopen(MQTTSNGW_CONFIG_FILE, "r")) == NULL)
|
||||
{
|
||||
WRITELOG("No config file:[%s]\n", MQTTSNGW_CONFIG_FILE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (fgets(str, MQTTSNGW_PARAM_MAX - 1, fp) == NULL)
|
||||
{
|
||||
fclose(fp);
|
||||
return -3;
|
||||
}
|
||||
if (!strncmp(str, parameter, strlen(parameter)))
|
||||
{
|
||||
while (str[i++] != '=')
|
||||
{
|
||||
;
|
||||
}
|
||||
while (str[i] != '\n')
|
||||
{
|
||||
param[j++] = str[i++];
|
||||
}
|
||||
param[j] = '\0';
|
||||
|
||||
for (i = strlen(param) - 1; i >= 0 && isspace(param[i]); i--)
|
||||
;
|
||||
param[i + 1] = '\0';
|
||||
for (i = 0; isspace(param[i]); i++)
|
||||
;
|
||||
if (i > 0)
|
||||
{
|
||||
j = 0;
|
||||
while (param[i])
|
||||
param[j++] = param[i++];
|
||||
param[j] = '\0';
|
||||
}
|
||||
strcpy(value, param);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
return -2;
|
||||
}
|
||||
|
||||
void Process::putLog(const char* format, ...)
|
||||
{
|
||||
_mt.lock();
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
vsprintf(_rbdata, format, arg);
|
||||
va_end(arg);
|
||||
if (strlen(_rbdata))
|
||||
{
|
||||
_rb->put(_rbdata);
|
||||
_rbsem->post();
|
||||
}
|
||||
_mt.unlock();
|
||||
}
|
||||
|
||||
const char* Process::getLog()
|
||||
{
|
||||
int len = 0;
|
||||
_mt.lock();
|
||||
while ((len = _rb->get(_rbdata, PROCESS_LOG_BUFFER_SIZE)) == 0)
|
||||
{
|
||||
_rbsem->timedwait(1000);
|
||||
if ( checkSignal() == SIGINT)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
*(_rbdata + len) = 0;
|
||||
_mt.unlock();
|
||||
return _rbdata;
|
||||
}
|
||||
|
||||
void Process::resetRingBuffer()
|
||||
{
|
||||
_rb->reset();
|
||||
}
|
||||
|
||||
int Process::checkSignal(void)
|
||||
{
|
||||
return theSignaled;
|
||||
}
|
||||
|
||||
/*=====================================
|
||||
Class MultiTaskProcess
|
||||
====================================*/
|
||||
MultiTaskProcess::MultiTaskProcess()
|
||||
{
|
||||
theMultiTaskProcess = this;
|
||||
_threadCount = 0;
|
||||
}
|
||||
|
||||
MultiTaskProcess::~MultiTaskProcess()
|
||||
{
|
||||
for (int i = 0; i < _threadCount; i++)
|
||||
{
|
||||
if ( _threadList[i] )
|
||||
{
|
||||
delete _threadList[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MultiTaskProcess::initialize(int argc, char** argv)
|
||||
{
|
||||
Process::initialize(argc, argv);
|
||||
for (int i = 0; i < _threadCount; i++)
|
||||
{
|
||||
_threadList[i]->initialize(argc, argv);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MultiTaskProcess::run(void)
|
||||
{
|
||||
for (int i = 0; i < _threadCount; i++)
|
||||
{
|
||||
_threadList[i]->start();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_stopProcessEvent.wait();
|
||||
}
|
||||
catch (Exception* ex)
|
||||
{
|
||||
ex->writeMessage();
|
||||
}
|
||||
}
|
||||
|
||||
Semaphore* MultiTaskProcess::getStopProcessEvent(void)
|
||||
{
|
||||
return &_stopProcessEvent;
|
||||
}
|
||||
|
||||
void MultiTaskProcess::attach(Thread* thread)
|
||||
{
|
||||
if (_threadCount < MQTTSNGW_MAX_TASK)
|
||||
{
|
||||
_threadList[_threadCount] = thread;
|
||||
_threadCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Exception("Full of Threads");
|
||||
}
|
||||
}
|
||||
|
||||
int MultiTaskProcess::getParam(const char* parameter, char* value)
|
||||
{
|
||||
_mutex.lock();
|
||||
int rc = Process::getParam(parameter, value);
|
||||
_mutex.unlock();
|
||||
if (rc == -1)
|
||||
{
|
||||
throw Exception("No config file.");
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*=====================================
|
||||
Class Exception
|
||||
======================================*/
|
||||
Exception::Exception(const string& message)
|
||||
{
|
||||
_message = message;
|
||||
_exNo = 0;
|
||||
_fileName = 0;
|
||||
_functionName = 0;
|
||||
_line = 0;
|
||||
}
|
||||
|
||||
Exception::Exception(const int exNo, const string& message)
|
||||
{
|
||||
_message = message;
|
||||
_exNo = exNo;
|
||||
_fileName = 0;
|
||||
_functionName = 0;
|
||||
_line = 0;
|
||||
}
|
||||
|
||||
Exception::Exception(const int exNo, const string& message, const char* file,
|
||||
const char* function, const int line)
|
||||
{
|
||||
_message = message;
|
||||
_exNo = exNo;
|
||||
_fileName = file;
|
||||
_functionName = function;
|
||||
_line = line;
|
||||
}
|
||||
|
||||
Exception::~Exception() throw ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
const char* Exception::what() const throw ()
|
||||
{
|
||||
return _message.c_str();
|
||||
}
|
||||
|
||||
const char* Exception::getFileName()
|
||||
{
|
||||
return _fileName;
|
||||
}
|
||||
|
||||
const char* Exception::getFunctionName()
|
||||
{
|
||||
return _functionName;
|
||||
}
|
||||
|
||||
const int Exception::getLineNo()
|
||||
{
|
||||
return _line;
|
||||
}
|
||||
|
||||
const int Exception::getExceptionNo()
|
||||
{
|
||||
return _exNo;
|
||||
}
|
||||
|
||||
void Exception::writeMessage()
|
||||
{
|
||||
if (getExceptionNo() == 0 )
|
||||
{
|
||||
WRITELOG("%s : %s\n", currentDateTime(), what());
|
||||
}
|
||||
else
|
||||
{
|
||||
WRITELOG("%s:%-6d %s line %-4d %s() : %s\n", currentDateTime(), getExceptionNo(),
|
||||
getFileName(), getLineNo(), getFunctionName(), what());
|
||||
}
|
||||
}
|
||||
248
MQTTSNGateway/src/MQTTSNGWProcess.h
Normal file
248
MQTTSNGateway/src/MQTTSNGWProcess.h
Normal file
@@ -0,0 +1,248 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#ifndef MQTTSNGWPROCESS_H_
|
||||
#define MQTTSNGWPROCESS_H_
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include "MQTTSNGWDefines.h"
|
||||
#include "Threading.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
|
||||
/*=================================
|
||||
* Parameters
|
||||
==================================*/
|
||||
#define MQTTSNGW_MAX_TASK 10 // number of Tasks
|
||||
#define PROCESS_LOG_BUFFER_SIZE 16384 // Ring buffer size for Logs
|
||||
#define MQTTSNGW_PARAM_MAX 128 // Max length of config records.
|
||||
|
||||
/*=================================
|
||||
* Macros
|
||||
==================================*/
|
||||
#ifdef RINGBUFFER
|
||||
#define WRITELOG theProcess->putLog
|
||||
#else
|
||||
#define WRITELOG printf
|
||||
#endif
|
||||
|
||||
|
||||
/*=================================
|
||||
Class Process
|
||||
==================================*/
|
||||
class Process
|
||||
{
|
||||
public:
|
||||
Process();
|
||||
virtual ~Process();
|
||||
virtual void initialize(int argc, char** argv);
|
||||
virtual void run(void);
|
||||
void putLog(const char* format, ...);
|
||||
void resetRingBuffer(void);
|
||||
int getArgc(void);
|
||||
char** getArgv(void);
|
||||
int getParam(const char* parameter, char* value);
|
||||
const char* getLog(void);
|
||||
int checkSignal(void);
|
||||
|
||||
private:
|
||||
int _argc;
|
||||
char** _argv;
|
||||
RingBuffer* _rb;
|
||||
Semaphore* _rbsem;
|
||||
Mutex _mt;
|
||||
char _rbdata[PROCESS_LOG_BUFFER_SIZE + 1];
|
||||
};
|
||||
|
||||
/*=====================================
|
||||
Class MultiTaskProcess
|
||||
====================================*/
|
||||
class MultiTaskProcess: public Process
|
||||
{
|
||||
public:
|
||||
MultiTaskProcess(void);
|
||||
~MultiTaskProcess();
|
||||
virtual void initialize(int argc, char** argv);
|
||||
virtual int getParam(const char* parameter, char* value);
|
||||
void run(void);
|
||||
void attach(Thread* thread);
|
||||
Semaphore* getStopProcessEvent(void);
|
||||
|
||||
private:
|
||||
Thread* _threadList[MQTTSNGW_MAX_TASK];
|
||||
Semaphore _stopProcessEvent;
|
||||
Mutex _mutex;
|
||||
int _threadCount;
|
||||
};
|
||||
|
||||
/*=====================================
|
||||
Class Exception
|
||||
=====================================*/
|
||||
class Exception: public exception
|
||||
{
|
||||
public:
|
||||
Exception(const string& message);
|
||||
Exception(const int exNo, const string& message);
|
||||
Exception(const int exNo, const string& message,
|
||||
const char* file, const char* func, const int line);
|
||||
virtual ~Exception() throw ();
|
||||
const char* getFileName();
|
||||
const char* getFunctionName();
|
||||
const int getLineNo();
|
||||
const int getExceptionNo();
|
||||
virtual const char* what() const throw ();
|
||||
void writeMessage();
|
||||
|
||||
private:
|
||||
int _exNo;
|
||||
string _message;
|
||||
const char* _fileName;
|
||||
const char* _functionName;
|
||||
int _line;
|
||||
};
|
||||
|
||||
|
||||
/*=====================================
|
||||
Class QueElement
|
||||
====================================*/
|
||||
template<class T>
|
||||
class QueElement
|
||||
{
|
||||
template<class U> friend class Que;
|
||||
public:
|
||||
QueElement(T* t)
|
||||
{
|
||||
_element = t;
|
||||
_next = 0;
|
||||
_prev = 0;
|
||||
}
|
||||
|
||||
~QueElement()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
T* _element;
|
||||
QueElement<T>* _next;
|
||||
QueElement<T>* _prev;
|
||||
};
|
||||
|
||||
/*=====================================
|
||||
Class Que
|
||||
====================================*/
|
||||
template<class T>
|
||||
class Que
|
||||
{
|
||||
public:
|
||||
Que()
|
||||
{
|
||||
_head = 0;
|
||||
_tail = 0;
|
||||
_cnt = 0;
|
||||
}
|
||||
|
||||
~Que()
|
||||
{
|
||||
QueElement<T>* elm = _head;
|
||||
while (elm)
|
||||
{
|
||||
QueElement<T>* next = elm->_next;
|
||||
delete elm->_element;
|
||||
delete elm;
|
||||
elm = next;
|
||||
}
|
||||
}
|
||||
|
||||
void pop(void)
|
||||
{
|
||||
if ( _head )
|
||||
{
|
||||
QueElement<T>* head = _head;
|
||||
if ( _head == _tail )
|
||||
{
|
||||
_head = _tail = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_head = head->_next;
|
||||
head->_prev = 0;
|
||||
}
|
||||
delete head;
|
||||
_cnt--;
|
||||
}
|
||||
}
|
||||
|
||||
T* front(void)
|
||||
{
|
||||
{
|
||||
if ( _head )
|
||||
{
|
||||
return _head->_element;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int post(T* t)
|
||||
{
|
||||
QueElement<T>* elm = new QueElement<T>(t);
|
||||
if ( _head )
|
||||
{
|
||||
if ( _tail == _head )
|
||||
{
|
||||
elm->_prev = _tail;
|
||||
_tail = elm;
|
||||
}
|
||||
else
|
||||
{
|
||||
_tail->_next = elm;
|
||||
elm->_prev = _tail;
|
||||
_tail = elm;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_head = elm;
|
||||
_tail = elm;
|
||||
}
|
||||
_cnt++;
|
||||
return _cnt;
|
||||
}
|
||||
|
||||
int size(void)
|
||||
{
|
||||
return _cnt;
|
||||
}
|
||||
|
||||
private:
|
||||
int _cnt;
|
||||
QueElement<T>* _head;
|
||||
QueElement<T>* _tail;
|
||||
};
|
||||
|
||||
|
||||
extern Process* theProcess;
|
||||
extern MultiTaskProcess* theMultiTaskProcess;
|
||||
|
||||
}
|
||||
#endif /* MQTTSNGWPROCESS_H_ */
|
||||
195
MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp
Normal file
195
MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include "MQTTSNGWPublishHandler.h"
|
||||
#include "MQTTSNGWPacket.h"
|
||||
#include "MQTTGWPacket.h"
|
||||
#include "MQTTSNGateway.h"
|
||||
#include "MQTTSNGWClient.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
MQTTSNPublishHandler::MQTTSNPublishHandler(Gateway* gateway)
|
||||
{
|
||||
_gateway = gateway;
|
||||
}
|
||||
|
||||
MQTTSNPublishHandler::~MQTTSNPublishHandler()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void MQTTSNPublishHandler::handlePublish(Client* client, MQTTSNPacket* packet)
|
||||
{
|
||||
uint8_t dup;
|
||||
int qos;
|
||||
uint8_t retained;
|
||||
uint16_t msgId;
|
||||
MQTTSN_topicid topicid;
|
||||
uint8_t* payload;
|
||||
int payloadlen;
|
||||
Publish pub;
|
||||
char shortTopic[2];
|
||||
|
||||
if ( !client->isActive() )
|
||||
{
|
||||
/* Reply DISCONNECT to the client */
|
||||
WRITELOG(" The client is not active. status = %s\n", client->getStatus());
|
||||
Event* ev = new Event();
|
||||
MQTTSNPacket* disconnect = new MQTTSNPacket();
|
||||
disconnect->setDISCONNECT(0);
|
||||
ev->setClientSendEvent(client, disconnect);
|
||||
_gateway->getClientSendQue()->post(ev);
|
||||
return;
|
||||
}
|
||||
|
||||
packet->getPUBLISH(&dup, &qos, &retained, &msgId, &topicid, &payload, &payloadlen);
|
||||
pub.msgId = msgId;
|
||||
pub.header.bits.dup = dup;
|
||||
pub.header.bits.qos = qos;
|
||||
pub.header.bits.retain = retained;
|
||||
|
||||
Topic* topic = 0;
|
||||
|
||||
if ( topicid.type == MQTTSN_TOPIC_TYPE_PREDEFINED)
|
||||
{
|
||||
/*
|
||||
* ToDo: PUBLISH predefined Topic procedures.
|
||||
*/
|
||||
|
||||
if(msgId)
|
||||
{
|
||||
/* Reply PubAck to the client */
|
||||
MQTTSNPacket* pubAck = new MQTTSNPacket();
|
||||
pubAck->setPUBACK( topicid.data.id, msgId, MQTTSN_RC_ACCEPTED);
|
||||
Event* ev1 = new Event();
|
||||
ev1->setClientSendEvent(client, pubAck);
|
||||
_gateway->getClientSendQue()->post(ev1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if( topicid.type == MQTTSN_TOPIC_TYPE_SHORT )
|
||||
{
|
||||
shortTopic[0] = topicid.data.short_name[0];
|
||||
shortTopic[1] = topicid.data.short_name[1];
|
||||
pub.topic = shortTopic;
|
||||
pub.topiclen = 2;
|
||||
}
|
||||
|
||||
if ( topicid.type == MQTTSN_TOPIC_TYPE_NORMAL )
|
||||
{
|
||||
topic = client->getTopics()->getTopic(topicid.data.id);
|
||||
if( !topic && msgId && qos > 0 )
|
||||
{
|
||||
/* Reply PubAck of INVALID_TOPIC_ID to the client */
|
||||
MQTTSNPacket* pubAck = new MQTTSNPacket();
|
||||
pubAck->setPUBACK( topicid.data.id, msgId, MQTTSN_RC_REJECTED_INVALID_TOPIC_ID);
|
||||
Event* ev1 = new Event();
|
||||
ev1->setClientSendEvent(client, pubAck);
|
||||
_gateway->getClientSendQue()->post(ev1);
|
||||
return;
|
||||
}
|
||||
if ( topic )
|
||||
{
|
||||
pub.topic = (char*)topic->getTopicName()->data();
|
||||
pub.topiclen = topic->getTopicName()->length();
|
||||
}
|
||||
}
|
||||
/* Save a msgId & a TopicId pare for PUBACK */
|
||||
if( msgId && qos > 0 )
|
||||
{
|
||||
client->setWaitedPubTopicId(msgId, topicid.data.id, topicid.type);
|
||||
}
|
||||
|
||||
pub.payload = (char*)payload;
|
||||
pub.payloadlen = payloadlen;
|
||||
|
||||
MQTTGWPacket* pulish = new MQTTGWPacket();
|
||||
pulish->setPUBLISH(&pub);
|
||||
Event* ev1 = new Event();
|
||||
ev1->setBrokerSendEvent(client, pulish);
|
||||
_gateway->getBrokerSendQue()->post(ev1);
|
||||
}
|
||||
|
||||
void MQTTSNPublishHandler::handlePuback(Client* client, MQTTSNPacket* packet)
|
||||
{
|
||||
uint16_t topicId;
|
||||
uint16_t msgId;
|
||||
uint8_t rc;
|
||||
|
||||
if ( !client->isActive() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
MQTTGWPacket* pubAck = new MQTTGWPacket();
|
||||
packet->getPUBACK(&topicId, &msgId, &rc);
|
||||
if ( rc == MQTTSN_RC_ACCEPTED)
|
||||
{
|
||||
pubAck->setAck(PUBACK, msgId);
|
||||
Event* ev1 = new Event();
|
||||
ev1->setBrokerSendEvent(client, pubAck);
|
||||
_gateway->getBrokerSendQue()->post(ev1);
|
||||
}
|
||||
else if ( rc == MQTTSN_RC_REJECTED_INVALID_TOPIC_ID)
|
||||
{
|
||||
WRITELOG(" PUBACK %d : Invalid Topic ID\n", msgId);
|
||||
}
|
||||
}
|
||||
|
||||
void MQTTSNPublishHandler::handleAck(Client* client, MQTTSNPacket* packet, uint8_t packetType)
|
||||
{
|
||||
uint16_t msgId;
|
||||
|
||||
if ( !client->isActive() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
packet->getACK(&msgId);
|
||||
MQTTGWPacket* ackPacket = new MQTTGWPacket();
|
||||
ackPacket->setAck(packetType, msgId);
|
||||
Event* ev1 = new Event();
|
||||
ev1->setBrokerSendEvent(client, ackPacket);
|
||||
_gateway->getBrokerSendQue()->post(ev1);
|
||||
}
|
||||
|
||||
void MQTTSNPublishHandler::handleRegister(Client* client, MQTTSNPacket* packet)
|
||||
{
|
||||
uint16_t id;
|
||||
uint16_t msgId;
|
||||
MQTTSNString topicName;
|
||||
MQTTSN_topicid topicid;
|
||||
|
||||
|
||||
if ( !client->isActive() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
MQTTSNPacket* regAck = new MQTTSNPacket();
|
||||
packet->getREGISTER(&id, &msgId, &topicName);
|
||||
|
||||
topicid.type = MQTTSN_TOPIC_TYPE_NORMAL;
|
||||
topicid.data.long_.len = topicName.lenstring.len;
|
||||
topicid.data.long_.name = topicName.lenstring.data;
|
||||
|
||||
id = client->getTopics()->add(&topicid)->getTopicId();
|
||||
regAck->setREGACK(id, msgId, MQTTSN_RC_ACCEPTED);
|
||||
Event* ev = new Event();
|
||||
ev->setClientSendEvent(client, regAck);
|
||||
_gateway->getClientSendQue()->post(ev);
|
||||
|
||||
}
|
||||
40
MQTTSNGateway/src/MQTTSNGWPublishHandler.h
Normal file
40
MQTTSNGateway/src/MQTTSNGWPublishHandler.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
#ifndef MQTTSNGWPUCLISHHANDLER_H_
|
||||
#define MQTTSNGWPUCLISHHANDLER_H_
|
||||
|
||||
#include "MQTTGWPacket.h"
|
||||
#include "MQTTSNGateway.h"
|
||||
#include "MQTTSNGWClient.h"
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
class MQTTSNPublishHandler
|
||||
{
|
||||
public:
|
||||
MQTTSNPublishHandler(Gateway* gateway);
|
||||
~MQTTSNPublishHandler();
|
||||
void handlePublish(Client* client, MQTTSNPacket* packet);
|
||||
void handlePuback(Client* client, MQTTSNPacket* packet);
|
||||
void handleAck(Client* client, MQTTSNPacket* packet, uint8_t packetType);
|
||||
void handleRegister(Client* client, MQTTSNPacket* packet);
|
||||
|
||||
private:
|
||||
Gateway* _gateway;
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* MQTTSNGWPUCLISHHANDLER_H_ */
|
||||
192
MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp
Normal file
192
MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp
Normal file
@@ -0,0 +1,192 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include "MQTTSNGWSubscribeHandler.h"
|
||||
#include "MQTTSNGWPacket.h"
|
||||
#include "MQTTGWPacket.h"
|
||||
#include "MQTTSNGateway.h"
|
||||
#include "MQTTSNGWClient.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
MQTTSNSubscribeHandler::MQTTSNSubscribeHandler(Gateway* gateway)
|
||||
{
|
||||
_gateway = gateway;
|
||||
}
|
||||
|
||||
MQTTSNSubscribeHandler::~MQTTSNSubscribeHandler()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void MQTTSNSubscribeHandler::handleSubscribe(Client* client, MQTTSNPacket* packet)
|
||||
{
|
||||
MQTTGWPacket* subscribe = new MQTTGWPacket();
|
||||
uint8_t dup;
|
||||
int qos;
|
||||
uint16_t msgId;
|
||||
MQTTSN_topicid topicFilter;
|
||||
Topic* topic = 0;
|
||||
|
||||
packet->getSUBSCRIBE(&dup, &qos, &msgId, &topicFilter);
|
||||
|
||||
if (topicFilter.type <= MQTTSN_TOPIC_TYPE_SHORT)
|
||||
{
|
||||
if (topicFilter.type == MQTTSN_TOPIC_TYPE_PREDEFINED)
|
||||
{
|
||||
/*----- Predefined TopicId ------*/
|
||||
MQTTSNPacket* sSuback = new MQTTSNPacket();
|
||||
|
||||
if (msgId)
|
||||
{
|
||||
int rc = MQTTSN_RC_ACCEPTED;
|
||||
|
||||
switch (topicFilter.data.id)
|
||||
{
|
||||
case 1: // check topicIds are defined.
|
||||
case 2:
|
||||
break;
|
||||
default:
|
||||
rc = MQTTSN_RC_REJECTED_INVALID_TOPIC_ID;
|
||||
}
|
||||
sSuback->setSUBACK(qos, topicFilter.data.id, msgId, rc);
|
||||
Event* evsuback = new Event();
|
||||
evsuback->setClientSendEvent(client, sSuback);
|
||||
_gateway->getClientSendQue()->post(evsuback);
|
||||
}
|
||||
switch (topicFilter.data.id)
|
||||
{
|
||||
case 1:
|
||||
/*
|
||||
* ToDo: write here Predefined Topic 01 Procedures.
|
||||
*/
|
||||
break;
|
||||
case 2:
|
||||
/*
|
||||
* ToDo: write here Predefined Topic 02 Procedures. so on
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
topic = client->getTopics()->getTopic(&topicFilter);
|
||||
if (topic == 0)
|
||||
{
|
||||
if (topicFilter.type == MQTTSN_TOPIC_TYPE_NORMAL)
|
||||
{
|
||||
topic = client->getTopics()->add(&topicFilter);
|
||||
subscribe->setSUBSCRIBE((char*)topic->getTopicName()->c_str(), (uint8_t)qos, (uint16_t)msgId);
|
||||
}
|
||||
else if (topicFilter.type == MQTTSN_TOPIC_TYPE_SHORT)
|
||||
{
|
||||
char topic[3];
|
||||
topic[0] = topicFilter.data.short_name[0];
|
||||
topic[1] = topicFilter.data.short_name[1];
|
||||
topic[2] = 0;
|
||||
subscribe->setSUBSCRIBE(topic, (uint8_t)qos, (uint16_t)msgId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
subscribe->setSUBSCRIBE((char*)topic->getTopicName()->c_str(), (uint8_t)qos, (uint16_t)msgId);
|
||||
}
|
||||
|
||||
if ( msgId > 0 )
|
||||
{
|
||||
client->setWaitedSubTopicId(msgId, topic->getTopicId(), topicFilter.type);
|
||||
}
|
||||
|
||||
Event* ev1 = new Event();
|
||||
ev1->setBrokerSendEvent(client, subscribe);
|
||||
_gateway->getBrokerSendQue()->post(ev1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*-- Invalid TopicIdType --*/
|
||||
if (msgId)
|
||||
{
|
||||
MQTTSNPacket* sSuback = new MQTTSNPacket();
|
||||
sSuback->setSUBACK(qos, topicFilter.data.id, msgId, MQTTSN_RC_REJECTED_INVALID_TOPIC_ID);
|
||||
Event* evsuback = new Event();
|
||||
evsuback->setClientSendEvent(client, sSuback);
|
||||
_gateway->getClientSendQue()->post(evsuback);
|
||||
}
|
||||
}
|
||||
}
|
||||
void MQTTSNSubscribeHandler::handleUnsubscribe(Client* client, MQTTSNPacket* packet)
|
||||
{
|
||||
uint16_t msgId;
|
||||
MQTTSN_topicid topicFilter;
|
||||
|
||||
packet->getUNSUBSCRIBE(&msgId, &topicFilter);
|
||||
|
||||
if ( topicFilter.type == MQTTSN_TOPIC_TYPE_PREDEFINED )
|
||||
{
|
||||
/*
|
||||
* ToDo: procedures for Predefined Topic
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
Topic* topic = client->getTopics()->getTopic(&topicFilter);
|
||||
MQTTGWPacket* unsubscribe = new MQTTGWPacket();
|
||||
|
||||
if (topicFilter.type == MQTTSN_TOPIC_TYPE_NORMAL)
|
||||
{
|
||||
if ( topic == 0 )
|
||||
{
|
||||
if (msgId)
|
||||
{
|
||||
MQTTSNPacket* sUnsuback = new MQTTSNPacket();
|
||||
sUnsuback->setUNSUBACK(msgId);
|
||||
Event* evsuback = new Event();
|
||||
evsuback->setClientSendEvent(client, sUnsuback);
|
||||
_gateway->getClientSendQue()->post(evsuback);
|
||||
delete unsubscribe;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsubscribe->setUNSUBSCRIBE(topic->getTopicName()->c_str(), msgId);
|
||||
}
|
||||
}
|
||||
else if (topicFilter.type == MQTTSN_TOPIC_TYPE_SHORT)
|
||||
{
|
||||
MQTTGWPacket* unsubscribe = new MQTTGWPacket();
|
||||
char shortTopic[3];
|
||||
shortTopic[0] = topicFilter.data.short_name[0];
|
||||
shortTopic[1] = topicFilter.data.short_name[1];
|
||||
shortTopic[2] = 0;
|
||||
unsubscribe->setUNSUBSCRIBE(shortTopic, msgId);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete unsubscribe;
|
||||
return;
|
||||
}
|
||||
|
||||
Event* ev1 = new Event();
|
||||
ev1->setBrokerSendEvent(client, unsubscribe);
|
||||
_gateway->getBrokerSendQue()->post(ev1);
|
||||
}
|
||||
|
||||
44
MQTTSNGateway/src/MQTTSNGWSubscribeHandler.h
Normal file
44
MQTTSNGateway/src/MQTTSNGWSubscribeHandler.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
#ifndef MQTTSNGWSUBSCRIBEHANDLER_H_
|
||||
#define MQTTSNGWSUBSCRIBEHANDLER_H_
|
||||
|
||||
#include "MQTTSNGWDefines.h"
|
||||
#include "MQTTSNGateway.h"
|
||||
#include "MQTTSNGWPacket.h"
|
||||
#include "MQTTSNGWClient.h"
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
/*=====================================
|
||||
Class MQTTSNSubscribeHandler
|
||||
=====================================*/
|
||||
class MQTTSNSubscribeHandler
|
||||
{
|
||||
public:
|
||||
MQTTSNSubscribeHandler(Gateway* gateway);
|
||||
~MQTTSNSubscribeHandler();
|
||||
void handleSubscribe(Client* client, MQTTSNPacket* packet);
|
||||
void handleUnsubscribe(Client* client, MQTTSNPacket* packet);
|
||||
|
||||
private:
|
||||
Gateway* _gateway;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* MQTTSNGWSUBSCRIBEHANDLER_H_ */
|
||||
328
MQTTSNGateway/src/MQTTSNGateway.cpp
Normal file
328
MQTTSNGateway/src/MQTTSNGateway.cpp
Normal file
@@ -0,0 +1,328 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include "MQTTSNGateway.h"
|
||||
#include "MQTTSNGWProcess.h"
|
||||
#include "SensorNetwork.h"
|
||||
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
char* currentDateTime(void);
|
||||
|
||||
/*=====================================
|
||||
Class Gateway
|
||||
=====================================*/
|
||||
Gateway::Gateway() :
|
||||
MultiTaskProcess()
|
||||
{
|
||||
theMultiTaskProcess = this;
|
||||
theProcess = this;
|
||||
resetRingBuffer();
|
||||
_params.loginId = 0;
|
||||
_params.password = 0;
|
||||
}
|
||||
|
||||
Gateway::~Gateway()
|
||||
{
|
||||
if ( _params.loginId )
|
||||
{
|
||||
free(_params.loginId);
|
||||
}
|
||||
if ( _params.password )
|
||||
{
|
||||
free(_params.password);
|
||||
}
|
||||
}
|
||||
|
||||
void Gateway::initialize(int argc, char** argv)
|
||||
{
|
||||
char param[MQTTSNGW_PARAM_MAX];
|
||||
|
||||
_params.gatewayId = 0;
|
||||
if (getParam("GatewayID", param) == 0)
|
||||
{
|
||||
_params.gatewayId = atoi(param);
|
||||
}
|
||||
|
||||
if (_params.gatewayId == 0 || _params.gatewayId > 255)
|
||||
{
|
||||
throw Exception( "Gateway::initialize: invalid Gateway Id");
|
||||
}
|
||||
|
||||
_params.mqttVersion = DEFAULT_MQTT_VERSION;
|
||||
if (getParam("MQTTVersion", param) == 0)
|
||||
{
|
||||
_params.mqttVersion = atoi(param);
|
||||
}
|
||||
|
||||
_params.maxInflightMsgs = DEFAULT_MQTT_VERSION;
|
||||
if (getParam("MaxInflightMsgs", param) == 0)
|
||||
{
|
||||
_params.maxInflightMsgs = atoi(param);
|
||||
}
|
||||
|
||||
_params.keepAlive = DEFAULT_KEEP_ALIVE_TIME;
|
||||
|
||||
if (getParam("KeepAlive", param) == 0)
|
||||
{
|
||||
_params.keepAlive = atoi(param);
|
||||
}
|
||||
|
||||
if (_params.keepAlive > 65536)
|
||||
{
|
||||
throw Exception("Gateway::initialize: KeepAliveTime is grater than 65536 Secs");
|
||||
}
|
||||
|
||||
if (getParam("LoginID", param) == 0)
|
||||
{
|
||||
_params.loginId = (uint8_t*) strdup(param);
|
||||
}
|
||||
|
||||
if (getParam("Password", param) == 0)
|
||||
{
|
||||
_params.password = (uint8_t*) strdup(param);
|
||||
}
|
||||
|
||||
if (getParam("ClientAuthorization", param) == 0)
|
||||
{
|
||||
if (!strcasecmp(param, "YES"))
|
||||
{
|
||||
if (!_clientList.authorize(MQTTSNGW_CLIENT_LIST))
|
||||
{
|
||||
throw Exception("Gateway::initialize: can't authorize clients.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MultiTaskProcess::initialize(argc, argv);
|
||||
}
|
||||
|
||||
void Gateway::run(void)
|
||||
{
|
||||
_lightIndicator.redLight(true);
|
||||
WRITELOG("%s MQTT-SN Gateway has been started. %s %s\n", currentDateTime(), _sensorNetwork.getType(), GATEWAY_VERSION);
|
||||
if ( getClientList()->isAuthorized() )
|
||||
{
|
||||
WRITELOG("\n Client authentication is required by the configuration settings.\n");
|
||||
}
|
||||
|
||||
/* execute threads & wait StopProcessEvent MQTTSNGWPacketHandleTask posts by CTL-C */
|
||||
MultiTaskProcess::run();
|
||||
WRITELOG("%s MQTT-SN Gateway stoped\n", currentDateTime());
|
||||
_lightIndicator.allLightOff();
|
||||
}
|
||||
|
||||
EventQue* Gateway::getPacketEventQue()
|
||||
{
|
||||
return &_packetEventQue;
|
||||
}
|
||||
|
||||
EventQue* Gateway::getClientSendQue()
|
||||
{
|
||||
return &_clientSendQue;
|
||||
}
|
||||
|
||||
EventQue* Gateway::getBrokerSendQue()
|
||||
{
|
||||
return &_brokerSendQue;
|
||||
}
|
||||
|
||||
ClientList* Gateway::getClientList()
|
||||
{
|
||||
return &_clientList;
|
||||
}
|
||||
|
||||
SensorNetwork* Gateway::getSensorNetwork()
|
||||
{
|
||||
return &_sensorNetwork;
|
||||
}
|
||||
|
||||
LightIndicator* Gateway::getLightIndicator()
|
||||
{
|
||||
return &_lightIndicator;
|
||||
}
|
||||
|
||||
GatewayParams* Gateway::getGWParams(void)
|
||||
{
|
||||
return &_params;
|
||||
}
|
||||
|
||||
/*=====================================
|
||||
Class EventQue
|
||||
=====================================*/
|
||||
EventQue::EventQue()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
EventQue::~EventQue()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Event* EventQue::wait(void)
|
||||
{
|
||||
Event* ev;
|
||||
while ( true )
|
||||
{
|
||||
_sem.wait();
|
||||
_mutex.lock();
|
||||
ev = _que.front();
|
||||
_que.pop();
|
||||
_mutex.unlock();
|
||||
if ( ev )
|
||||
{
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Event* EventQue::timedwait(uint16_t millsec)
|
||||
{
|
||||
Event* ev;
|
||||
_sem.timedwait(millsec);
|
||||
_mutex.lock();
|
||||
|
||||
if (_que.size() == 0)
|
||||
{
|
||||
ev = new Event();
|
||||
ev->setTimeout();
|
||||
}
|
||||
else
|
||||
{
|
||||
ev = _que.front();
|
||||
_que.pop();
|
||||
if ( !ev )
|
||||
{
|
||||
ev = new Event();
|
||||
ev->setTimeout();
|
||||
}
|
||||
}
|
||||
_mutex.unlock();
|
||||
return ev;
|
||||
}
|
||||
|
||||
int EventQue::post(Event* ev)
|
||||
{
|
||||
if ( ev )
|
||||
{
|
||||
_mutex.lock();
|
||||
_que.post(ev);
|
||||
_sem.post();
|
||||
_mutex.unlock();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EventQue::size()
|
||||
{
|
||||
_mutex.lock();
|
||||
int sz = _que.size();
|
||||
_mutex.unlock();
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
/*=====================================
|
||||
Class Event
|
||||
=====================================*/
|
||||
Event::Event()
|
||||
{
|
||||
_eventType = Et_NA;
|
||||
_client = 0;
|
||||
_mqttSNPacket = 0;
|
||||
_mqttGWPacket = 0;
|
||||
}
|
||||
|
||||
Event::Event(EventType type)
|
||||
{
|
||||
_eventType = type;
|
||||
_client = 0;
|
||||
_mqttSNPacket = 0;
|
||||
_mqttGWPacket = 0;
|
||||
}
|
||||
|
||||
Event::~Event()
|
||||
{
|
||||
if (_mqttSNPacket)
|
||||
{
|
||||
delete _mqttSNPacket;
|
||||
}
|
||||
|
||||
if (_mqttGWPacket)
|
||||
{
|
||||
delete _mqttGWPacket;
|
||||
}
|
||||
}
|
||||
|
||||
EventType Event::getEventType()
|
||||
{
|
||||
return _eventType;
|
||||
}
|
||||
|
||||
void Event::setClientSendEvent(Client* client, MQTTSNPacket* packet)
|
||||
{
|
||||
_client = client;
|
||||
_eventType = EtClientSend;
|
||||
_mqttSNPacket = packet;
|
||||
}
|
||||
|
||||
void Event::setBrokerSendEvent(Client* client, MQTTGWPacket* packet)
|
||||
{
|
||||
_client = client;
|
||||
_eventType = EtBrokerSend;
|
||||
_mqttGWPacket = packet;
|
||||
}
|
||||
|
||||
void Event::setClientRecvEvent(Client* client, MQTTSNPacket* packet)
|
||||
{
|
||||
_client = client;
|
||||
_eventType = EtClientRecv;
|
||||
_mqttSNPacket = packet;
|
||||
}
|
||||
|
||||
void Event::setBrokerRecvEvent(Client* client, MQTTGWPacket* packet)
|
||||
{
|
||||
_client = client;
|
||||
_eventType = EtBrokerRecv;
|
||||
_mqttGWPacket = packet;
|
||||
}
|
||||
|
||||
void Event::setTimeout(void)
|
||||
{
|
||||
_eventType = EtTimeout;
|
||||
}
|
||||
|
||||
void Event::setBrodcastEvent(MQTTSNPacket* msg)
|
||||
{
|
||||
_mqttSNPacket = msg;
|
||||
_eventType = EtBroadcast;
|
||||
}
|
||||
|
||||
Client* Event::getClient(void)
|
||||
{
|
||||
return _client;
|
||||
}
|
||||
|
||||
MQTTSNPacket* Event::getMQTTSNPacket()
|
||||
{
|
||||
return _mqttSNPacket;
|
||||
}
|
||||
|
||||
MQTTGWPacket* Event::getMQTTGWPacket(void)
|
||||
{
|
||||
return _mqttGWPacket;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014, 2016 IBM Corp.
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
@@ -11,286 +11,168 @@
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(MQTTSNGATEWAY_H)
|
||||
#define MQTTSNGATEWAY_H
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
#ifndef MQTTSNGATEWAY_H_
|
||||
#define MQTTSNGATEWAY_H_
|
||||
|
||||
#include "MQTTSNGWProcess.h"
|
||||
#include "MQTTSNGWClient.h"
|
||||
#include "MQTTSNPacket.h"
|
||||
#include "MQTTConnection.h"
|
||||
#include "MQTTGWPacket.h"
|
||||
|
||||
namespace MQTTSN
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
|
||||
#define MAX_PACKET_SIZE 256
|
||||
#define MQTTSNGATEWAY_QOS2 0
|
||||
#define MQTTSNGATEWAY_QOS1 0
|
||||
#define MAX_MQTT_CONNECTIONS 5
|
||||
|
||||
struct Parms
|
||||
{
|
||||
char* hostname;
|
||||
int port;
|
||||
char* username;
|
||||
char* password;
|
||||
};
|
||||
|
||||
enum QoS { QOS0, QOS1, QOS2 };
|
||||
/*==========================================================
|
||||
* Log Formats
|
||||
===========================================================*/
|
||||
#define BROKER "Broker"
|
||||
#define GATEWAY "Gateway"
|
||||
#define CLIENT "Client"
|
||||
#define CLIENTS "Clients"
|
||||
#define LEFTARROW "<---"
|
||||
#define RIGHTARROW "--->"
|
||||
|
||||
enum Modes { AGGREGATING, TRANSPARENT };
|
||||
|
||||
// all failure return codes must be negative
|
||||
enum returnCode { MAX_SUBSCRIPTIONS_EXCEEDED = -3, BUFFER_OVERFLOW = -2, FAILURE = -1, SUCCESS = 0 };
|
||||
#define FORMAT_WHITE_NL "%s %-18s%-6s%-26s%s\n"
|
||||
#define FORMAT_WH_NL "\n%s %-18s%-6s%-26s%s\n"
|
||||
#define FORMAT_WH_MSGID "%s %-11s%-5s %-6s%-26s%s\n"
|
||||
#define FORMAT_WH_MSGID_NL "\n%s %-11s%-5s %-6s%-26s%s\n"
|
||||
#define FORMAT_WH_GR "%s %-18s%-6s\x1b[0m\x1b[32m%-26s\x1b[0m\x1b[37m%s\n"
|
||||
#define FORMAT_WH_GR_MSGID "%s %-11s%-5s %-6s\x1b[0m\x1b[32m%-26s\x1b[0m\x1b[37m%s\n"
|
||||
#define FORMAT_WH_GR_MSGID_NL "\n%s %-11s%-5s %-6s\x1b[0m\x1b[32m%-26s\x1b[0m\x1b[37m%s\n"
|
||||
|
||||
struct Message
|
||||
{
|
||||
enum QoS qos;
|
||||
bool retained;
|
||||
bool dup;
|
||||
unsigned short id;
|
||||
void *payload;
|
||||
size_t payloadlen;
|
||||
#define FORMAT_GR "%s \x1b[0m\x1b[32m%-18s%-6s\x1b[0m\x1b[37m%-26s%s\n"
|
||||
#define FORMAT_GR_NL "\n%s \x1b[0m\x1b[32m%-18s%-6s\x1b[0m\x1b[37m%-26s%s\n"
|
||||
#define FORMAT_GR_MSGID "%s \x1b[0m\x1b[32m%-11s%-5s %-6s%-26s\x1b[0m\x1b[37m%s\n"
|
||||
#define FORMAT_GR_MSGID_NL "\n%s \x1b[0m\x1b[32m%-11s%-5s %-6s%-26s\x1b[0m\x1b[37m%s\n"
|
||||
#define FORMAT_GR_WH_MSGID "%s \x1b[0m\x1b[32m%-11s%-5s %-6s\x1b[0m\x1b[37m%-26s%s\n"
|
||||
#define FORMAT_GR_WH_MSGID_NL "\n%s \x1b[0m\x1b[32m%-11s%-5s %-6s\x1b[0m\x1b[37m%-26s%s\n"
|
||||
|
||||
#define FORMAT_YE "%s \x1b[0m\x1b[33m%-18s%-6s%-44s\x1b[0m\x1b[37m%s\n"
|
||||
#define FORMAT_YE_NL "\n%s \x1b[0m\x1b[33m%-18s%-6s%-26s\x1b[0m\x1b[37m%s\n"
|
||||
#define FORMAT_YE_WH "%s \x1b[0m\x1b[33m%-18s%-6s\x1b[0m\x1b[37m%-26s\x1b[0m\x1b[37m%s\n"
|
||||
#define FORMAT_YE_WH_NL "\n%s \x1b[0m\x1b[33m%-18s%-6s\x1b[0m\x1b[37m%-26s\x1b[0m\x1b[37m%s\n"
|
||||
#define FORMAT_YE_GR "%s \x1b[0m\x1b[33m%-18s%-6s\x1b[0m\x1b[32m%-26s\x1b[0m\x1b[37m%s\n"
|
||||
#define FORMAT_YE_GR_MSGID "%s \x1b[0m\x1b[33m%-11s%-5s %-6s\x1b[0m\x1b[32m%-26s\x1b[0m\x1b[37m%s\n"
|
||||
|
||||
#define FORMAT_CY_ANY "%s \x1b[0m\x1b[36m%-18s%-6s%-44s\x1b[0m\x1b[37m%s\n"
|
||||
#define FORMAT_CY "%s \x1b[0m\x1b[36m%-18s%-6s%-26s\x1b[0m\x1b[37m%s\n"
|
||||
#define FORMAT_CY_NL "\n%s \x1b[0m\x1b[36m%-18s%-6s%-26s\x1b[0m\x1b[37m%s\n"
|
||||
|
||||
#define FORMAT_BL_NL "\n%s \x1b[0m\x1b[34m%-18s%-6s%-26s\x1b[0m\x1b[37m%s\n"
|
||||
#define FORMAT_RED "%s \x1b[0m\x1b[31m%-18s%-6s%-44s\x1b[0m\x1b[37m%s\n"
|
||||
#define FORMAT_RED_NL "\n%s \x1b[0m\x1b[31m%-18s%-6s%-26s\x1b[0m\x1b[37m%s\n"
|
||||
#define ERRMSG_HEADER "\x1b[0m\x1b[31mError:"
|
||||
#define ERRMSG_FOOTER "\x1b[0m\x1b[37m"
|
||||
|
||||
/*==========================================================
|
||||
* Gateway default parameters
|
||||
===========================================================*/
|
||||
#define DEFAULT_KEEP_ALIVE_TIME (900) // 900 secs = 15 mins
|
||||
#define DEFAULT_MAX_CLIENTS (100) // Number of Clients can be handled.
|
||||
#define DEFAULT_MQTT_VERSION (4) // Defualt MQTT version
|
||||
#define DEFAULT_INFLIGHTMESSAGE (10) // Number of inflight messages
|
||||
|
||||
/*=====================================
|
||||
Class Event
|
||||
====================================*/
|
||||
enum EventType{
|
||||
Et_NA = 0,
|
||||
EtTimeout,
|
||||
EtBrokerRecv,
|
||||
EtBrokerSend,
|
||||
EtClientRecv,
|
||||
EtClientSend,
|
||||
EtBroadcast,
|
||||
EtSocketAlive
|
||||
};
|
||||
|
||||
|
||||
template<class UDPNetwork, class TCPNetwork, class Timer, class Thread, class Mutex>
|
||||
class Gateway
|
||||
class Event{
|
||||
public:
|
||||
Event();
|
||||
Event(EventType);
|
||||
~Event();
|
||||
EventType getEventType(void);
|
||||
void setClientRecvEvent(Client*, MQTTSNPacket*);
|
||||
void setClientSendEvent(Client*, MQTTSNPacket*);
|
||||
void setBrokerRecvEvent(Client*, MQTTGWPacket*);
|
||||
void setBrokerSendEvent(Client*, MQTTGWPacket*);
|
||||
void setBrodcastEvent(MQTTSNPacket*); // ADVERTISE and GWINFO
|
||||
void setTimeout(void); // Required by EventQue<Event>.timedwait()
|
||||
Client* getClient(void);
|
||||
MQTTSNPacket* getMQTTSNPacket(void);
|
||||
MQTTGWPacket* getMQTTGWPacket(void);
|
||||
|
||||
private:
|
||||
EventType _eventType;
|
||||
Client* _client;
|
||||
MQTTSNPacket* _mqttSNPacket;
|
||||
MQTTGWPacket* _mqttGWPacket;
|
||||
};
|
||||
|
||||
/*=====================================
|
||||
Class EventQue
|
||||
====================================*/
|
||||
class EventQue
|
||||
{
|
||||
public:
|
||||
EventQue();
|
||||
~EventQue();
|
||||
Event* wait(void);
|
||||
Event* timedwait(uint16_t millsec);
|
||||
int post(Event*);
|
||||
int size();
|
||||
|
||||
Gateway(UDPNetwork&, unsigned int command_timeout_ms = 30000);
|
||||
|
||||
void run(void const* arg);
|
||||
|
||||
private:
|
||||
|
||||
int cycle(Timer& timer);
|
||||
int sendPacket(int length, Timer& timer);
|
||||
int readPacket(Timer& timer);
|
||||
|
||||
UDPNetwork& udpstack; // Not restricted to UDP - for want of a better name
|
||||
|
||||
unsigned char sendbuf[MAX_PACKET_SIZE];
|
||||
unsigned char readbuf[MAX_PACKET_SIZE];
|
||||
|
||||
enum Modes mode;
|
||||
|
||||
MQTT::Connection<TCPNetwork, Timer> connections[MAX_MQTT_CONNECTIONS];
|
||||
|
||||
Que<Event> _que;
|
||||
Mutex _mutex;
|
||||
Semaphore _sem;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace
|
||||
|
||||
|
||||
template<class UDPNetwork, class TCPNetwork, class Timer, class Thread, class Mutex>
|
||||
MQTTSN::Gateway<UDPNetwork, TCPNetwork, Timer, Thread, Mutex>::Gateway(UDPNetwork& network, unsigned int command_timeout_ms) : udpstack(network)
|
||||
{
|
||||
mode = AGGREGATING;
|
||||
}
|
||||
|
||||
|
||||
template<class UDPNetwork, class TCPNetwork, class Timer, class Thread, class Mutex>
|
||||
void MQTTSN::Gateway<UDPNetwork, TCPNetwork, Timer, Thread, Mutex>::run(void const* arg)
|
||||
{
|
||||
Timer timer;
|
||||
|
||||
printf("Gateway run 0\n");
|
||||
if (mode == AGGREGATING)
|
||||
{
|
||||
// set up connection 0 information
|
||||
Thread mythread(&connections[0].run);
|
||||
}
|
||||
|
||||
printf("Gateway run 1\n");
|
||||
while (true)
|
||||
{
|
||||
printf("Gateway cycle\n");
|
||||
cycle(timer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<class UDPNetwork, class TCPNetwork, class Timer, class Thread, class Mutex>
|
||||
int MQTTSN::Gateway<UDPNetwork, TCPNetwork, Timer, Thread, Mutex>::cycle(Timer& timer)
|
||||
{
|
||||
/* get one piece of work off the wire and one pass through */
|
||||
|
||||
// read the socket, see what work is due
|
||||
unsigned short packet_type = readPacket(timer);
|
||||
|
||||
printf("read packet\n");
|
||||
|
||||
int len = 0;
|
||||
int rc = SUCCESS;
|
||||
|
||||
switch (packet_type)
|
||||
{
|
||||
case MQTTSN_CONNECT:
|
||||
{
|
||||
MQTTSNPacket_connectData data = MQTTSNPacket_connectData_initializer;
|
||||
MQTTSNDeserialize_connect(&data, readbuf, MAX_PACKET_SIZE);
|
||||
|
||||
if (mode == TRANSPARENT)
|
||||
{
|
||||
//start a new MQTT connection at this point
|
||||
}
|
||||
|
||||
len = MQTTSNSerialize_connack(sendbuf, MAX_PACKET_SIZE, 0);
|
||||
if (len <= 0)
|
||||
rc = FAILURE;
|
||||
else
|
||||
rc = sendPacket(len, timer);
|
||||
break;
|
||||
}
|
||||
|
||||
case MQTTSN_REGISTER:
|
||||
{
|
||||
unsigned short topicid, packetid;
|
||||
MQTTSNString topicName;
|
||||
unsigned char reg_rc = MQTTSN_RC_ACCEPTED;
|
||||
if (MQTTSNDeserialize_register(&topicid, &packetid, &topicName, readbuf, MAX_PACKET_SIZE) != 1)
|
||||
goto exit;
|
||||
|
||||
// store topic registration info
|
||||
|
||||
len = MQTTSNSerialize_regack(connections[0].sendbuf, MAX_PACKET_SIZE, topicid, packetid, reg_rc);
|
||||
if (len <= 0)
|
||||
rc = FAILURE;
|
||||
else
|
||||
rc = connections[0].sendPacket(len, timer);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MQTTSN_SUBSCRIBE:
|
||||
{
|
||||
unsigned char dup;
|
||||
int qos;
|
||||
unsigned short packetid;
|
||||
MQTTSN_topicid topicFilter;
|
||||
MQTTSNDeserialize_subscribe(&dup, &qos, &packetid, &topicFilter, readbuf, MAX_PACKET_SIZE);
|
||||
MQTTString topic = MQTTString_initializer;
|
||||
|
||||
if (topicFilter.type == MQTTSN_TOPIC_TYPE_NORMAL)
|
||||
{
|
||||
topic.lenstring.len = topicFilter.data.long_.len;
|
||||
topic.lenstring.data = topicFilter.data.long_.name;
|
||||
}
|
||||
|
||||
len = MQTTSerialize_subscribe(connections[0].sendbuf, MAX_PACKET_SIZE, 0, packetid, 1, &topic, (int*)&qos);
|
||||
if (len <= 0)
|
||||
goto exit;
|
||||
if ((rc = connections[0].sendPacket(len, timer)) != SUCCESS) // send the subscribe packet
|
||||
goto exit; // there was a problem
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MQTTSN_PUBLISH:
|
||||
{
|
||||
MQTTString topic = MQTTString_initializer;
|
||||
MQTTSN_topicid topicid;
|
||||
Message msg;
|
||||
|
||||
if (MQTTSNDeserialize_publish((unsigned char*)&msg.dup, (int*)&msg.qos, (unsigned char*)&msg.retained, &msg.id, &topicid,
|
||||
(unsigned char**)&msg.payload, (int*)&msg.payloadlen, readbuf, MAX_PACKET_SIZE) != 1)
|
||||
goto exit;
|
||||
|
||||
|
||||
len = MQTTSerialize_publish(connections[0].sendbuf, MAX_PACKET_SIZE, msg.dup, msg.qos, msg.retained, msg.id, topic,
|
||||
(unsigned char*)msg.payload, msg.payloadlen);
|
||||
if (len <= 0)
|
||||
goto exit;
|
||||
if ((rc = connections[0].sendPacket(len, timer)) != SUCCESS) // send the subscribe packet
|
||||
goto exit; // there was a problem
|
||||
|
||||
}
|
||||
|
||||
|
||||
case MQTTSN_PINGRESP:
|
||||
//ping_outstanding = false;
|
||||
break;
|
||||
}
|
||||
//keepalive();
|
||||
exit:
|
||||
if (rc == SUCCESS)
|
||||
rc = packet_type;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class UDPNetwork, class TCPNetwork, class Timer, class Thread, class Mutex>
|
||||
int MQTTSN::Gateway<UDPNetwork, TCPNetwork, Timer, Thread, Mutex>::sendPacket(int length, Timer& timer)
|
||||
{
|
||||
int rc = FAILURE,
|
||||
sent = 0;
|
||||
|
||||
do
|
||||
{
|
||||
sent = udpstack.write(sendbuf, length, timer.left_ms());
|
||||
printf("sendPacket, rc %d from write of %d bytes\n", sent, length);
|
||||
if (sent < 0) // there was an error writing the data
|
||||
break;
|
||||
}
|
||||
while (sent != length && !timer.expired());
|
||||
|
||||
if (sent == length)
|
||||
{
|
||||
//if (this->duration > 0)
|
||||
// last_sent.countdown(this->duration); // record the fact that we have successfully sent the packet
|
||||
rc = SUCCESS;
|
||||
}
|
||||
else
|
||||
rc = FAILURE;
|
||||
|
||||
#if defined(MQTT_DEBUG)
|
||||
char printbuf[50];
|
||||
DEBUG("Rc %d from sending packet %s\n", rc, MQTTSNPacket_toString(printbuf, sizeof(printbuf), sendbuf, length));
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If any read fails in this method, then we should disconnect from the network, as on reconnect
|
||||
* the packets can be retried.
|
||||
* @param timeout the max time to wait for the packet read to complete, in milliseconds
|
||||
* @return the MQTT packet type, or -1 if none
|
||||
/*
|
||||
* GatewayParams
|
||||
*/
|
||||
template<class UDPNetwork, class TCPNetwork, class Timer, class Thread, class Mutex>
|
||||
int MQTTSN::Gateway<UDPNetwork, TCPNetwork, Timer, Thread, Mutex>::readPacket(Timer& timer)
|
||||
typedef struct
|
||||
{
|
||||
int rc = FAILURE;
|
||||
int len = 0; // the length of the whole packet including length field
|
||||
int lenlen = 0;
|
||||
int datalen = 0;
|
||||
uint8_t* loginId;
|
||||
uint8_t* password;
|
||||
uint16_t keepAlive;
|
||||
uint8_t gatewayId;
|
||||
uint8_t mqttVersion;
|
||||
uint16_t maxInflightMsgs;
|
||||
}GatewayParams;
|
||||
|
||||
/*=====================================
|
||||
Class Gateway
|
||||
=====================================*/
|
||||
class Gateway: public MultiTaskProcess{
|
||||
public:
|
||||
Gateway();
|
||||
~Gateway();
|
||||
virtual void initialize(int argc, char** argv);
|
||||
void run(void);
|
||||
|
||||
EventQue* getPacketEventQue(void);
|
||||
EventQue* getClientSendQue(void);
|
||||
EventQue* getBrokerSendQue(void);
|
||||
ClientList* getClientList(void);
|
||||
SensorNetwork* getSensorNetwork(void);
|
||||
LightIndicator* getLightIndicator(void);
|
||||
GatewayParams* getGWParams(void);
|
||||
|
||||
private:
|
||||
ClientList _clientList;
|
||||
EventQue _packetEventQue;
|
||||
EventQue _brokerSendQue;
|
||||
EventQue _clientSendQue;
|
||||
LightIndicator _lightIndicator;
|
||||
GatewayParams _params;
|
||||
SensorNetwork _sensorNetwork;
|
||||
};
|
||||
|
||||
#define MQTTSN_MIN_PACKET_LENGTH 3
|
||||
// 1. read the packet, datagram style
|
||||
if ((len = udpstack.read(readbuf, MAX_PACKET_SIZE, timer.left_ms())) < MQTTSN_MIN_PACKET_LENGTH)
|
||||
goto exit;
|
||||
|
||||
// 2. read the length. This is variable in itself
|
||||
lenlen = MQTTSNPacket_decode(readbuf, len, &datalen);
|
||||
if (datalen != len)
|
||||
goto exit; // there was an error
|
||||
|
||||
rc = readbuf[lenlen];
|
||||
//if (this->duration > 0)
|
||||
// last_received.countdown(this->duration); // record the fact that we have successfully received a packet
|
||||
exit:
|
||||
|
||||
#if defined(MQTT_DEBUG)
|
||||
char printbuf[50];
|
||||
DEBUG("Rc %d from receiving packet %s\n", rc, MQTTSNPacket_toString(printbuf, sizeof(printbuf), readbuf, len));
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
#endif /* MQTTSNGATEWAY_H_ */
|
||||
|
||||
563
MQTTSNGateway/src/linux/Network.cpp
Normal file
563
MQTTSNGateway/src/linux/Network.cpp
Normal file
@@ -0,0 +1,563 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <error.h>
|
||||
|
||||
#include "Network.h"
|
||||
#include "MQTTSNGWDefines.h"
|
||||
#include "MQTTSNGWProcess.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
#define SOCKET_MAXCONNECTIONS 5
|
||||
char* currentDateTime();
|
||||
|
||||
/*========================================
|
||||
Class TCPStack
|
||||
=======================================*/
|
||||
TCPStack::TCPStack()
|
||||
{
|
||||
_addrinfo = 0;
|
||||
_sockfd = 0;
|
||||
}
|
||||
|
||||
TCPStack::~TCPStack()
|
||||
{
|
||||
if (_addrinfo)
|
||||
{
|
||||
freeaddrinfo(_addrinfo);
|
||||
}
|
||||
}
|
||||
|
||||
bool TCPStack::isValid()
|
||||
{
|
||||
return (_sockfd > 0);
|
||||
}
|
||||
|
||||
void TCPStack::close()
|
||||
{
|
||||
if (_sockfd > 0)
|
||||
{
|
||||
::close(_sockfd);
|
||||
_sockfd = 0;
|
||||
if (_addrinfo)
|
||||
{
|
||||
freeaddrinfo(_addrinfo);
|
||||
_addrinfo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool TCPStack::bind(const char* service)
|
||||
{
|
||||
if (isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
addrinfo hints;
|
||||
memset(&hints, 0, sizeof(addrinfo));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
if (_addrinfo)
|
||||
{
|
||||
freeaddrinfo(_addrinfo);
|
||||
}
|
||||
int err = getaddrinfo(0, service, &hints, &_addrinfo);
|
||||
if (err)
|
||||
{
|
||||
WRITELOG("\n%s \x1b[0m\x1b[31merror:\x1b[0m\x1b[37mgetaddrinfo(): %s\n", currentDateTime(),
|
||||
gai_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
_sockfd = socket(_addrinfo->ai_family, _addrinfo->ai_socktype, _addrinfo->ai_protocol);
|
||||
if (_sockfd < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int on = 1;
|
||||
if (setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*) &on, sizeof(on)) == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (::bind(_sockfd, _addrinfo->ai_addr, _addrinfo->ai_addrlen) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TCPStack::listen()
|
||||
{
|
||||
if (!isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int listen_return = ::listen(_sockfd, SOCKET_MAXCONNECTIONS);
|
||||
if (listen_return == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TCPStack::accept(TCPStack& new_socket)
|
||||
{
|
||||
sockaddr_storage sa;
|
||||
socklen_t len = sizeof(sa);
|
||||
new_socket._sockfd = ::accept(_sockfd, (struct sockaddr*) &sa, &len);
|
||||
if (new_socket._sockfd <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int TCPStack::send(const uint8_t* buf, int length)
|
||||
{
|
||||
return ::send(_sockfd, buf, length, MSG_NOSIGNAL);
|
||||
}
|
||||
|
||||
int TCPStack::recv(uint8_t* buf, int len)
|
||||
{
|
||||
return ::recv(_sockfd, buf, len, 0);
|
||||
}
|
||||
|
||||
bool TCPStack::connect(const char* host, const char* service)
|
||||
{
|
||||
if (isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
addrinfo hints;
|
||||
memset(&hints, 0, sizeof(addrinfo));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
if (_addrinfo)
|
||||
{
|
||||
freeaddrinfo(_addrinfo);
|
||||
}
|
||||
|
||||
int err = getaddrinfo(host, service, &hints, &_addrinfo);
|
||||
if (err)
|
||||
{
|
||||
WRITELOG("\n%s \x1b[0m\x1b[31merror:\x1b[0m\x1b[37mgetaddrinfo(): %s\n", currentDateTime(),
|
||||
gai_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
int sockfd = socket(_addrinfo->ai_family, _addrinfo->ai_socktype, _addrinfo->ai_protocol);
|
||||
|
||||
if (sockfd < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int on = 1;
|
||||
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*) &on, sizeof(on)) == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (::connect(sockfd, _addrinfo->ai_addr, _addrinfo->ai_addrlen) < 0)
|
||||
{
|
||||
//perror("TCPStack connect");
|
||||
::close(sockfd);
|
||||
return false;
|
||||
}
|
||||
|
||||
_sockfd = sockfd;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TCPStack::setNonBlocking(const bool b)
|
||||
{
|
||||
int opts;
|
||||
|
||||
opts = fcntl(_sockfd, F_GETFL);
|
||||
|
||||
if (opts < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (b)
|
||||
{
|
||||
opts = (opts | O_NONBLOCK);
|
||||
}
|
||||
else
|
||||
{
|
||||
opts = (opts & ~O_NONBLOCK);
|
||||
}
|
||||
fcntl(_sockfd, F_SETFL, opts);
|
||||
}
|
||||
|
||||
int TCPStack::getSock()
|
||||
{
|
||||
return _sockfd;
|
||||
}
|
||||
|
||||
/*========================================
|
||||
Class Network
|
||||
=======================================*/
|
||||
int Network::_numOfInstance = 0;
|
||||
SSL_CTX* Network::_ctx = 0;
|
||||
SSL_SESSION* Network::_session = 0;
|
||||
|
||||
Network::Network(bool secure) :
|
||||
TCPStack()
|
||||
{
|
||||
char error[256];
|
||||
if (secure)
|
||||
{
|
||||
_numOfInstance++;
|
||||
if (_ctx == 0)
|
||||
{
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
_ctx = SSL_CTX_new(TLSv1_2_client_method());
|
||||
if (_ctx == 0)
|
||||
{
|
||||
ERR_error_string_n(ERR_get_error(), error, sizeof(error));
|
||||
WRITELOG("SSL_CTX_new() %s\n", error);
|
||||
throw Exception( ERR_get_error(), "Network can't create SSL context.");
|
||||
}
|
||||
if (!SSL_CTX_load_verify_locations(_ctx, 0, MQTTSNGW_TLS_CA_DIR))
|
||||
{
|
||||
ERR_error_string_n(ERR_get_error(), error, sizeof(error));
|
||||
WRITELOG("SSL_CTX_load_verify_locations() %s\n", error);
|
||||
throw Exception( ERR_get_error(), "Network can't load CA_LIST.");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ssl = 0;
|
||||
_disconReq = false;
|
||||
_secureFlg = secure;
|
||||
_busy = false;
|
||||
}
|
||||
|
||||
Network::~Network()
|
||||
{
|
||||
if (_secureFlg)
|
||||
{
|
||||
_numOfInstance--;
|
||||
}
|
||||
if (_ssl)
|
||||
{
|
||||
SSL_free(_ssl);
|
||||
}
|
||||
if (_session && _numOfInstance == 0)
|
||||
{
|
||||
SSL_SESSION_free(_session);
|
||||
_session = 0;
|
||||
}
|
||||
if (_ctx && _numOfInstance == 0)
|
||||
{
|
||||
SSL_CTX_free(_ctx);
|
||||
_ctx = 0;
|
||||
ERR_free_strings();
|
||||
}
|
||||
}
|
||||
|
||||
bool Network::connect(const char* host, const char* service)
|
||||
{
|
||||
char errmsg[256];
|
||||
int rc = 0;
|
||||
char peer_CN[256];
|
||||
SSL_SESSION* sess = 0;
|
||||
X509* peer;
|
||||
|
||||
if (isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!TCPStack::connect(host, service))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!_secureFlg)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
SSL* ssl = SSL_new(_ctx);
|
||||
if (ssl == 0)
|
||||
{
|
||||
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
|
||||
WRITELOG("SSL_new() %s\n", errmsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = SSL_set_fd(ssl, TCPStack::getSock());
|
||||
if (rc == 0)
|
||||
{
|
||||
SSL_free(ssl);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_session)
|
||||
{
|
||||
rc = SSL_set_session(ssl, sess);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = SSL_connect(ssl);
|
||||
}
|
||||
if (rc != 1)
|
||||
{
|
||||
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
|
||||
WRITELOG("SSL_connect() %s\n", errmsg);
|
||||
SSL_free(ssl);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SSL_get_verify_result(ssl) != X509_V_OK)
|
||||
{
|
||||
WRITELOG("SSL_get_verify_result() error: Certificate doesn't verify.\n");
|
||||
SSL_free(ssl);
|
||||
return false;
|
||||
}
|
||||
|
||||
peer = SSL_get_peer_certificate(ssl);
|
||||
X509_NAME_get_text_by_NID(X509_get_subject_name(peer), NID_commonName, peer_CN, 256);
|
||||
if (strcasecmp(peer_CN, host))
|
||||
{
|
||||
WRITELOG("SSL_get_peer_certificate() error: Broker dosen't much host name.\n");
|
||||
SSL_free(ssl);
|
||||
return false;
|
||||
}
|
||||
if (_session == 0)
|
||||
{
|
||||
_session = sess;
|
||||
}
|
||||
_ssl = ssl;
|
||||
return true;
|
||||
}
|
||||
|
||||
int Network::send(const uint8_t* buf, uint16_t length)
|
||||
{
|
||||
char errmsg[256];
|
||||
fd_set rset;
|
||||
fd_set wset;
|
||||
bool writeBlockedOnRead = false;
|
||||
int bpos = 0;
|
||||
|
||||
if (_secureFlg)
|
||||
{
|
||||
_mutex.lock();
|
||||
_busy = true;
|
||||
|
||||
while (true)
|
||||
{
|
||||
FD_ZERO(&rset);
|
||||
FD_ZERO(&wset);
|
||||
FD_SET(getSock(), &rset);
|
||||
FD_SET(getSock(), &wset);
|
||||
|
||||
int activity = select(getSock() + 1, &rset, &wset, 0, 0);
|
||||
if (activity > 0)
|
||||
{
|
||||
if (FD_ISSET(getSock(), &wset) || (writeBlockedOnRead && FD_ISSET(getSock(), &rset)))
|
||||
{
|
||||
|
||||
writeBlockedOnRead = false;
|
||||
int r = SSL_write(_ssl, buf + bpos, length);
|
||||
|
||||
switch (SSL_get_error(_ssl, r))
|
||||
{
|
||||
case SSL_ERROR_NONE:
|
||||
length -= r;
|
||||
bpos += r;
|
||||
if (length == 0)
|
||||
{
|
||||
_busy = false;
|
||||
_mutex.unlock();
|
||||
return bpos;
|
||||
}
|
||||
break;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
break;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
writeBlockedOnRead = true;
|
||||
break;
|
||||
default:
|
||||
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
|
||||
WRITELOG("TLSStack::send() default %s\n", errmsg);
|
||||
_busy = false;
|
||||
_mutex.unlock();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return TCPStack::send(buf, length);
|
||||
}
|
||||
}
|
||||
|
||||
int Network::recv(uint8_t* buf, uint16_t len)
|
||||
{
|
||||
char errmsg[256];
|
||||
bool writeBlockedOnRead = false;
|
||||
bool readBlockedOnWrite = false;
|
||||
bool readBlocked = false;
|
||||
int rlen = 0;
|
||||
int bpos = 0;
|
||||
fd_set rset;
|
||||
fd_set wset;
|
||||
|
||||
if (_secureFlg)
|
||||
{
|
||||
if (_busy)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
_mutex.lock();
|
||||
_busy = true;
|
||||
|
||||
loop: do
|
||||
{
|
||||
readBlockedOnWrite = false;
|
||||
readBlocked = false;
|
||||
|
||||
rlen = SSL_read(_ssl, buf + bpos, len - bpos);
|
||||
|
||||
switch (SSL_get_error(_ssl, rlen))
|
||||
{
|
||||
case SSL_ERROR_NONE:
|
||||
_busy = false;
|
||||
_mutex.unlock();
|
||||
return rlen + bpos;
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
SSL_shutdown(_ssl);
|
||||
_ssl = 0;
|
||||
TCPStack::close();
|
||||
_busy = false;
|
||||
_mutex.unlock();
|
||||
return -1;
|
||||
break;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
readBlocked = true;
|
||||
break;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
readBlockedOnWrite = true;
|
||||
break;
|
||||
default:
|
||||
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
|
||||
WRITELOG("TLSStack::recv() default %s\n", errmsg);
|
||||
_busy = false;
|
||||
_mutex.unlock();
|
||||
return -1;
|
||||
}
|
||||
} while (SSL_pending(_ssl) && !readBlocked);
|
||||
|
||||
bpos += rlen;
|
||||
while (true)
|
||||
{
|
||||
FD_ZERO(&rset);
|
||||
FD_ZERO(&wset);
|
||||
FD_SET(getSock(), &rset);
|
||||
FD_SET(getSock(), &wset);
|
||||
|
||||
int activity = select(getSock() + 1, &rset, &wset, 0, 0);
|
||||
if (activity > 0)
|
||||
{
|
||||
if ((FD_ISSET(getSock(),&rset) && !writeBlockedOnRead)
|
||||
|| (readBlockedOnWrite && FD_ISSET(getSock(), &wset)))
|
||||
{
|
||||
goto loop;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
|
||||
WRITELOG("TLSStack::recv() select %s\n", errmsg);
|
||||
_busy = false;
|
||||
_mutex.unlock();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TCPStack::recv(buf, len);
|
||||
}
|
||||
|
||||
bool Network::isValid()
|
||||
{
|
||||
if (!_secureFlg)
|
||||
{
|
||||
return TCPStack::isValid();
|
||||
}
|
||||
if (_ssl)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Network::disconnect()
|
||||
{
|
||||
if (_ssl)
|
||||
{
|
||||
SSL_shutdown(_ssl);
|
||||
_ssl = 0;
|
||||
TCPStack::close();
|
||||
}
|
||||
else
|
||||
{
|
||||
TCPStack::close();
|
||||
}
|
||||
}
|
||||
|
||||
int Network::getSock()
|
||||
{
|
||||
return TCPStack::getSock();
|
||||
}
|
||||
|
||||
SSL* Network::getSSL()
|
||||
{
|
||||
if (_secureFlg)
|
||||
{
|
||||
return _ssl;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool Network::isSecure()
|
||||
{
|
||||
return _secureFlg;
|
||||
}
|
||||
|
||||
95
MQTTSNGateway/src/linux/Network.h
Normal file
95
MQTTSNGateway/src/linux/Network.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#ifndef NETWORK_H_
|
||||
#define NETWORK_H_
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <resolv.h>
|
||||
#include <netdb.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "Threading.h"
|
||||
#include "MQTTSNGWDefines.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
/*========================================
|
||||
Class TCPStack
|
||||
=======================================*/
|
||||
class TCPStack
|
||||
{
|
||||
public:
|
||||
TCPStack();
|
||||
virtual ~TCPStack();
|
||||
|
||||
// Server initialization
|
||||
bool bind(const char* service);
|
||||
bool listen();
|
||||
bool accept(TCPStack&);
|
||||
|
||||
// Client initialization
|
||||
bool connect(const char* host, const char* service);
|
||||
|
||||
int send(const uint8_t* buf, int length);
|
||||
int recv(uint8_t* buf, int len);
|
||||
void close();
|
||||
|
||||
void setNonBlocking(const bool);
|
||||
|
||||
bool isValid();
|
||||
int getSock();
|
||||
|
||||
private:
|
||||
int _sockfd;
|
||||
addrinfo* _addrinfo;
|
||||
};
|
||||
|
||||
/*========================================
|
||||
Class Network
|
||||
=======================================*/
|
||||
class Network: public TCPStack
|
||||
{
|
||||
public:
|
||||
Network(bool secure);
|
||||
virtual ~Network();
|
||||
|
||||
bool connect(const char* host, const char* service);
|
||||
void disconnect();
|
||||
int send(const uint8_t* buf, uint16_t length);
|
||||
int recv(uint8_t* buf, uint16_t len);
|
||||
|
||||
bool isValid();
|
||||
bool isSecure();
|
||||
int getSock();
|
||||
SSL* getSSL();
|
||||
|
||||
private:
|
||||
static SSL_CTX* _ctx;
|
||||
static int _numOfInstance;
|
||||
static SSL_SESSION* _session;
|
||||
|
||||
SSL* _ssl;
|
||||
bool _secureFlg;
|
||||
bool _disconReq;
|
||||
Mutex _mutex;
|
||||
bool _busy;
|
||||
};
|
||||
|
||||
#endif /* NETWORK_H_ */
|
||||
502
MQTTSNGateway/src/linux/Threading.cpp
Normal file
502
MQTTSNGateway/src/linux/Threading.cpp
Normal file
@@ -0,0 +1,502 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include "MQTTSNGWProcess.h"
|
||||
#include "Threading.h"
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/stat.h>
|
||||
#include <semaphore.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
/*=====================================
|
||||
Class Mutex
|
||||
=====================================*/
|
||||
|
||||
Mutex::Mutex(void)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutex_init(&_mutex, &attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
_shmid = 0;
|
||||
_pmutex = 0;
|
||||
}
|
||||
|
||||
Mutex::Mutex(const char* fileName)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
key_t key = ftok(fileName, 1);
|
||||
|
||||
if ((_shmid = shmget(key, sizeof(pthread_mutex_t), IPC_CREAT | 0666)) < 0)
|
||||
{
|
||||
throw Exception( -1, "Mutex can't create a shared memory.");
|
||||
}
|
||||
_pmutex = (pthread_mutex_t*) shmat(_shmid, NULL, 0);
|
||||
if (_pmutex < 0)
|
||||
{
|
||||
throw Exception( -1, "Mutex can't attach shared memory.");
|
||||
}
|
||||
|
||||
pthread_mutexattr_init(&attr);
|
||||
|
||||
if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED) != 0)
|
||||
{
|
||||
throw Exception( -1, "Mutex can't set the process-shared flag");
|
||||
}
|
||||
if (pthread_mutex_init(_pmutex, &attr) != 0)
|
||||
{
|
||||
throw Exception( -1, "Mutex can't initialize.");
|
||||
}
|
||||
}
|
||||
|
||||
Mutex::~Mutex(void)
|
||||
{
|
||||
if (_pmutex)
|
||||
{
|
||||
pthread_mutex_lock(_pmutex);
|
||||
pthread_mutex_unlock(_pmutex);
|
||||
pthread_mutex_destroy(_pmutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_mutex_lock(&_mutex);
|
||||
pthread_mutex_unlock(&_mutex);
|
||||
pthread_mutex_destroy(&_mutex);
|
||||
}
|
||||
if (_shmid)
|
||||
{
|
||||
shmctl(_shmid, IPC_RMID, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void Mutex::lock(void)
|
||||
{
|
||||
if (_pmutex)
|
||||
{
|
||||
pthread_mutex_lock(_pmutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pthread_mutex_lock(&_mutex))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
} catch (char* errmsg)
|
||||
{
|
||||
throw Exception( -1, "The same thread can't aquire a mutex twice.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mutex::unlock(void)
|
||||
{
|
||||
|
||||
if (_pmutex)
|
||||
{
|
||||
pthread_mutex_unlock(_pmutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pthread_mutex_unlock(&_mutex))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
} catch (char* errmsg)
|
||||
{
|
||||
throw Exception( -1, "Mutex can't unlock.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*=====================================
|
||||
Class Semaphore
|
||||
=====================================*/
|
||||
|
||||
Semaphore::Semaphore()
|
||||
{
|
||||
sem_init(&_sem, 0, 0);
|
||||
_name = 0;
|
||||
_psem = 0;
|
||||
}
|
||||
|
||||
Semaphore::Semaphore(unsigned int val)
|
||||
{
|
||||
sem_init(&_sem, 0, val);
|
||||
_name = 0;
|
||||
_psem = 0;
|
||||
}
|
||||
|
||||
Semaphore::Semaphore(const char* name, unsigned int val)
|
||||
{
|
||||
_psem = sem_open(name, O_CREAT, 0666, val);
|
||||
if (_psem == SEM_FAILED)
|
||||
{
|
||||
throw Exception( -1, "Semaphore can't be created.");
|
||||
}
|
||||
_name = (char*) calloc(strlen(name + 1), 1);
|
||||
if (_name == NULL)
|
||||
{
|
||||
throw Exception( -1, "Semaphore can't allocate memories.");
|
||||
}
|
||||
_name = strdup(name);
|
||||
}
|
||||
|
||||
Semaphore::~Semaphore()
|
||||
{
|
||||
if (_name)
|
||||
{
|
||||
sem_close(_psem);
|
||||
sem_unlink(_name);
|
||||
free((void*) _name);
|
||||
}
|
||||
else
|
||||
{
|
||||
sem_destroy(&_sem);
|
||||
}
|
||||
}
|
||||
|
||||
void Semaphore::post(void)
|
||||
{
|
||||
int val = 0;
|
||||
if (_psem)
|
||||
{
|
||||
sem_getvalue(_psem, &val);
|
||||
if (val <= 0)
|
||||
{
|
||||
sem_post(_psem);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sem_getvalue(&_sem, &val);
|
||||
if (val <= 0)
|
||||
{
|
||||
sem_post(&_sem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Semaphore::wait(void)
|
||||
{
|
||||
if (_psem)
|
||||
{
|
||||
sem_wait(_psem);
|
||||
}
|
||||
else
|
||||
{
|
||||
sem_wait(&_sem);
|
||||
}
|
||||
}
|
||||
|
||||
void Semaphore::timedwait(uint16_t millsec)
|
||||
{
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
ts.tv_sec += millsec / 1000;
|
||||
ts.tv_nsec = (millsec % 1000) * 1000000;
|
||||
if (_psem)
|
||||
{
|
||||
sem_timedwait(_psem, &ts);
|
||||
}
|
||||
else
|
||||
{
|
||||
sem_timedwait(&_sem, &ts);
|
||||
}
|
||||
}
|
||||
|
||||
/*=========================================
|
||||
Class RingBuffer
|
||||
=========================================*/
|
||||
RingBuffer::RingBuffer()
|
||||
{
|
||||
key_t key = ftok(MQTTSNGW_RINGBUFFER_KEY, 1);
|
||||
|
||||
if ((_shmid = shmget(key, PROCESS_LOG_BUFFER_SIZE,
|
||||
IPC_CREAT | IPC_EXCL | 0666)) >= 0)
|
||||
{
|
||||
if ((_shmaddr = (uint16_t*) shmat(_shmid, NULL, 0)) > 0)
|
||||
{
|
||||
_length = (uint16_t*) _shmaddr;
|
||||
_start = (uint16_t*) _length + sizeof(uint16_t*);
|
||||
_end = (uint16_t*) _start + sizeof(uint16_t*);
|
||||
_buffer = (char*) _end + sizeof(uint16_t*);
|
||||
_createFlg = true;
|
||||
|
||||
*_length = PROCESS_LOG_BUFFER_SIZE - sizeof(uint16_t*) * 3 - 16;
|
||||
*_start = *_end = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Exception(-1, "RingBuffer can't attach shared memory.");
|
||||
}
|
||||
}
|
||||
else if ((_shmid = shmget(key, PROCESS_LOG_BUFFER_SIZE, IPC_CREAT | 0666)) >= 0)
|
||||
{
|
||||
if ((_shmaddr = (uint16_t*) shmat(_shmid, NULL, 0)) > 0)
|
||||
{
|
||||
_length = (uint16_t*) _shmaddr;
|
||||
_start = (uint16_t*) _length + sizeof(uint16_t*);
|
||||
_end = (uint16_t*) _start + sizeof(uint16_t*);
|
||||
_buffer = (char*) _end + sizeof(uint16_t*);
|
||||
_createFlg = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Exception(-1, "RingBuffer can't create a shared memory.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Exception(-1, "RingBuffer can't create a shared memory.");
|
||||
}
|
||||
|
||||
_pmx = new Mutex(MQTTSNGW_RB_MUTEX_KEY);
|
||||
}
|
||||
|
||||
RingBuffer::~RingBuffer()
|
||||
{
|
||||
if (_createFlg)
|
||||
{
|
||||
if (_shmid > 0)
|
||||
{
|
||||
shmctl(_shmid, IPC_RMID, NULL);
|
||||
}
|
||||
if (_pmx > 0)
|
||||
{
|
||||
delete _pmx;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_shmid > 0)
|
||||
{
|
||||
shmdt(_shmaddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RingBuffer::put(char* data)
|
||||
{
|
||||
_pmx->lock();
|
||||
|
||||
uint16_t dlen = strlen(data);
|
||||
uint16_t blen = *_length - *_end;
|
||||
|
||||
if (*_end > *_start)
|
||||
{
|
||||
if (dlen < blen)
|
||||
{
|
||||
strncpy(_buffer + *_end, data, dlen);
|
||||
if (*_end - *_start == 1)
|
||||
{ // Buffer is empty.
|
||||
*_start = *_end;
|
||||
}
|
||||
*_end += dlen;
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(_buffer + *_end, data, blen);
|
||||
strncpy(_buffer, data + blen, dlen - blen);
|
||||
if (*_end - *_start == 1)
|
||||
{ // Buffer is empty.
|
||||
*_start = *_end;
|
||||
*_end = dlen - blen;
|
||||
}
|
||||
else
|
||||
{
|
||||
*_end = dlen - blen;
|
||||
*_start = *_end + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (*_end == *_start)
|
||||
{
|
||||
if (dlen < blen)
|
||||
{
|
||||
strncpy(_buffer + *_end, data, dlen);
|
||||
*_end += dlen;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* errmsg = "RingBuffer Error: data is too long";
|
||||
strcpy(_buffer + *_end, errmsg);
|
||||
*_end += strlen(errmsg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // *_end < *_start
|
||||
if (dlen < *_start - *_end)
|
||||
{
|
||||
strncpy(_buffer + *_end, data, dlen);
|
||||
*_end += dlen;
|
||||
*_start = *_end + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dlen < blen)
|
||||
{
|
||||
strncpy(_buffer + *_end, data, dlen);
|
||||
*_end += dlen;
|
||||
*_start = *_end + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(_buffer + *_end, data, blen);
|
||||
strncpy(_buffer, data + blen, dlen - blen);
|
||||
*_start = *_end;
|
||||
*_end = dlen - blen;
|
||||
}
|
||||
}
|
||||
}
|
||||
_pmx->unlock();
|
||||
}
|
||||
|
||||
int RingBuffer::get(char* buf, int length)
|
||||
{
|
||||
int len = 0;
|
||||
_pmx->lock();
|
||||
|
||||
if (*_end > *_start)
|
||||
{
|
||||
if (length > *_end - *_start)
|
||||
{
|
||||
len = *_end - *_start;
|
||||
if (len == 1)
|
||||
{
|
||||
len = 0;
|
||||
}
|
||||
strncpy(buf, _buffer + *_start, len);
|
||||
*_start = *_end - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = length;
|
||||
strncpy(buf, _buffer + *_start, len);
|
||||
*_start = *_start + len;
|
||||
}
|
||||
}
|
||||
else if (*_end < *_start)
|
||||
{
|
||||
int blen = *_length - *_start;
|
||||
if (length > blen)
|
||||
{
|
||||
strncpy(buf, _buffer + *_start, blen);
|
||||
*_start = 0;
|
||||
if (length - (blen + *_end) > 0)
|
||||
{
|
||||
strncpy(buf + blen, _buffer, *_end);
|
||||
len = blen + *_end;
|
||||
if (*_end > 0)
|
||||
{
|
||||
*_start = *_end - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(buf + blen, _buffer, length - blen);
|
||||
len = length;
|
||||
*_start = length - blen;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(buf, _buffer + *_start, length);
|
||||
*_start += length;
|
||||
len = length;
|
||||
}
|
||||
}
|
||||
_pmx->unlock();
|
||||
return len;
|
||||
}
|
||||
|
||||
void RingBuffer::reset()
|
||||
{
|
||||
_pmx->lock();
|
||||
if ( _start && _end )
|
||||
{
|
||||
*_start = *_end = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Exception(-1, "RingBuffer can't reset. need to clear shared memory.");
|
||||
}
|
||||
_pmx->unlock();
|
||||
}
|
||||
|
||||
/*=====================================
|
||||
Class Thread
|
||||
=====================================*/
|
||||
Thread::Thread()
|
||||
{
|
||||
_stopProcessEvent = theMultiTaskProcess->getStopProcessEvent();
|
||||
_threadID = 0;
|
||||
}
|
||||
|
||||
Thread::~Thread()
|
||||
{
|
||||
pthread_cancel(_threadID);
|
||||
pthread_join(_threadID, 0);
|
||||
}
|
||||
|
||||
void* Thread::_run(void* runnable)
|
||||
{
|
||||
static_cast<Runnable*>(runnable)->EXECRUN();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Thread::initialize(int argc, char** argv)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
pthread_t Thread::getID()
|
||||
{
|
||||
return pthread_self();
|
||||
}
|
||||
|
||||
bool Thread::equals(pthread_t *t1, pthread_t *t2)
|
||||
{
|
||||
return (pthread_equal(*t1, *t2) ? false : true);
|
||||
}
|
||||
|
||||
int Thread::start(void)
|
||||
{
|
||||
Runnable *runnable = this;
|
||||
return pthread_create(&_threadID, 0, _run, runnable);
|
||||
}
|
||||
|
||||
void Thread::stopProcess(void)
|
||||
{
|
||||
_stopProcessEvent->post();
|
||||
}
|
||||
|
||||
void Thread::testThreadCancel(void)
|
||||
{
|
||||
pthread_testcancel();
|
||||
}
|
||||
@@ -1,36 +1,145 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#ifndef THREADING_H_
|
||||
#define THREADING_H_
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "Thread.h"
|
||||
}
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include "MQTTSNGWDefines.h"
|
||||
|
||||
|
||||
class Thread
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
|
||||
/*
|
||||
Thread(void (*fn)(void const *argument), void *argument)
|
||||
{
|
||||
Thread_start(fn, arg);
|
||||
}*/
|
||||
|
||||
public:
|
||||
|
||||
Thread(void (*fn)(void const *argument))
|
||||
{
|
||||
const void* arg = NULL;
|
||||
|
||||
//Thread_start((void (*)(void *))fn, arg);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define MQTTSNGW_RINGBUFFER_KEY "/usr/local/etc/mqttsnGateway/config/ringbuffer.key"
|
||||
#define MQTTSNGW_RB_MUTEX_KEY "/usr/local/etc/mqttsnGateway/config/rbmutex.key"
|
||||
#define MQTTSNGW_RB_SEMAPHOR_NAME "/rbsemaphor"
|
||||
|
||||
/*=====================================
|
||||
Class Mutex
|
||||
====================================*/
|
||||
class Mutex
|
||||
{
|
||||
public:
|
||||
Mutex();
|
||||
Mutex(const char* name);
|
||||
~Mutex();
|
||||
void lock(void);
|
||||
void unlock(void);
|
||||
|
||||
private:
|
||||
pthread_mutex_t _mutex;
|
||||
pthread_mutex_t* _pmutex;
|
||||
int _shmid;
|
||||
};
|
||||
|
||||
/*=====================================
|
||||
Class Semaphore
|
||||
====================================*/
|
||||
class Semaphore
|
||||
{
|
||||
public:
|
||||
Semaphore();
|
||||
Semaphore(unsigned int val);
|
||||
Semaphore(const char* name, unsigned int val);
|
||||
~Semaphore();
|
||||
void post(void);
|
||||
void wait(void);
|
||||
void timedwait(uint16_t millsec);
|
||||
|
||||
private:
|
||||
sem_t* _psem;
|
||||
sem_t _sem;
|
||||
char* _name;
|
||||
};
|
||||
|
||||
/*=====================================
|
||||
Class RingBuffer
|
||||
=====================================*/
|
||||
class RingBuffer
|
||||
{
|
||||
public:
|
||||
RingBuffer();
|
||||
~RingBuffer();
|
||||
void put(char* buffer);
|
||||
int get(char* buffer, int bufferLength);
|
||||
void reset();
|
||||
private:
|
||||
void* _shmaddr;
|
||||
uint16_t* _length;
|
||||
uint16_t* _start;
|
||||
uint16_t* _end;
|
||||
char* _buffer;
|
||||
int _shmid;
|
||||
Mutex* _pmx;
|
||||
bool _createFlg;
|
||||
};
|
||||
|
||||
|
||||
/*=====================================
|
||||
Class Runnable
|
||||
====================================*/
|
||||
class Runnable
|
||||
{
|
||||
public:
|
||||
Runnable(){}
|
||||
virtual ~Runnable(){}
|
||||
virtual void EXECRUN(){}
|
||||
};
|
||||
|
||||
|
||||
#define MAGIC_WORD_FOR_THREAD \
|
||||
public: void EXECRUN() \
|
||||
{ \
|
||||
try \
|
||||
{ \
|
||||
run(); \
|
||||
} \
|
||||
catch(Exception& ex) \
|
||||
{ \
|
||||
ex.writeMessage();\
|
||||
stopProcess(); \
|
||||
} \
|
||||
catch(...) \
|
||||
{ \
|
||||
throw; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*=====================================
|
||||
Class Thread
|
||||
====================================*/
|
||||
class Thread : virtual public Runnable{
|
||||
public:
|
||||
Thread();
|
||||
~Thread();
|
||||
int start(void);
|
||||
static pthread_t getID();
|
||||
static bool equals(pthread_t*, pthread_t*);
|
||||
virtual void initialize(int argc, char** argv);
|
||||
void stopProcess(void);
|
||||
void testThreadCancel(void);
|
||||
private:
|
||||
pthread_t _threadID;
|
||||
Semaphore* _stopProcessEvent;
|
||||
|
||||
static void* _run(void*);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* THREADING_H_ */
|
||||
|
||||
222
MQTTSNGateway/src/linux/Timer.cpp
Normal file
222
MQTTSNGateway/src/linux/Timer.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include "Timer.h"
|
||||
#include "MQTTSNGWDefines.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
/*=====================================
|
||||
Print Current Date & Time
|
||||
=====================================*/
|
||||
char theCurrentTime[32];
|
||||
|
||||
char* currentDateTime()
|
||||
{
|
||||
struct timeval now;
|
||||
struct tm tstruct;
|
||||
gettimeofday(&now, 0);
|
||||
tstruct = *localtime(&now.tv_sec);
|
||||
strftime(theCurrentTime, sizeof(theCurrentTime), "%Y%m%d %H%M%S", &tstruct);
|
||||
sprintf(theCurrentTime + 15, " %03d", (int)now.tv_usec / 1000 );
|
||||
return theCurrentTime;
|
||||
}
|
||||
|
||||
/*============================================
|
||||
Timer
|
||||
============================================*/
|
||||
Timer::Timer(void)
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
Timer::~Timer(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Timer::start(uint32_t msecs)
|
||||
{
|
||||
gettimeofday(&_startTime, 0);
|
||||
_millis = msecs;
|
||||
}
|
||||
|
||||
bool Timer::isTimeup(void)
|
||||
{
|
||||
return isTimeup(_millis);
|
||||
}
|
||||
|
||||
bool Timer::isTimeup(uint32_t msecs)
|
||||
{
|
||||
struct timeval curTime;
|
||||
long secs, usecs;
|
||||
if (_startTime.tv_sec == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
gettimeofday(&curTime, 0);
|
||||
secs = (curTime.tv_sec - _startTime.tv_sec) * 1000;
|
||||
usecs = (curTime.tv_usec - _startTime.tv_usec) / 1000.0;
|
||||
return ((secs + usecs) > (long) msecs);
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::stop()
|
||||
{
|
||||
_startTime.tv_sec = 0;
|
||||
_millis = 0;
|
||||
}
|
||||
|
||||
/*=====================================
|
||||
Class LightIndicator
|
||||
=====================================*/
|
||||
|
||||
LightIndicator::LightIndicator()
|
||||
{
|
||||
_greenStatus = false;
|
||||
for ( int i = 0; i <= MAX_GPIO; i++)
|
||||
{
|
||||
_gpio[i] = 0;
|
||||
}
|
||||
init();
|
||||
}
|
||||
|
||||
LightIndicator::~LightIndicator()
|
||||
{
|
||||
for ( int i = 0; i <= MAX_GPIO; i++)
|
||||
{
|
||||
if ( _gpio[i] )
|
||||
{
|
||||
close( _gpio[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LightIndicator::greenLight(bool on)
|
||||
{
|
||||
if (on)
|
||||
{
|
||||
if (!_greenStatus)
|
||||
{
|
||||
_greenStatus = true;
|
||||
//Turn Green on & turn Red off
|
||||
lit(LIGHT_INDICATOR_GREEN, "1");
|
||||
lit(LIGHT_INDICATOR_RED, "0");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_greenStatus)
|
||||
{
|
||||
_greenStatus = false;
|
||||
//Turn Green off & turn Red on
|
||||
lit(LIGHT_INDICATOR_GREEN, "0");
|
||||
lit(LIGHT_INDICATOR_RED, "1");
|
||||
}
|
||||
}
|
||||
}
|
||||
void LightIndicator::blueLight(bool on)
|
||||
{
|
||||
if (on)
|
||||
{
|
||||
lit(LIGHT_INDICATOR_BLUE, "1");
|
||||
if ( !_greenStatus )
|
||||
{
|
||||
greenLight(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lit(LIGHT_INDICATOR_BLUE, "0");
|
||||
}
|
||||
}
|
||||
|
||||
void LightIndicator::redLight(bool on)
|
||||
{
|
||||
if (on)
|
||||
{
|
||||
lit(LIGHT_INDICATOR_RED, "1");
|
||||
}
|
||||
else
|
||||
{
|
||||
lit(LIGHT_INDICATOR_RED, "0");
|
||||
}
|
||||
}
|
||||
|
||||
void LightIndicator::allLightOff(void)
|
||||
{
|
||||
lit(LIGHT_INDICATOR_RED, "0");
|
||||
lit(LIGHT_INDICATOR_BLUE, "0");
|
||||
lit(LIGHT_INDICATOR_GREEN, "0");
|
||||
_greenStatus = false;
|
||||
}
|
||||
|
||||
void LightIndicator::init()
|
||||
{
|
||||
pinMode(LIGHT_INDICATOR_GREEN);
|
||||
pinMode(LIGHT_INDICATOR_RED);
|
||||
pinMode(LIGHT_INDICATOR_BLUE);
|
||||
}
|
||||
|
||||
void LightIndicator::lit(int gpioNo, const char* onoff)
|
||||
{
|
||||
if( _gpio[gpioNo] )
|
||||
{
|
||||
write(_gpio[gpioNo], onoff, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void LightIndicator::pinMode(int gpioNo)
|
||||
{
|
||||
int fd = open("/sys/class/gpio/export", O_WRONLY);
|
||||
if ( fd < 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
char no[4];
|
||||
sprintf(no,"%d", gpioNo);
|
||||
write(fd, no, strlen(no));
|
||||
close(fd);
|
||||
|
||||
char fileName[64];
|
||||
sprintf( fileName, "/sys/class/gpio/gpio%d/direction", gpioNo);
|
||||
|
||||
fd = open(fileName, O_WRONLY);
|
||||
if ( fd < 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
write(fd,"out", 3);
|
||||
close(fd);
|
||||
|
||||
sprintf( fileName, "/sys/class/gpio/gpio%d/value", gpioNo);
|
||||
fd = open(fileName, O_WRONLY);
|
||||
if ( fd > 0 )
|
||||
{
|
||||
_gpio[gpioNo] = fd;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
72
MQTTSNGateway/src/linux/Timer.h
Normal file
72
MQTTSNGateway/src/linux/Timer.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation
|
||||
**************************************************************************************/
|
||||
#ifndef MQTTSNGATEWAY_SRC_LINUX_TIMER_H_
|
||||
#define MQTTSNGATEWAY_SRC_LINUX_TIMER_H_
|
||||
|
||||
#include "MQTTSNGWDefines.h"
|
||||
#include <time.h>
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
/*==========================================================
|
||||
* Light Indicators
|
||||
===========================================================*/
|
||||
#define MAX_GPIO 27 // GPIO02 - GPIO27
|
||||
#define LIGHT_INDICATOR_GREEN 23 // RPi connector 16
|
||||
#define LIGHT_INDICATOR_RED 24 // RPi connector 18
|
||||
#define LIGHT_INDICATOR_BLUE 25 // RPi connector 22
|
||||
|
||||
/*============================================
|
||||
Timer
|
||||
============================================*/
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
Timer(void);
|
||||
~Timer(void);
|
||||
void start(uint32_t msecs = 0);
|
||||
bool isTimeup(void);
|
||||
bool isTimeup(uint32_t msecs);
|
||||
void stop();
|
||||
|
||||
private:
|
||||
struct timeval _startTime;
|
||||
uint32_t _millis;
|
||||
};
|
||||
|
||||
/*=====================================
|
||||
Class LightIndicator
|
||||
=====================================*/
|
||||
class LightIndicator
|
||||
{
|
||||
public:
|
||||
LightIndicator();
|
||||
~LightIndicator();
|
||||
void greenLight(bool on);
|
||||
void blueLight(bool on);
|
||||
void redLight(bool on);
|
||||
void allLightOff(void);
|
||||
|
||||
private:
|
||||
void init();
|
||||
void lit(int gpioNo, const char* onoff);
|
||||
void pinMode(int gpioNo);
|
||||
bool _greenStatus;
|
||||
int _gpio[MAX_GPIO + 1];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* MQTTSNGATEWAY_SRC_LINUX_TIMER_H_ */
|
||||
@@ -1,2 +0,0 @@
|
||||
g++ main.cpp -I MQTTPacket/src -I MQTTSNPacket/src -I linux MQTTPacket/src/*.c MQTTSNPacket/src/*.c
|
||||
|
||||
@@ -1,224 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014, 2015 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
class IPStack
|
||||
{
|
||||
public:
|
||||
IPStack()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int Socket_error(const char* aString)
|
||||
{
|
||||
int rc = 0;
|
||||
//if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS && errno != EWOULDBLOCK)
|
||||
//{
|
||||
if (strcmp(aString, "shutdown") != 0 || (errno != ENOTCONN && errno != ECONNRESET))
|
||||
{
|
||||
if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS && errno != EWOULDBLOCK)
|
||||
printf("Socket error %s in %s for socket %d\n", strerror(errno), aString, mysock);
|
||||
rc = errno;
|
||||
}
|
||||
//}
|
||||
return errno;
|
||||
}
|
||||
|
||||
int connect(const char* hostname, int port)
|
||||
{
|
||||
int type = SOCK_STREAM;
|
||||
struct sockaddr_in address;
|
||||
int rc = -1;
|
||||
sa_family_t family = AF_INET;
|
||||
struct addrinfo *result = NULL;
|
||||
struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL};
|
||||
|
||||
if ((rc = getaddrinfo(hostname, NULL, &hints, &result)) == 0)
|
||||
{
|
||||
struct addrinfo* res = result;
|
||||
|
||||
/* prefer ip4 addresses */
|
||||
while (res)
|
||||
{
|
||||
if (res->ai_family == AF_INET)
|
||||
{
|
||||
result = res;
|
||||
break;
|
||||
}
|
||||
res = res->ai_next;
|
||||
}
|
||||
|
||||
if (result->ai_family == AF_INET)
|
||||
{
|
||||
address.sin_port = htons(port);
|
||||
address.sin_family = family = AF_INET;
|
||||
address.sin_addr = ((struct sockaddr_in*)(result->ai_addr))->sin_addr;
|
||||
}
|
||||
else
|
||||
rc = -1;
|
||||
|
||||
freeaddrinfo(result);
|
||||
}
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
mysock = socket(family, type, 0);
|
||||
if (mysock != -1)
|
||||
{
|
||||
int opt = 1;
|
||||
|
||||
//if (setsockopt(mysock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&opt, sizeof(opt)) != 0)
|
||||
// printf("Could not set SO_NOSIGPIPE for socket %d", mysock);
|
||||
|
||||
rc = ::connect(mysock, (struct sockaddr*)&address, sizeof(address));
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int read(unsigned char* buffer, int len, int timeout_ms)
|
||||
{
|
||||
struct timeval interval = {timeout_ms / 1000, (timeout_ms % 1000) * 1000};
|
||||
if (interval.tv_sec < 0 || (interval.tv_sec == 0 && interval.tv_usec <= 0))
|
||||
{
|
||||
interval.tv_sec = 0;
|
||||
interval.tv_usec = 100;
|
||||
}
|
||||
|
||||
setsockopt(mysock, SOL_SOCKET, SO_RCVTIMEO, (char *)&interval, sizeof(struct timeval));
|
||||
|
||||
int bytes = 0;
|
||||
while (bytes < len)
|
||||
{
|
||||
int rc = ::recv(mysock, &buffer[bytes], (size_t)(len - bytes), 0);
|
||||
if (rc == -1)
|
||||
{
|
||||
if (Socket_error("read") != 0)
|
||||
{
|
||||
bytes = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
bytes += rc;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
int write(unsigned char* buffer, int len, int timeout)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = 0; /* 30 Secs Timeout */
|
||||
tv.tv_usec = timeout * 1000; // Not init'ing this can cause strange errors
|
||||
|
||||
setsockopt(mysock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
|
||||
int rc = ::write(mysock, buffer, len);
|
||||
//printf("write rc %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int disconnect()
|
||||
{
|
||||
return ::close(mysock);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
int mysock;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class Countdown
|
||||
{
|
||||
public:
|
||||
Countdown()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Countdown(int ms)
|
||||
{
|
||||
countdown_ms(ms);
|
||||
}
|
||||
|
||||
|
||||
bool expired()
|
||||
{
|
||||
struct timeval now, res;
|
||||
gettimeofday(&now, NULL);
|
||||
timersub(&end_time, &now, &res);
|
||||
//printf("left %d ms\n", (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000);
|
||||
//if (res.tv_sec > 0 || res.tv_usec > 0)
|
||||
// printf("expired %d %d\n", res.tv_sec, res.tv_usec);
|
||||
return res.tv_sec < 0 || (res.tv_sec == 0 && res.tv_usec <= 0);
|
||||
}
|
||||
|
||||
|
||||
void countdown_ms(int ms)
|
||||
{
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
struct timeval interval = {ms / 1000, (ms % 1000) * 1000};
|
||||
//printf("interval %d %d\n", interval.tv_sec, interval.tv_usec);
|
||||
timeradd(&now, &interval, &end_time);
|
||||
}
|
||||
|
||||
|
||||
void countdown(int seconds)
|
||||
{
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
struct timeval interval = {seconds, 0};
|
||||
timeradd(&now, &interval, &end_time);
|
||||
}
|
||||
|
||||
|
||||
int left_ms()
|
||||
{
|
||||
struct timeval now, res;
|
||||
gettimeofday(&now, NULL);
|
||||
timersub(&end_time, &now, &res);
|
||||
//printf("left %d ms\n", (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000);
|
||||
return (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct timeval end_time;
|
||||
};
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
|
||||
#include "Threading.h"
|
||||
|
||||
//#include "MQTTSNUDP.h"
|
||||
//#include "MQTTEthernet.h"
|
||||
#include "linux.cpp"
|
||||
#include "MQTTSNGateway.h"
|
||||
|
||||
MQTTSN::Parms parms();
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
// set up MQTT-SN network listening
|
||||
UDPStack net;
|
||||
net.listen(1884);
|
||||
|
||||
MQTTSN::Gateway<UDPStack, IPStack, Countdown, Thread, Mutex> gateway =
|
||||
MQTTSN::Gateway<UDPStack, IPStack, Countdown, Thread, Mutex>(net);
|
||||
|
||||
gateway.run(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
336
MQTTSNGateway/src/linux/udp/SensorNetwork.cpp
Normal file
336
MQTTSNGateway/src/linux/udp/SensorNetwork.cpp
Normal file
@@ -0,0 +1,336 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
#include "SensorNetwork.h"
|
||||
#include "MQTTSNGWProcess.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
/*===========================================
|
||||
Class SensorNetAddreess
|
||||
============================================*/
|
||||
SensorNetAddress::SensorNetAddress()
|
||||
{
|
||||
_portNo = 0;
|
||||
_IpAddr = 0;
|
||||
}
|
||||
|
||||
SensorNetAddress::~SensorNetAddress()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SensorNetAddress::setAddress(uint32_t IpAddr, uint16_t port)
|
||||
{
|
||||
_IpAddr = IpAddr;
|
||||
_portNo = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert Text data to SensorNetAddress
|
||||
* @param buf is pointer of PortNo@IP_Address format text
|
||||
* @return success = 0, Invalid format = -1
|
||||
*/
|
||||
int SensorNetAddress::setAddress(string* data)
|
||||
{
|
||||
size_t pos = data->find_first_of("@");
|
||||
|
||||
if ( pos == string::npos )
|
||||
{
|
||||
_portNo = 0;
|
||||
_IpAddr = INADDR_NONE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
string port = data->substr(0, pos);
|
||||
string ip = data->substr(pos + 1);
|
||||
int portNo = 0;
|
||||
|
||||
if ((portNo = atoi(port.c_str())) == 0 || (_IpAddr = inet_addr(ip.c_str())) == INADDR_NONE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
_portNo = htons(portNo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SensorNetAddress::isMatch(SensorNetAddress* addr)
|
||||
{
|
||||
return ((this->_portNo == addr->_portNo) && (this->_IpAddr == addr->_IpAddr));
|
||||
}
|
||||
|
||||
SensorNetAddress& SensorNetAddress::operator =(SensorNetAddress& addr)
|
||||
{
|
||||
this->_portNo = addr._portNo;
|
||||
this->_IpAddr = addr._IpAddr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*===========================================
|
||||
Class SensorNetwork
|
||||
============================================*/
|
||||
SensorNetwork::SensorNetwork()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SensorNetwork::~SensorNetwork()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int SensorNetwork::unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendToAddr)
|
||||
{
|
||||
return UDPPort::unicast(payload, payloadLength, sendToAddr);
|
||||
}
|
||||
|
||||
int SensorNetwork::broadcast(const uint8_t* payload, uint16_t payloadLength)
|
||||
{
|
||||
return UDPPort::broadcast(payload, payloadLength);
|
||||
}
|
||||
|
||||
int SensorNetwork::read(uint8_t* buf, uint16_t bufLen)
|
||||
{
|
||||
return UDPPort::recv(buf, bufLen, &_clientAddr);
|
||||
}
|
||||
|
||||
int SensorNetwork::initialize(void)
|
||||
{
|
||||
char param[MQTTSNGW_PARAM_MAX];
|
||||
uint16_t multicastPortNo = 0;
|
||||
uint16_t unicastPortNo = 0;
|
||||
|
||||
if (theProcess->getParam("MulticastPortNo", param) == 0)
|
||||
{
|
||||
multicastPortNo = atoi(param);
|
||||
}
|
||||
if (theProcess->getParam("GatewayPortNo", param) == 0)
|
||||
{
|
||||
unicastPortNo = atoi(param);
|
||||
}
|
||||
|
||||
theProcess->getParam("MulticastIP", param);
|
||||
return UDPPort::open(param, multicastPortNo, unicastPortNo);
|
||||
}
|
||||
|
||||
const char* SensorNetwork::getType(void)
|
||||
{
|
||||
return "UDP";
|
||||
}
|
||||
|
||||
/*=========================================
|
||||
Class udpStack
|
||||
=========================================*/
|
||||
|
||||
UDPPort::UDPPort()
|
||||
{
|
||||
_disconReq = false;
|
||||
_sockfdUnicast = -1;
|
||||
_sockfdMulticast = -1;
|
||||
}
|
||||
|
||||
UDPPort::~UDPPort()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void UDPPort::close(void)
|
||||
{
|
||||
if (_sockfdUnicast > 0)
|
||||
{
|
||||
::close(_sockfdUnicast);
|
||||
_sockfdUnicast = -1;
|
||||
}
|
||||
if (_sockfdMulticast > 0)
|
||||
{
|
||||
::close(_sockfdMulticast);
|
||||
_sockfdMulticast = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int UDPPort::open(char* ipAddress, uint16_t multiPortNo, uint16_t uniPortNo)
|
||||
{
|
||||
char loopch = 0;
|
||||
const int reuse = 1;
|
||||
|
||||
if (uniPortNo == 0 || multiPortNo == 0)
|
||||
{
|
||||
D_NWSTACK("error portNo undefined in UDPPort::open\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t ip = inet_addr(ipAddress);
|
||||
_grpAddr.setAddress(ip, htons(multiPortNo));
|
||||
_clientAddr.setAddress(ip, htons(uniPortNo));
|
||||
|
||||
/*------ Create unicast socket --------*/
|
||||
_sockfdUnicast = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (_sockfdUnicast < 0)
|
||||
{
|
||||
D_NWSTACK("error can't create unicast socket in UDPPort::open\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
setsockopt(_sockfdUnicast, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
|
||||
|
||||
sockaddr_in addru;
|
||||
addru.sin_family = AF_INET;
|
||||
addru.sin_port = htons(uniPortNo);
|
||||
addru.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
if (::bind(_sockfdUnicast, (sockaddr*) &addru, sizeof(addru)) < 0)
|
||||
{
|
||||
D_NWSTACK("error can't bind unicast socket in UDPPort::open\n");
|
||||
return -1;
|
||||
}
|
||||
if (setsockopt(_sockfdUnicast, IPPROTO_IP, IP_MULTICAST_LOOP, (char*) &loopch, sizeof(loopch)) < 0)
|
||||
{
|
||||
D_NWSTACK("error IP_MULTICAST_LOOP in UDPPort::open\n");
|
||||
close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*------ Create Multicast socket --------*/
|
||||
_sockfdMulticast = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (_sockfdMulticast < 0)
|
||||
{
|
||||
D_NWSTACK("error can't create multicast socket in UDPPort::open\n");
|
||||
close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
setsockopt(_sockfdMulticast, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
|
||||
|
||||
sockaddr_in addrm;
|
||||
addrm.sin_family = AF_INET;
|
||||
addrm.sin_port = _grpAddr.getPortNo();
|
||||
addrm.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
if (::bind(_sockfdMulticast, (sockaddr*) &addrm, sizeof(addrm)) < 0)
|
||||
{
|
||||
D_NWSTACK("error can't bind multicast socket in UDPPort::open\n");
|
||||
return -1;
|
||||
}
|
||||
if (setsockopt(_sockfdMulticast, IPPROTO_IP, IP_MULTICAST_LOOP, (char*) &loopch, sizeof(loopch)) < 0)
|
||||
{
|
||||
D_NWSTACK("error IP_MULTICAST_LOOP in UDPPort::open\n");
|
||||
close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
ip_mreq mreq;
|
||||
mreq.imr_interface.s_addr = INADDR_ANY;
|
||||
mreq.imr_multiaddr.s_addr = _grpAddr.getIpAddress();
|
||||
|
||||
if (setsockopt(_sockfdMulticast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
|
||||
{
|
||||
D_NWSTACK("error Multicast IP_ADD_MEMBERSHIP in UDPPort::open\n");
|
||||
close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setsockopt(_sockfdUnicast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
|
||||
{
|
||||
D_NWSTACK("error Unicast IP_ADD_MEMBERSHIP in UDPPort::open\n");
|
||||
close();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UDPPort::unicast(const uint8_t* buf, uint32_t length, SensorNetAddress* addr)
|
||||
{
|
||||
sockaddr_in dest;
|
||||
dest.sin_family = AF_INET;
|
||||
dest.sin_port = addr->getPortNo();
|
||||
dest.sin_addr.s_addr = addr->getIpAddress();
|
||||
;
|
||||
|
||||
int status = ::sendto(_sockfdUnicast, buf, length, 0, (const sockaddr*) &dest, sizeof(dest));
|
||||
if (status < 0)
|
||||
{
|
||||
D_NWSTACK("errno == %d in UDPPort::sendto\n", errno);
|
||||
}
|
||||
D_NWSTACK("sendto %s:%u length = %d\n", inet_ntoa(dest.sin_addr), htons(addr->getPortNo()), status);
|
||||
return status;
|
||||
}
|
||||
|
||||
int UDPPort::broadcast(const uint8_t* buf, uint32_t length)
|
||||
{
|
||||
return unicast(buf, length, &_grpAddr);
|
||||
}
|
||||
|
||||
int UDPPort::recv(uint8_t* buf, uint16_t len, SensorNetAddress* addr)
|
||||
{
|
||||
fd_set recvfds;
|
||||
int maxSock = 0;
|
||||
|
||||
FD_ZERO(&recvfds);
|
||||
FD_SET(_sockfdUnicast, &recvfds);
|
||||
FD_SET(_sockfdMulticast, &recvfds);
|
||||
|
||||
if (_sockfdMulticast > _sockfdUnicast)
|
||||
{
|
||||
maxSock = _sockfdMulticast;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxSock = _sockfdUnicast;
|
||||
}
|
||||
|
||||
select(maxSock + 1, &recvfds, 0, 0, 0);
|
||||
|
||||
if (FD_ISSET(_sockfdUnicast, &recvfds))
|
||||
{
|
||||
return recvfrom(_sockfdUnicast, buf, len, 0, addr);
|
||||
}
|
||||
else if (FD_ISSET(_sockfdMulticast, &recvfds))
|
||||
{
|
||||
return recvfrom(_sockfdMulticast, buf, len, 0, &_grpAddr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UDPPort::recvfrom(int sockfd, uint8_t* buf, uint16_t len, uint8_t flags, SensorNetAddress* addr)
|
||||
{
|
||||
sockaddr_in sender;
|
||||
socklen_t addrlen = sizeof(sender);
|
||||
memset(&sender, 0, addrlen);
|
||||
|
||||
int status = ::recvfrom(sockfd, buf, len, flags, (sockaddr*) &sender, &addrlen);
|
||||
|
||||
if (status < 0 && errno != EAGAIN)
|
||||
{
|
||||
D_NWSTACK("errno == %d in UDPPort::recvfrom\n", errno);
|
||||
return -1;
|
||||
}
|
||||
addr->setAddress(sender.sin_addr.s_addr, sender.sin_port);
|
||||
D_NWSTACK("recved from %s:%d length = %d\n", inet_ntoa(sender.sin_addr), htons(addr->getPortNo()), status);
|
||||
return status;
|
||||
}
|
||||
|
||||
114
MQTTSNGateway/src/linux/udp/SensorNetwork.h
Normal file
114
MQTTSNGateway/src/linux/udp/SensorNetwork.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#ifndef SENSORNETWORK_H_
|
||||
#define SENSORNETWORK_H_
|
||||
|
||||
#include "MQTTSNGWDefines.h"
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
|
||||
#ifdef DEBUG_NWSTACK
|
||||
#define D_NWSTACK(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define D_NWSTACK(...)
|
||||
#endif
|
||||
|
||||
#define SENSORNETWORK_TYPE "UDP"
|
||||
/*===========================================
|
||||
Class SensorNetAddreess
|
||||
============================================*/
|
||||
class SensorNetAddress
|
||||
{
|
||||
public:
|
||||
SensorNetAddress();
|
||||
~SensorNetAddress();
|
||||
void setAddress(uint32_t IpAddr, uint16_t port);
|
||||
int setAddress(string* data);
|
||||
uint32_t getIpAddress(void)
|
||||
{
|
||||
return _IpAddr;
|
||||
}
|
||||
uint16_t getPortNo(void)
|
||||
{
|
||||
return _portNo;
|
||||
}
|
||||
bool isMatch(SensorNetAddress* addr);
|
||||
SensorNetAddress& operator =(SensorNetAddress& addr);
|
||||
|
||||
private:
|
||||
uint16_t _portNo;
|
||||
uint32_t _IpAddr;
|
||||
};
|
||||
|
||||
/*========================================
|
||||
Class UpdPort
|
||||
=======================================*/
|
||||
class UDPPort
|
||||
{
|
||||
public:
|
||||
UDPPort();
|
||||
virtual ~UDPPort();
|
||||
|
||||
int open(char* ipAddress, uint16_t multiPortNo, uint16_t uniPortNo);
|
||||
void close(void);
|
||||
int unicast(const uint8_t* buf, uint32_t length, SensorNetAddress* sendToAddr);
|
||||
int broadcast(const uint8_t* buf, uint32_t length);
|
||||
int recv(uint8_t* buf, uint16_t len, SensorNetAddress* addr);
|
||||
|
||||
private:
|
||||
void setNonBlocking(const bool);
|
||||
int recvfrom(int sockfd, uint8_t* buf, uint16_t len, uint8_t flags, SensorNetAddress* addr);
|
||||
|
||||
int _sockfdUnicast;
|
||||
int _sockfdMulticast;
|
||||
|
||||
SensorNetAddress _grpAddr;
|
||||
SensorNetAddress _clientAddr;
|
||||
bool _disconReq;
|
||||
|
||||
};
|
||||
|
||||
/*===========================================
|
||||
Class SensorNetwork
|
||||
============================================*/
|
||||
class SensorNetwork: public UDPPort
|
||||
{
|
||||
public:
|
||||
SensorNetwork();
|
||||
~SensorNetwork();
|
||||
|
||||
int unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendto);
|
||||
int broadcast(const uint8_t* payload, uint16_t payloadLength);
|
||||
int read(uint8_t* buf, uint16_t bufLen);
|
||||
int initialize(void);
|
||||
const char* getType(void);
|
||||
SensorNetAddress* getSenderAddress(void)
|
||||
{
|
||||
return &_clientAddr;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
SensorNetAddress _clientAddr; // Sender's address. not gateway's one.
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* SENSORNETWORK_H_ */
|
||||
434
MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp
Normal file
434
MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp
Normal file
@@ -0,0 +1,434 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation
|
||||
**************************************************************************************/
|
||||
|
||||
#include "SensorNetwork.h"
|
||||
#include "MQTTSNGWProcess.h"
|
||||
#include "Threading.h"
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
/*===========================================
|
||||
Class SensorNetAddreess
|
||||
============================================*/
|
||||
SensorNetAddress::SensorNetAddress()
|
||||
{
|
||||
memset(_address64, 0, sizeof(_address64));
|
||||
memset(_address16, 0, sizeof(_address16));
|
||||
}
|
||||
|
||||
SensorNetAddress::~SensorNetAddress()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SensorNetAddress::setAddress(uint8_t* address64, uint8_t* address16)
|
||||
{
|
||||
memcpy(_address64, address64, 8);
|
||||
memcpy(_address16, address16, 2);
|
||||
}
|
||||
|
||||
|
||||
int SensorNetAddress::setAddress(string* address64)
|
||||
{
|
||||
memcpy(_address64, address64->c_str(), 8);
|
||||
memset(_address16, 0, sizeof(_address16));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SensorNetAddress::setBroadcastAddress(void)
|
||||
{
|
||||
memset(_address64, 0, 6);
|
||||
_address64[6] = 0xff;
|
||||
_address64[7] = 0xff;
|
||||
_address16[0] = 0xff;
|
||||
_address16[1] = 0xfe;
|
||||
}
|
||||
|
||||
bool SensorNetAddress::isMatch(SensorNetAddress* addr)
|
||||
{
|
||||
|
||||
return (memcmp(this->_address64, addr->_address64, 8 ) == 0 && memcmp(this->_address16, addr->_address16, 2) == 0);
|
||||
}
|
||||
|
||||
SensorNetAddress& SensorNetAddress::operator =(SensorNetAddress& addr)
|
||||
{
|
||||
memcpy(_address64, addr._address64, 8);
|
||||
memcpy(_address16, addr._address16, 2);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*===========================================
|
||||
Class SensorNetwork
|
||||
============================================*/
|
||||
SensorNetwork::SensorNetwork()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SensorNetwork::~SensorNetwork()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int SensorNetwork::unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendToAddr)
|
||||
{
|
||||
return XBee::unicast(payload, payloadLength, sendToAddr);
|
||||
}
|
||||
|
||||
int SensorNetwork::broadcast(const uint8_t* payload, uint16_t payloadLength)
|
||||
{
|
||||
return XBee::broadcast(payload, payloadLength);
|
||||
}
|
||||
|
||||
int SensorNetwork::read(uint8_t* buf, uint16_t bufLen)
|
||||
{
|
||||
return XBee::recv(buf, bufLen, &_clientAddr);
|
||||
}
|
||||
|
||||
int SensorNetwork::initialize(void)
|
||||
{
|
||||
char param[MQTTSNGW_PARAM_MAX];
|
||||
uint16_t baudrate = 9600;
|
||||
|
||||
if (theProcess->getParam("Baudrate", param) == 0)
|
||||
{
|
||||
baudrate = (uint16_t)atoi(param);
|
||||
}
|
||||
|
||||
theProcess->getParam("SerialDevice", param);
|
||||
|
||||
return XBee::open(param, baudrate);
|
||||
}
|
||||
|
||||
const char* SensorNetwork::getType(void)
|
||||
{
|
||||
return "XBee";
|
||||
}
|
||||
|
||||
/*===========================================
|
||||
Class XBee
|
||||
============================================*/
|
||||
XBee::XBee(){
|
||||
_serialPort = new SerialPort();
|
||||
_respCd = 0;
|
||||
_dataLen = 0;
|
||||
_frameId = 0;
|
||||
}
|
||||
|
||||
XBee::~XBee(){
|
||||
if ( _serialPort )
|
||||
{
|
||||
delete _serialPort;
|
||||
}
|
||||
}
|
||||
|
||||
int XBee::open(char* device, int baudrate)
|
||||
{
|
||||
int rate = B9600;
|
||||
|
||||
switch (baudrate)
|
||||
{
|
||||
case 9600:
|
||||
rate = B9600;
|
||||
break;
|
||||
case 19200:
|
||||
rate = B19200;
|
||||
break;
|
||||
case 38400:
|
||||
rate = B38400;
|
||||
break;
|
||||
case 57600:
|
||||
rate = B57600;
|
||||
break;
|
||||
case 115200:
|
||||
rate = B115200;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _serialPort->open(device, rate, false, 1, O_RDWR | O_NOCTTY);
|
||||
}
|
||||
|
||||
int XBee::broadcast(const uint8_t* payload, uint16_t payloadLen){
|
||||
SensorNetAddress addr;
|
||||
addr.setBroadcastAddress();
|
||||
send(payload, (uint8_t) payloadLen, &addr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int XBee:: unicast(const uint8_t* payload, uint16_t payloadLen, SensorNetAddress* addr){
|
||||
send(payload, (uint8_t) payloadLen, addr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int XBee::recv(uint8_t* buf, uint16_t bufLen, SensorNetAddress* clientAddr)
|
||||
{
|
||||
uint8_t data[128];
|
||||
int len;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
|
||||
if ( (len = readApiFrame(data)) > 0 )
|
||||
{
|
||||
|
||||
if ( data[0] == API_RESPONSE )
|
||||
{
|
||||
memcpy(clientAddr->_address64, data + 1, 8);
|
||||
memcpy(clientAddr->_address16, data + 9, 2);
|
||||
len -= 12;
|
||||
memcpy( buf, data + 12, len);
|
||||
return len;
|
||||
}
|
||||
else if ( data[0] == API_XMITSTATUS )
|
||||
{
|
||||
_respCd = data[5];
|
||||
_respId = data[1];
|
||||
_sem.post();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int XBee::readApiFrame(uint8_t* recvData){
|
||||
uint8_t buf;
|
||||
uint8_t pos = 0;
|
||||
uint8_t checksum = 0;
|
||||
uint8_t len = 0;
|
||||
|
||||
while ( _serialPort->recv(&buf) )
|
||||
{
|
||||
if ( buf == START_BYTE)
|
||||
{
|
||||
pos = 1;
|
||||
D_NWSTACK("\r\n===> Recv: ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( pos == 0 )
|
||||
{
|
||||
goto errexit;
|
||||
}
|
||||
|
||||
if ( recv(&buf) < 0 ) // MSB length
|
||||
{
|
||||
goto errexit;
|
||||
}
|
||||
|
||||
if ( recv(&buf) < 0 ) // LSB length
|
||||
{
|
||||
goto errexit;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = buf;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
while ( len-- )
|
||||
{
|
||||
if ( recv(&buf) < 0 )
|
||||
{
|
||||
goto errexit;
|
||||
}
|
||||
recvData[pos++] = buf;
|
||||
checksum += buf;
|
||||
}
|
||||
|
||||
recv(&buf); // checksum
|
||||
if ( (0xff - checksum ) == buf ){
|
||||
D_NWSTACK(" checksum ok\r\n");
|
||||
return pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
D_NWSTACK(" checksum error %02x\r\n", 0xff - checksum);
|
||||
goto errexit;
|
||||
}
|
||||
errexit:
|
||||
_serialPort->flush();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int XBee::send(const uint8_t* payload, uint8_t pLen, SensorNetAddress* addr){
|
||||
D_NWSTACK("\r\n===> Send: ");
|
||||
uint8_t checksum = 0;
|
||||
_respCd = -1;
|
||||
|
||||
_serialPort->send(START_BYTE);
|
||||
send(0x00); // Message Length
|
||||
send(14 + pLen); // Message Length
|
||||
|
||||
_serialPort->send(API_XMITREQUEST); // Transmit Request API
|
||||
checksum += API_XMITREQUEST;
|
||||
|
||||
if (_frameId++ == 0x00 ) // Frame ID
|
||||
{
|
||||
_frameId = 1;
|
||||
}
|
||||
send(_frameId);
|
||||
checksum += _frameId;
|
||||
|
||||
for ( int i = 0; i < 8; i++) // Address64
|
||||
{
|
||||
send(addr->_address64[i]);
|
||||
checksum += addr->_address64[i];
|
||||
}
|
||||
for ( int i = 0; i < 2; i++) // Address16
|
||||
{
|
||||
send(addr->_address16[i]);
|
||||
checksum += addr->_address16[i];
|
||||
}
|
||||
|
||||
send(0x00); // Broadcast Radius
|
||||
checksum += 0x00;
|
||||
|
||||
send(0x00); // Option: Use the extended transmission timeout 0x40
|
||||
checksum += 0x00;
|
||||
|
||||
D_NWSTACK("\r\n Payload: ");
|
||||
|
||||
for ( uint8_t i = 0; i < pLen; i++ ){
|
||||
send(payload[i]); // Payload
|
||||
checksum += payload[i];
|
||||
}
|
||||
|
||||
checksum = 0xff - checksum;
|
||||
D_NWSTACK(" checksum ");
|
||||
send(checksum);
|
||||
D_NWSTACK("\r\n");
|
||||
|
||||
/* wait Txim Status 0x8B */
|
||||
_sem.timedwait(5000); // 5sec
|
||||
|
||||
if ( _respCd || _frameId != _respId )
|
||||
{
|
||||
D_NWSTACK(" frameId = %02x Not Acknowleged\r\n", _frameId);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void XBee::send(uint8_t c)
|
||||
{
|
||||
if(c == START_BYTE || c == ESCAPE || c == XON || c == XOFF){
|
||||
_serialPort->send(ESCAPE);
|
||||
_serialPort->send(c ^ 0x20);
|
||||
}else{
|
||||
_serialPort->send(c);
|
||||
}
|
||||
}
|
||||
|
||||
int XBee::recv(uint8_t* buf)
|
||||
{
|
||||
if (_serialPort->recv(buf) )
|
||||
{
|
||||
if ( *buf == ESCAPE)
|
||||
{
|
||||
_serialPort->recv(buf);
|
||||
*buf = 0x20 ^ *buf;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*=========================================
|
||||
Class SerialPort
|
||||
=========================================*/
|
||||
SerialPort::SerialPort()
|
||||
{
|
||||
_tio.c_iflag = IGNBRK | IGNPAR;
|
||||
_tio.c_cflag = CS8 | CLOCAL | CRTSCTS;
|
||||
_tio.c_cc[VINTR] = 0;
|
||||
_tio.c_cc[VTIME] = 0;
|
||||
_tio.c_cc[VMIN] = 1;
|
||||
_fd = 0;
|
||||
}
|
||||
|
||||
SerialPort::~SerialPort()
|
||||
{
|
||||
if (_fd)
|
||||
{
|
||||
::close(_fd);
|
||||
}
|
||||
}
|
||||
|
||||
int SerialPort::open(char* devName, unsigned int baudrate, bool parity,
|
||||
unsigned int stopbit, unsigned int flg)
|
||||
{
|
||||
_fd = ::open(devName, flg);
|
||||
if (_fd < 0)
|
||||
{
|
||||
return _fd;
|
||||
}
|
||||
|
||||
if (parity)
|
||||
{
|
||||
_tio.c_cflag = _tio.c_cflag | PARENB;
|
||||
}
|
||||
if (stopbit == 2)
|
||||
{
|
||||
_tio.c_cflag = _tio.c_cflag | CSTOPB;
|
||||
}
|
||||
|
||||
if (cfsetspeed(&_tio, baudrate) < 0)
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
return tcsetattr(_fd, TCSANOW, &_tio);
|
||||
}
|
||||
|
||||
bool SerialPort::send(unsigned char b)
|
||||
{
|
||||
if (write(_fd, &b, 1) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
D_NWSTACK( " %02x", b);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool SerialPort::recv(unsigned char* buf)
|
||||
{
|
||||
if (read(_fd, buf, 1) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
D_NWSTACK( " %02x",buf[0] );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void SerialPort::flush(void)
|
||||
{
|
||||
tcsetattr(_fd, TCSAFLUSH, &_tio);
|
||||
}
|
||||
|
||||
141
MQTTSNGateway/src/linux/xbee/SensorNetwork.h
Normal file
141
MQTTSNGateway/src/linux/xbee/SensorNetwork.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation
|
||||
**************************************************************************************/
|
||||
#ifndef SENSORNETWORKX_H_
|
||||
#define SENSORNETWORKX_H_
|
||||
|
||||
#include "MQTTSNGWDefines.h"
|
||||
#include "MQTTSNGWProcess.h"
|
||||
#include <string>
|
||||
#include <termios.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace MQTTSNGW
|
||||
{
|
||||
//#define DEBUG_NWSTACK
|
||||
|
||||
#ifdef DEBUG_NWSTACK
|
||||
#define D_NWSTACK(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define D_NWSTACK(...)
|
||||
#endif
|
||||
|
||||
#define API_XMITREQUEST 0x10
|
||||
#define API_RESPONSE 0x90
|
||||
#define API_MODEMSTATUS 0x8A
|
||||
#define API_XMITSTATUS 0x8B
|
||||
|
||||
#define START_BYTE 0x7e
|
||||
#define ESCAPE 0x7d
|
||||
#define XON 0x11
|
||||
#define XOFF 0x13
|
||||
|
||||
/*===========================================
|
||||
Class SerialPort
|
||||
============================================*/
|
||||
class SerialPort{
|
||||
public:
|
||||
SerialPort();
|
||||
~SerialPort();
|
||||
int open(char* devName, unsigned int baudrate, bool parity, unsigned int stopbit, unsigned int flg);
|
||||
bool send(unsigned char b);
|
||||
bool recv(unsigned char* b);
|
||||
void flush();
|
||||
|
||||
private:
|
||||
int _fd; // file descriptor
|
||||
struct termios _tio;
|
||||
};
|
||||
|
||||
/*===========================================
|
||||
Class SensorNetAddreess
|
||||
============================================*/
|
||||
class SensorNetAddress
|
||||
{
|
||||
friend class XBee;
|
||||
public:
|
||||
SensorNetAddress();
|
||||
~SensorNetAddress();
|
||||
void setAddress(uint8_t* address64, uint8_t* address16);
|
||||
int setAddress(string* data);
|
||||
void setBroadcastAddress(void);
|
||||
bool isMatch(SensorNetAddress* addr);
|
||||
SensorNetAddress& operator =(SensorNetAddress& addr);
|
||||
|
||||
private:
|
||||
uint8_t _address16[2];
|
||||
uint8_t _address64[8];
|
||||
};
|
||||
|
||||
/*========================================
|
||||
Class XBee
|
||||
=======================================*/
|
||||
class XBee
|
||||
{
|
||||
public:
|
||||
XBee();
|
||||
~XBee();
|
||||
|
||||
int open(char* device, int boudrate);
|
||||
void close(void);
|
||||
int unicast(const uint8_t* buf, uint16_t length, SensorNetAddress* sendToAddr);
|
||||
int broadcast(const uint8_t* buf, uint16_t length);
|
||||
int recv(uint8_t* buf, uint16_t len, SensorNetAddress* addr);
|
||||
|
||||
private:
|
||||
int readApiFrame(uint8_t* recvData);
|
||||
int recv(uint8_t* buf);
|
||||
int send(const uint8_t* payload, uint8_t pLen, SensorNetAddress* addr);
|
||||
void send(uint8_t b);
|
||||
|
||||
Semaphore _sem;
|
||||
Mutex _meutex;
|
||||
SerialPort* _serialPort;
|
||||
uint8_t _frameId;
|
||||
|
||||
uint8_t _respCd;
|
||||
uint8_t _respId;
|
||||
uint8_t _dataLen;
|
||||
};
|
||||
|
||||
/*===========================================
|
||||
Class SensorNetwork
|
||||
============================================*/
|
||||
class SensorNetwork: public XBee
|
||||
{
|
||||
public:
|
||||
SensorNetwork();
|
||||
~SensorNetwork();
|
||||
|
||||
int unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendto);
|
||||
int broadcast(const uint8_t* payload, uint16_t payloadLength);
|
||||
int read(uint8_t* buf, uint16_t bufLen);
|
||||
int initialize(void);
|
||||
const char* getType(void);
|
||||
|
||||
SensorNetAddress* getSenderAddress(void)
|
||||
{
|
||||
return &_clientAddr;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
SensorNetAddress _clientAddr; // Sender's address. not gateway's one.
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SENSORNETWORKX_H_ */
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* main.cpp
|
||||
*
|
||||
* Created on: Jan 5, 2016
|
||||
* Author: icraggs
|
||||
*/
|
||||
|
||||
|
||||
void read_config()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
|
||||
|
||||
// 1. listen for MQTT-SN connections
|
||||
|
||||
// 2. connect to MQTT broker
|
||||
|
||||
// 3. listen for MQTT-SN packets, and act on them
|
||||
// 4. listen for MQTT packets too, and act on them
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
46
MQTTSNGateway/src/mainGateway.cpp
Normal file
46
MQTTSNGateway/src/mainGateway.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
#include "MQTTSNGateway.h"
|
||||
#include "MQTTSNGWBrokerRecvTask.h"
|
||||
#include "MQTTSNGWBrokerSendTask.h"
|
||||
#include "MQTTSNGWClientRecvTask.h"
|
||||
#include "MQTTSNGWClientSendTask.h"
|
||||
#include "MQTTSNGWPacketHandleTask.h"
|
||||
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
/*
|
||||
* Gateway Process
|
||||
*
|
||||
* Configure file "/usr/local/etc/mqttsnGateway/config/param.conf"
|
||||
* Clientlist file "/usr/local/etc/mqttsnGateway/config/clientList.conf"
|
||||
* Certificate file "/etc/ssl/certs"
|
||||
* These are defined in MQTTSNGWDefines.h
|
||||
*/
|
||||
Gateway* gateway = new Gateway();
|
||||
PacketHandleTask* t0 = new PacketHandleTask(gateway);
|
||||
ClientRecvTask* t1 = new ClientRecvTask(gateway);
|
||||
ClientSendTask* t2 = new ClientSendTask(gateway);
|
||||
BrokerRecvTask* t3 = new BrokerRecvTask(gateway);
|
||||
BrokerSendTask* t4 = new BrokerSendTask(gateway);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
theProcess->initialize(argc, argv);
|
||||
theProcess->run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
33
MQTTSNGateway/src/mainLogmonitor.cpp
Normal file
33
MQTTSNGateway/src/mainLogmonitor.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
/**************************************************************************************
|
||||
* Copyright (c) 2016, Tomoaki Yamaguchi
|
||||
*
|
||||
* 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:
|
||||
* Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
|
||||
**************************************************************************************/
|
||||
|
||||
#include "MQTTSNGWProcess.h"
|
||||
#include "MQTTSNGWLogmonitor.h"
|
||||
|
||||
using namespace MQTTSNGW;
|
||||
|
||||
|
||||
/*
|
||||
* Logmonitor process
|
||||
*/
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Logmonitor monitor = Logmonitor();
|
||||
monitor.initialize(argc, argv);
|
||||
monitor.run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#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
|
||||
@@ -116,7 +117,7 @@ int MQTTSNSerialize_disconnectLength(int duration)
|
||||
int len = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
len = (duration >= 0) ? 3 : 1;
|
||||
len = (duration > 0) ? 3 : 1;
|
||||
FUNC_EXIT_RC(len);
|
||||
return len;
|
||||
}
|
||||
@@ -144,7 +145,7 @@ int MQTTSNSerialize_disconnect(unsigned char* buf, int buflen, int duration)
|
||||
ptr += MQTTSNPacket_encode(ptr, len); /* write length */
|
||||
writeChar(&ptr, MQTTSN_DISCONNECT); /* write message type */
|
||||
|
||||
if (duration >= 0)
|
||||
if (duration > 0)
|
||||
writeInt(&ptr, duration);
|
||||
|
||||
rc = ptr - buf;
|
||||
|
||||
@@ -56,7 +56,7 @@ int MQTTSNDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retai
|
||||
*qos = flags.bits.QoS;
|
||||
*retained = flags.bits.retain;
|
||||
|
||||
topic->type = flags.bits.topicIdType;
|
||||
topic->type = (MQTTSN_topicTypes)flags.bits.topicIdType;
|
||||
if (topic->type == MQTTSN_TOPIC_TYPE_NORMAL && *qos == 3)
|
||||
{
|
||||
/* special arrangement for long topic names in QoS -1 publishes. The length of the topic is in the topicid field */
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static char* packet_names[] =
|
||||
static const char* packet_names[] =
|
||||
{
|
||||
"ADVERTISE", "SEARCHGW", "GWINFO", "RESERVED", "CONNECT", "CONNACK",
|
||||
"WILLTOPICREQ", "WILLTOPIC", "WILLMSGREQ", "WILLMSG", "REGISTER", "REGACK",
|
||||
@@ -35,7 +35,7 @@ static char* packet_names[] =
|
||||
* @param code MsgType code
|
||||
* @return the corresponding packet name
|
||||
*/
|
||||
char* MQTTSNPacket_name(int code)
|
||||
const char* MQTTSNPacket_name(int code)
|
||||
{
|
||||
return (code >= 0 && code <= MQTTSN_WILLMSGRESP) ? packet_names[code] : "UNKNOWN";
|
||||
}
|
||||
@@ -51,7 +51,6 @@ 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
|
||||
@@ -95,7 +94,7 @@ int MQTTSNPacket_decode(unsigned char* buf, int buflen, int* value)
|
||||
if (buf[0] == 1)
|
||||
{
|
||||
unsigned char* bufptr = &buf[1];
|
||||
if (buflen < 3)
|
||||
if (buflen < MAX_NO_OF_LENGTH_BYTES)
|
||||
goto exit;
|
||||
*value = readInt(&bufptr);
|
||||
len = 3;
|
||||
@@ -188,7 +187,7 @@ void writeMQTTSNString(unsigned char** pptr, MQTTSNString MQTTSNString)
|
||||
{
|
||||
if (MQTTSNString.lenstring.len > 0)
|
||||
{
|
||||
memcpy(*pptr, MQTTSNString.lenstring.data, MQTTSNString.lenstring.len);
|
||||
memcpy(*pptr, (const unsigned char*)MQTTSNString.lenstring.data, MQTTSNString.lenstring.len);
|
||||
*pptr += MQTTSNString.lenstring.len;
|
||||
}
|
||||
else if (MQTTSNString.cstring)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* TomoakiiYamaguchi - modify for C++
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef MQTTSNPACKET_H_
|
||||
@@ -35,15 +36,15 @@ enum MQTTSN_connackCodes
|
||||
MQTTSN_RC_ACCEPTED,
|
||||
MQTTSN_RC_REJECTED_CONGESTED,
|
||||
MQTTSN_RC_REJECTED_INVALID_TOPIC_ID,
|
||||
MQTTSN_RC_NOT_SUPPORTED
|
||||
};
|
||||
|
||||
enum MQTTSN_topicTypes
|
||||
typedef enum
|
||||
{
|
||||
MQTTSN_TOPIC_TYPE_NORMAL, /* topic id in publish, topic name in subscribe */
|
||||
MQTTSN_TOPIC_TYPE_PREDEFINED,
|
||||
MQTTSN_TOPIC_TYPE_SHORT,
|
||||
};
|
||||
|
||||
}MQTTSN_topicTypes;
|
||||
|
||||
enum MQTTSN_msgTypes
|
||||
{
|
||||
@@ -60,7 +61,7 @@ enum MQTTSN_msgTypes
|
||||
|
||||
typedef struct
|
||||
{
|
||||
enum MQTTSN_topicTypes type;
|
||||
MQTTSN_topicTypes type;
|
||||
union
|
||||
{
|
||||
unsigned short id;
|
||||
@@ -73,7 +74,6 @@ typedef struct
|
||||
} data;
|
||||
} MQTTSN_topicid;
|
||||
|
||||
|
||||
/**
|
||||
* Bitfields for the MQTT-SN flags byte.
|
||||
*/
|
||||
@@ -126,7 +126,7 @@ int MQTTSNstrlen(MQTTSNString mqttsnstring);
|
||||
#include "MQTTSNUnsubscribe.h"
|
||||
#include "MQTTSNSearch.h"
|
||||
|
||||
char* MQTTSNPacket_name(int ptype);
|
||||
const char* MQTTSNPacket_name(int ptype);
|
||||
int MQTTSNPacket_len(int length);
|
||||
|
||||
int MQTTSNPacket_encode(unsigned char* buf, int length);
|
||||
|
||||
@@ -41,5 +41,6 @@ int MQTTSNSerialize_regack(unsigned char* buf, int buflen, unsigned short topici
|
||||
unsigned char return_code);
|
||||
int MQTTSNDeserialize_regack(unsigned short* topicid, unsigned short* packetid, unsigned char* return_code,
|
||||
unsigned char* buf, int buflen);
|
||||
int MQTTSNSerialize_pubrel(unsigned char* buf, int buflen, unsigned short packetid);
|
||||
|
||||
#endif /* MQTTSNPUBLISH_H_ */
|
||||
|
||||
@@ -53,7 +53,7 @@ int MQTTSNDeserialize_subscribe(unsigned char* dup, int* qos, unsigned short* pa
|
||||
|
||||
*packetid = readInt(&curdata);
|
||||
|
||||
topicFilter->type = flags.bits.topicIdType;
|
||||
topicFilter->type = (MQTTSN_topicTypes)flags.bits.topicIdType;
|
||||
|
||||
if (topicFilter->type == MQTTSN_TOPIC_TYPE_NORMAL)
|
||||
{
|
||||
|
||||
@@ -38,7 +38,7 @@ int MQTTSNDeserialize_unsubscribe(unsigned short* packetid, MQTTSN_topicid* topi
|
||||
flags.all = readChar(&curdata);
|
||||
*packetid = readInt(&curdata);
|
||||
|
||||
topicFilter->type = flags.bits.topicIdType;
|
||||
topicFilter->type = (MQTTSN_topicTypes)flags.bits.topicIdType;
|
||||
if (topicFilter->type == MQTTSN_TOPIC_TYPE_NORMAL)
|
||||
{
|
||||
topicFilter->data.long_.len = enddata - curdata;
|
||||
|
||||
106
Makefile
Normal file
106
Makefile
Normal file
@@ -0,0 +1,106 @@
|
||||
PROGNAME := MQTT-SNGateway
|
||||
APPL := mainGateway
|
||||
|
||||
LPROGNAME := MQTT-SNLogmonitor
|
||||
LAPPL := mainLogmonitor
|
||||
|
||||
SRCDIR := MQTTSNGateway/src
|
||||
SUBDIR := MQTTSNPacket/src
|
||||
|
||||
OS := linux
|
||||
SENSORNET := udp
|
||||
|
||||
CPPSRCS := \
|
||||
$(SRCDIR)/MQTTGWConnectionHandler.cpp \
|
||||
$(SRCDIR)/MQTTGWPacket.cpp \
|
||||
$(SRCDIR)/MQTTGWPublishHandler.cpp \
|
||||
$(SRCDIR)/MQTTGWSubscribeHandler.cpp \
|
||||
$(SRCDIR)/MQTTSNGateway.cpp \
|
||||
$(SRCDIR)/MQTTSNGWBrokerRecvTask.cpp \
|
||||
$(SRCDIR)/MQTTSNGWBrokerSendTask.cpp \
|
||||
$(SRCDIR)/MQTTSNGWClient.cpp \
|
||||
$(SRCDIR)/MQTTSNGWClientRecvTask.cpp \
|
||||
$(SRCDIR)/MQTTSNGWClientSendTask.cpp \
|
||||
$(SRCDIR)/MQTTSNGWConnectionHandler.cpp \
|
||||
$(SRCDIR)/MQTTSNGWLogmonitor.cpp \
|
||||
$(SRCDIR)/MQTTSNGWPacket.cpp \
|
||||
$(SRCDIR)/MQTTSNGWPacketHandleTask.cpp \
|
||||
$(SRCDIR)/MQTTSNGWProcess.cpp \
|
||||
$(SRCDIR)/MQTTSNGWPublishHandler.cpp \
|
||||
$(SRCDIR)/MQTTSNGWSubscribeHandler.cpp \
|
||||
$(SRCDIR)/$(OS)/$(SENSORNET)/SensorNetwork.cpp \
|
||||
$(SRCDIR)/$(OS)/Timer.cpp \
|
||||
$(SRCDIR)/$(OS)/Network.cpp \
|
||||
$(SRCDIR)/$(OS)/Threading.cpp
|
||||
|
||||
CSRCS := $(SUBDIR)/MQTTSNConnectClient.c \
|
||||
$(SUBDIR)/MQTTSNConnectServer.c \
|
||||
$(SUBDIR)/MQTTSNDeserializePublish.c \
|
||||
$(SUBDIR)/MQTTSNPacket.c \
|
||||
$(SUBDIR)/MQTTSNSearchClient.c \
|
||||
$(SUBDIR)/MQTTSNSearchServer.c \
|
||||
$(SUBDIR)/MQTTSNSerializePublish.c \
|
||||
$(SUBDIR)/MQTTSNSubscribeClient.c \
|
||||
$(SUBDIR)/MQTTSNSubscribeServer.c \
|
||||
$(SUBDIR)/MQTTSNUnsubscribeClient.c \
|
||||
$(SUBDIR)/MQTTSNUnsubscribeServer.c
|
||||
|
||||
CXX := g++
|
||||
CPPFLAGS +=
|
||||
|
||||
INCLUDES += -IMQTTSNGateway/src \
|
||||
-IMQTTSNGateway/src/$(OS) \
|
||||
-IMQTTSNGateway/src/$(OS)/$(SENSORNET) \
|
||||
-IMQTTSNPacket/src
|
||||
|
||||
DEFS :=
|
||||
LIBS +=
|
||||
LDFLAGS :=
|
||||
CXXFLAGS := -Wall -O3 -std=c++11
|
||||
LDADD := -lpthread -lssl -lcrypto
|
||||
OUTDIR := Build
|
||||
|
||||
PROG := $(OUTDIR)/$(PROGNAME)
|
||||
LPROG := $(OUTDIR)/$(LPROGNAME)
|
||||
OBJS := $(CPPSRCS:%.cpp=$(OUTDIR)/%.o)
|
||||
OBJS += $(CSRCS:%.c=$(OUTDIR)/%.o)
|
||||
DEPS := $(CPPSRCS:%.cpp=$(OUTDIR)/%.d)
|
||||
DEPS += $(CSRCS:%.c=$(OUTDIR)/%.d)
|
||||
|
||||
.PHONY: install clean
|
||||
|
||||
all: $(PROG)
|
||||
|
||||
monitor: $(LPROG)
|
||||
|
||||
-include $(DEPS)
|
||||
|
||||
$(PROG): $(OBJS) $(OUTDIR)/$(SRCDIR)/$(APPL).o
|
||||
$(CXX) $(LDFLAGS) -o $@ $^ $(LIBS) $(LDADD)
|
||||
|
||||
$(LPROG): $(OBJS) $(OUTDIR)/$(SRCDIR)/$(LAPPL).o
|
||||
$(CXX) $(LDFLAGS) -o $@ $^ $(LIBS) $(LDADD)
|
||||
|
||||
$(OUTDIR)/$(SRCDIR)/%.o:$(SRCDIR)/%.cpp
|
||||
@if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi
|
||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) $(DEFS) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $<
|
||||
|
||||
$(OUTDIR)/$(SRCDIR)/$(APPL).o:$(SRCDIR)/$(APPL).cpp
|
||||
@if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi
|
||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) $(DEFS) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $<
|
||||
|
||||
$(OUTDIR)/$(SRCDIR)/$(LAPPL).o:$(SRCDIR)/$(LAPPL).cpp
|
||||
@if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi
|
||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) $(DEFS) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $<
|
||||
|
||||
$(OUTDIR)/$(SUBDIR)/%.o:$(SUBDIR)/%.c
|
||||
@if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi
|
||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) $(DEFS) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $<
|
||||
|
||||
clean:
|
||||
rm -rf $(OUTDIR)
|
||||
|
||||
install:
|
||||
cp -pf $(PROG) ../
|
||||
|
||||
|
||||
Reference in New Issue
Block a user