diff --git a/.cproject b/.cproject
index 6dc5729..e99b880 100644
--- a/.cproject
+++ b/.cproject
@@ -1,4 +1,5 @@
-
+
+
@@ -22,6 +23,16 @@
+
+
+
+
@@ -34,14 +45,24 @@
-
+
+
+
+
+
+
+
-
+
@@ -69,6 +90,15 @@
+
+
+
+
@@ -81,14 +111,27 @@
-
+
+
+
+
+
+
+
-
+
+
+
+
@@ -98,23 +141,29 @@
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
diff --git a/.project b/.project
index 09b1b50..e1e29d1 100644
--- a/.project
+++ b/.project
@@ -20,6 +20,7 @@
org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.core.ccnature
org.eclipse.cdt.managedbuilder.core.managedBuildNature
org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
diff --git a/MQTTSNClient/src/linux/linux.cpp b/MQTTSNClient/src/linux/linux.cpp
index 222acda..0e9872c 100644
--- a/MQTTSNClient/src/linux/linux.cpp
+++ b/MQTTSNClient/src/linux/linux.cpp
@@ -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);
diff --git a/MQTTSNGateway/src/MQTTConnection.h b/MQTTSNGateway/src/MQTTConnection.h
deleted file mode 100644
index e2df956..0000000
--- a/MQTTSNGateway/src/MQTTConnection.h
+++ /dev/null
@@ -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 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
-void MQTT::Connection::run(void const* arg)
-{
-
-
-
-
-}
-
-
-template
-void MQTT::Connection::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
-MQTT::Connection::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
-bool MQTT::Connection::isQoS2msgidFree(unsigned short id)
-{
- for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i)
- {
- if (incomingQoS2messages[i] == id)
- return false;
- }
- return true;
-}
-
-
-template
-bool MQTT::Connection::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
-void MQTT::Connection::freeQoS2msgid(unsigned short id)
-{
- for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i)
- {
- if (incomingQoS2messages[i] == id)
- {
- incomingQoS2messages[i] = 0;
- return;
- }
- }
-}
-#endif
-
-
-template
-int MQTT::Connection::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
-int MQTT::Connection::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
-int MQTT::Connection::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
-int MQTT::Connection::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
-int MQTT::Connection::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
-int MQTT::Connection::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
-int MQTT::Connection::connect()
-{
- MQTTPacket_connectData default_options = MQTTPacket_connectData_initializer;
- return connect(default_options);
-}
-
-
-
-template
-int MQTT::Connection::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
diff --git a/MQTTSNGateway/src/MQTTGWConnectionHandler.cpp b/MQTTSNGateway/src/MQTTGWConnectionHandler.cpp
new file mode 100644
index 0000000..88263da
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTGWConnectionHandler.cpp
@@ -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);
+}
+
diff --git a/MQTTSNGateway/src/MQTTGWConnectionHandler.h b/MQTTSNGateway/src/MQTTGWConnectionHandler.h
new file mode 100644
index 0000000..8d8af3c
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTGWConnectionHandler.h
@@ -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_ */
diff --git a/MQTTSNGateway/src/MQTTGWPacket.cpp b/MQTTSNGateway/src/MQTTGWPacket.cpp
new file mode 100644
index 0000000..858bf35
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTGWPacket.cpp
@@ -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
+
+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;
+}
+
diff --git a/MQTTSNGateway/src/MQTTGWPacket.h b/MQTTSNGateway/src/MQTTGWPacket.h
new file mode 100644
index 0000000..ecba6bb
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTGWPacket.h
@@ -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_ */
diff --git a/MQTTSNGateway/src/MQTTGWPublishHandler.cpp b/MQTTSNGateway/src/MQTTGWPublishHandler.cpp
new file mode 100644
index 0000000..cebb633
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTGWPublishHandler.cpp
@@ -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
+
+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);
+}
+
diff --git a/MQTTSNGateway/src/MQTTGWPublishHandler.h b/MQTTSNGateway/src/MQTTGWPublishHandler.h
new file mode 100644
index 0000000..72ac8b1
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTGWPublishHandler.h
@@ -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_ */
diff --git a/MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp b/MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp
new file mode 100644
index 0000000..b31ac7d
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp
@@ -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);
+}
+
diff --git a/MQTTSNGateway/src/MQTTGWSubscribeHandler.h b/MQTTSNGateway/src/MQTTGWSubscribeHandler.h
new file mode 100644
index 0000000..1775826
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTGWSubscribeHandler.h
@@ -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_ */
diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp
new file mode 100644
index 0000000..83f1c05
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp
@@ -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;
+ }
+}
diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.h b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.h
new file mode 100644
index 0000000..e506e95
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.h
@@ -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_ */
diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp
new file mode 100644
index 0000000..b0ee3a2
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp
@@ -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;
+ }
+}
diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.h b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.h
new file mode 100644
index 0000000..0d30004
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.h
@@ -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_ */
diff --git a/MQTTSNGateway/src/MQTTSNGWClient.cpp b/MQTTSNGateway/src/MQTTSNGWClient.cpp
new file mode 100644
index 0000000..d8dd663
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWClient.cpp
@@ -0,0 +1,1142 @@
+/**************************************************************************************
+ * 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 "MQTTSNGWClient.h"
+#include "MQTTSNGateway.h"
+#include "SensorNetwork.h"
+#include "Network.h"
+#include
+#include
+#include
+
+using namespace MQTTSNGW;
+
+/*=====================================
+ Class ClientList
+ =====================================*/
+ClientList::ClientList()
+{
+ _clientCnt = 0;
+ _authorize = false;
+ _firstClient = 0;
+ _endClient = 0;
+}
+
+ClientList::~ClientList()
+{
+ _mutex.lock();
+ Client* cl = _firstClient;
+ Client* ncl;
+
+ while (cl != 0)
+ {
+ ncl = cl->_nextClient;
+ delete cl;
+ cl = ncl;
+ };
+ _mutex.unlock();
+}
+
+/**
+ * Create ClientList from a client list file.
+ * @param File name of the client list
+ * @return true: Reject client connection that is not registered in the client list
+ *
+ * File format is:
+ * Lines bigning with # are comment line.
+ * ClientId, SensorNetAddress, "unstableLine", "secureConnection"
+ * in case of UDP, SensorNetAddress format is portNo@IPAddress.
+ * if the SensorNetwork is not stable, write unstableLine.
+ * if BrokerConnection is SSL, write secureConnection.
+ *
+ * Ex:
+ * #Client List
+ * ClientId1,11200@192.168.10.10
+ * ClientID2,35000@192.168.50.200,unstableLine
+ * ClientID3,40000@192.168.200.50,secureConnection
+ * ClientID4,41000@192.168.200.51,unstableLine,secureConnection
+ */
+bool ClientList::authorize(const char* fileName)
+{
+ FILE* fp;
+ char buf[258];
+ size_t pos;;
+ bool secure;
+ bool stable;
+ SensorNetAddress netAddr;
+ MQTTSNString clientId;
+
+ clientId.cstring = 0;
+ clientId.lenstring.data = 0;
+ clientId.lenstring.len = 0;
+
+ if ((fp = fopen(fileName, "r")) != 0)
+ {
+ while (fgets(buf, 256, fp) != 0)
+ {
+ if (*buf == '#')
+ {
+ continue;
+ }
+ string data = string(buf);
+ while ((pos = data.find_first_of("  \t\n")) != string::npos)
+ {
+ data.erase(pos, 1);
+ }
+ if (data.empty())
+ {
+ continue;
+ }
+ pos = data.find_first_of(",");
+ string id = data.substr(0, pos);
+
+ clientId.cstring = strdup(id.c_str());
+
+ string addr = data.substr(pos + 1);
+
+ if (netAddr.setAddress(&addr) == 0)
+ {
+ secure = (data.find("secureConnection") != string::npos);
+ stable = !(data.find("unstableLine") != string::npos);
+ createClient(&netAddr, &clientId, stable, secure);
+ }
+ else
+ {
+ WRITELOG("Invalid address %s\n", data.c_str());
+ }
+ }
+ fclose(fp);
+ _authorize = true;
+ }
+ return _authorize;
+}
+
+void ClientList::erase(Client* client)
+{
+ _mutex.lock();
+ Client* prev = client->_prevClient;
+ Client* next = client->_nextClient;
+
+ if (prev)
+ {
+ prev->_nextClient = next;
+ }
+ else
+ {
+ _firstClient = next;
+
+ }
+ if (next)
+ {
+ next->_prevClient = prev;
+ }
+ else
+ {
+ _endClient = prev;
+ }
+ _clientCnt--;
+ _authorize = false;
+ _mutex.unlock();
+}
+
+Client* ClientList::getClient(SensorNetAddress* addr)
+{
+ _mutex.lock();
+ Client* client = _firstClient;
+
+ while (client != 0)
+ {
+ if (client->getSensorNetAddress()->isMatch(addr) )
+ {
+ _mutex.unlock();
+ return client;
+ }
+ client = client->_nextClient;
+ }
+ _mutex.unlock();
+ return 0;
+}
+
+Client* ClientList::getClient(void)
+{
+ return _firstClient;
+}
+
+Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, bool unstableLine, bool secure)
+{
+ Client* client = 0;
+
+ /* clients must be authorized */
+ if ( _authorize )
+ {
+ /* search cliene with sensorNetAddress from the list */
+ return getClient(addr);
+ }
+
+ /* anonimous clients */
+ if ( _clientCnt > DEFAULT_MAX_CLIENTS )
+ {
+ return 0; // full of clients
+ }
+
+ client = getClient(addr);
+ if ( client )
+ {
+ return client;
+ }
+
+ /* creat a new client */
+ client = new Client(secure);
+ client->setClientAddress(addr);
+ client->setSensorNetType(unstableLine);
+ if ( MQTTSNstrlen(*clientId) )
+ {
+ client->setClientId(*clientId);
+ }
+
+ /* add the list */
+ if ( _firstClient == 0 )
+ {
+ _firstClient = client;
+ _endClient = client;
+ }
+ else
+ {
+ _endClient->_nextClient = client;
+ client->_prevClient = _endClient;
+ _endClient = client;
+ }
+ _clientCnt++;
+ _mutex.unlock();
+ return client;
+}
+
+uint16_t ClientList::getClientCount()
+{
+ return _clientCnt;
+}
+
+bool ClientList::isAuthorized()
+{
+ return _authorize;
+}
+
+/*=====================================
+ Class Client
+ =====================================*/
+static const char* theClientStatus[] = { "Disconnected", "TryConnecting", "Connecting", "Active", "Awake", "Asleep", "Lost" };
+
+Client::Client(bool secure)
+{
+ _packetId = 0;
+ _snMsgId = 0;
+ _status = Cstat_Disconnected;
+ _keepAliveMsec = 0;
+ _topics = new Topics();
+ _clientId = 0;
+ _willTopic = 0;
+ _willMsg = 0;
+ _connectData.Protocol = 0;
+ _connectData.clientID = 0;
+ _connectData.flags.all = 0;
+ _connectData.header.byte = 0;
+ _connectData.keepAliveTimer = 0;
+ _connectData.version = 0;
+ _connectData.willMsg = 0;
+ _connectData.willTopic = 0;
+ _network = new Network(secure);
+ _secureNetwork = secure;
+ _sensorNetype = true;
+ _connAck = 0;
+ _waitWillMsgFlg = false;
+ _prevClient = 0;
+ _nextClient = 0;
+}
+
+Client::~Client()
+{
+ if ( _topics )
+ {
+ delete _topics;
+ }
+
+ if ( _clientId )
+ {
+ free(_clientId);
+ }
+
+ if ( _willTopic )
+ {
+ free(_willTopic);
+ }
+
+ if ( _willMsg )
+ {
+ free(_willMsg);
+ }
+
+ if (_connAck)
+ {
+ delete _connAck;
+ }
+
+ if (_network)
+ {
+ delete _network;
+ }
+}
+
+uint16_t Client::getWaitedPubTopicId(uint16_t msgId)
+{
+ MQTTSN_topicTypes type;
+ return _waitedPubTopicIdMap.getTopicId(msgId, &type);
+}
+
+uint16_t Client::getWaitedSubTopicId(uint16_t msgId)
+{
+ MQTTSN_topicTypes type;
+ return _waitedSubTopicIdMap.getTopicId(msgId, &type);
+}
+
+MQTTSNPacket* Client::getClientSleepPacket()
+{
+ return _clientSleepPacketQue.getPacket();
+}
+
+Connect* Client::getConnectData(void)
+{
+ return &_connectData;
+}
+
+void Client::eraseWaitedPubTopicId(uint16_t msgId)
+{
+ _waitedPubTopicIdMap.erase(msgId);
+}
+
+void Client::eraseWaitedSubTopicId(uint16_t msgId)
+{
+ _waitedSubTopicIdMap.erase(msgId);
+}
+
+void Client::clearWaitedPubTopicId(void)
+{
+ _waitedPubTopicIdMap.clear();
+}
+
+void Client::clearWaitedSubTopicId(void)
+{
+ _waitedSubTopicIdMap.clear();
+}
+
+void Client::setWaitedPubTopicId(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type)
+{
+ _waitedPubTopicIdMap.add(msgId, topicId, type);
+}
+void Client::setWaitedSubTopicId(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type)
+{
+ _waitedSubTopicIdMap.add(msgId, topicId, type);
+}
+
+void Client::setClientSleepPacket(MQTTSNPacket* packet)
+{
+ updateStatus(packet);
+ _clientSleepPacketQue.post(packet);
+}
+
+void Client::checkTimeover(void)
+{
+ if (_status == Cstat_Active && _keepAliveTimer.isTimeup())
+ {
+ _status = Cstat_Lost;
+ _network->disconnect();
+ }
+}
+
+void Client::setKeepAlive(MQTTSNPacket* packet)
+{
+ MQTTSNPacket_connectData param;
+ if (packet->getCONNECT(¶m))
+ {
+ _keepAliveMsec = param.duration * 1000UL;
+ _keepAliveTimer.start(_keepAliveMsec * 1.5);
+ }
+}
+
+void Client::updateStatus(MQTTSNPacket* packet)
+{
+ if (((_status == Cstat_Disconnected) || (_status == Cstat_Lost)) && packet->getType() == MQTTSN_CONNECT)
+ {
+ setKeepAlive(packet);
+ }
+ else if (_status == Cstat_Active)
+ {
+ switch (packet->getType())
+ {
+ case MQTTSN_PINGREQ:
+ case MQTTSN_PUBLISH:
+ case MQTTSN_SUBSCRIBE:
+ case MQTTSN_UNSUBSCRIBE:
+ case MQTTSN_PUBACK:
+ case MQTTSN_PUBCOMP:
+ case MQTTSN_PUBREL:
+ case MQTTSN_PUBREC:
+ _keepAliveTimer.start(_keepAliveMsec * 1.5);
+ break;
+ case MQTTSN_DISCONNECT:
+ {
+ uint16_t duration;
+ packet->getDISCONNECT(&duration);
+ if (duration)
+ {
+ _status = Cstat_Asleep;
+ _keepAliveMsec = duration * 1000UL;
+ }
+ else
+ {
+ disconnected();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ }
+ else if (_status == Cstat_Asleep)
+ {
+ if (packet->getType() == MQTTSN_CONNECT)
+ {
+ setKeepAlive(packet);
+ _status = Cstat_Connecting;
+ }
+ else if (packet->getType() == MQTTSN_PINGREQ)
+ {
+ if ( packet->getPINGREQ() > 0 )
+ {
+ _status = Cstat_Awake;
+ }
+ }
+ }
+ else if (_status == Cstat_Awake)
+ {
+ switch (packet->getType())
+ {
+ case MQTTSN_CONNECT:
+ _status = Cstat_Connecting;
+ setKeepAlive(packet);
+ break;
+ case MQTTSN_DISCONNECT:
+ disconnected();
+ break;
+ case MQTTSN_PINGRESP:
+ _status = Cstat_Asleep;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void Client::updateStatus(ClientStatus stat)
+{
+ _status = stat;
+}
+
+void Client::connectSended()
+{
+ _status = Cstat_Connecting;
+}
+
+void Client::connackSended(int rc)
+{
+ if (rc == MQTTSN_RC_ACCEPTED)
+ {
+ _status = Cstat_Active;
+ }
+ else
+ {
+ disconnected();
+ }
+}
+
+void Client::disconnected(void)
+{
+ _status = Cstat_Disconnected;
+ _waitWillMsgFlg = false;
+}
+
+bool Client::isConnectSendable(void)
+{
+ if (_status == Cstat_Lost || _status == Cstat_TryConnecting)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+uint16_t Client::getNextPacketId(void)
+{
+ _packetId++;
+ if ( _packetId == 0xffff )
+ {
+ _packetId = 1;
+ }
+ return _packetId;
+}
+
+uint8_t Client::getNextSnMsgId(void)
+{
+ _snMsgId++;
+ if (_snMsgId == 0)
+ {
+ _snMsgId++;
+ }
+ return _snMsgId;
+}
+
+Topics* Client::getTopics(void)
+{
+ return _topics;
+}
+
+Network* Client::getNetwork(void)
+{
+ return _network;
+}
+
+void Client::setClientAddress(SensorNetAddress* sensorNetAddr)
+{
+ _sensorNetAddr = *sensorNetAddr;
+}
+
+SensorNetAddress* Client::getSensorNetAddress(void)
+{
+ return &_sensorNetAddr;
+}
+
+void Client::setSensorNetType(bool stable)
+{
+ _sensorNetype = stable;
+}
+
+void Client::setTopics(Topics* topics)
+{
+ _topics = topics;
+}
+
+void Client::setWaitWillMsgFlg(bool flg)
+{
+ _waitWillMsgFlg = flg;
+}
+
+bool Client::isWaitWillMsg(void)
+{
+ return _waitWillMsgFlg;
+}
+
+bool Client::isDisconnect(void)
+{
+ return (_status == Cstat_Disconnected);
+}
+
+bool Client::isActive(void)
+{
+ return (_status == Cstat_Active);
+}
+
+bool Client::isSleep(void)
+{
+ return (_status == Cstat_Asleep);
+}
+
+bool Client::isSecureNetwork(void)
+{
+ return _secureNetwork;
+}
+
+bool Client::isSensorNetStable(void)
+{
+ return _sensorNetype;
+}
+
+WaitREGACKPacketList* Client::getWaitREGACKPacketList()
+{
+ return &_waitREGACKList;
+}
+
+Client* Client::getNextClient(void)
+{
+ return _nextClient;
+}
+
+void Client::setClientId(MQTTSNString id)
+{
+ if ( _clientId )
+ {
+ free(_clientId);
+ }
+
+ /* save clientId into (char*)_clientId NULL terminated */
+ _clientId = (char*)calloc(MQTTSNstrlen(id) + 1, 1);
+ unsigned char* ptr = (unsigned char*)_clientId;
+ writeMQTTSNString((unsigned char**)&ptr, id);
+}
+
+void Client::setWillTopic(MQTTSNString willTopic)
+{
+ if ( _willTopic )
+ {
+ free(_willTopic);
+ }
+
+ _willTopic = (char*)calloc(MQTTSNstrlen(willTopic) + 1, 1);
+ /* save willTopic into (char*)_willTopic with NULL termination */
+ unsigned char* ptr = (unsigned char*)_willTopic;
+ writeMQTTSNString((unsigned char**)&ptr, willTopic);
+}
+
+void Client::setWillMsg(MQTTSNString willMsg)
+{
+ if ( _willMsg)
+ {
+ free(_willMsg);
+ }
+
+ _willMsg = (char*)calloc(MQTTSNstrlen(willMsg) + 1, 1);
+ /* save willMsg into (char*)_willMsg with NULL termination */
+ unsigned char* ptr = (unsigned char*)_willMsg;
+ writeMQTTSNString((unsigned char**)&ptr, willMsg);
+}
+
+char* Client::getClientId(void)
+{
+ return _clientId;
+}
+
+char* Client::getWillTopic(void)
+{
+ return _willTopic;
+}
+
+char* Client::getWillMsg(void)
+{
+ return _willMsg;
+}
+
+const char* Client::getStatus(void)
+{
+ return theClientStatus[_status];
+}
+
+/*=====================================
+ Class Topic
+ ======================================*/
+Topic::Topic()
+{
+ _topicName = 0;
+ _topicId = 0;
+ _next = 0;
+}
+
+Topic::Topic(string* topic)
+{
+ _topicName = topic;
+ _topicId = 0;
+ _next = 0;
+}
+
+Topic::~Topic()
+{
+ if ( _topicName )
+ {
+ delete _topicName;
+ }
+}
+
+string* Topic::getTopicName(void)
+{
+ return _topicName;
+}
+
+uint16_t Topic::getTopicId(void)
+{
+ return _topicId;
+}
+
+int Topic::hasWildCard(unsigned int* pos)
+{
+ unsigned int p = _topicName->find("+", 0);
+ if (p != string::npos)
+ {
+ *pos = p;
+ return 1;
+ }
+ else
+ {
+ string::iterator it = _topicName->end();
+ if (*it == '#')
+ {
+ *pos = _topicName->size() - 1;
+ return 2;
+ }
+ }
+ *pos = 0;
+ return 0;
+}
+
+bool Topic::isMatch(string* topicName)
+{
+ unsigned int pos;
+
+ if (topicName->size() < _topicName->size())
+ {
+ return false;
+ }
+
+ if (hasWildCard(&pos) == 1)
+ {
+ if (_topicName->compare(0, pos - 1, *topicName, 0, pos - 1) == 0)
+ {
+ if (_topicName->compare(pos + 1, 1, "/") == 0)
+ {
+ unsigned int loc = topicName->find('/', pos);
+ if (loc != 0)
+ {
+ if (_topicName->compare(pos + 1, _topicName->size() - pos - 1, *topicName, loc,
+ topicName->size() - pos - 1) == 0)
+ {
+ return true;
+ }
+ }
+ }
+ else
+ {
+ unsigned int loc = _topicName->find(pos, '/');
+ if (loc != 0)
+ {
+ if (topicName->find('/', loc) != 0)
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }
+ else if (hasWildCard(&pos) == 2 && (_topicName->compare(0, pos, *topicName, 0, pos) == 0))
+ {
+ return true;
+ }
+ else if (_topicName->compare(*topicName) == 0)
+ {
+ return true;
+ }
+ return false;
+}
+
+/*=====================================
+ Class Topics
+ ======================================*/
+Topics::Topics()
+{
+ _first = 0;
+ _nextTopicId = 0;
+}
+
+Topics::~Topics()
+{
+ Topic* p = _first;
+ while (p)
+ {
+ Topic* q = p->_next;
+ delete p;
+ p = q;
+ }
+}
+
+uint16_t Topics::getTopicId(MQTTSN_topicid* topicid)
+{
+ if (topicid->type != MQTTSN_TOPIC_TYPE_NORMAL)
+ {
+ return 0;
+ }
+
+ Topic* p = _first;
+ while (p)
+ {
+ if (strncmp(p->_topicName->c_str(), topicid->data.long_.name, topicid->data.long_.len) == 0)
+ {
+ return p->_topicId;
+ }
+ p = p->_next;
+ }
+ return 0;
+}
+
+Topic* Topics::getTopic(uint16_t id)
+{
+ Topic* p = _first;
+ while (p)
+ {
+ if (p->_topicId == id)
+ {
+ return p;
+ }
+ p = p->_next;
+ }
+ return 0;
+}
+
+Topic* Topics::getTopic(MQTTSN_topicid* topicid)
+{
+ Topic* p = _first;
+ while (p)
+ {
+ if (p->_topicId == topicid->data.id)
+ {
+ return p;
+ }
+ p = p->_next;
+ }
+ return 0;
+}
+
+Topic* Topics::add(MQTTSN_topicid* topicid)
+{
+ Topic* topic;
+ uint16_t id = 0;
+ string* topicName = 0;
+
+ if (topicid->type != MQTTSN_TOPIC_TYPE_NORMAL)
+ {
+ return 0;
+ }
+ id = getTopicId(topicid);
+
+ if (id)
+ {
+ topic = getTopic(id);
+ }
+ else
+ {
+ topicName = new string(topicid->data.long_.name, topicid->data.long_.len);
+ topic = add(topicName);
+ }
+ return topic;
+}
+
+
+Topic* Topics::add(string* topicName)
+{
+ Topic* topic = 0;
+
+ Topic* tp = _first;
+
+ topic = new Topic();
+
+ if (topic == 0)
+ {
+ return 0;
+ }
+ string* name = new string(*topicName);
+ topic->_topicName = name;
+ topic->_topicId = getNextTopicId();
+
+ if (tp == 0)
+ {
+ _first = topic;
+ }
+
+ while (tp)
+ {
+ if (tp->_next == 0)
+ {
+ tp->_next = topic;
+ break;
+ }
+ else
+ {
+ tp = tp->_next;
+ }
+ }
+ return topic;
+}
+
+uint16_t Topics::getNextTopicId()
+{
+ return ++_nextTopicId == 0xffff ? _nextTopicId += 2 : _nextTopicId;
+}
+
+Topic* Topics::match(MQTTSN_topicid* topicid)
+{
+ if (topicid->type != MQTTSN_TOPIC_TYPE_NORMAL)
+ {
+ return 0;
+ }
+ string topicName(topicid->data.long_.name, topicid->data.long_.len);
+
+ Topic* topic = _first;
+ while (topic)
+ {
+ if (topic->isMatch(&topicName))
+ {
+ return topic;
+ }
+ topic = topic->_next;
+ }
+ return 0;
+}
+
+/*=====================================
+ Class TopicIdMap
+ =====================================*/
+TopicIdMapelement::TopicIdMapelement(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type)
+{
+ _msgId = msgId;
+ _topicId = topicId;
+ _type = type;
+ _next = 0;
+ _prev = 0;
+}
+
+TopicIdMapelement::~TopicIdMapelement()
+{
+
+}
+
+TopicIdMap::TopicIdMap()
+{
+ char param[MQTTSNGW_PARAM_MAX];
+
+ _maxInflight = DEFAULT_INFLIGHTMESSAGE;
+ if ( theProcess->getParam("MaxInflightMsg", param) == 0 )
+ {
+ _maxInflight = atoi(param);
+ }
+
+ _msgIds = 0;
+ _first = 0;
+ _end = 0;
+ _cnt = 0;
+}
+
+TopicIdMap::~TopicIdMap()
+{
+ TopicIdMapelement* p = _first;
+ while ( p )
+ {
+ TopicIdMapelement* q = p->_next;
+ delete p;
+ p = q;
+ }
+}
+
+uint16_t TopicIdMap::getTopicId(uint16_t msgId, MQTTSN_topicTypes* type)
+{
+ TopicIdMapelement* p = _first;
+ while ( p )
+ {
+ if ( p->_msgId == msgId )
+ {
+ *type = p->_type;
+ return p->_topicId;
+ }
+ p = p->_next;
+ }
+ return 0;
+}
+
+int TopicIdMap::add(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type)
+{
+ if ( _cnt > _maxInflight * 2 || topicId == 0)
+ {
+ return 0;
+ }
+ if ( getTopicId(msgId, &type) > 0 )
+ {
+ erase(msgId);
+ }
+
+ TopicIdMapelement* elm = new TopicIdMapelement(msgId, topicId, type);
+ if ( elm == 0 )
+ {
+ return 0;
+ }
+ if ( _first == 0 )
+ {
+ _first = elm;
+ _end = elm;
+ }
+ else
+ {
+ elm->_prev = _end;
+ _end->_next = elm;
+ _end = elm;
+ }
+ _cnt++;
+ return 1;
+}
+
+void TopicIdMap::erase(uint16_t msgId)
+{
+ TopicIdMapelement* p = _first;
+ while ( p )
+ {
+ if ( p->_msgId == msgId )
+ {
+ if ( p->_prev == 0 )
+ {
+ _first = p->_next;
+ }
+ else
+ {
+ p->_prev->_next = p->_next;
+ }
+
+ if ( p->_next == 0 )
+ {
+ _end = p->_prev;
+ }
+ else
+ {
+ p->_next->_prev = p->_prev;
+ }
+ delete p;
+ break;
+
+ }
+ p = p->_next;
+ }
+ _cnt--;
+}
+
+void TopicIdMap::clear(void)
+{
+ TopicIdMapelement* p = _first;
+ while ( p )
+ {
+ TopicIdMapelement* q = p->_next;
+ delete p;
+ p = q;
+ }
+ _first = 0;
+ _end = 0;
+ _cnt = 0;
+}
+
+/*=====================================
+ Class WaitREGACKPacket
+ =====================================*/
+waitREGACKPacket::waitREGACKPacket(MQTTSNPacket* packet, uint16_t REGACKMsgId)
+{
+ _packet = packet;
+ _msgId = REGACKMsgId;
+ _next = 0;
+ _prev = 0;
+}
+
+waitREGACKPacket::~waitREGACKPacket()
+{
+ delete _packet;
+}
+
+/*=====================================
+ Class WaitREGACKPacketList
+ =====================================*/
+
+WaitREGACKPacketList::WaitREGACKPacketList()
+{
+ _first = 0;
+ _end = 0;
+}
+
+WaitREGACKPacketList::~WaitREGACKPacketList()
+{
+ waitREGACKPacket* p = _first;
+ while (p)
+ {
+ waitREGACKPacket* q = p->_next;
+ delete p;
+ p = q;
+ }
+}
+
+int WaitREGACKPacketList::setPacket(MQTTSNPacket* packet, uint16_t REGACKMsgId)
+{
+ waitREGACKPacket* elm = new waitREGACKPacket(packet, REGACKMsgId);
+ if (elm == 0)
+ {
+ return 0;
+ }
+
+ if (_first == 0)
+ {
+ _first = elm;
+ _end = elm;
+ }
+ elm->_prev = _end;
+ _end->_next = elm;
+ return 1;
+}
+
+MQTTSNPacket* WaitREGACKPacketList::getPacket(uint16_t REGACKMsgId)
+{
+ waitREGACKPacket* p = _first;
+ while (p)
+ {
+ if (p->_msgId == REGACKMsgId)
+ {
+ return p->_packet;
+ }
+ p = p->_next;
+ }
+ return 0;
+}
+
+void WaitREGACKPacketList::erase(uint16_t REGACKMsgId)
+{
+ waitREGACKPacket* p = _first;
+ while (p)
+ {
+ if (p->_msgId == REGACKMsgId)
+ {
+ if (p->_prev == 0)
+ {
+ _first = p->_next;
+
+ }
+ else
+ {
+ p->_prev->_next = p->_next;
+ }
+ if (p->_next == 0)
+ {
+ _end = p->_prev;
+ }
+ else
+ {
+ p->_next->_prev = p->_prev;
+ }
+ break;
+ // Do not delete element. Element is deleted after sending to Client.
+ }
+ p = p->_next;
+ }
+}
+
diff --git a/MQTTSNGateway/src/MQTTSNGWClient.h b/MQTTSNGateway/src/MQTTSNGWClient.h
new file mode 100644
index 0000000..48a7f9a
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWClient.h
@@ -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 PacketQue
+{
+public:
+ PacketQue()
+ {
+ _que = new Que;
+ }
+
+ ~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* _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 _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_ */
diff --git a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp
new file mode 100644
index 0000000..c905459
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp
@@ -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;
+ }
+}
diff --git a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.h b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.h
new file mode 100644
index 0000000..4af4f0d
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.h
@@ -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_ */
diff --git a/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp
new file mode 100644
index 0000000..ff74aae
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp
@@ -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;
+ }
+}
diff --git a/MQTTSNGateway/src/MQTTSNGWClientSendTask.h b/MQTTSNGateway/src/MQTTSNGWClientSendTask.h
new file mode 100644
index 0000000..d9e1646
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWClientSendTask.h
@@ -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_ */
diff --git a/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp b/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp
new file mode 100644
index 0000000..28baeae
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp
@@ -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);
+}
diff --git a/MQTTSNGateway/src/MQTTSNGWConnectionHandler.h b/MQTTSNGateway/src/MQTTSNGWConnectionHandler.h
new file mode 100644
index 0000000..044e766
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWConnectionHandler.h
@@ -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_ */
diff --git a/MQTTSNGateway/src/MQTTSNGWDefines.h b/MQTTSNGateway/src/MQTTSNGWDefines.h
new file mode 100644
index 0000000..541dad5
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWDefines.h
@@ -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_ */
diff --git a/MQTTSNGateway/src/MQTTSNGWLogmonitor.cpp b/MQTTSNGateway/src/MQTTSNGWLogmonitor.cpp
new file mode 100644
index 0000000..50dc482
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWLogmonitor.cpp
@@ -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
+
+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);
+ }
+ }
+}
+
diff --git a/MQTTSNGateway/src/MQTTSNGWLogmonitor.h b/MQTTSNGateway/src/MQTTSNGWLogmonitor.h
new file mode 100644
index 0000000..cb5838a
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWLogmonitor.h
@@ -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_ */
diff --git a/MQTTSNGateway/src/MQTTSNGWPacket.cpp b/MQTTSNGateway/src/MQTTSNGWPacket.cpp
new file mode 100644
index 0000000..b52116a
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWPacket.cpp
@@ -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
+#include
+#include
+
+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;
+}
diff --git a/MQTTSNGateway/src/MQTTSNGWPacket.h b/MQTTSNGateway/src/MQTTSNGWPacket.h
new file mode 100644
index 0000000..5cd7578
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWPacket.h
@@ -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_ */
diff --git a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp
new file mode 100644
index 0000000..c24659b
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp
@@ -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;
+ }
+}
+
diff --git a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.h b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.h
new file mode 100644
index 0000000..c91e690
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.h
@@ -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_ */
diff --git a/MQTTSNGateway/src/MQTTSNGWProcess.cpp b/MQTTSNGateway/src/MQTTSNGWProcess.cpp
new file mode 100644
index 0000000..c8e07fb
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWProcess.cpp
@@ -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
+#include
+#include
+#include
+#include
+#include
+#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());
+ }
+}
diff --git a/MQTTSNGateway/src/MQTTSNGWProcess.h b/MQTTSNGateway/src/MQTTSNGWProcess.h
new file mode 100644
index 0000000..55b223b
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWProcess.h
@@ -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
+#include
+#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 QueElement
+{
+ template friend class Que;
+public:
+ QueElement(T* t)
+ {
+ _element = t;
+ _next = 0;
+ _prev = 0;
+ }
+
+ ~QueElement()
+ {
+ }
+
+private:
+ T* _element;
+ QueElement* _next;
+ QueElement* _prev;
+};
+
+/*=====================================
+ Class Que
+ ====================================*/
+template
+class Que
+{
+public:
+ Que()
+ {
+ _head = 0;
+ _tail = 0;
+ _cnt = 0;
+ }
+
+ ~Que()
+ {
+ QueElement* elm = _head;
+ while (elm)
+ {
+ QueElement* next = elm->_next;
+ delete elm->_element;
+ delete elm;
+ elm = next;
+ }
+ }
+
+ void pop(void)
+ {
+ if ( _head )
+ {
+ QueElement* 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* elm = new QueElement(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* _head;
+ QueElement* _tail;
+};
+
+
+extern Process* theProcess;
+extern MultiTaskProcess* theMultiTaskProcess;
+
+}
+#endif /* MQTTSNGWPROCESS_H_ */
diff --git a/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp b/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp
new file mode 100644
index 0000000..7029fce
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp
@@ -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);
+
+}
diff --git a/MQTTSNGateway/src/MQTTSNGWPublishHandler.h b/MQTTSNGateway/src/MQTTSNGWPublishHandler.h
new file mode 100644
index 0000000..7213cbe
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWPublishHandler.h
@@ -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_ */
diff --git a/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp
new file mode 100644
index 0000000..6dcfb98
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp
@@ -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);
+}
+
diff --git a/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.h b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.h
new file mode 100644
index 0000000..21410d5
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.h
@@ -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_ */
diff --git a/MQTTSNGateway/src/MQTTSNGateway.cpp b/MQTTSNGateway/src/MQTTSNGateway.cpp
new file mode 100644
index 0000000..9dd10ee
--- /dev/null
+++ b/MQTTSNGateway/src/MQTTSNGateway.cpp
@@ -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;
+}
diff --git a/MQTTSNGateway/src/MQTTSNGateway.h b/MQTTSNGateway/src/MQTTSNGateway.h
index 94ffa59..8115a65 100644
--- a/MQTTSNGateway/src/MQTTSNGateway.h
+++ b/MQTTSNGateway/src/MQTTSNGateway.h
@@ -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 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.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 connections[MAX_MQTT_CONNECTIONS];
-
+ Que _que;
+ Mutex _mutex;
+ Semaphore _sem;
};
-
-} // end namespace
-
-
-template
-MQTTSN::Gateway::Gateway(UDPNetwork& network, unsigned int command_timeout_ms) : udpstack(network)
-{
- mode = AGGREGATING;
-}
-
-
-template
-void MQTTSN::Gateway::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
-int MQTTSN::Gateway::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
-int MQTTSN::Gateway::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
-int MQTTSN::Gateway::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_ */
diff --git a/MQTTSNGateway/src/linux/Network.cpp b/MQTTSNGateway/src/linux/Network.cpp
new file mode 100644
index 0000000..cde1d02
--- /dev/null
+++ b/MQTTSNGateway/src/linux/Network.cpp
@@ -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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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;
+}
+
diff --git a/MQTTSNGateway/src/linux/Network.h b/MQTTSNGateway/src/linux/Network.h
new file mode 100644
index 0000000..5c6b79f
--- /dev/null
+++ b/MQTTSNGateway/src/linux/Network.h
@@ -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
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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_ */
diff --git a/MQTTSNGateway/src/linux/Threading.cpp b/MQTTSNGateway/src/linux/Threading.cpp
new file mode 100644
index 0000000..4dee15a
--- /dev/null
+++ b/MQTTSNGateway/src/linux/Threading.cpp
@@ -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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+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)->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();
+}
diff --git a/MQTTSNGateway/src/linux/Threading.h b/MQTTSNGateway/src/linux/Threading.h
index 016421e..3c86d31 100644
--- a/MQTTSNGateway/src/linux/Threading.h
+++ b/MQTTSNGateway/src/linux/Threading.h
@@ -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
+#include
+#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_ */
diff --git a/MQTTSNGateway/src/linux/build.sh b/MQTTSNGateway/src/linux/build.sh
deleted file mode 100644
index e597508..0000000
--- a/MQTTSNGateway/src/linux/build.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-g++ main.cpp -I MQTTPacket/src -I MQTTSNPacket/src -I linux MQTTPacket/src/*.c MQTTSNPacket/src/*.c
-
diff --git a/MQTTSNGateway/src/linux/linux.cpp b/MQTTSNGateway/src/linux/linux.cpp
index 222acda..1b948c6 100644
--- a/MQTTSNGateway/src/linux/linux.cpp
+++ b/MQTTSNGateway/src/linux/linux.cpp
@@ -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
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
#include
+#include
+#include
#include
-#include
#include
-
-#include
#include
-#include
+#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;
-};
diff --git a/MQTTSNGateway/src/linux/linux.h b/MQTTSNGateway/src/linux/linux.h
new file mode 100644
index 0000000..c73e544
--- /dev/null
+++ b/MQTTSNGateway/src/linux/linux.h
@@ -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_ */
diff --git a/MQTTSNGateway/src/linux/main.cpp b/MQTTSNGateway/src/linux/main.cpp
deleted file mode 100644
index 3505782..0000000
--- a/MQTTSNGateway/src/linux/main.cpp
+++ /dev/null
@@ -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 gateway =
- MQTTSN::Gateway(net);
-
- gateway.run(NULL);
-
- return 0;
-}
diff --git a/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp b/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp
new file mode 100644
index 0000000..0144e79
--- /dev/null
+++ b/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp
@@ -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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#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;
+}
+
diff --git a/MQTTSNGateway/src/linux/udp/SensorNetwork.h b/MQTTSNGateway/src/linux/udp/SensorNetwork.h
new file mode 100644
index 0000000..b474f16
--- /dev/null
+++ b/MQTTSNGateway/src/linux/udp/SensorNetwork.h
@@ -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
+
+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_ */
diff --git a/MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp b/MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp
new file mode 100644
index 0000000..5996401
--- /dev/null
+++ b/MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp
@@ -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
+#include
+#include
+#include
+#include
+#include
+
+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);
+}
+
diff --git a/MQTTSNGateway/src/linux/xbee/SensorNetwork.h b/MQTTSNGateway/src/linux/xbee/SensorNetwork.h
new file mode 100644
index 0000000..f4a18ee
--- /dev/null
+++ b/MQTTSNGateway/src/linux/xbee/SensorNetwork.h
@@ -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
+#include
+
+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_ */
diff --git a/MQTTSNGateway/src/main.cpp b/MQTTSNGateway/src/main.cpp
deleted file mode 100644
index ae9c9fb..0000000
--- a/MQTTSNGateway/src/main.cpp
+++ /dev/null
@@ -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;
-}
-
diff --git a/MQTTSNGateway/src/mainGateway.cpp b/MQTTSNGateway/src/mainGateway.cpp
new file mode 100644
index 0000000..e33d915
--- /dev/null
+++ b/MQTTSNGateway/src/mainGateway.cpp
@@ -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;
+}
+
diff --git a/MQTTSNGateway/src/mainLogmonitor.cpp b/MQTTSNGateway/src/mainLogmonitor.cpp
new file mode 100644
index 0000000..f73a2a9
--- /dev/null
+++ b/MQTTSNGateway/src/mainLogmonitor.cpp
@@ -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;
+}
+
diff --git a/MQTTSNPacket/src/MQTTSNConnectClient.c b/MQTTSNPacket/src/MQTTSNConnectClient.c
index 5a1179f..d62d3c1 100644
--- a/MQTTSNPacket/src/MQTTSNConnectClient.c
+++ b/MQTTSNPacket/src/MQTTSNConnectClient.c
@@ -20,6 +20,7 @@
#include
+
/**
* 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;
diff --git a/MQTTSNPacket/src/MQTTSNDeserializePublish.c b/MQTTSNPacket/src/MQTTSNDeserializePublish.c
index 9aae227..8dd0f7e 100644
--- a/MQTTSNPacket/src/MQTTSNDeserializePublish.c
+++ b/MQTTSNPacket/src/MQTTSNDeserializePublish.c
@@ -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 */
diff --git a/MQTTSNPacket/src/MQTTSNPacket.c b/MQTTSNPacket/src/MQTTSNPacket.c
index 4f98b6a..80f55f4 100644
--- a/MQTTSNPacket/src/MQTTSNPacket.c
+++ b/MQTTSNPacket/src/MQTTSNPacket.c
@@ -19,7 +19,7 @@
#include
-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)
diff --git a/MQTTSNPacket/src/MQTTSNPacket.h b/MQTTSNPacket/src/MQTTSNPacket.h
index 974619f..a3466c6 100644
--- a/MQTTSNPacket/src/MQTTSNPacket.h
+++ b/MQTTSNPacket/src/MQTTSNPacket.h
@@ -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);
diff --git a/MQTTSNPacket/src/MQTTSNPublish.h b/MQTTSNPacket/src/MQTTSNPublish.h
index 937817b..a020f96 100644
--- a/MQTTSNPacket/src/MQTTSNPublish.h
+++ b/MQTTSNPacket/src/MQTTSNPublish.h
@@ -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_ */
diff --git a/MQTTSNPacket/src/MQTTSNSubscribeServer.c b/MQTTSNPacket/src/MQTTSNSubscribeServer.c
index d16f80a..8e48919 100644
--- a/MQTTSNPacket/src/MQTTSNSubscribeServer.c
+++ b/MQTTSNPacket/src/MQTTSNSubscribeServer.c
@@ -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)
{
diff --git a/MQTTSNPacket/src/MQTTSNUnsubscribeServer.c b/MQTTSNPacket/src/MQTTSNUnsubscribeServer.c
index 4dff54f..c2205d9 100644
--- a/MQTTSNPacket/src/MQTTSNUnsubscribeServer.c
+++ b/MQTTSNPacket/src/MQTTSNUnsubscribeServer.c
@@ -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;
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..8c8ec4c
--- /dev/null
+++ b/Makefile
@@ -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) ../
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index bc7a72d..9396809 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Eclipse Paho MQTT-SN Embedded C client
+# Eclipse Paho MQTT-SN Embedded C
## Project description: