First Commit of MQTT-SN Gateway

Add    new SensorNetwork XBee
Add    a sensor network type in a start message.
Update MQTTSNClient to avoid build warning.
Update WiringPi's functions to my original ones. 
BugFix check msgId before adding waitdTopicId table.
BugFix Process termination procedures
Update print curent time in millseconds.
update move currentDateTime() to linux directory.
Bugfix: blink blue lightiIndicator.
Bugfix: Register returns wrong id.
change a status of the client to Disconnected.
change client status procedure
Update README
BugFix: change Network Disconnect procedures.

Signed-off-by: tomoaki <tomoaki@tomy-tech.com>
This commit is contained in:
tomoaki
2016-05-13 19:18:47 +09:00
parent 826b2a83b0
commit 64fa07b391
63 changed files with 9206 additions and 1138 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 "MQTTSNGWProcess.h"
#include "MQTTGWPacket.h"
#include "MQTTSNGWPacket.h"
#include "MQTTSNPacket.h"
#include "Network.h"
#include "SensorNetwork.h"
#include "MQTTSNPacket.h"
#include "linux.h" // Timer class
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 "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"
#include "linux.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 <exception>
#include "MQTTSNGWProcess.h"
#include "Threading.h"
#include "linux.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

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

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2014, 2015 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,214 +11,214 @@
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
* Tomoaki Yamaguchi - 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 <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include "MQTTSNGWDefines.h"
#include "linux.h"
class IPStack
using namespace std;
using namespace MQTTSNGW;
/*=====================================
Print Current Date & Time
=====================================*/
char theCurrentTime[32];
char* currentDateTime()
{
public:
IPStack()
{
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;
}
}
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
/*============================================
Timer
============================================*/
Timer::Timer(void)
{
public:
Countdown()
{
}
stop();
}
Countdown(int ms)
{
countdown_ms(ms);
}
Timer::~Timer(void)
{
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 Timer::start(uint32_t msecs)
{
gettimeofday(&_startTime, 0);
_millis = msecs;
}
void countdown(int seconds)
{
struct timeval now;
gettimeofday(&now, NULL);
struct timeval interval = {seconds, 0};
timeradd(&now, &interval, &end_time);
}
bool Timer::isTimeup(void)
{
return isTimeup(_millis);
}
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:
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;
}
}
struct timeval end_time;
};

View File

@@ -0,0 +1,70 @@
/**************************************************************************************
* 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_LINUX_H_
#define MQTTSNGATEWAY_SRC_LINUX_LINUX_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_LINUX_H_ */

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)/$(OS).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: