Merge pull request #10 from ty4tw/gateway

First Commit of MQTT-SN Gateway
This commit is contained in:
Ian Craggs
2016-06-22 20:06:22 -04:00
committed by GitHub
64 changed files with 9234 additions and 1166 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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);

View File

@@ -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

View 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);
}

View 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_ */

View 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;
}

View 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_ */

View 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);
}

View 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_ */

View 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);
}

View 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_ */

View 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;
}
}

View 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_ */

View 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;
}
}

View 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_ */

File diff suppressed because it is too large Load Diff

View 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_ */

View 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;
}
}

View 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_ */

View 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;
}
}

View 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_ */

View 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);
}

View 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_ */

View 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_ */

View 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);
}
}
}

View 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_ */

View 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;
}

View 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_ */

View 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;
}
}

View 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_ */

View 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());
}
}

View 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_ */

View 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);
}

View 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_ */

View 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);
}

View 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_ */

View 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;
}

View File

@@ -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_ */

View 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;
}

View 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_ */

View 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();
}

View File

@@ -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_ */

View 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;
}
}

View 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_ */

View File

@@ -1,2 +0,0 @@
g++ main.cpp -I MQTTPacket/src -I MQTTSNPacket/src -I linux MQTTPacket/src/*.c MQTTSNPacket/src/*.c

View File

@@ -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;
};

View File

@@ -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;
}

View 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;
}

View 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_ */

View 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);
}

View 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_ */

View File

@@ -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;
}

View 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;
}

View 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;
}

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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)

View File

@@ -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);

View File

@@ -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_ */

View File

@@ -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)
{

View File

@@ -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
View 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) ../

View File

@@ -1,4 +1,4 @@
# Eclipse Paho MQTT-SN Embedded C client
# Eclipse Paho MQTT-SN Embedded C
## Project description: