From f7fc5c49f5b7522394e945c27b7e7478a0cf25e7 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Sat, 4 Aug 2018 17:46:42 +0900 Subject: [PATCH] Update: Add Aggregate Gateway functions. #127 Signed-off-by: tomoaki --- .cproject | 4 +- .settings/language.settings.xml | 25 + .travis.yml | 2 - MQTTSNGateway/Makefile | 12 +- MQTTSNGateway/README.md | 73 +- MQTTSNGateway/clients.conf | 27 +- MQTTSNGateway/gateway.conf | 17 +- MQTTSNGateway/predefinedTopic.conf | 33 +- MQTTSNGateway/qos-1clients.conf | 30 - MQTTSNGateway/src/MQTTGWPacket.cpp | 86 +- MQTTSNGateway/src/MQTTGWPacket.h | 19 + MQTTSNGateway/src/MQTTGWPublishHandler.cpp | 90 +- MQTTSNGateway/src/MQTTGWPublishHandler.h | 5 + MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp | 27 +- MQTTSNGateway/src/MQTTGWSubscribeHandler.h | 2 + .../src/MQTTSNAggregateConnectionHandler.cpp | 202 ++++ .../src/MQTTSNAggregateConnectionHandler.h | 48 + MQTTSNGateway/src/MQTTSNGWAdapter.cpp | 321 ++++++ MQTTSNGateway/src/MQTTSNGWAdapter.h | 99 ++ MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp | 253 +++++ MQTTSNGateway/src/MQTTSNGWAdapterManager.h | 70 ++ .../src/MQTTSNGWAggregateTopicTable.cpp | 161 +++ .../src/MQTTSNGWAggregateTopicTable.h | 98 ++ MQTTSNGateway/src/MQTTSNGWAggregater.cpp | 143 +++ MQTTSNGateway/src/MQTTSNGWAggregater.h | 76 ++ MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp | 13 +- MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp | 21 +- MQTTSNGateway/src/MQTTSNGWBrokerSendTask.h | 3 + MQTTSNGateway/src/MQTTSNGWClient.cpp | 944 ++---------------- MQTTSNGateway/src/MQTTSNGWClient.h | 136 +-- MQTTSNGateway/src/MQTTSNGWClientList.cpp | 460 +++++++++ MQTTSNGateway/src/MQTTSNGWClientList.h | 70 ++ MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp | 94 +- MQTTSNGateway/src/MQTTSNGWClientRecvTask.h | 7 +- MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp | 35 +- MQTTSNGateway/src/MQTTSNGWClientSendTask.h | 9 +- .../src/MQTTSNGWConnectionHandler.cpp | 8 +- MQTTSNGateway/src/MQTTSNGWDefines.h | 2 +- .../src/MQTTSNGWEncapsulatedPacket.cpp | 4 +- MQTTSNGateway/src/MQTTSNGWForwarder.cpp | 67 +- MQTTSNGateway/src/MQTTSNGWForwarder.h | 22 +- MQTTSNGateway/src/MQTTSNGWMessageIdTable.cpp | 218 ++++ MQTTSNGateway/src/MQTTSNGWMessageIdTable.h | 78 ++ MQTTSNGateway/src/MQTTSNGWPacket.cpp | 132 ++- MQTTSNGateway/src/MQTTSNGWPacket.h | 9 +- .../src/MQTTSNGWPacketHandleTask.cpp | 309 ++++-- MQTTSNGateway/src/MQTTSNGWPacketHandleTask.h | 58 +- MQTTSNGateway/src/MQTTSNGWProcess.cpp | 8 +- MQTTSNGateway/src/MQTTSNGWProcess.h | 30 +- MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp | 105 +- MQTTSNGateway/src/MQTTSNGWPublishHandler.h | 6 +- MQTTSNGateway/src/MQTTSNGWQoS-1Proxy.cpp | 275 ----- MQTTSNGateway/src/MQTTSNGWQoS-1Proxy.h | 79 -- MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.cpp | 75 ++ MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.h | 53 + .../src/MQTTSNGWSubscribeHandler.cpp | 121 ++- MQTTSNGateway/src/MQTTSNGWSubscribeHandler.h | 6 +- MQTTSNGateway/src/MQTTSNGWTopic.cpp | 519 ++++++++++ MQTTSNGateway/src/MQTTSNGWTopic.h | 115 +++ MQTTSNGateway/src/MQTTSNGWVersion.h | 2 +- MQTTSNGateway/src/MQTTSNGateway.cpp | 206 ++-- MQTTSNGateway/src/MQTTSNGateway.h | 93 +- MQTTSNGateway/src/linux/Threading.cpp | 14 + MQTTSNGateway/src/mainGateway.cpp | 19 +- MQTTSNGateway/src/tests/TestTopicIdMap.cpp | 2 +- 65 files changed, 4368 insertions(+), 1982 deletions(-) create mode 100644 .settings/language.settings.xml delete mode 100644 MQTTSNGateway/qos-1clients.conf create mode 100644 MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.cpp create mode 100644 MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.h create mode 100644 MQTTSNGateway/src/MQTTSNGWAdapter.cpp create mode 100644 MQTTSNGateway/src/MQTTSNGWAdapter.h create mode 100644 MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp create mode 100644 MQTTSNGateway/src/MQTTSNGWAdapterManager.h create mode 100644 MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.cpp create mode 100644 MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.h create mode 100644 MQTTSNGateway/src/MQTTSNGWAggregater.cpp create mode 100644 MQTTSNGateway/src/MQTTSNGWAggregater.h create mode 100644 MQTTSNGateway/src/MQTTSNGWClientList.cpp create mode 100644 MQTTSNGateway/src/MQTTSNGWClientList.h create mode 100644 MQTTSNGateway/src/MQTTSNGWMessageIdTable.cpp create mode 100644 MQTTSNGateway/src/MQTTSNGWMessageIdTable.h delete mode 100644 MQTTSNGateway/src/MQTTSNGWQoS-1Proxy.cpp delete mode 100644 MQTTSNGateway/src/MQTTSNGWQoS-1Proxy.h create mode 100644 MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.cpp create mode 100644 MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.h create mode 100644 MQTTSNGateway/src/MQTTSNGWTopic.cpp create mode 100644 MQTTSNGateway/src/MQTTSNGWTopic.h diff --git a/.cproject b/.cproject index fae7107..f52491d 100644 --- a/.cproject +++ b/.cproject @@ -66,7 +66,7 @@ - + @@ -137,7 +137,7 @@ - + diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml new file mode 100644 index 0000000..f557f24 --- /dev/null +++ b/.settings/language.settings.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.travis.yml b/.travis.yml index 04f67cf..ed564b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: cpp compiler: - g++ - - clang install: - if ["$CXX" = "g++" ]; then export CXX="g++-4.8"; fi @@ -14,7 +13,6 @@ addons: - g++-4.8 - cmake - cmake-data - - clang script: - ./travis-build.sh diff --git a/MQTTSNGateway/Makefile b/MQTTSNGateway/Makefile index 0eca7fd..fb4562b 100644 --- a/MQTTSNGateway/Makefile +++ b/MQTTSNGateway/Makefile @@ -11,7 +11,6 @@ CONFIG := gateway.conf CLIENTS := clients.conf PREDEFTOPIC := predefinedTopic.conf FORWARDERS := forwarders.conf -QOSM1CLIENT := qos-1clients.conf SRCDIR := src SUBDIR := ../MQTTSNPacket/src @@ -40,7 +39,15 @@ $(SRCDIR)/MQTTSNGWPublishHandler.cpp \ $(SRCDIR)/MQTTSNGWSubscribeHandler.cpp \ $(SRCDIR)/MQTTSNGWEncapsulatedPacket.cpp \ $(SRCDIR)/MQTTSNGWForwarder.cpp \ -$(SRCDIR)/MQTTSNGWQoS-1Proxy.cpp \ +$(SRCDIR)/MQTTSNGWQoSm1Proxy.cpp \ +$(SRCDIR)/MQTTSNGWAdapter.cpp \ +$(SRCDIR)/MQTTSNGWAggregater.cpp \ +$(SRCDIR)/MQTTSNGWClientList.cpp \ +$(SRCDIR)/MQTTSNGWTopic.cpp \ +$(SRCDIR)/MQTTSNGWAdapterManager.cpp \ +$(SRCDIR)/MQTTSNAggregateConnectionHandler.cpp \ +$(SRCDIR)/MQTTSNGWMessageIdTable.cpp \ +$(SRCDIR)/MQTTSNGWAggregateTopicTable.cpp \ $(SRCDIR)/$(OS)/$(SENSORNET)/SensorNetwork.cpp \ $(SRCDIR)/$(OS)/Timer.cpp \ $(SRCDIR)/$(OS)/Network.cpp \ @@ -143,7 +150,6 @@ install: cp -pf $(CLIENTS) ../../ cp -pf $(PREDEFTOPIC) ../../ cp -pf $(FORWARDERS) ../../ - cp -pf $(QOSM1CLIENT) ../../ exectest: diff --git a/MQTTSNGateway/README.md b/MQTTSNGateway/README.md index 3bae83e..5d1627a 100644 --- a/MQTTSNGateway/README.md +++ b/MQTTSNGateway/README.md @@ -2,7 +2,7 @@ ### **step1. Build the gateway** ```` -$ git clone https://github.com/eclipse/paho.mqtt-sn.embedded-c +$ git clone -b experiment https://github.com/eclipse/paho.mqtt-sn.embedded-c $ cd paho.mqtt-sn.embedded-c/MQTTSNGateway $ make $ make install @@ -22,58 +22,69 @@ $ ./MQTT-SNGateway [-f Config file name] ### **How to Change the configuration of the gateway** **../gateway.conf** Contents are follows: -```` +
    
 
 # config file of MQTT-SN Gateway
+#
 
 BrokerName=iot.eclipse.org
 BrokerPortNo=1883
-BrokerSecurePortNo=8883    
+BrokerSecurePortNo=8883
 
+#
+# When AggregateGateway=YES or ClientAuthentication=YES,
+# All clients must be specified by the ClientList File  
+#
+
+AggregateGateway=NO
 ClientAuthentication=NO
-#ClientsList=/path/to/your_clients.conf    
 
-PredefinedTopic=NO
+#ClientsList=/path/to/your_clients.conf
+
+QoS-1=NO
+OoS-1ProxyName=Proxy007
+
 #PredefinedTopicList=/path/to/your_predefinedTopic.conf
 
 Forwarder=NO
-#ForwardersList=/home/tomoaki/tmp/forwarders.conf
+#ForwardersList=/path/to/your_forwarers.conf
+
+#RootCAfile=/etc/ssl/certs/ca-certificates.crt
+#RootCApath=/etc/ssl/certs/
+#CertsFile=/path/to/certKey.pem
+#PrivateKey=/path/to/privateKey.pem
+
+GatewayID=1
+GatewayName=PahoGateway-01
+KeepAlive=900
+#LoginID=your_ID
+#Password=your_Password
 
-QoS-1=NO
-QoS-1ProxyName=Proxy007
-#QoS-1ClientsList=/path/to/your_qos-1clients.conf
-    
-#RootCAfile=/path/to/your_Root_CA.crt    
-#RootCApath=/path/to/your_certs_directory/   
-#CertKey=/path/to/your_cert.pem
-#PrivateKey=/path/to/your_private-key.pem
-    
-GatewayID=1    
-GatewayName=PahoGateway-01    
-KeepAlive=900    
-#LoginID=your_ID    
-#Password=your_Password    
 
 # UDP
-GatewayPortNo=10000    
-MulticastIP=225.1.1.1    
-MulticastPortNo=1883    
+GatewayPortNo=10000
+MulticastIP=225.1.1.1
+MulticastPortNo=1883
 
 # XBee
-Baudrate=38400    
-SerialDevice=/dev/ttyUSB0    
-ApiMode=2    
-````    
+Baudrate=38400
+SerialDevice=/dev/ttyUSB0
+ApiMode=2
+
+# LOG
+ShearedMemory=NO;
+
+
**BrokerName** to specify a domain name of the Broker, and **BrokerPortNo** is a port No of the Broker. **BrokerSecurePortNo** is for TLS connection. **MulticastIP** and **MulticastPortNo** is a multicast address for GWSEARCH messages. Gateway is waiting GWSEARCH and when receiving it send GWINFO message via MulticastIP address. Clients can get the gateway address (Gateway IP address and **GatewayPortNo**) from GWINFO message by means of std::recvfrom(). Client should know the MulticastIP and MulticastPortNo to send a SEARCHGW message. **GatewayId** is used by GWINFO message. **KeepAlive** is a duration of ADVERTISE message in seconds. -when **ClientAuthentication** is YES, see MQTTSNGWClient.cpp line53, clients file specified by ClientsList is required. This file defines connect allowed clients by ClientId and SensorNetwork Address. e.g. IP address and Port No. -When **PredefinedTopic** is YES, Pre-definedTopicID file specified by PredefinedTopicList is effective. This file defines Pre-definedTopics of the clients. In this file, ClientID,TopicName and TopicID are declared in CSV format. -When **Forwarder** is YES, Forwarder Encapsulation Message is available. Connectable Forwarders are specifed by ForwardersList file. In this file, ForwarderIds and those sensorNet addresses are declared in CSV format. -When **QoS-1** is YES, QoS-1 PUBLISH Message is available. Clients which allow to send it, are specifed by QoS-1ClientsList file. In this file, ClientsId and those sensorNet addresses are declared in CSV format. QoS-1ProxyName is a ClientId of the proxy. +when **AggregateGateway** or **ClientAuthentication** is **YES**, All clients which connect to the gateway must be declared by a **ClientsList** file. +Format of the file is ClientId and SensorNetwork Address. e.g. IP address and Port No etc, in CSV. more detail see clients.conf +When **PredefinedTopic** is **YES**, **Pre-definedTopicId**s specified by **PredefinedTopicList** are effective. This file defines Pre-definedTopics of the clients. In this file, ClientID,TopicName and TopicID are declared in CSV format. +When **Forwarder** is **YE**S, Forwarder Encapsulation Message is available. Connectable Forwarders are specifed by **ForwardersList** file. In this file, ForwarderIds and those sensorNet addresses are declared in CSV format. diff --git a/MQTTSNGateway/clients.conf b/MQTTSNGateway/clients.conf index 16d128a..28d2bab 100644 --- a/MQTTSNGateway/clients.conf +++ b/MQTTSNGateway/clients.conf @@ -11,8 +11,29 @@ # http://www.eclipse.org/org/documents/edl-v10.php. #*********************************************************************** # +# 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 Broker's Connection is SSL, write secureConnection. +# if the client send PUBLISH QoS-1, QoS-1 is required. +# +# 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 +# ClientID5,41000@192.168.200.51,unstableLine,secureConnection,QoS-1 +# # SensorNetwork address format is defined by SensorNetAddress::setAddress(string* data) function. # -Client02,172.16.1.7:12002 -Client03,172.16.1.8:13003 -Client01,172.16.1.6:12001 + +Client02,172.16.1.11:12002 +Client03,172.16.1.11:13003 +Client01,172.16.1.11:12001 + +QoS-1_Client01,172.16.1.11:20001,QoS-1 +QoS-1_Client02,172.16.1.11:20002,QoS-1 +QoS-1_Client03,172.16.1.11:20003,QoS-1 diff --git a/MQTTSNGateway/gateway.conf b/MQTTSNGateway/gateway.conf index 277f7ae..e2a1d25 100644 --- a/MQTTSNGateway/gateway.conf +++ b/MQTTSNGateway/gateway.conf @@ -10,26 +10,33 @@ # and the Eclipse Distribution License is available at # http://www.eclipse.org/org/documents/edl-v10.php. #*************************************************************************** - +# # config file of MQTT-SN Gateway +# BrokerName=iot.eclipse.org BrokerPortNo=1883 BrokerSecurePortNo=8883 +# +# When AggregateGateway=YES or ClientAuthentication=YES, +# All clients must be specified by the ClientList File +# + +AggregateGateway=NO ClientAuthentication=NO + #ClientsList=/path/to/your_clients.conf +QoS-1=NO +OoS-1ProxyName=Proxy007 + PredefinedTopic=NO #PredefinedTopicList=/path/to/your_predefinedTopic.conf Forwarder=NO #ForwardersList=/path/to/your_forwarers.conf -QoS-1=NO -OoS-1ProxyName=Proxy007 -#QoS-1ClientsList=/path/to/your_qos-1clients.conf - #RootCAfile=/etc/ssl/certs/ca-certificates.crt #RootCApath=/etc/ssl/certs/ #CertsFile=/path/to/certKey.pem diff --git a/MQTTSNGateway/predefinedTopic.conf b/MQTTSNGateway/predefinedTopic.conf index eec33f4..95d23ea 100644 --- a/MQTTSNGateway/predefinedTopic.conf +++ b/MQTTSNGateway/predefinedTopic.conf @@ -20,28 +20,27 @@ # One for QoS-1 PUBLISH Clients, the other for another clients. # -# pre-defined-topics for QoS-1 clients. -# ClientIDs should be "ClientProxy" -# - -ClientProxy, ty4tw/proxy/predefTopic1, 1 -ClientProxy, ty4tw/proxy/predefTopic2, 2 -ClientProxy, ty4tw/proxy/predefTopic3, 3 - - -# -# pre-defined-topics for another clients +# pre-defined-topics for Clients # GatewayTestClient,ty4tw/predefinedTopic1, 1 GatewayTestClient,ty4tw/predefinedTopic2, 2 GatewayTestClient,ty4tw/predefinedTopic3, 3 -ClientPUB,ty4tw/predefinedTopic1, 1 -ClientPUB,ty4tw/predefinedTopic2, 2 -ClientPUB,ty4tw/predefinedTopic3, 3 +# +# pre-defined-topics for QoS-1 clients. +# + +QoS-1_Client01,ty4tw/proxy/predefTopic1, 1 +QoS-1_Client01,ty4tw/proxy/predefTopic2, 2 +QoS-1_Client01,ty4tw/proxy/predefTopic3, 3 + +QoS-1_Client02,ty4tw/proxy/predefTopic1, 1 +QoS-1_Client02,ty4tw/proxy/predefTopic3, 2 +QoS-1_Client02,ty4tw/proxy/predefTopic3, 3 + +QoS-1_Client03,ty4tw/proxy/predefTopic1, 1 +QoS-1_Client03,ty4tw/proxy/predefTopic2, 2 +QoS-1_Client03,ty4tw/proxy/predefTopic3, 3 -ClientSUB,ty4tw/predefinedTopic1, 1 -ClientSUB,ty4tw/predefinedTopic2, 2 -ClientSUB,ty4tw/predefinedTopic3, 3 diff --git a/MQTTSNGateway/qos-1clients.conf b/MQTTSNGateway/qos-1clients.conf deleted file mode 100644 index 58ed914..0000000 --- a/MQTTSNGateway/qos-1clients.conf +++ /dev/null @@ -1,30 +0,0 @@ -#*********************************************************************** -# Copyright (c) 2018, 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. -#*********************************************************************** -# -# Clients which send QoS-1 PUBLISH are defined by this file. -# -# Clients are defined by the ClientId and those SensorNetAddress -# in a CSV format as follow: -# -# ClientId, SensorNetAddress -# -# where SensorNetwork address format is defined by -# SensorNetAddress::setAddress(string* data) function. -# -# - -QoS-1_Client01,172.16.1.11:20001 -QoS-1_Clien02t,172.16.1.11:20002 -QoS-1_Client03,172.16.1.11:20003 -QoS-1_Client04,172.16.1.11:20004 -QoS-1_Client05,172.16.1.11:20005 diff --git a/MQTTSNGateway/src/MQTTGWPacket.cpp b/MQTTSNGateway/src/MQTTGWPacket.cpp index 55532fc..67ff660 100644 --- a/MQTTSNGateway/src/MQTTGWPacket.cpp +++ b/MQTTSNGateway/src/MQTTGWPacket.cpp @@ -21,6 +21,9 @@ using namespace MQTTSNGW; +int readInt(char** ptr); +void writeInt(unsigned char** pptr, int msgId); + #define MAX_NO_OF_REMAINING_LENGTH_BYTES 3 /** * List of the predefined MQTT v3 packet names. @@ -511,12 +514,12 @@ char* MQTTGWPacket::getMsgId(char* pbuf) sprintf(pbuf, " %04X", pub.msgId); } break; + case SUBSCRIBE: + case UNSUBSCRIBE: case PUBACK: case PUBREC: case PUBREL: case PUBCOMP: - case SUBSCRIBE: - case UNSUBSCRIBE: case SUBACK: case UNSUBACK: sprintf(pbuf, " %02X%02X", _data[0], _data[1]); @@ -525,9 +528,77 @@ char* MQTTGWPacket::getMsgId(char* pbuf) sprintf(pbuf, " "); break; } + if ( strcmp(pbuf, " 0000") == 0 ) + { + sprintf(pbuf, " "); + } return pbuf; } +int MQTTGWPacket::getMsgId(void) +{ + int type = getType(); + int msgId = 0; + + switch ( type ) + { + case PUBLISH: + Publish pub; + pub.msgId = 0; + getPUBLISH(&pub); + msgId = pub.msgId; + break; + case PUBACK: + case PUBREC: + case PUBREL: + case PUBCOMP: + case SUBSCRIBE: + case UNSUBSCRIBE: + case SUBACK: + case UNSUBACK: + msgId = 256 * (unsigned char)_data[0] + (unsigned char)_data[1]; + break; + default: + break; + } + return msgId; +} + +void MQTTGWPacket::setMsgId(int msgId) +{ + int type = getType(); + unsigned char* ptr = 0; + int len = 0; + + switch ( type ) + { + case PUBLISH: + Publish pub; + pub.msgId = 0; + getPUBLISH(&pub); + pub.msgId = msgId; + ptr = _data + pub.topiclen; + writeInt(&ptr, pub.msgId); + *ptr++ = (unsigned char)(msgId / 256); + *ptr = (unsigned char)(msgId % 256); + break; + case SUBSCRIBE: + case UNSUBSCRIBE: + case PUBACK: + case PUBREC: + case PUBREL: + case PUBCOMP: + case SUBACK: + case UNSUBACK: + ptr = _data; + *ptr++ = (unsigned char)(msgId / 256); + *ptr = (unsigned char)(msgId % 256); + break; + default: + break; + } +} + char* MQTTGWPacket::print(char* pbuf) { uint8_t packetData[MQTTSNGW_MAX_PACKET_SIZE]; @@ -561,3 +632,14 @@ MQTTGWPacket& MQTTGWPacket::operator =(MQTTGWPacket& packet) return *this; } +UTF8String MQTTGWPacket::getTopic(void) +{ + UTF8String str = {0, nullptr}; + if ( _header.bits.type == SUBSCRIBE || _header.bits.type == UNSUBSCRIBE ) + { + char* ptr = (char*)(_data + 2); + str.len = readInt(&ptr); + str.data = (char*)(_data + 4); + } + return str; +} diff --git a/MQTTSNGateway/src/MQTTGWPacket.h b/MQTTSNGateway/src/MQTTGWPacket.h index 458dd4d..bc35d97 100644 --- a/MQTTSNGateway/src/MQTTGWPacket.h +++ b/MQTTSNGateway/src/MQTTGWPacket.h @@ -116,6 +116,12 @@ typedef struct unsigned char version; /**< MQTT version number */ } Connect; +#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, 0 } +#define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'C'}, 0, 4, {NULL, {0, NULL}}, 60, 1, 0, \ + MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} } + + + /** * Data for a willMessage. */ @@ -177,6 +183,15 @@ typedef struct int msgId; /**< MQTT message id */ } Ack; +/** + * UTF8String. + */ +typedef struct +{ + unsigned char len; + char* data; +} UTF8String; + /** * Class MQTT Packet */ @@ -203,7 +218,11 @@ public: int setHeader(unsigned char msgType); int setSUBSCRIBE(const char* topic, unsigned char qos, unsigned short msgId); int setUNSUBSCRIBE(const char* topics, unsigned short msgid); + + UTF8String getTopic(void); char* getMsgId(char* buf); + int getMsgId(void); + void setMsgId(int msgId); char* print(char* buf); MQTTGWPacket& operator =(MQTTGWPacket& packet); diff --git a/MQTTSNGateway/src/MQTTGWPublishHandler.cpp b/MQTTSNGateway/src/MQTTGWPublishHandler.cpp index 5a2b5a6..b264a36 100644 --- a/MQTTSNGateway/src/MQTTGWPublishHandler.cpp +++ b/MQTTSNGateway/src/MQTTGWPublishHandler.cpp @@ -106,7 +106,7 @@ void MQTTGWPublishHandler::handlePublish(Client* client, MQTTGWPacket* packet) /* This message might be subscribed with wild card. */ topicId.type = MQTTSN_TOPIC_TYPE_NORMAL; Topic* topic = client->getTopics()->match(&topicId); - if (topic == 0) + if (topic == nullptr) { WRITELOG(" Invalid Topic. PUBLISH message is canceled.\n"); if (pub.header.bits.qos == 1) @@ -181,7 +181,7 @@ void MQTTGWPublishHandler::handlePuback(Client* client, MQTTGWPacket* packet) { Ack ack; packet->getAck(&ack); - TopicIdMapelement* topicId = client->getWaitedPubTopicId((uint16_t)ack.msgId); + TopicIdMapElement* topicId = client->getWaitedPubTopicId((uint16_t)ack.msgId); if (topicId) { MQTTSNPacket* mqttsnPacket = new MQTTSNPacket(); @@ -234,3 +234,89 @@ void MQTTGWPublishHandler::handleAck(Client* client, MQTTGWPacket* packet, int t } } + + +void MQTTGWPublishHandler::handleAggregatePuback(Client* client, MQTTGWPacket* packet) +{ + uint16_t msgId = packet->getMsgId(); + uint16_t clientMsgId = 0; + Client* newClient = _gateway->getAdapterManager()->convertClient(msgId, &clientMsgId); + if ( newClient != nullptr ) + { + packet->setMsgId((int)clientMsgId); + handlePuback(newClient, packet); + } +} + +void MQTTGWPublishHandler::handleAggregateAck(Client* client, MQTTGWPacket* packet, int type) +{ + uint16_t msgId = packet->getMsgId(); + uint16_t clientMsgId = 0; + Client* newClient = _gateway->getAdapterManager()->convertClient(msgId, &clientMsgId); + if ( newClient != nullptr ) + { + packet->setMsgId((int)clientMsgId); + handleAck(newClient, packet,type); + } +} + +void MQTTGWPublishHandler::handleAggregatePubrel(Client* client, MQTTGWPacket* packet) +{ + Publish pub; + packet->getPUBLISH(&pub); + replyACK(client, &pub, PUBCOMP); +} + +void MQTTGWPublishHandler::handleAggregatePublish(Client* client, MQTTGWPacket* packet) +{ + Publish pub; + packet->getPUBLISH(&pub); + + WRITELOG(FORMAT_Y_G_G, currentDateTime(), packet->getName(), + RIGHTARROW, client->getClientId(), "is sleeping. a message was saved."); + + if (pub.header.bits.qos == 1) + { + replyACK(client, &pub, PUBACK); + } + else if ( pub.header.bits.qos == 2) + { + replyACK(client, &pub, PUBREC); + } + + MQTTGWPacket* msg = new MQTTGWPacket(); + *msg = *packet; + if ( msg->getType() == 0 ) + { + WRITELOG("%s MQTTGWPublishHandler::handleAggregatePublish can't allocate memories for Packet.%s\n", ERRMSG_HEADER,ERRMSG_FOOTER); + delete msg; + return; + } + + string* topicName = new string(pub.topic); + Topic topic = Topic(topicName, MQTTSN_TOPIC_TYPE_NORMAL); + AggregateTopicElement* list = _gateway->getAdapterManager()->createClientList(&topic); + if ( list != nullptr ) + { + ClientTopicElement* p = list->getFirstElement(); + + while ( p ) + { + Client* devClient = p->getClient(); + if ( devClient != nullptr ) + { + Event* ev = new Event(); + ev->setBrokerRecvEvent(devClient, packet); + _gateway->getPacketEventQue()->post(ev); + } + else + { + break; + } + + p = list->getNextElement(p); + } + delete list; + } +} + diff --git a/MQTTSNGateway/src/MQTTGWPublishHandler.h b/MQTTSNGateway/src/MQTTGWPublishHandler.h index 72ac8b1..fee60e8 100644 --- a/MQTTSNGateway/src/MQTTGWPublishHandler.h +++ b/MQTTSNGateway/src/MQTTGWPublishHandler.h @@ -32,6 +32,11 @@ public: void handlePuback(Client* client, MQTTGWPacket* packet); void handleAck(Client* client, MQTTGWPacket* packet, int type); + void handleAggregatePublish(Client* client, MQTTGWPacket* packet); + void handleAggregatePuback(Client* client, MQTTGWPacket* packet); + void handleAggregateAck(Client* client, MQTTGWPacket* packet, int type); + void handleAggregatePubrel(Client* client, MQTTGWPacket* packet); + private: void replyACK(Client* client, Publish* pub, int type); diff --git a/MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp b/MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp index a8264ac..2df4815 100644 --- a/MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp +++ b/MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp @@ -38,7 +38,7 @@ void MQTTGWSubscribeHandler::handleSuback(Client* client, MQTTGWPacket* packet) int qos = 0; packet->getSUBACK(&msgId, &rc); - TopicIdMapelement* topicId = client->getWaitedSubTopicId(msgId); + TopicIdMapElement* topicId = client->getWaitedSubTopicId(msgId); if (topicId) { @@ -72,3 +72,28 @@ void MQTTGWSubscribeHandler::handleUnsuback(Client* client, MQTTGWPacket* packet _gateway->getClientSendQue()->post(evt); } +void MQTTGWSubscribeHandler::handleAggregateSuback(Client* client, MQTTGWPacket* packet) +{ + uint16_t msgId = packet->getMsgId(); + uint16_t clientMsgId = 0; + Client* newClient = _gateway->getAdapterManager()->getAggregater()->convertClient(msgId, &clientMsgId); + if ( newClient != nullptr ) + { + packet->setMsgId((int)clientMsgId); + handleSuback(newClient, packet); + } +} + +void MQTTGWSubscribeHandler::handleAggregateUnsuback(Client* client, MQTTGWPacket* packet) +{ + uint16_t msgId = packet->getMsgId(); + uint16_t clientMsgId = 0; + Client* newClient = _gateway->getAdapterManager()->getAggregater()->convertClient(msgId, &clientMsgId); + if ( newClient != nullptr ) + { + packet->setMsgId((int)clientMsgId); + handleUnsuback(newClient, packet); + } +} + + diff --git a/MQTTSNGateway/src/MQTTGWSubscribeHandler.h b/MQTTSNGateway/src/MQTTGWSubscribeHandler.h index 1775826..d52b70f 100644 --- a/MQTTSNGateway/src/MQTTGWSubscribeHandler.h +++ b/MQTTSNGateway/src/MQTTGWSubscribeHandler.h @@ -31,6 +31,8 @@ public: ~MQTTGWSubscribeHandler(); void handleSuback(Client* clnode, MQTTGWPacket* packet); void handleUnsuback(Client* clnode, MQTTGWPacket* packet); + void handleAggregateSuback(Client* client, MQTTGWPacket* packet); + void handleAggregateUnsuback(Client* client, MQTTGWPacket* packet); private: Gateway* _gateway; diff --git a/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.cpp b/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.cpp new file mode 100644 index 0000000..dded6df --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.cpp @@ -0,0 +1,202 @@ +/************************************************************************************** + * Copyright (c) 2018, 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 "MQTTSNAggregateConnectionHandler.h" +#include "MQTTSNGateway.h" +#include "MQTTSNGWPacket.h" +#include "MQTTGWPacket.h" +#include + +using namespace std; +using namespace MQTTSNGW; + +/*===================================== + Class MQTTSNAggregateConnectionHandler + =====================================*/ +MQTTSNAggregateConnectionHandler::MQTTSNAggregateConnectionHandler(Gateway* gateway) +{ + _gateway = gateway; +} + +MQTTSNAggregateConnectionHandler::~MQTTSNAggregateConnectionHandler() +{ + +} + + +/* + * CONNECT + */ +void MQTTSNAggregateConnectionHandler::handleConnect(Client* client, MQTTSNPacket* packet) +{ + MQTTSNPacket_connectData data; + if ( packet->getCONNECT(&data) == 0 ) + { + return; + } + + /* return CONNACK when the client is sleeping */ + if ( client->isSleep() || client->isAwake() ) + { + MQTTSNPacket* packet = new MQTTSNPacket(); + packet->setCONNACK(MQTTSN_RC_ACCEPTED); + Event* ev = new Event(); + ev->setClientSendEvent(client, packet); + _gateway->getClientSendQue()->post(ev); + sendStoredPublish(client); + return; + } + + //* 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 */ + + + client->setSessionStatus(false); + if (data.cleansession) + { + /* reset the table of msgNo and TopicId pare */ + client->clearWaitedPubTopicId(); + client->clearWaitedSubTopicId(); + + /* renew the TopicList */ + if (topics) + { + _gateway->getAdapterManager()->removeAggregateTopicList(topics, client); + topics->eraseNormal(); + } + client->setSessionStatus(true); + } + + 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 + { + /* create CONNACK & send it to the client */ + MQTTSNPacket* packet = new MQTTSNPacket(); + packet->setCONNACK(MQTTSN_RC_ACCEPTED); + Event* ev = new Event(); + ev->setClientSendEvent(client, packet); + _gateway->getClientSendQue()->post(ev); + client->connackSended(MQTTSN_RC_ACCEPTED); + sendStoredPublish(client); + return; + } +} + + +/* + * WILLMSG + */ +void MQTTSNAggregateConnectionHandler::handleWillmsg(Client* client, MQTTSNPacket* packet) +{ + if ( !client->isWaitWillMsg() ) + { + DEBUGLOG(" MQTTSNConnectionHandler::handleWillmsg WaitWillMsgFlg is off.\n"); + return; + } + + MQTTSNString willmsg = MQTTSNString_initializer; + //Connect* connectData = client->getConnectData(); + + if( client->isConnectSendable() ) + { + /* save WillMsg in the client */ + if ( packet->getWILLMSG(&willmsg) == 0 ) + { + return; + } + client->setWillMsg(willmsg); + + /* Send CONNACK to the client */ + MQTTSNPacket* packet = new MQTTSNPacket(); + packet->setCONNACK(MQTTSN_RC_ACCEPTED); + Event* ev = new Event(); + ev->setClientSendEvent(client, packet); + _gateway->getClientSendQue()->post(ev); + + sendStoredPublish(client); + return; + } +} + +/* + * DISCONNECT + */ +void MQTTSNAggregateConnectionHandler::handleDisconnect(Client* client, MQTTSNPacket* packet) +{ + MQTTSNPacket* snMsg = new MQTTSNPacket(); + snMsg->setDISCONNECT(0); + Event* evt = new Event(); + evt->setClientSendEvent(client, snMsg); + _gateway->getClientSendQue()->post(evt); +} + +/* + * PINGREQ + */ +void MQTTSNAggregateConnectionHandler::handlePingreq(Client* client, MQTTSNPacket* packet) +{ + if ( ( client->isSleep() || client->isAwake() ) && client->getClientSleepPacket() ) + { + sendStoredPublish(client); + client->holdPingRequest(); + } + else + { + /* create and send PINGRESP to the PacketHandler */ + client->resetPingRequest(); + + MQTTGWPacket* pingresp = new MQTTGWPacket(); + + pingresp->setHeader(PINGRESP); + + Event* evt = new Event(); + evt->setBrokerRecvEvent(client, pingresp); + _gateway->getPacketEventQue()->post(evt); + } +} + +void MQTTSNAggregateConnectionHandler::sendStoredPublish(Client* client) +{ + MQTTGWPacket* msg = nullptr; + + while ( ( msg = client->getClientSleepPacket() ) != nullptr ) + { + // ToDo: This version can't re-send PUBLISH when PUBACK is not returned. + client->deleteFirstClientSleepPacket(); // pop the que to delete element. + + Event* ev = new Event(); + ev->setBrokerRecvEvent(client, msg); + _gateway->getPacketEventQue()->post(ev); + } +} + diff --git a/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.h b/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.h new file mode 100644 index 0000000..46bf4f0 --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.h @@ -0,0 +1,48 @@ +/************************************************************************************** + * Copyright (c) 2018, 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 MQTTSNGATEWAY_SRC_MQTTSNAGGREGATECONNECTIONHANDLER_H_ +#define MQTTSNGATEWAY_SRC_MQTTSNAGGREGATECONNECTIONHANDLER_H_ + +#include "MQTTSNGWDefines.h" + +namespace MQTTSNGW +{ +class Gateway; +class Client; +class MQTTSNPacket; + +class MQTTSNAggregateConnectionHandler +{ +public: + MQTTSNAggregateConnectionHandler(Gateway* gateway); + ~MQTTSNAggregateConnectionHandler(void); + + void handleConnect(Client* client, MQTTSNPacket* packet); + void handleWillmsg(Client* client, MQTTSNPacket* packet); + void handleDisconnect(Client* client, MQTTSNPacket* packet); + void handlePingreq(Client* client, MQTTSNPacket* packet); + +private: + void sendStoredPublish(Client* client); + + char _pbuf[MQTTSNGW_MAX_PACKET_SIZE * 3]; + Gateway* _gateway; +}; + +} + +#endif /* MQTTSNGATEWAY_SRC_MQTTSNAGGREGATECONNECTIONHANDLER_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWAdapter.cpp b/MQTTSNGateway/src/MQTTSNGWAdapter.cpp new file mode 100644 index 0000000..73cbc29 --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWAdapter.cpp @@ -0,0 +1,321 @@ +/************************************************************************************** + * 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 "Timer.h" +#include "MQTTSNGWDefines.h" +#include "MQTTSNGateway.h" +#include "MQTTSNGWAdapter.h" +#include "SensorNetwork.h" +#include "MQTTSNGWProcess.h" +#include "MQTTSNGWClient.h" + +#include +using namespace MQTTSNGW; + + +/*===================================== + Class Adapter + =====================================*/ +Adapter:: Adapter(Gateway* gw) +{ + _gateway = gw; + _proxy = new Proxy(gw); + _proxySecure = new Proxy(gw); +} + +Adapter::~Adapter(void) +{ + if ( _proxy ) + { + delete _proxy; + } + + if ( _proxySecure ) + { + delete _proxySecure; + } +} + + +void Adapter::setup(const char* adpterName, AdapterType adapterType) +{ + _isSecure = false; + if ( _gateway->hasSecureConnection() ) + { + _isSecure = true; + } + + MQTTSNString id = MQTTSNString_initializer; + MQTTSNString idSecure = MQTTSNString_initializer; + + string name = string(adpterName); + id.cstring = const_cast(name.c_str()); + string nameSecure = string(adpterName) + "-S"; + idSecure.cstring = const_cast(nameSecure.c_str()); + + Client* client = _gateway->getClientList()->createClient(0, &id, true, false, TRANSPEARENT_TYPE); + setClient(client, false); + client->setAdapterType(adapterType); + + client = _gateway->getClientList()->createClient(0, &idSecure, true, true, TRANSPEARENT_TYPE); + setClient(client, true); + client->setAdapterType(adapterType); +} + + +Client* Adapter::getClient(SensorNetAddress* addr) +{ + Client* client = _gateway->getClientList()->getClient(addr); + if ( !client ) + { + return nullptr; + } + else if ( client->isQoSm1() ) + { + return client; + } + else + { + return nullptr; + } +} + +const char* Adapter::getClientId(SensorNetAddress* addr) +{ + Client* client = getClient(addr); + if ( !client ) + { + return nullptr; + } + else if ( client->isQoSm1() ) + { + return client->getClientId(); + } + else + { + return nullptr; + } +} + +bool Adapter::isSecure(SensorNetAddress* addr) +{ + Client* client = getClient(addr); + if ( !client ) + { + return false; + } + else if ( client->isSecureNetwork() ) + { + return true; + } + else + { + return false; + } +} + +void Adapter::setClient(Client* client, bool secure) +{ + if ( secure ) + { + _clientSecure = client; + } + else + { + _client = client; + } +} + +Client* Adapter::getClient(void) +{ + return _client; +} + +Client* Adapter::getSecureClient(void) +{ + return _clientSecure; +} + +void Adapter::checkConnection(void) +{ + _proxy->checkConnection(_client); + + if ( _isSecure ) + { + _proxySecure->checkConnection(_clientSecure); + } +} + +void Adapter::send(MQTTSNPacket* packet, Client* client) +{ + Proxy* proxy = _proxy; + if ( client->isSecureNetwork() && !_isSecure ) + { + if ( _isSecure ) + { + proxy = _proxySecure; + } + else + { + WRITELOG("%s %s No Secure connections %s 's packet is discarded.%s\n", ERRMSG_HEADER, client->getClientId() , ERRMSG_FOOTER); + return; + } + } + + proxy->recv(packet, client); + +} + +void Adapter::resetPingTimer(bool secure) +{ + if ( secure ) + { + _proxySecure->resetPingTimer(); + } + else + { + _proxy->resetPingTimer(); + } +} + +bool Adapter::isActive(void) +{ + return _isActive; +} + +void Adapter::savePacket(Client* client, MQTTSNPacket* packet) +{ + if ( client->isSecureNetwork()) + { + _proxySecure->savePacket(client, packet); + } + else + { + _proxy->savePacket(client, packet); + } +} + + +Client* Adapter::getAdapterClient(Client* client) +{ + if ( client->isSecureNetwork() ) + { + return _client; + } + else + { + return _client; + } +} + +/*===================================== + Class Proxy + =====================================*/ +Proxy::Proxy(Gateway* gw) +{ + _gateway = gw; + _suspendedPacketEventQue = new EventQue(); +} +Proxy::~Proxy(void) +{ + if ( _suspendedPacketEventQue ) + { + delete _suspendedPacketEventQue; + } +} + +void Proxy::checkConnection(Client* client) +{ + if ( client->isDisconnect() || ( client->isConnecting() && _responseTimer.isTimeup()) ) + { + client->connectSended(); + _responseTimer.start(QOSM1_PROXY_RESPONSE_DURATION * 1000UL); + MQTTSNPacket_connectData options = MQTTSNPacket_connectData_initializer; + options.clientID.cstring = client->getClientId(); + options.duration = QOSM1_PROXY_KEEPALIVE_DURATION; + + MQTTSNPacket* packet = new MQTTSNPacket(); + packet->setCONNECT(&options); + Event* ev = new Event(); + ev->setClientRecvEvent(client, packet); + _gateway->getPacketEventQue()->post(ev); + } + else if ( (client->isActive() && _keepAliveTimer.isTimeup() ) || (_isWaitingResp && _responseTimer.isTimeup() ) ) + { + MQTTSNPacket* packet = new MQTTSNPacket(); + MQTTSNString clientId = MQTTSNString_initializer; + packet->setPINGREQ(&clientId); + Event* ev = new Event(); + ev->setClientRecvEvent(client, packet); + _gateway->getPacketEventQue()->post(ev); + _responseTimer.start(QOSM1_PROXY_RESPONSE_DURATION * 1000UL); + _isWaitingResp = true; + + if ( ++_retryCnt > QOSM1_PROXY_MAX_RETRY_CNT ) + { + client->disconnected(); + } + resetPingTimer(); + } +} + + +void Proxy::resetPingTimer(void) +{ + _keepAliveTimer.start(QOSM1_PROXY_KEEPALIVE_DURATION * 1000UL); +} + +void Proxy::recv(MQTTSNPacket* packet, Client* client) +{ + if ( packet->getType() == MQTTSN_CONNACK ) + { + if ( packet->isAccepted() ) + { + _responseTimer.stop(); + _retryCnt = 0; + resetPingTimer(); + sendSuspendedPacket(); + } + } + else if ( packet->getType() == MQTTSN_PINGRESP ) + { + _isWaitingResp = false; + _responseTimer.stop(); + _retryCnt = 0; + resetPingTimer(); + } + else if ( packet->getType() == MQTTSN_DISCONNECT ) + { + // blank + } +} + +void Proxy::savePacket(Client* client, MQTTSNPacket* packet) +{ + MQTTSNPacket* pk = new MQTTSNPacket(*packet); + Event* ev = new Event(); + ev->setClientRecvEvent(client, pk); + _suspendedPacketEventQue->post(ev); +} + +void Proxy::sendSuspendedPacket(void) +{ + while ( _suspendedPacketEventQue->size() ) + { + Event* ev = _suspendedPacketEventQue->wait(); + _gateway->getPacketEventQue()->post(ev); + } +} + diff --git a/MQTTSNGateway/src/MQTTSNGWAdapter.h b/MQTTSNGateway/src/MQTTSNGWAdapter.h new file mode 100644 index 0000000..8ea4b45 --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWAdapter.h @@ -0,0 +1,99 @@ +/************************************************************************************** + * 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 MQTTSNGATEWAY_SRC_MQTTSNGWADAPTER_H_ +#define MQTTSNGATEWAY_SRC_MQTTSNGWADAPTER_H_ + +#include +#include "Timer.h" +namespace MQTTSNGW +{ +class Gateway; +class Client; +class Proxy; +class SensorNetAddress; +class MQTTSNPacket; +class MQTTSNGWPacket; +class EventQue; +class Timer; + +/* When you add a new type, Client::setAdapterType() and Client::isAdapter() functions must be modified. */ +typedef enum{ + Atype_QoSm1Proxy, Atype_Aggregater +}AdapterType; + +/*===================================== + Class Adapter + =====================================*/ +class Adapter +{ +public: + Adapter(Gateway* gw); + ~Adapter(void); + + void setup(const char* adpterName, AdapterType adapterType); + const char* getClientId(SensorNetAddress* addr); + void setClient(Client* client, bool secure); + Client* getClient(SensorNetAddress* addr); + Client* getClient(void); + Client* getSecureClient(void); + Client* getAdapterClient(Client* client); + void resetPingTimer(bool secure); + void checkConnection(void); + void send(MQTTSNPacket* packet, Client* client); + bool isActive(void); + bool isSecure(SensorNetAddress* addr); + void savePacket(Client* client, MQTTSNPacket* packet); + +private: + Gateway* _gateway {nullptr}; + Proxy* _proxy {nullptr}; + Proxy* _proxySecure {nullptr}; + Client* _client {nullptr}; + Client* _clientSecure {nullptr}; + bool _isActive {false}; + bool _isSecure{false}; +}; + + +/*===================================== + Class Proxy + =====================================*/ +class Proxy +{ +public: + Proxy(Gateway* gw); + ~Proxy(void); + + void setKeepAlive(uint16_t secs); + void checkConnection(Client* client); + void resetPingTimer(void); + void recv(MQTTSNPacket* packet, Client* client); + void savePacket(Client* client, MQTTSNPacket* packet); + +private: + void sendSuspendedPacket(void); + Gateway* _gateway; + EventQue* _suspendedPacketEventQue {nullptr}; + Timer _keepAliveTimer; + Timer _responseTimer; + bool _isWaitingResp {false}; + int _retryCnt {0}; +}; + +} + +#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWADAPTER_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp b/MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp new file mode 100644 index 0000000..6cbef35 --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp @@ -0,0 +1,253 @@ +/************************************************************************************** + * 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 "MQTTSNGateway.h" +#include "SensorNetwork.h" +#include "MQTTSNGWProcess.h" +#include "MQTTSNGWVersion.h" +#include "MQTTSNGWClientRecvTask.h" +#include "MQTTSNGWClientSendTask.h" +#include "MQTTSNGWClient.h" +#include "MQTTSNGWAggregater.h" +#include "MQTTSNGWQoSm1Proxy.h" +#include +using namespace MQTTSNGW; + +char* currentDateTime(void); + +/*===================================== + Class AdapterManager + =====================================*/ +AdapterManager::AdapterManager(Gateway* gw) +{ + _gateway = gw; + _forwarders = new ForwarderList(); + _qosm1Proxy = new QoSm1Proxy(gw); + _aggregater = new Aggregater(gw); +} + + +void AdapterManager::initialize(void) +{ + _aggregater->initialize(); + _forwarders->initialize(_gateway); + _qosm1Proxy->initialize(); +} + + +AdapterManager::~AdapterManager(void) +{ + if ( _forwarders ) + { + delete _forwarders; + } + if ( _qosm1Proxy ) + { + delete _qosm1Proxy; + } + if ( _aggregater ) + { + delete _aggregater; + } +} + +ForwarderList* AdapterManager::getForwarderList(void) +{ + return _forwarders; +} + +QoSm1Proxy* AdapterManager::getQoSm1Proxy(void) +{ + return _qosm1Proxy; +} + +Aggregater* AdapterManager::getAggregater(void) +{ + return _aggregater; +} + +bool AdapterManager::isAggregatedClient(Client* client) +{ + if ( !_aggregater->isActive() || client->isQoSm1() || client->isAggregater() || client->isQoSm1Proxy()) + { + return false; + } + else + { + return true; + } +} + + +Client* AdapterManager::getClient(MQTTSNPacket* packet, ClientRecvTask* task) +{ + char buf[128]; + WirelessNodeId nodeId; + SensorNetAddress* senderAddr = _gateway->getSensorNetwork()->getSenderAddress(); + + Client* client = nullptr; + + if ( packet->getType() == MQTTSN_ENCAPSULATED ) + { + Forwarder* fwd = getForwarderList()->getForwarder(senderAddr); + + if ( fwd == nullptr ) + { + task->log(0, packet, 0); + WRITELOG("%s Forwarder %s is not authenticated.%s\n", ERRMSG_HEADER, senderAddr->sprint(buf), ERRMSG_FOOTER); + delete packet; + return client; + } + else + { + MQTTSNString fwdName = MQTTSNString_initializer; + fwdName.cstring = const_cast( fwd->getName() ); + task->log(0, packet, &fwdName); + + /* get the packet from the encapsulation message */ + MQTTSNGWEncapsulatedPacket encap; + encap.desirialize(packet->getPacketData(), packet->getPacketLength()); + nodeId.setId( encap.getWirelessNodeId() ); + client = fwd->getClient(&nodeId); + delete packet; + packet = encap.getMQTTSNPacket(); + } + } + else + { + /* Check the client belonging to QoS-1Proxy ? */ + + if ( _qosm1Proxy->isActive() ) + { + /* get ClientId not Client which can send QoS-1 PUBLISH */ + const char* clientName = _qosm1Proxy->getClientId(senderAddr); + + if ( clientName ) + { + if ( !packet->isQoSMinusPUBLISH() ) + { + client = _qosm1Proxy->getClient(); + task->log(clientName, packet); + WRITELOG("%s %s %s can send only PUBLISH with QoS-1.%s\n", ERRMSG_HEADER, clientName, senderAddr->sprint(buf), ERRMSG_FOOTER); + delete packet; + return client; + } + } + } + } + + if ( client == nullptr ) + { + /* get client from the ClientList of Gateway by sensorNetAddress. */ + client = _gateway->getClientList()->getClient(senderAddr); + } + return client; +} + +Client* AdapterManager::getClient(Client& client) +{ + bool secure = client.isSecureNetwork(); + Client* newClient = &client; + if ( client.isQoSm1() ) + { + newClient = _qosm1Proxy->getAdapterClient(&client); + _qosm1Proxy->resetPingTimer(secure); + } + else if ( client.isAggregated() ) + + { + newClient = _aggregater->getAdapterClient(&client); + _aggregater->resetPingTimer(secure); + } + + return newClient; +} + +int AdapterManager::unicastToClient(Client* client, MQTTSNPacket* packet, ClientSendTask* task) +{ + char pbuf[SIZE_OF_LOG_PACKET * 3]; + Forwarder* fwd = client->getForwarder(); + int rc = 0; + + if ( fwd ) + { + MQTTSNGWEncapsulatedPacket encap(packet); + WirelessNodeId* wnId = fwd->getWirelessNodeId(client); + encap.setWirelessNodeId(wnId); + WRITELOG(FORMAT_Y_W_G, currentDateTime(), encap.getName(), RIGHTARROW, fwd->getId(), encap.print(pbuf)); + task->log(client, packet); + rc = encap.unicast(_gateway->getSensorNetwork(),fwd->getSensorNetAddr()); + } + else + { + task->log(client, packet); + if ( client->isQoSm1Proxy() ) + { + _qosm1Proxy->send(packet, client); + } + else if ( client->isAggregater() ) + { + _aggregater->send(packet, client); + } + else + { + rc = packet->unicast(_gateway->getSensorNetwork(), client->getSensorNetAddress()); + } + } + return rc; +} + +void AdapterManager::checkConnection(void) +{ + if ( _aggregater->isActive()) + { + _aggregater->checkConnection(); + } + else if ( _qosm1Proxy->isActive()) + { + _qosm1Proxy->checkConnection(); + } +} + +Client* AdapterManager::convertClient(uint16_t msgId, uint16_t* clientMsgId) +{ + return _aggregater->convertClient(msgId, clientMsgId); +} + +bool AdapterManager::isAggregaterActive(void) +{ + return _aggregater->isActive(); +} + +AggregateTopicElement* AdapterManager::createClientList(Topic* topic) +{ + return _aggregater->createClientList(topic); +} + +int AdapterManager::addAggregateTopic(Topic* topic, Client* client) +{ + return _aggregater->addAggregateTopic(topic, client); +} + +void AdapterManager::removeAggregateTopic(Topic* topic, Client* client) +{ + _aggregater->removeAggregateTopic(topic, client); +} + +void AdapterManager::removeAggregateTopicList(Topics* topics, Client* client) +{ + _aggregater->removeAggregateTopicList(topics, client); +} diff --git a/MQTTSNGateway/src/MQTTSNGWAdapterManager.h b/MQTTSNGateway/src/MQTTSNGWAdapterManager.h new file mode 100644 index 0000000..749f1a9 --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWAdapterManager.h @@ -0,0 +1,70 @@ +/************************************************************************************** + * Copyright (c) 2018, 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 MQTTSNGATEWAY_SRC_MQTTSNGWADAPTERMANAGER_H_ +#define MQTTSNGATEWAY_SRC_MQTTSNGWADAPTERMANAGER_H_ + +#include "MQTTSNGWAggregater.h" +#include "MQTTSNGWQoSm1Proxy.h" +namespace MQTTSNGW +{ +class Gateway; +class Client; +class QoSm1Proxy; +class Aggregater; +class ForwarderList; +class MQTTSNPacket; +class MQTTSNGWPacket; +class ClientRecvTask; +class ClientSendTask; + +/*===================================== + Class AdapterManager + =====================================*/ +class AdapterManager +{ +public: + AdapterManager(Gateway* gw); + ~AdapterManager(void); + void initialize(void); + ForwarderList* getForwarderList(void); + QoSm1Proxy* getQoSm1Proxy(void); + Aggregater* getAggregater(void); + void checkConnection(void); + + bool isAggregatedClient(Client* client); + Client* getClient(MQTTSNPacket* packet, ClientRecvTask* task); + Client* getClient(Client& client); + Client* convertClient(uint16_t msgId, uint16_t* clientMsgId); + int unicastToClient(Client* client, MQTTSNPacket* packet, ClientSendTask* task); + bool isAggregaterActive(void); + AggregateTopicElement* createClientList(Topic* topic); + int addAggregateTopic(Topic* topic, Client* client); + void removeAggregateTopic(Topic* topic, Client* client); + void removeAggregateTopicList(Topics* topics, Client* client); + +private: + Gateway* _gateway {nullptr}; + ForwarderList* _forwarders {nullptr}; + QoSm1Proxy* _qosm1Proxy {nullptr}; + Aggregater* _aggregater {nullptr}; +}; + + + + +} +#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWADAPTERMANAGER_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.cpp b/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.cpp new file mode 100644 index 0000000..b53aea1 --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.cpp @@ -0,0 +1,161 @@ +/************************************************************************************** + * Copyright (c) 2018, 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 "MQTTSNGWAggregateTopicTable.h" +#include "MQTTSNGWClient.h" + +/*===================================== + Class ClientTopicElement + =====================================*/ +ClientTopicElement::ClientTopicElement(Client* client) +{ + _client = client; +} + +ClientTopicElement::~ClientTopicElement() +{ + +} + +Client* ClientTopicElement::getClient(void) +{ + return _client; +} + +/*===================================== + Class AggregateTopicElement + =====================================*/ +AggregateTopicElement::AggregateTopicElement(void) +{ + +} + +AggregateTopicElement::AggregateTopicElement(Topic* topic, Client* client) +{ + ClientTopicElement* elm = new ClientTopicElement(client); + if ( elm != nullptr ) + { + _head = elm; + _tail = elm; + } +} + +AggregateTopicElement::~AggregateTopicElement(void) +{ + _mutex.lock(); + if ( _head != nullptr ) + { + ClientTopicElement* p = _tail; + while ( p ) + { + ClientTopicElement* pPrev = p; + delete p; + p = pPrev->_prev; + } + _head = _tail = nullptr; + } + _mutex.unlock(); +} + +ClientTopicElement* AggregateTopicElement::add(Client* client) +{ + ClientTopicElement* elm = new ClientTopicElement(client); + if ( elm == nullptr ) + { + return nullptr; + } + _mutex.lock(); + if ( _head == nullptr ) + { + _head = elm; + _tail = elm; + } + else + { + ClientTopicElement* p = find(client); + if ( p == nullptr ) + { + p = _tail; + _tail = elm; + elm->_prev = p; + p->_next = elm; + } + else + { + delete elm; + elm = nullptr; + } + } + _mutex.unlock(); + return elm; +} + +ClientTopicElement* AggregateTopicElement::find(Client* client) +{ + ClientTopicElement* p = _head; + while ( p ) + { + if ( p->_client == client) + { + break; + } + p = p->_next; + } + return p; +} + +ClientTopicElement* AggregateTopicElement::getFirstElement(void) +{ + return _head; +} + +ClientTopicElement* AggregateTopicElement::getNextElement(ClientTopicElement* elm) +{ + return elm->_next; +} + + +/*===================================== + Class AggregateTopicTable + ======================================*/ + +AggregateTopicTable::AggregateTopicTable() +{ + +} + +AggregateTopicTable::~AggregateTopicTable() +{ + +} + +AggregateTopicElement* AggregateTopicTable::add(Topic* topic, Client* client) +{ + //ToDo: AggregateGW + return 0; +} + +void AggregateTopicTable::remove(Topic* topic, Client* client) +{ + //ToDo: AggregateGW +} + +AggregateTopicElement* AggregateTopicTable::getClientList(Topic* client) +{ + // ToDo: AggregateGW + return 0; +} + + diff --git a/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.h b/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.h new file mode 100644 index 0000000..624743f --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.h @@ -0,0 +1,98 @@ +/************************************************************************************** + * Copyright (c) 2018, 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 MQTTSNGATEWAY_SRC_MQTTSNGWAGGREGATETOPICTABLE_H_ +#define MQTTSNGATEWAY_SRC_MQTTSNGWAGGREGATETOPICTABLE_H_ + +#include "MQTTSNGWDefines.h" +#include "MQTTSNGWProcess.h" +#include +namespace MQTTSNGW +{ + +class Client; +class Topic; +class AggregateTopicElement; +class ClientTopicElement; +class Mutex; + +/*===================================== + Class AggregateTopicTable + ======================================*/ +class AggregateTopicTable +{ +public: + AggregateTopicTable(); + ~AggregateTopicTable(); + + AggregateTopicElement* add(Topic* topic, Client* client); + AggregateTopicElement* getClientList(Topic* client); + void remove(Topic* topic, Client* client); + void clear(void); +private: + AggregateTopicElement* _head {nullptr}; + AggregateTopicElement* _tail {nullptr}; + int _cnt {0}; + int _maxSize {MAX_MESSAGEID_TABLE_SIZE}; +}; + +/*===================================== + Class AggregateTopicElement + =====================================*/ +class AggregateTopicElement +{ + friend class AggregateTopicTable; +public: + AggregateTopicElement(void); + AggregateTopicElement(Topic* topic, Client* client); + ~AggregateTopicElement(void); + + ClientTopicElement* add(Client* client); + ClientTopicElement* getFirstElement(void); + ClientTopicElement* getNextElement(ClientTopicElement* elm); + void erase(ClientTopicElement* elm); + ClientTopicElement* find(Client* client); + +private: + Mutex _mutex; + Topic* _topic {nullptr}; + ClientTopicElement* _head {nullptr}; + ClientTopicElement* _tail {nullptr}; +}; + +/*===================================== + Class ClientTopicElement + =====================================*/ +class ClientTopicElement +{ + friend class AggregateTopicTable; + friend class AggregateTopicElement; +public: + ClientTopicElement(Client* client); + ~ClientTopicElement(void); + Client* getClient(void); + +private: + Client* _client {nullptr}; + ClientTopicElement* _next {nullptr}; + ClientTopicElement* _prev {nullptr}; +}; + +} + + + +#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWAGGREGATETOPICTABLE_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWAggregater.cpp b/MQTTSNGateway/src/MQTTSNGWAggregater.cpp new file mode 100644 index 0000000..a091625 --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWAggregater.cpp @@ -0,0 +1,143 @@ +/************************************************************************************** + * 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 "MQTTSNGWAggregater.h" +#include "MQTTSNGateway.h" +#include "MQTTSNGWClient.h" +#include "MQTTSNGWAdapter.h" +#include "MQTTSNGWAdapterManager.h" +#include "MQTTSNGWMessageIdTable.h" +#include "MQTTSNGWTopic.h" +#include +#include +#include + +using namespace MQTTSNGW; + +Aggregater::Aggregater(Gateway* gw) : Adapter(gw) +{ + _gateway = gw; +} + +Aggregater::~Aggregater(void) +{ + +} + +void Aggregater::initialize(void) +{ + char param[MQTTSNGW_PARAM_MAX]; + + if (_gateway->getParam("AggregateGateway", param) == 0 ) + { + if (!strcasecmp(param, "YES") ) + { + /* Create Aggregated Clients */ + _gateway->getClientList()->setClientList(_gateway, AGGREGATER_TYPE); + setup((const char*)(_gateway->getGWParams()->gatewayName), Atype_Aggregater); + _isActive = true; + } + } + + //testMessageIdTable(); + +} + +bool Aggregater::isActive(void) +{ + return _isActive; +} + +uint16_t Aggregater::msgId(void) +{ + return Adapter::getSecureClient()->getNextPacketId(); +} + +Client* Aggregater::convertClient(uint16_t msgId, uint16_t* clientMsgId) +{ + return _msgIdTable.getClientMsgId(msgId, clientMsgId); +} + + +uint16_t Aggregater::addMessageIdTable(Client* client, uint16_t msgId) +{ + /* set Non secure client`s nextMsgId. otherwise Id is duplicated.*/ + + MessageIdElement* elm = _msgIdTable.add(this, client, msgId); + if ( elm == nullptr ) + { + return 0; + } + else + { + return elm->_msgId; + } +} + +uint16_t Aggregater::getMsgId(Client* client, uint16_t clientMsgId) +{ + return _msgIdTable.getMsgId(client, clientMsgId); +} + +void Aggregater::removeAggregateTopic(Topic* topic, Client* client) +{ + // ToDo: AggregateGW this method called when the client disconnect and erase it`s Topics. this method call */ +} + +void Aggregater::removeAggregateTopicList(Topics* topics, Client* client) +{ + // ToDo: AggregateGW this method called when the client disconnect and erase it`s Topics. this method call */ +} + +int Aggregater::addAggregateTopic(Topic* topic, Client* client) +{ + // ToDo: AggregateGW */ + return 0; +} + +AggregateTopicElement* Aggregater::createClientList(Topic* topic) +{ + // ToDo: AggregateGW */ + return 0; +} + +bool Aggregater::testMessageIdTable(void) +{ + Client* client = new Client(); + uint16_t msgId = 0; + + printf("msgId=%d\n", addMessageIdTable(client,1)); + printf("msgId=%d\n", addMessageIdTable(client,2)); + printf("msgId=%d\n", addMessageIdTable(client,3)); + printf("msgId=%d\n", addMessageIdTable(client,1)); + printf("msgId=%d\n", addMessageIdTable(client,2)); + printf("msgId=%d\n", addMessageIdTable(client,3)); + printf("msgId=%d\n", addMessageIdTable(client,4)); + printf("msgId=%d\n", addMessageIdTable(client,4)); + printf("msgId=%d\n", addMessageIdTable(client,4)); + + convertClient(1,&msgId); + printf("msgId=%d\n",msgId); + convertClient(2,&msgId); + printf("msgId=%d\n",msgId); + convertClient(5,&msgId); + printf("msgId=%d\n",msgId); + convertClient(4,&msgId); + printf("msgId=%d\n",msgId); + convertClient(3,&msgId); + printf("msgId=%d\n",msgId); + return true; +} + diff --git a/MQTTSNGateway/src/MQTTSNGWAggregater.h b/MQTTSNGateway/src/MQTTSNGWAggregater.h new file mode 100644 index 0000000..9baaa15 --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWAggregater.h @@ -0,0 +1,76 @@ +/************************************************************************************** + * Copyright (c) 2018, 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 MQTTSNGATEWAY_SRC_MQTTSNGWAGGREGATER_H_ +#define MQTTSNGATEWAY_SRC_MQTTSNGWAGGREGATER_H_ + +#include "MQTTSNGWAdapter.h" +#include "MQTTSNGWMessageIdTable.h" +#include "MQTTSNGWAggregateTopicTable.h" +namespace MQTTSNGW +{ +class Gateway; +class Adapter; +class Client; +class SensorNetAddress; +class MessageIdTable; +class AggregateTopicTable; +class Topics; + +/*===================================== + Class Aggregater + =====================================*/ +class Aggregater : public Adapter +{ + friend class MessageIdTable; +public: + Aggregater(Gateway* gw); + ~Aggregater(void); + + void initialize(void); + + const char* getClientId(SensorNetAddress* addr); + Client* getClient(SensorNetAddress* addr); + Client* convertClient(uint16_t msgId, uint16_t* clientMsgId); + uint16_t addMessageIdTable(Client* client, uint16_t msgId); + uint16_t getMsgId(Client* client, uint16_t clientMsgId); + + + AggregateTopicElement* createClientList(Topic* topic); + int addAggregateTopic(Topic* topic, Client* client); + void removeAggregateTopic(Topic* topic, Client* client); + void removeAggregateTopicList(Topics* topics, Client* client); + bool isActive(void); + + bool testMessageIdTable(void); + +private: + uint16_t msgId(void); + Gateway* _gateway {nullptr}; + MessageIdTable _msgIdTable; + AggregateTopicTable _topicTable; + + bool _isActive {false}; + bool _isSecure {false}; +}; + + + +} + + + +#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWAGGREGATER_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp index 36c122c..01f6fb1 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp @@ -16,6 +16,7 @@ #include "MQTTSNGWBrokerRecvTask.h" #include "MQTTSNGWClient.h" +#include "MQTTSNGWClientList.h" #include using namespace std; @@ -30,7 +31,7 @@ BrokerRecvTask::BrokerRecvTask(Gateway* gateway) { _gateway = gateway; _gateway->attach((Thread*)this); - _light = 0; + _light = nullptr; } BrokerRecvTask::~BrokerRecvTask() @@ -52,9 +53,9 @@ void BrokerRecvTask::initialize(int argc, char** argv) void BrokerRecvTask::run(void) { struct timeval timeout; - MQTTGWPacket* packet = 0; + MQTTGWPacket* packet = nullptr; int rc; - Event* ev = 0; + Event* ev = nullptr; fd_set rset; fd_set wset; @@ -74,9 +75,9 @@ void BrokerRecvTask::run(void) int sockfd = 0; /* Prepare sockets list to read */ - Client* client = _gateway->getClientList()->getClient(); + Client* client = _gateway->getClientList()->getClient(0); - while (client > 0) + while ( client ) { if (client->getNetwork()->isValid()) { @@ -101,7 +102,7 @@ void BrokerRecvTask::run(void) int activity = select(maxSock + 1, &rset, 0, 0, &timeout); if (activity > 0) { - client = _gateway->getClientList()->getClient(); + client = _gateway->getClientList()->getClient(0); while (client > 0) { diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp index cc7798e..b886c9a 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp @@ -14,6 +14,7 @@ * Tomoaki Yamaguchi - initial API and implementation and/or initial documentation **************************************************************************************/ +#include #include "MQTTSNGWBrokerSendTask.h" #include "MQTTSNGWDefines.h" #include "MQTTSNGateway.h" @@ -34,8 +35,8 @@ BrokerSendTask::BrokerSendTask(Gateway* gateway) { _gateway = gateway; _gateway->attach((Thread*)this); - _gwparams = 0; - _light = 0; + _gwparams = nullptr; + _light = nullptr; } BrokerSendTask::~BrokerSendTask() @@ -57,9 +58,10 @@ void BrokerSendTask::initialize(int argc, char** argv) */ void BrokerSendTask::run() { - Event* ev = 0; - MQTTGWPacket* packet = 0; - Client* client = 0; + Event* ev = nullptr; + MQTTGWPacket* packet = nullptr; + Client* client = nullptr; + AdapterManager* adpMgr = _gateway->getAdapterManager(); int rc = 0; while (true) @@ -78,6 +80,9 @@ void BrokerSendTask::run() client = ev->getClient(); packet = ev->getMQTTGWPacket(); + /* Check Client is managed by Adapters */ + client = adpMgr->getClient(*client); + if ( packet->getType() == CONNECT && client->getNetwork()->isValid() ) { client->getNetwork()->close(); @@ -89,12 +94,12 @@ void BrokerSendTask::run() if (client->isSecureNetwork()) { - rc = client->getNetwork()->connect(_gwparams->brokerName, _gwparams->portSecure, _gwparams->rootCApath, - _gwparams->rootCAfile, _gwparams->certKey, _gwparams->privateKey); + rc = client->getNetwork()->connect((const char*)_gwparams->brokerName, (const char*)_gwparams->portSecure, (const char*)_gwparams->rootCApath, + (const char*)_gwparams->rootCAfile, (const char*)_gwparams->certKey, (const char*)_gwparams->privateKey); } else { - rc = client->getNetwork()->connect(_gwparams->brokerName, _gwparams->port); + rc = client->getNetwork()->connect((const char*)_gwparams->brokerName, (const char*)_gwparams->port); } if ( !rc ) diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.h b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.h index f287536..8244112 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.h +++ b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.h @@ -22,12 +22,15 @@ namespace MQTTSNGW { +class Adapter; + /*===================================== Class BrokerSendTask =====================================*/ class BrokerSendTask : public Thread { MAGIC_WORD_FOR_THREAD; + friend AdapterManager; public: BrokerSendTask(Gateway* gateway); ~BrokerSendTask(); diff --git a/MQTTSNGateway/src/MQTTSNGWClient.cpp b/MQTTSNGateway/src/MQTTSNGWClient.cpp index deda727..f524d0b 100644 --- a/MQTTSNGateway/src/MQTTSNGWClient.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClient.cpp @@ -16,10 +16,9 @@ **************************************************************************************/ #include "MQTTSNGWDefines.h" -#include "MQTTSNGWClient.h" +#include "MQTTSNGWClientList.h" #include "MQTTSNGateway.h" #include "SensorNetwork.h" -#include "Network.h" #include #include #include @@ -28,350 +27,7 @@ using namespace MQTTSNGW; char* currentDateTime(void); -/*===================================== - 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[MAX_CLIENTID_LENGTH + 256]; - size_t pos; - bool secure; - bool stable; - SensorNetAddress netAddr; - MQTTSNString clientId = MQTTSNString_initializer; - - if ((fp = fopen(fileName, "r")) != 0) - { - while (fgets(buf, MAX_CLIENTID_LENGTH + 254, 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()); - } - free(clientId.cstring); - } - fclose(fp); - _authorize = true; - } - return _authorize; -} - -bool ClientList::setPredefinedTopics(const char* fileName) -{ - FILE* fp; - char buf[MAX_CLIENTID_LENGTH + 256]; - size_t pos0, pos1; - MQTTSNString clientId = MQTTSNString_initializer;; - bool rc = false; - - if ((fp = fopen(fileName, "r")) != 0) - { - while (fgets(buf, MAX_CLIENTID_LENGTH + 254, fp) != 0) - { - if (*buf == '#') - { - continue; - } - string data = string(buf); - while ((pos0 = data.find_first_of("  \t\n")) != string::npos) - { - data.erase(pos0, 1); - } - if (data.empty()) - { - continue; - } - - pos0 = data.find_first_of(","); - pos1 = data.find(",", pos0 + 1) ; - string id = data.substr(0, pos0); - clientId.cstring = strdup(id.c_str()); - string topicName = data.substr(pos0 + 1, pos1 - pos0 -1); - uint16_t topicID = stoul(data.substr(pos1 + 1)); - createPredefinedTopic( &clientId, topicName, topicID); - free(clientId.cstring); - } - fclose(fp); - rc = true; - } - else - { - WRITELOG("Can not open the Predefined Topic List. %s\n", fileName); - return false; - } - return rc; -} - -void ClientList::erase(Client*& client) -{ - if ( !_authorize && client->erasable()) - { - _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--; - Forwarder* fwd = client->getForwarder(); - if ( fwd ) - { - fwd->eraseClient(client); - } - delete client; - client = 0; - _mutex.unlock(); - } -} - -Client* ClientList::getClient(SensorNetAddress* addr) -{ - if ( 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::getClient(MQTTSNString* clientId) -{ - _mutex.lock(); - Client* client = _firstClient; - const char* clID =clientId->cstring; - - if (clID == 0 ) - { - clID = clientId->lenstring.data; - } - - while (client != 0) - { - if (strncmp((const char*)client->getClientId(), clID, MQTTSNstrlen(*clientId)) == 0 ) - { - _mutex.unlock(); - return client; - } - client = client->_nextClient; - } - _mutex.unlock(); - return 0; -} - -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 > MAX_CLIENTS ) - { - return 0; // full of clients - } - - client = getClient(addr); - if ( client ) - { - return client; - } - - /* creat a new client */ - client = new Client(secure); - if ( addr ) - { - client->setClientAddress(addr); - } - client->setSensorNetType(unstableLine); - if ( MQTTSNstrlen(*clientId) ) - { - client->setClientId(*clientId); - } - else - { - MQTTSNString dummyId MQTTSNString_initializer;; - dummyId.cstring = strdup(""); - client->setClientId(dummyId); - free(dummyId.cstring); - } - - _mutex.lock(); - - /* add the list */ - if ( _firstClient == 0 ) - { - _firstClient = client; - _endClient = client; - } - else - { - _endClient->_nextClient = client; - client->_prevClient = _endClient; - _endClient = client; - } - _clientCnt++; - _mutex.unlock(); - return client; -} - -Client* ClientList::createPredefinedTopic( MQTTSNString* clientId, string topicName, uint16_t topicId) -{ - Client* client = getClient(clientId); - - if ( _authorize && client == 0) - { - return 0; - } - - /* anonimous clients */ - if ( _clientCnt > MAX_CLIENTS ) - { - return 0; // full of clients - } - - if ( client == 0 ) - { - /* creat a new client */ - client = new Client(); - client->setClientId(*clientId); - - _mutex.lock(); - - /* add the list */ - if ( _firstClient == 0 ) - { - _firstClient = client; - _endClient = client; - } - else - { - _endClient->_nextClient = client; - client->_prevClient = _endClient; - _endClient = client; - } - _clientCnt++; - _mutex.unlock(); - } - - // create Topic & Add it - client->getTopics()->add((const char*)topicName.c_str(), topicId); - client->_hasPredefTopic = true; - return client; -} - -uint16_t ClientList::getClientCount() -{ - return _clientCnt; -} - -bool ClientList::isAuthorized() -{ - return _authorize; -} /*===================================== Class Client @@ -385,31 +41,24 @@ Client::Client(bool secure) _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; + _clientId = nullptr; + _willTopic = nullptr; + _willMsg = nullptr; + _connectData = {0, 0, 0, 0, 0, 0, 0}; _network = new Network(secure); _secureNetwork = secure; _sensorNetype = true; - _connAck = 0; + _connAck = nullptr; _waitWillMsgFlg = false; _sessionStatus = false; - _prevClient = 0; - _nextClient = 0; + _prevClient = nullptr; + _nextClient = nullptr; _clientSleepPacketQue.setMaxSize(MAX_SAVED_PUBLISH); _proxyPacketQue.setMaxSize(MAX_SAVED_PUBLISH); _hasPredefTopic = false; _holdPingRequest = false; - _forwarder = 0; - _isProxy = false; + _forwarder = nullptr; + _clientType = Ctype_Regular; } Client::~Client() @@ -445,12 +94,12 @@ Client::~Client() } } -TopicIdMapelement* Client::getWaitedPubTopicId(uint16_t msgId) +TopicIdMapElement* Client::getWaitedPubTopicId(uint16_t msgId) { return _waitedPubTopicIdMap.getElement(msgId); } -TopicIdMapelement* Client::getWaitedSubTopicId(uint16_t msgId) +TopicIdMapElement* Client::getWaitedSubTopicId(uint16_t msgId) { return _waitedSubTopicIdMap.getElement(msgId); } @@ -555,6 +204,7 @@ void Client::setKeepAlive(MQTTSNPacket* packet) void Client::setForwarder(Forwarder* forwarder) { _forwarder = forwarder; + _clientType = Ctype_Forwarded; } Forwarder* Client::getForwarder(void) @@ -569,7 +219,7 @@ void Client::setSessionStatus(bool status) bool Client::erasable(void) { - return _sessionStatus && !_hasPredefTopic && _forwarder == 0; + return _sessionStatus && !_hasPredefTopic && _forwarder == nullptr; } void Client::updateStatus(MQTTSNPacket* packet) @@ -590,7 +240,7 @@ void Client::updateStatus(MQTTSNPacket* packet) case MQTTSN_PUBCOMP: case MQTTSN_PUBREL: case MQTTSN_PUBREC: - if ( !_isProxy ) + if ( _clientType != Ctype_Proxy ) { _keepAliveTimer.start(_keepAliveMsec * 1.5); } @@ -856,14 +506,60 @@ const char* Client::getStatus(void) return theClientStatus[_status]; } -bool Client::isProxy(void) +bool Client::isQoSm1Proxy(void) { - return _isProxy; + return _clientType == Ctype_Proxy; } -void Client::setPorxy(bool isProxy) +bool Client::isForwarded(void) { - _isProxy = isProxy;; + return _clientType == Ctype_Forwarded; +} + +bool Client::isAggregated(void) +{ + return _clientType == Ctype_Aggregated; +} + +bool Client::isAggregater(void) +{ + return _clientType == Ctype_Aggregater; +} + +void Client::setAdapterType(AdapterType type) +{ + switch ( type ) + { + case Atype_QoSm1Proxy: + _clientType = Ctype_Proxy; + break; + case Atype_Aggregater: + _clientType = Ctype_Aggregater; + break; + default: + throw Exception("Client::setAdapterType(): Invalid Type."); + break; + } +} + +bool Client::isAdapter(void) +{ + return _clientType == Ctype_Proxy || _clientType == Ctype_Aggregater; +} + +bool Client::isQoSm1(void) +{ + return _clientType == Ctype_QoS_1; +} + +void Client::setQoSm1(void) +{ + _clientType = Ctype_QoS_1; +} + +void Client::setAggregated(void) +{ + _clientType = Ctype_Aggregated; } void Client::holdPingRequest(void) @@ -881,499 +577,7 @@ bool Client::isHoldPringReqest(void) return _holdPingRequest; } -/*===================================== - Class Topic - ======================================*/ -Topic::Topic() -{ - _type = MQTTSN_TOPIC_TYPE_NORMAL; - _topicName = 0; - _topicId = 0; - _next = 0; -} -Topic::Topic(string* topic, MQTTSN_topicTypes type) -{ - _type = type; - _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; -} - -MQTTSN_topicTypes Topic::getType(void) -{ - return _type; -} - -bool Topic::isMatch(string* topicName) -{ - string::size_type tlen = _topicName->size(); - - string::size_type tpos = 0; - string::size_type tloc = 0; - string::size_type pos = 0; - string::size_type loc = 0; - string wildcard = "#"; - string wildcards = "+"; - - while(true) - { - loc = topicName->find('/', pos); - tloc = _topicName->find('/', tpos); - - if ( loc != string::npos && tloc != string::npos ) - { - string subtopic = topicName->substr(pos, loc - pos); - string subtopict = _topicName->substr(tpos, tloc - tpos); - if (subtopict == wildcard) - { - return true; - } - else if (subtopict == wildcards) - { - if ( (tpos = tloc + 1 ) > tlen ) - { - pos = loc + 1; - loc = topicName->find('/', pos); - if ( loc == string::npos ) - { - return true; - } - else - { - return false; - } - } - pos = loc + 1; - } - else if ( subtopic != subtopict ) - { - return false; - } - else - { - if ( (tpos = tloc + 1) > tlen ) - { - return false; - } - - pos = loc + 1; - } - } - else if ( loc == string::npos && tloc == string::npos ) - { - string subtopic = topicName->substr(pos); - string subtopict = _topicName->substr(tpos); - if ( subtopict == wildcard || subtopict == wildcards) - { - return true; - } - else if ( subtopic == subtopict ) - { - return true; - } - else - { - return false; - } - } - else if ( loc == string::npos && tloc != string::npos ) - { - string subtopic = topicName->substr(pos); - string subtopict = _topicName->substr(tpos, tloc - tpos); - if ( subtopic != subtopict) - { - return false; - } - - tpos = tloc + 1; - - return _topicName->substr(tpos) == wildcard; - } - else if ( loc != string::npos && tloc == string::npos ) - { - return _topicName->substr(tpos) == wildcard; - } - } -} - -void Topic::print(void) -{ - WRITELOG("TopicName=%s ID=%d Type=%d\n", _topicName->c_str(), _topicId, _type); -} - -/*===================================== - Class Topics - ======================================*/ -Topics::Topics() -{ - _first = 0; - _nextTopicId = 0; - _cnt = 0; -} - -Topics::~Topics() -{ - Topic* p = _first; - while (p) - { - Topic* q = p->_next; - delete p; - p = q; - } -} - -Topic* Topics::getTopicByName(const MQTTSN_topicid* topicid) -{ - Topic* p = _first; - char* ch = topicid->data.long_.name; - - string sname = string(ch, ch + topicid->data.long_.len); - while (p) - { - if ( p->_topicName->compare(sname) == 0 ) - { - return p; - } - p = p->_next; - } - return 0; -} - -Topic* Topics::getTopicById(const MQTTSN_topicid* topicid) -{ - Topic* p = _first; - - while (p) - { - if ( p->_type == topicid->type && p->_topicId == topicid->data.id ) - { - return p; - } - p = p->_next; - } - return 0; -} - -// For MQTTSN_TOPIC_TYPE_NORMAL */ -Topic* Topics::add(const MQTTSN_topicid* topicid) -{ - if (topicid->type != MQTTSN_TOPIC_TYPE_NORMAL ) - { - return 0; - } - - Topic* topic = getTopicByName(topicid); - - if ( topic ) - { - return topic; - } - string name(topicid->data.long_.name, topicid->data.long_.len); - return add(name.c_str(), 0); -} - -Topic* Topics::add(const char* topicName, uint16_t id) -{ - MQTTSN_topicid topicId; - - if ( _cnt >= MAX_TOPIC_PAR_CLIENT ) - { - return 0; - } - - topicId.data.long_.name = (char*)const_cast(topicName); - topicId.data.long_.len = strlen(topicName); - - - Topic* topic = getTopicByName(&topicId); - - if ( topic ) - { - return topic; - } - - topic = new Topic(); - - if (topic == 0) - { - return 0; - } - - string* name = new string(topicName); - topic->_topicName = name; - - if ( id == 0 ) - { - topic->_type = MQTTSN_TOPIC_TYPE_NORMAL; - topic->_topicId = getNextTopicId(); - } - else - { - topic->_type = MQTTSN_TOPIC_TYPE_PREDEFINED; - topic->_topicId = id; - } - - _cnt++; - - if ( _first == 0) - { - _first = topic; - } - else - { - Topic* tp = _first; - 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(const 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; -} - - -void Topics::eraseNormal(void) -{ - Topic* topic = _first; - Topic* next = 0; - Topic* prev = 0; - - while (topic) - { - if ( topic->_type == MQTTSN_TOPIC_TYPE_NORMAL ) - { - next = topic->_next; - if ( _first == topic ) - { - _first = next; - } - if ( prev ) - { - prev->_next = next; - } - delete topic; - _cnt--; - topic = next; - } - else - { - prev = topic; - topic = topic->_next; - } - } -} - -void Topics::print(void) -{ - Topic* topic = _first; - if (topic == 0 ) - { - WRITELOG("No Topic.\n"); - } - else - { - while (topic) - { - topic->print(); - topic = topic->_next; - } - } -} - -uint8_t Topics::getCount(void) -{ - return _cnt; -} - -/*===================================== - 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() -{ - -} - -MQTTSN_topicTypes TopicIdMapelement::getTopicType(void) -{ - return _type; -} - -uint16_t TopicIdMapelement::getTopicId(void) -{ - return _topicId; -} - -TopicIdMap::TopicIdMap() -{ - _maxInflight = MAX_INFLIGHTMESSAGES; - _msgIds = 0; - _first = 0; - _end = 0; - _cnt = 0; -} - -TopicIdMap::~TopicIdMap() -{ - TopicIdMapelement* p = _first; - while ( p ) - { - TopicIdMapelement* q = p->_next; - delete p; - p = q; - } -} - -TopicIdMapelement* TopicIdMap::getElement(uint16_t msgId) -{ - TopicIdMapelement* p = _first; - while ( p ) - { - if ( p->_msgId == msgId ) - { - return p; - } - p = p->_next; - } - return 0; -} - -TopicIdMapelement* TopicIdMap::add(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type) -{ - if ( _cnt > _maxInflight * 2 || ( topicId == 0 && type != MQTTSN_TOPIC_TYPE_SHORT ) ) - { - return 0; - } - if ( getElement(msgId) > 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 elm; -} - -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 @@ -1382,8 +586,8 @@ waitREGACKPacket::waitREGACKPacket(MQTTSNPacket* packet, uint16_t REGACKMsgId) { _packet = packet; _msgId = REGACKMsgId; - _next = 0; - _prev = 0; + _next = nullptr; + _prev = nullptr; } waitREGACKPacket::~waitREGACKPacket() @@ -1397,8 +601,8 @@ waitREGACKPacket::~waitREGACKPacket() WaitREGACKPacketList::WaitREGACKPacketList() { - _first = 0; - _end = 0; + _first = nullptr; + _end = nullptr; _cnt = 0; } @@ -1416,12 +620,12 @@ WaitREGACKPacketList::~WaitREGACKPacketList() int WaitREGACKPacketList::setPacket(MQTTSNPacket* packet, uint16_t REGACKMsgId) { waitREGACKPacket* elm = new waitREGACKPacket(packet, REGACKMsgId); - if (elm == 0) + if (elm == nullptr) { return 0; } - if (_first == 0) + if (_first == nullptr) { _first = elm; _end = elm; @@ -1447,7 +651,7 @@ MQTTSNPacket* WaitREGACKPacketList::getPacket(uint16_t REGACKMsgId) } p = p->_next; } - return 0; + return nullptr; } void WaitREGACKPacketList::erase(uint16_t REGACKMsgId) @@ -1457,7 +661,7 @@ void WaitREGACKPacketList::erase(uint16_t REGACKMsgId) { if (p->_msgId == REGACKMsgId) { - if (p->_prev == 0) + if (p->_prev == nullptr) { _first = p->_next; @@ -1466,7 +670,7 @@ void WaitREGACKPacketList::erase(uint16_t REGACKMsgId) { p->_prev->_next = p->_next; } - if (p->_next == 0) + if (p->_next == nullptr) { _end = p->_prev; } diff --git a/MQTTSNGateway/src/MQTTSNGWClient.h b/MQTTSNGateway/src/MQTTSNGWClient.h index c4757e7..5529ed0 100644 --- a/MQTTSNGateway/src/MQTTSNGWClient.h +++ b/MQTTSNGateway/src/MQTTSNGWClient.h @@ -28,6 +28,9 @@ #include "MQTTSNPacket.h" #include "MQTTSNGWEncapsulatedPacket.h" #include "MQTTSNGWForwarder.h" +#include "MQTTSNGWTopic.h" +#include "MQTTSNGWClientList.h" +#include "MQTTSNGWAdapter.h" namespace MQTTSNGW { @@ -111,87 +114,6 @@ private: }; -/*===================================== - Class Topic - ======================================*/ -class Topic -{ - friend class Topics; -public: - Topic(); - Topic(string* topic, MQTTSN_topicTypes type); - ~Topic(); - string* getTopicName(void); - uint16_t getTopicId(void); - MQTTSN_topicTypes getType(void); - bool isMatch(string* topicName); - void print(void); -private: - MQTTSN_topicTypes _type; - uint16_t _topicId; - string* _topicName; - Topic* _next; -}; - -/*===================================== - Class Topics - ======================================*/ -class Topics -{ -public: - Topics(); - ~Topics(); - Topic* add(const MQTTSN_topicid* topicid); - Topic* add(const char* topicName, uint16_t id = 0); - Topic* getTopicByName(const MQTTSN_topicid* topic); - Topic* getTopicById(const MQTTSN_topicid* topicid); - Topic* match(const MQTTSN_topicid* topicid); - void eraseNormal(void); - uint16_t getNextTopicId(); - void print(void); - uint8_t getCount(void); -private: - uint16_t _nextTopicId; - Topic* _first; - uint8_t _cnt; -}; - -/*===================================== - Class TopicIdMap - =====================================*/ -class TopicIdMapelement -{ - friend class TopicIdMap; -public: - TopicIdMapelement(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type); - ~TopicIdMapelement(); - MQTTSN_topicTypes getTopicType(void); - uint16_t getTopicId(void); - -private: - uint16_t _msgId; - uint16_t _topicId; - MQTTSN_topicTypes _type; - TopicIdMapelement* _next; - TopicIdMapelement* _prev; -}; - -class TopicIdMap -{ -public: - TopicIdMap(); - ~TopicIdMap(); - TopicIdMapelement* getElement(uint16_t msgId); - TopicIdMapelement* add(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type); - void erase(uint16_t msgId); - void clear(void); -private: - uint16_t* _msgIds; - TopicIdMapelement* _first; - TopicIdMapelement* _end; - int _cnt; - int _maxInflight; -}; /*===================================== Class WaitREGACKPacket @@ -229,15 +151,21 @@ private: waitREGACKPacket* _end; }; + + /*===================================== Class Client =====================================*/ - typedef enum { Cstat_Disconnected = 0, Cstat_TryConnecting, Cstat_Connecting, Cstat_Active, Cstat_Asleep, Cstat_Awake, Cstat_Lost } ClientStatus; +typedef enum +{ + Ctype_Regular = 0, Ctype_Forwarded, Ctype_QoS_1, Ctype_Aggregated, Ctype_Proxy, Ctype_Aggregater +}ClientType; + class Forwarder; class Client @@ -249,8 +177,8 @@ public: ~Client(); Connect* getConnectData(void); - TopicIdMapelement* getWaitedPubTopicId(uint16_t msgId); - TopicIdMapelement* getWaitedSubTopicId(uint16_t msgId); + TopicIdMapElement* getWaitedPubTopicId(uint16_t msgId); + TopicIdMapElement* getWaitedSubTopicId(uint16_t msgId); MQTTGWPacket* getClientSleepPacket(void); void deleteFirstClientSleepPacket(void); @@ -292,8 +220,15 @@ public: Forwarder* getForwarder(void); void setForwarder(Forwarder* forwader); - void setPorxy(bool isProxy); - bool isProxy(void); + void setAdapterType(AdapterType type); + void setQoSm1(void); + void setAggregated(void); + bool isQoSm1Proxy(void); + bool isForwarded(void); + bool isAggregated(void); + bool isAggregater(void); + bool isQoSm1(void); + bool isAdapter(void); void setClientId(MQTTSNString id); void setWillTopic(MQTTSNString willTopic); @@ -355,8 +290,7 @@ private: SensorNetAddress _sensorNetAddr; Forwarder* _forwarder; - bool _isProxy; - + ClientType _clientType; bool _sessionStatus; bool _hasPredefTopic; @@ -365,32 +299,6 @@ private: Client* _prevClient; }; -/*===================================== - Class ClientList - =====================================*/ -class ClientList -{ -public: - ClientList(); - ~ClientList(); - bool authorize(const char* fileName); - bool setPredefinedTopics(const char* fileName); - void erase(Client*&); - Client* createClient(SensorNetAddress* addr, MQTTSNString* clientId, bool unstableLine, bool secure); - Client* getClient(SensorNetAddress* addr); - Client* getClient(MQTTSNString* clientId); - uint16_t getClientCount(void); - Client* getClient(void); - bool isAuthorized(); -private: - Client* createPredefinedTopic( MQTTSNString* clientId, string topicName, uint16_t toipcId); - Client* _firstClient; - Client* _endClient; - Mutex _mutex; - uint16_t _clientCnt; - bool _authorize; -}; - } diff --git a/MQTTSNGateway/src/MQTTSNGWClientList.cpp b/MQTTSNGateway/src/MQTTSNGWClientList.cpp new file mode 100644 index 0000000..23bdcdd --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWClientList.cpp @@ -0,0 +1,460 @@ +/************************************************************************************** + * 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 + * Tieto Poland Sp. z o.o. - Gateway improvements + **************************************************************************************/ +#include "MQTTSNGWClientList.h" +#include +#include + +/*===================================== + Class ClientList + =====================================*/ +ClientList::ClientList() +{ + _clientCnt = 0; + _authorize = false; + _firstClient = nullptr; + _endClient = nullptr; +} + +ClientList::~ClientList() +{ + _mutex.lock(); + Client* cl = _firstClient; + Client* ncl; + + while (cl != nullptr) + { + ncl = cl->_nextClient; + delete cl; + cl = ncl; + }; + _mutex.unlock(); +} + +void ClientList::initialize(Gateway* gw, bool aggregate) +{ + if (gw->getGWParams()->clientAuthentication ) + { + int type = TRANSPEARENT_TYPE; + if ( aggregate ) + { + type = AGGREGATER_TYPE; + } + setClientList(gw, type); + _authorize = true; + } +} + +void ClientList::setClientList(Gateway* gw, int type) +{ + char param[MQTTSNGW_PARAM_MAX]; + string fileName; + GatewayParams* params = gw->getGWParams(); + if (gw->getParam("ClientsList", param) == 0) + { + fileName = string(param); + } + else + { + fileName = params->configDir + string(CLIENT_LIST); + } + + if (!createList(fileName.c_str(), type)) + { + throw Exception("ClientList::initialize(): No client list defined by the configuration."); + } + params->clientListName = strdup(fileName.c_str()); +} + +void ClientList::setPredefinedTopics(Gateway* gw, bool aggrecate) +{ + char param[MQTTSNGW_PARAM_MAX]; + + string fileName; + GatewayParams* params = gw->getGWParams(); + + if (gw->getParam("PredefinedTopicList", param) == 0) + { + fileName = string(param); + } + else + { + fileName = params->configDir + string(PREDEFINEDTOPIC_FILE); + } + + if ( readPredefinedList(fileName.c_str(), aggrecate) ) + { + params->predefinedTopicFileName = strdup(fileName.c_str()); + } +} + +/** + * 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. + * if the client send PUBLISH QoS-1, QoS-1 is required. + * + * 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 + * ClientID5,41000@192.168.200.51,unstableLine,secureConnection,QoS-1 + */ + +bool ClientList::createList(const char* fileName, int type) +{ + FILE* fp; + char buf[MAX_CLIENTID_LENGTH + 256]; + size_t pos; + bool secure; + bool stable; + bool qos_1; + bool rc = true; + SensorNetAddress netAddr; + MQTTSNString clientId = MQTTSNString_initializer; + + if ((fp = fopen(fileName, "r")) != 0) + { + while (fgets(buf, MAX_CLIENTID_LENGTH + 254, 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) + { + qos_1 = (data.find("QoS-1") != string::npos); + secure = (data.find("secureConnection") != string::npos); + stable = !(data.find("unstableLine") != string::npos); + if ( (qos_1 && type == QOSM1PROXY_TYPE) || (!qos_1 && type == AGGREGATER_TYPE) ) + { + createClient(&netAddr, &clientId, stable, secure, type); + } + else + { + createClient(&netAddr, &clientId, stable, secure, TRANSPEARENT_TYPE); + } + } + else + { + WRITELOG("Invalid address %s\n", data.c_str()); + rc = false; + } + free(clientId.cstring); + } + fclose(fp); + } + return rc; +} + +bool ClientList::readPredefinedList(const char* fileName, bool aggregate) +{ + FILE* fp; + char buf[MAX_CLIENTID_LENGTH + 256]; + size_t pos0, pos1; + MQTTSNString clientId = MQTTSNString_initializer;; + bool rc = false; + + if ((fp = fopen(fileName, "r")) != 0) + { + while (fgets(buf, MAX_CLIENTID_LENGTH + 254, fp) != 0) + { + if (*buf == '#') + { + continue; + } + string data = string(buf); + while ((pos0 = data.find_first_of("  \t\n")) != string::npos) + { + data.erase(pos0, 1); + } + if (data.empty()) + { + continue; + } + + pos0 = data.find_first_of(","); + pos1 = data.find(",", pos0 + 1) ; + string id = data.substr(0, pos0); + clientId.cstring = strdup(id.c_str()); + string topicName = data.substr(pos0 + 1, pos1 - pos0 -1); + uint16_t topicID = stoul(data.substr(pos1 + 1)); + createPredefinedTopic( &clientId, topicName, topicID, aggregate); + free(clientId.cstring); + } + fclose(fp); + rc = true; + } + else + { + WRITELOG("ClientList can not open the Predefined Topic List. %s\n", fileName); + return false; + } + return rc; +} + +void ClientList::erase(Client*& client) +{ + if ( !_authorize && client->erasable()) + { + _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--; + Forwarder* fwd = client->getForwarder(); + if ( fwd ) + { + fwd->eraseClient(client); + } + delete client; + client = nullptr; + _mutex.unlock(); + } +} + +Client* ClientList::getClient(SensorNetAddress* addr) +{ + if ( addr ) + { + _mutex.lock(); + Client* client = _firstClient; + + while (client != nullptr) + { + if (client->getSensorNetAddress()->isMatch(addr) ) + { + _mutex.unlock(); + return client; + } + client = client->_nextClient; + } + _mutex.unlock(); + } + return 0; +} + +Client* ClientList::getClient(int index) +{ + Client* client = _firstClient; + int p = 0; + while ( client != nullptr ) + { + if ( p == index ) + { + return client; + } + else + { + client = client->_nextClient; + p++; + } + } + return nullptr; +} + + +Client* ClientList::getClient(MQTTSNString* clientId) +{ + _mutex.lock(); + Client* client = _firstClient; + const char* clID =clientId->cstring; + + if (clID == nullptr ) + { + clID = clientId->lenstring.data; + } + + while (client != nullptr) + { + if (strncmp((const char*)client->getClientId(), clID, MQTTSNstrlen(*clientId)) == 0 ) + { + _mutex.unlock(); + return client; + } + client = client->_nextClient; + } + _mutex.unlock(); + return 0; +} + +Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, int type) +{ + return createClient(addr, clientId, false, false, type); +} + +Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, bool unstableLine, bool secure, int type) +{ + Client* client = nullptr; + + /* anonimous clients */ + if ( _clientCnt > MAX_CLIENTS ) + { + return 0; // full of clients + } + + client = getClient(addr); + if ( client ) + { + return client; + } + + /* creat a new client */ + client = new Client(secure); + if ( addr ) + { + client->setClientAddress(addr); + } + client->setSensorNetType(unstableLine); + if ( MQTTSNstrlen(*clientId) ) + { + client->setClientId(*clientId); + } + else + { + MQTTSNString dummyId MQTTSNString_initializer;; + dummyId.cstring = strdup(""); + client->setClientId(dummyId); + free(dummyId.cstring); + } + + if ( type == AGGREGATER_TYPE ) + { + client->setAggregated(); + } + else if ( type == QOSM1PROXY_TYPE ) + { + client->setQoSm1(); + } + + _mutex.lock(); + + /* add the list */ + if ( _firstClient == nullptr ) + { + _firstClient = client; + _endClient = client; + } + else + { + _endClient->_nextClient = client; + client->_prevClient = _endClient; + _endClient = client; + } + _clientCnt++; + _mutex.unlock(); + return client; +} + +Client* ClientList::createPredefinedTopic( MQTTSNString* clientId, string topicName, uint16_t topicId, bool aggregate) +{ + Client* client = getClient(clientId); + + if ( _authorize && client == nullptr) + { + return 0; + } + + /* anonimous clients */ + if ( _clientCnt > MAX_CLIENTS ) + { + return nullptr; // full of clients + } + + if ( client == nullptr ) + { + /* creat a new client */ + client = new Client(); + client->setClientId(*clientId); + if ( aggregate ) + { + client->setAggregated(); + } + _mutex.lock(); + + /* add the list */ + if ( _firstClient == nullptr ) + { + _firstClient = client; + _endClient = client; + } + else + { + _endClient->_nextClient = client; + client->_prevClient = _endClient; + _endClient = client; + } + _clientCnt++; + _mutex.unlock(); + } + + // create Topic & Add it + client->getTopics()->add((const char*)topicName.c_str(), topicId); + client->_hasPredefTopic = true; + return client; +} + +uint16_t ClientList::getClientCount() +{ + return _clientCnt; +} + +bool ClientList::isAuthorized() +{ + return _authorize; +} + + diff --git a/MQTTSNGateway/src/MQTTSNGWClientList.h b/MQTTSNGateway/src/MQTTSNGWClientList.h new file mode 100644 index 0000000..4e0f81e --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWClientList.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 and/or initial documentation + * Tieto Poland Sp. z o.o. - Gateway improvements + **************************************************************************************/ + +#ifndef MQTTSNGATEWAY_SRC_MQTTSNGWCLIENTLIST_H_ +#define MQTTSNGATEWAY_SRC_MQTTSNGWCLIENTLIST_H_ + +#include "MQTTSNGWClient.h" +#include "MQTTSNGateway.h" + +namespace MQTTSNGW +{ +#define TRANSPEARENT_TYPE 0 +#define QOSM1PROXY_TYPE 1 +#define AGGREGATER_TYPE 2 + +class Client; + +/*===================================== + Class ClientList + =====================================*/ +class ClientList +{ +public: + ClientList(); + ~ClientList(); + + void initialize(Gateway* gw, bool aggregate); + void setClientList(Gateway* gw, int type); + void setPredefinedTopics(Gateway* gw, bool aggregate); + void erase(Client*&); + Client* createClient(SensorNetAddress* addr, MQTTSNString* clientId,int type); + Client* createClient(SensorNetAddress* addr, MQTTSNString* clientId, bool unstableLine, bool secure, int type); + bool createList(const char* fileName, int type); + Client* getClient(SensorNetAddress* addr); + Client* getClient(MQTTSNString* clientId); + Client* getClient(int index); + uint16_t getClientCount(void); + Client* getClient(void); + bool isAuthorized(); + +private: + bool readPredefinedList(const char* fileName, bool _aggregate); + Client* createPredefinedTopic( MQTTSNString* clientId, string topicName, uint16_t toipcId, bool _aggregate); + Client* _firstClient; + Client* _endClient; + Mutex _mutex; + uint16_t _clientCnt; + bool _authorize {false}; +}; + + +} + + + +#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWCLIENTLIST_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp index d5397b4..b1e805a 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp @@ -15,12 +15,12 @@ **************************************************************************************/ #include "MQTTSNGWClientRecvTask.h" -#include "MQTTSNGateway.h" #include "MQTTSNPacket.h" +#include "MQTTSNGWQoSm1Proxy.h" #include "MQTTSNGWEncapsulatedPacket.h" #include -#include "MQTTSNGWForwarder.h" +//#include "MQTTSNGWForwarder.h" using namespace MQTTSNGW; char* currentDateTime(void); @@ -57,14 +57,18 @@ void ClientRecvTask::initialize(int argc, char** argv) */ void ClientRecvTask::run() { - Event* ev = 0; - Client* client = 0; - char buf[128]; + Event* ev = nullptr; + Client* client = nullptr; + AdapterManager* adpMgr = _gateway->getAdapterManager(); + bool isAggrActive = adpMgr->isAggregaterActive(); + ClientList* clientList = _gateway->getClientList(); + EventQue* packetEventQue = _gateway->getPacketEventQue(); + char buf[128]; while (true) { - Forwarder* fwd = 0; + Forwarder* fwd = nullptr; WirelessNodeId nodeId; MQTTSNPacket* packet = new MQTTSNPacket(); @@ -95,73 +99,11 @@ void ClientRecvTask::run() log(0, packet, 0); ev = new Event(); ev->setBrodcastEvent(packet); - _gateway->getPacketEventQue()->post(ev); + packetEventQue->post(ev); continue; } - - if ( packet->getType() == MQTTSN_ENCAPSULATED ) - { - fwd = _gateway->getForwarderList()->getForwarder(_sensorNetwork->getSenderAddress()); - - if ( fwd == 0 ) - { - log(0, packet, 0); - WRITELOG("%s Forwarder %s is not authenticated.%s\n", ERRMSG_HEADER, _sensorNetwork->getSenderAddress()->sprint(buf), ERRMSG_FOOTER); - delete packet; - continue; - } - else - { - MQTTSNString fwdName = MQTTSNString_initializer; - fwdName.cstring = const_cast( fwd->getName() ); - log(0, packet, &fwdName); - - /* get the packet from the encapsulation message */ - MQTTSNGWEncapsulatedPacket encap; - encap.desirialize(packet->getPacketData(), packet->getPacketLength()); - nodeId.setId( encap.getWirelessNodeId() ); - client = fwd->getClient(&nodeId); - delete packet; - packet = encap.getMQTTSNPacket(); - } - } - else - { - client = 0; - - /* when QoSm1Proxy is available, select QoS-1 PUBLISH message */ - QoSm1Proxy* pxy = _gateway->getQoSm1Proxy(); - if ( pxy ) - { - /* get ClientId not Client which can send QoS-1 PUBLISH */ - const char* clientName = pxy->getClientId(_sensorNetwork->getSenderAddress()); - - if ( clientName ) - { - if ( packet->isQoSMinusPUBLISH() ) - { - /* QoS1Proxy takes responsibility of the client */ - client = _gateway->getQoSm1Proxy()->getClient(); - } - else - { - client = _gateway->getQoSm1Proxy()->getClient(); - log(clientName, packet); - WRITELOG("%s %s %s can send only PUBLISH with QoS-1.%s\n", ERRMSG_HEADER, clientName, _sensorNetwork->getSenderAddress()->sprint(buf), ERRMSG_FOOTER); - delete packet; - continue; - } - } - } - - if ( client == 0 ) - { - /* get client from the ClientList of Gateway by sensorNetAddress. */ - client = _gateway->getClientList()->getClient(_sensorNetwork->getSenderAddress()); - } - } - + client = adpMgr->getClient(packet, this); if ( client ) { @@ -169,7 +111,7 @@ void ClientRecvTask::run() log(client, packet, 0); ev = new Event(); ev->setClientRecvEvent(client,packet); - _gateway->getPacketEventQue()->post(ev); + packetEventQue->post(ev); } else { @@ -186,14 +128,14 @@ void ClientRecvTask::run() continue; } - client = _gateway->getClientList()->getClient(&data.clientID); + client = clientList->getClient(&data.clientID); if ( fwd ) { - if ( client == 0 ) + if ( client == nullptr ) { /* create a new client */ - client = _gateway->getClientList()->createClient(0, &data.clientID, false, false); + client = clientList->createClient(0, &data.clientID, isAggrActive); } /* Add to af forwarded client list of forwarder. */ fwd->addClient(client, &nodeId); @@ -208,7 +150,7 @@ void ClientRecvTask::run() else { /* create a new client */ - client = _gateway->getClientList()->createClient(_sensorNetwork->getSenderAddress(), &data.clientID, false, false); + client = clientList->createClient(_sensorNetwork->getSenderAddress(), &data.clientID, isAggrActive); } } @@ -224,7 +166,7 @@ void ClientRecvTask::run() /* post Client RecvEvent */ ev = new Event(); ev->setClientRecvEvent(client, packet); - _gateway->getPacketEventQue()->post(ev); + packetEventQue->post(ev); } else { diff --git a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.h b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.h index b681a24..30a63e9 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.h +++ b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.h @@ -21,6 +21,7 @@ namespace MQTTSNGW { +class AdapterManager; /*===================================== Class ClientRecvTask @@ -28,15 +29,17 @@ namespace MQTTSNGW class ClientRecvTask:public Thread { MAGIC_WORD_FOR_THREAD; + friend AdapterManager; public: ClientRecvTask(Gateway*); - ~ClientRecvTask(); + ~ClientRecvTask(void); virtual void initialize(int argc, char** argv); - void run(); + void run(void); private: void log(Client*, MQTTSNPacket*, MQTTSNString* id); void log(const char* clientId, MQTTSNPacket* packet); + Gateway* _gateway; SensorNetwork* _sensorNetwork; }; diff --git a/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp index 54107a5..788d024 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp @@ -15,9 +15,9 @@ **************************************************************************************/ #include "MQTTSNGWClientSendTask.h" #include "MQTTSNGWPacket.h" -#include "MQTTSNGWPacket.h" #include "MQTTSNGateway.h" #include "MQTTSNGWEncapsulatedPacket.h" +#include "MQTTSNGWQoSm1Proxy.h" using namespace MQTTSNGW; using namespace std; @@ -39,8 +39,9 @@ ClientSendTask::~ClientSendTask() void ClientSendTask::run() { - Client* client = 0; - MQTTSNPacket* packet = 0; + Client* client = nullptr; + MQTTSNPacket* packet = nullptr; + AdapterManager* adpMgr = _gateway->getAdapterManager(); int rc = 0; while (true) @@ -57,27 +58,7 @@ void ClientSendTask::run() { client = ev->getClient(); packet = ev->getMQTTSNPacket(); - Forwarder* fwd = client->getForwarder(); - - if ( fwd ) - { - MQTTSNGWEncapsulatedPacket encap(packet); - WirelessNodeId* wnId = fwd->getWirelessNodeId(client); - encap.setWirelessNodeId(wnId); - log(fwd, &encap); - log(client, packet); - rc = encap.unicast(_sensorNetwork,fwd->getSensorNetAddr()); - } - else - { - log(client, packet); - if ( client->isProxy() ) - { - _gateway->getQoSm1Proxy()->send(packet); - continue; - } - rc = packet->unicast(_sensorNetwork, client->getSensorNetAddress()); - } + rc = adpMgr->unicastToClient(client, packet, this); } else if (ev->getEventType() == EtBroadcast) { @@ -140,9 +121,3 @@ void ClientSendTask::log(Client* client, MQTTSNPacket* packet) } } -void ClientSendTask::log(Forwarder* forwarder, MQTTSNGWEncapsulatedPacket* packet) -{ - char pbuf[SIZE_OF_LOG_PACKET * 3]; - const char* forwarderId = forwarder->getId(); - WRITELOG(FORMAT_Y_W_G, currentDateTime(), packet->getName(), RIGHTARROW, forwarderId, packet->print(pbuf)); -} diff --git a/MQTTSNGateway/src/MQTTSNGWClientSendTask.h b/MQTTSNGateway/src/MQTTSNGWClientSendTask.h index b6cff2f..3eaf84f 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientSendTask.h +++ b/MQTTSNGateway/src/MQTTSNGWClientSendTask.h @@ -21,6 +21,7 @@ namespace MQTTSNGW { +class AdapterManager; /*===================================== Class ClientSendTask @@ -28,14 +29,14 @@ namespace MQTTSNGW class ClientSendTask: public Thread { MAGIC_WORD_FOR_THREAD; + friend AdapterManager; public: ClientSendTask(Gateway* gateway); - ~ClientSendTask(); - void run(); + ~ClientSendTask(void); + void run(void); private: - void log(Client*, MQTTSNPacket*); - void log(Forwarder*, MQTTSNGWEncapsulatedPacket*); + void log(Client* client, MQTTSNPacket* packet); Gateway* _gateway; SensorNetwork* _sensorNetwork; diff --git a/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp b/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp index 43aea61..33b3ef8 100644 --- a/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp @@ -90,7 +90,7 @@ void MQTTSNConnectionHandler::handleConnect(Client* client, MQTTSNPacket* packet //* clear ConnectData of Client */ Connect* connectData = client->getConnectData(); memset(connectData, 0, sizeof(Connect)); - if ( !client->isProxy() ) + if ( !client->isAdapter() ) { client->disconnected(); } @@ -104,7 +104,7 @@ void MQTTSNConnectionHandler::handleConnect(Client* client, MQTTSNPacket* packet connectData->keepAliveTimer = data.duration; connectData->flags.bits.will = data.willFlag; - if ((const char*) _gateway->getGWParams()->loginId != 0 && (const char*) _gateway->getGWParams()->password != 0) + if ((const char*) _gateway->getGWParams()->loginId != nullptr && (const char*) _gateway->getGWParams()->password != 0) { connectData->flags.bits.password = 1; connectData->flags.bits.username = 1; @@ -291,9 +291,9 @@ void MQTTSNConnectionHandler::handlePingreq(Client* client, MQTTSNPacket* packet void MQTTSNConnectionHandler::sendStoredPublish(Client* client) { - MQTTGWPacket* msg = 0; + MQTTGWPacket* msg = nullptr; - while ( ( msg = client->getClientSleepPacket() ) != 0 ) + while ( ( msg = client->getClientSleepPacket() ) != nullptr ) { // ToDo: This version can't re-send PUBLISH when PUBACK is not returned. client->deleteFirstClientSleepPacket(); // pop the que to delete element. diff --git a/MQTTSNGateway/src/MQTTSNGWDefines.h b/MQTTSNGateway/src/MQTTSNGWDefines.h index c15ae45..0cc22b6 100644 --- a/MQTTSNGateway/src/MQTTSNGWDefines.h +++ b/MQTTSNGateway/src/MQTTSNGWDefines.h @@ -27,7 +27,6 @@ namespace MQTTSNGW #define CLIENT_LIST "clients.conf" #define PREDEFINEDTOPIC_FILE "predefinedTopic.conf" #define FORWARDER_LIST "forwarders.conf" -#define QOS_1CLIENT_LIST "qos-1clients.conf" /*========================================================== * Gateway default parameters @@ -41,6 +40,7 @@ namespace MQTTSNGW #define MAX_CLIENTS (100) // Number of Clients can be handled. #define MAX_CLIENTID_LENGTH (64) // Max length of clientID #define MAX_INFLIGHTMESSAGES (10) // Number of inflight messages +#define MAX_MESSAGEID_TABLE_SIZE (500) // Number of MessageIdTable size #define MAX_SAVED_PUBLISH (20) // Max number of PUBLISH message for Asleep state #define MAX_TOPIC_PAR_CLIENT (50) // Max Topic count for a client. it should be less than 256 #define MQTTSNGW_MAX_PACKET_SIZE (1024) // Max Packet size (5+2+TopicLen+PayloadLen + Foward Encapsulation) diff --git a/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.cpp b/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.cpp index 1c06d13..750867f 100644 --- a/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.cpp +++ b/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.cpp @@ -52,7 +52,7 @@ void WirelessNodeId::setId(uint8_t* id, uint8_t len) } else { - _nodeId = 0; + _nodeId = nullptr; _len = 0; } } @@ -123,7 +123,7 @@ int MQTTSNGWEncapsulatedPacket::desirialize(unsigned char* buf, unsigned short l if ( _mqttsn ) { delete _mqttsn; - _mqttsn = 0; + _mqttsn = nullptr; } _ctrl = buf[2]; diff --git a/MQTTSNGateway/src/MQTTSNGWForwarder.cpp b/MQTTSNGateway/src/MQTTSNGWForwarder.cpp index ad1e94b..20a05e9 100644 --- a/MQTTSNGateway/src/MQTTSNGWForwarder.cpp +++ b/MQTTSNGateway/src/MQTTSNGWForwarder.cpp @@ -20,13 +20,13 @@ using namespace MQTTSNGW; using namespace std; -/* - * Class ForwarderList - */ +/*===================================== + Class ForwarderList + =====================================*/ ForwarderList::ForwarderList() { - _head = 0; + _head = nullptr; } ForwarderList::~ForwarderList() @@ -43,6 +43,35 @@ ForwarderList::~ForwarderList() } } + +void ForwarderList::initialize(Gateway* gw) +{ + char param[MQTTSNGW_PARAM_MAX]; + string fileName; + GatewayParams* params = gw->getGWParams(); + + if (gw->getParam("Forwarder", param) == 0 ) + { + if (!strcasecmp(param, "YES") ) + { + if (gw->getParam("ForwardersList", param) == 0) + { + fileName = string(param); + } + else + { + fileName = params->configDir + string(FORWARDER_LIST); + } + if ( !setFowerder(fileName.c_str()) ) + { + throw Exception("ForwarderList::initialize: No ForwardersList file defined by the configuration.."); + } + params->forwarderListName = strdup(fileName.c_str()); + } + } +} + + Forwarder* ForwarderList::getForwarder(SensorNetAddress* addr) { Forwarder* p = _head; @@ -111,7 +140,7 @@ bool ForwarderList::setFowerder(const char* fileName) Forwarder* ForwarderList::addForwarder(SensorNetAddress* addr, string* forwarderId) { Forwarder* fdr = new Forwarder(addr, forwarderId); - if ( _head == 0 ) + if ( _head == nullptr ) { _head = fdr; } @@ -120,7 +149,7 @@ Forwarder* ForwarderList::addForwarder(SensorNetAddress* addr, string* forwarde Forwarder* p = _head; while ( p ) { - if ( p->_next == 0 ) + if ( p->_next == nullptr ) { p->_next = fdr; break; @@ -136,20 +165,20 @@ Forwarder* ForwarderList::addForwarder(SensorNetAddress* addr, string* forwarde Forwarder::Forwarder() { - _headClient = 0; - _next = 0; + _headClient = nullptr; + _next = nullptr; } -/* - * Class Forwarder - */ +/*===================================== + Class ForwarderList + =====================================*/ Forwarder::Forwarder(SensorNetAddress* addr, string* forwarderId) { _forwarderName = *forwarderId; _sensorNetAddr = *addr; - _headClient = 0; - _next = 0; + _headClient = nullptr; + _next = nullptr; } Forwarder::~Forwarder(void) @@ -174,11 +203,11 @@ const char* Forwarder::getId(void) void Forwarder::addClient(Client* client, WirelessNodeId* id) { ForwarderElement* p = _headClient; - ForwarderElement* prev = 0; + ForwarderElement* prev = nullptr; client->setForwarder(this); - if ( p != 0 ) + if ( p != nullptr ) { while ( p ) { @@ -209,7 +238,7 @@ void Forwarder::addClient(Client* client, WirelessNodeId* id) Client* Forwarder::getClient(WirelessNodeId* id) { - Client* cl = 0; + Client* cl = nullptr; _mutex.lock(); ForwarderElement* p = _headClient; while ( p ) @@ -235,7 +264,7 @@ const char* Forwarder::getName(void) WirelessNodeId* Forwarder::getWirelessNodeId(Client* client) { - WirelessNodeId* nodeId = 0; + WirelessNodeId* nodeId = nullptr; _mutex.lock(); ForwarderElement* p = _headClient; while ( p ) @@ -256,7 +285,7 @@ WirelessNodeId* Forwarder::getWirelessNodeId(Client* client) void Forwarder::eraseClient(Client* client) { - ForwarderElement* prev = 0; + ForwarderElement* prev = nullptr; _mutex.lock(); ForwarderElement* p = _headClient; @@ -314,7 +343,7 @@ void ForwarderElement::setClient(Client* client) void ForwarderElement::setWirelessNodeId(WirelessNodeId* id) { - if ( _wirelessNodeId == 0 ) + if ( _wirelessNodeId == nullptr ) { _wirelessNodeId = new WirelessNodeId(); } diff --git a/MQTTSNGateway/src/MQTTSNGWForwarder.h b/MQTTSNGateway/src/MQTTSNGWForwarder.h index 2c58e66..354067f 100644 --- a/MQTTSNGateway/src/MQTTSNGWForwarder.h +++ b/MQTTSNGateway/src/MQTTSNGWForwarder.h @@ -18,22 +18,27 @@ #define MQTTSNGATEWAY_SRC_MQTTSNGWFORWARDER_H_ #include "MQTTSNGWClient.h" +#include "MQTTSNGateway.h" #include "MQTTSNGWEncapsulatedPacket.h" #include "SensorNetwork.h" namespace MQTTSNGW { - +class Gateway; class Client; class WirelessNodeId; +/*===================================== + Class ForwarderElement + =====================================*/ class ForwarderElement { friend class Forwarder; public: ForwarderElement(); ~ForwarderElement(); + void setClient(Client* client); void setWirelessNodeId(WirelessNodeId* id); private: @@ -42,15 +47,18 @@ private: ForwarderElement* _next; }; - +/*===================================== + Class Forwarder + =====================================*/ class Forwarder { friend class ForwarderList; public: - Forwarder(); + Forwarder(void); Forwarder(SensorNetAddress* addr, string* forwarderId); ~Forwarder(); + void initialize(void); const char* getId(void); void addClient(Client* client, WirelessNodeId* id); Client* getClient(WirelessNodeId* id); @@ -62,17 +70,21 @@ public: private: string _forwarderName; SensorNetAddress _sensorNetAddr; - ForwarderElement* _headClient; - Forwarder* _next; + ForwarderElement* _headClient{nullptr}; + Forwarder* _next {nullptr}; Mutex _mutex; }; +/*===================================== + Class ForwarderList + =====================================*/ class ForwarderList { public: ForwarderList(); ~ForwarderList(); + void initialize(Gateway* gw); Forwarder* getForwarder(SensorNetAddress* addr); bool setFowerder(const char* fileName); Forwarder* addForwarder(SensorNetAddress* addr, string* forwarderId); diff --git a/MQTTSNGateway/src/MQTTSNGWMessageIdTable.cpp b/MQTTSNGateway/src/MQTTSNGWMessageIdTable.cpp new file mode 100644 index 0000000..b87e06c --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWMessageIdTable.cpp @@ -0,0 +1,218 @@ +/************************************************************************************** + * Copyright (c) 2018, 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 "MQTTSNGWMessageIdTable.h" +#include "MQTTSNGWClient.h" + +using namespace MQTTSNGW; + +/*=============================== + * Class MessageIdTable + ===============================*/ +MessageIdTable::MessageIdTable() +{ + +} + +MessageIdTable::~MessageIdTable() +{ + _mutex.lock(); + if ( _head != nullptr ) + { + MessageIdElement* p = _tail; + while ( p ) + { + MessageIdElement* pPrev = p; + delete p; + _cnt--; + p = pPrev->_prev; + } + _head = _tail = nullptr; + } + _mutex.unlock(); +} + +MessageIdElement* MessageIdTable::add(Aggregater* aggregater, Client* client, uint16_t clientMsgId) +{ + if ( _cnt > _maxSize ) + { + return nullptr; + } + + MessageIdElement* elm = new MessageIdElement(0, client, clientMsgId); + if ( elm == nullptr ) + { + return nullptr; + } + _mutex.lock(); + if ( _head == nullptr ) + { + elm->_msgId = aggregater->msgId(); + _head = elm; + _tail = elm; + _cnt++; + } + else + { + MessageIdElement* p = find(client, clientMsgId); + if ( p == nullptr ) + { + elm->_msgId = aggregater->msgId(); + p = _tail; + _tail = elm; + elm->_prev = p; + p->_next = elm; + _cnt++; + } + else + { + delete elm; + elm = nullptr; + } + } + _mutex.unlock(); + return elm; +} + +MessageIdElement* MessageIdTable::find(uint16_t msgId) +{ + MessageIdElement* p = _head; + while ( p ) + { + if ( p->_msgId == msgId) + { + break; + } + p = p->_next; + } + return p; +} + +MessageIdElement* MessageIdTable::find(Client* client, uint16_t clientMsgId) +{ + MessageIdElement* p = _head; + while ( p ) + { + if ( p->_clientMsgId == clientMsgId && p->_client == client) + { + break; + } + p = p->_next; + } + return p; +} + + +Client* MessageIdTable::getClientMsgId(uint16_t msgId, uint16_t* clientMsgId) +{ + Client* clt = nullptr; + *clientMsgId = 0; + _mutex.lock(); + MessageIdElement* p = find(msgId); + if ( p != nullptr ) + { + clt = p->_client; + *clientMsgId = p->_clientMsgId; + clear(p); + } + _mutex.unlock(); + return clt; +} + +void MessageIdTable::erase(uint16_t msgId) +{ + _mutex.lock(); + MessageIdElement* p = find(msgId); + clear(p); + _mutex.unlock(); +} + +void MessageIdTable::clear(MessageIdElement* elm) +{ + if ( elm == nullptr ) + { + return; + } + + if ( elm->_prev == nullptr ) + { + _head = elm->_next; + if ( _head == nullptr) + { + _tail = nullptr; + } + else + { + _head->_prev = nullptr; + } + delete elm; + _cnt--; + return; + } + else + { + elm->_prev->_next = elm->_next; + if ( elm->_next == nullptr ) + { + _tail = elm->_prev; + } + else + { + elm->_next->_prev = elm->_prev; + } + delete elm; + _cnt--; + return; + } +} + + +uint16_t MessageIdTable::getMsgId(Client* client, uint16_t clientMsgId) +{ + uint16_t msgId = 0; + MessageIdElement* p = find(client, clientMsgId); + if ( p != nullptr ) + { + msgId = p->_msgId; + } + return msgId; +} + +/*=============================== + * Class MessageIdElement + ===============================*/ +MessageIdElement::MessageIdElement(void) + : _msgId{0} + , _clientMsgId {0} + , _client {nullptr} + , _next {nullptr} + , _prev {nullptr} +{ + +} + +MessageIdElement::MessageIdElement(uint16_t msgId, Client* client, uint16_t clientMsgId) + : MessageIdElement() +{ + _msgId = msgId; + _client = client; + _clientMsgId = clientMsgId; +} + +MessageIdElement::~MessageIdElement(void) +{ + +} diff --git a/MQTTSNGateway/src/MQTTSNGWMessageIdTable.h b/MQTTSNGateway/src/MQTTSNGWMessageIdTable.h new file mode 100644 index 0000000..59f7be6 --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWMessageIdTable.h @@ -0,0 +1,78 @@ +/************************************************************************************** + * Copyright (c) 2018, 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 MQTTSNGATEWAY_SRC_MQTTSNGWMESSAGEIDTABLE_H_ +#define MQTTSNGATEWAY_SRC_MQTTSNGWMESSAGEIDTABLE_H_ + +#include "MQTTSNGWDefines.h" +#include "MQTTSNGWProcess.h" + +#include +namespace MQTTSNGW +{ + +class Client; +class MessageIdElement; +class Meutex; +class Aggregater; +/*===================================== + Class MessageIdTable + ======================================*/ +class MessageIdTable +{ +public: + MessageIdTable(); + ~MessageIdTable(); + + MessageIdElement* add(Aggregater* aggregater, Client* client, uint16_t clientMsgId); + Client* getClientMsgId(uint16_t msgId, uint16_t* clientMsgId); + uint16_t getMsgId(Client* client, uint16_t clientMsgId); + void erase(uint16_t msgId); + void clear(MessageIdElement* elm); +private: + MessageIdElement* find(uint16_t msgId); + MessageIdElement* find(Client* client, uint16_t clientMsgId); + MessageIdElement* _head {nullptr}; + MessageIdElement* _tail {nullptr}; + int _cnt {0}; + int _maxSize {MAX_MESSAGEID_TABLE_SIZE}; + Mutex _mutex; +}; + +/*===================================== + Class MessageIdElement + =====================================*/ +class MessageIdElement +{ + friend class MessageIdTable; + friend class Aggregater; +public: + MessageIdElement(void); + MessageIdElement(uint16_t msgId, Client* client, uint16_t clientMsgId); + ~MessageIdElement(void); + +private: + uint16_t _msgId; + uint16_t _clientMsgId; + Client* _client; + MessageIdElement* _next; + MessageIdElement* _prev; +}; + + +} + +#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWMESSAGEIDTABLE_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWPacket.cpp b/MQTTSNGateway/src/MQTTSNGWPacket.cpp index 222597f..998eaf1 100644 --- a/MQTTSNGateway/src/MQTTSNGWPacket.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPacket.cpp @@ -24,12 +24,30 @@ using namespace std; using namespace MQTTSNGW; +int readInt(char** pptr); +void writeInt(unsigned char** pptr, int msgId); -MQTTSNPacket::MQTTSNPacket() +MQTTSNPacket::MQTTSNPacket(void) { - _buf = 0; + _buf = nullptr; _bufLen = 0; } + +MQTTSNPacket::MQTTSNPacket(MQTTSNPacket& packet) +{ + _buf = (unsigned char*)malloc(packet._bufLen); + if (_buf) + { + _bufLen = packet._bufLen; + memcpy(_buf, packet._buf, _bufLen); + } + else + { + _buf = nullptr; + _bufLen = 0; + } +} + MQTTSNPacket::~MQTTSNPacket() { if (_buf) @@ -154,6 +172,11 @@ int MQTTSNPacket::setConnect(void) return desirialize(buf, len); } +bool MQTTSNPacket::isAccepted(void) +{ + return ( getType() == MQTTSN_CONNACK) && (_buf[2] == MQTTSN_RC_ACCEPTED); +} + int MQTTSNPacket::setCONNACK(uint8_t returnCode) { unsigned char buf[3]; @@ -455,5 +478,110 @@ char* MQTTSNPacket::getMsgId(char* pbuf) sprintf(pbuf, " "); break; } + if ( strcmp(pbuf, " 0000") == 0 ) + { + sprintf(pbuf, " "); + } return pbuf; } + +int MQTTSNPacket::getMsgId(void) +{ + int value = 0; + int p = 0; + int msgId = 0; + char* ptr = 0; + + switch ( getType() ) + { + case MQTTSN_PUBLISH: + p = MQTTSNPacket_decode(_buf, _bufLen, &value); + ptr = (char*)_buf + p + 4; + msgId = readInt((char**)&ptr); + break; + case MQTTSN_PUBACK: + case MQTTSN_REGISTER: + case MQTTSN_REGACK: + ptr = (char*)_buf + 4; + msgId = readInt((char**)&ptr); + break; + case MQTTSN_PUBREC: + case MQTTSN_PUBREL: + case MQTTSN_PUBCOMP: + case MQTTSN_UNSUBACK: + ptr = (char*)_buf + 2; + msgId = readInt((char**)&ptr); + break; + case MQTTSN_SUBSCRIBE: + case MQTTSN_UNSUBSCRIBE: + p = MQTTSNPacket_decode(_buf, _bufLen, &value); + ptr = (char*)_buf + p + 2; + msgId = readInt((char**)&ptr); + break; + case MQTTSN_SUBACK: + ptr = (char*)_buf + 5; + msgId = readInt((char**)&ptr); + break; + default: + break; + } + return msgId; +} + +void MQTTSNPacket::setMsgId(uint16_t msgId) +{ + int value = 0; + int p = 0; + //unsigned char* ptr = 0; + + switch ( getType() ) + { + case MQTTSN_PUBLISH: + p = MQTTSNPacket_decode(_buf, _bufLen, &value); + _buf[p + 4] = (unsigned char)(msgId / 256); + _buf[p + 5] = (unsigned char)(msgId % 256); + //ptr = _buf + p + 4; + //writeInt(&ptr, msgId); + break; + case MQTTSN_PUBACK: + case MQTTSN_REGISTER: + case MQTTSN_REGACK: + _buf[4] = (unsigned char)(msgId / 256); + _buf[5] = (unsigned char)(msgId % 256); + //ptr = _buf + 4; + //writeInt(&ptr, msgId); + break; + case MQTTSN_PUBREC: + case MQTTSN_PUBREL: + case MQTTSN_PUBCOMP: + case MQTTSN_UNSUBACK: + _buf[2] = (unsigned char)(msgId / 256); + _buf[3] = (unsigned char)(msgId % 256); + //ptr = _buf + 2; + //writeInt(&ptr, msgId); + break; + case MQTTSN_SUBSCRIBE: + case MQTTSN_UNSUBSCRIBE: + p = MQTTSNPacket_decode(_buf, _bufLen, &value); + _buf[p + 2] = (unsigned char)(msgId / 256); + _buf[p + 3] = (unsigned char)(msgId % 256); + //ptr = _buf + p + 2; + //writeInt(&ptr, msgId); +break; + case MQTTSN_SUBACK: + _buf[5] = (unsigned char)(msgId / 256); + _buf[6] = (unsigned char)(msgId % 256); + //ptr = _buf + 5; + //writeInt(&ptr, msgId); +break; + default: + break; + } +} + +bool MQTTSNPacket::isDuplicate(void) +{ + int value = 0; + int p = MQTTSNPacket_decode(_buf, _bufLen, &value); + return ( _buf[p + 1] & 0x80 ); +} diff --git a/MQTTSNGateway/src/MQTTSNGWPacket.h b/MQTTSNGateway/src/MQTTSNGWPacket.h index 22e3bd7..7a624a3 100644 --- a/MQTTSNGateway/src/MQTTSNGWPacket.h +++ b/MQTTSNGateway/src/MQTTSNGWPacket.h @@ -26,8 +26,9 @@ namespace MQTTSNGW class MQTTSNPacket { public: - MQTTSNPacket(); - ~MQTTSNPacket(); + MQTTSNPacket(void); + MQTTSNPacket(MQTTSNPacket &packet); + ~MQTTSNPacket(void); int unicast(SensorNetwork* network, SensorNetAddress* sendTo); int broadcast(SensorNetwork* network); int recv(SensorNetwork* network); @@ -80,8 +81,12 @@ public: int getWILLTOPICUPD(uint8_t* willQoS, uint8_t* willRetain, MQTTSNString* willTopic); int getWILLMSGUPD(MQTTSNString* willMsg); + bool isAccepted(void); + bool isDuplicate(void); bool isQoSMinusPUBLISH(void); char* getMsgId(char* buf); + int getMsgId(void); + void setMsgId(uint16_t msgId); char* print(char* buf); private: diff --git a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp index 53ad17a..47f1eae 100644 --- a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp @@ -21,12 +21,16 @@ #include "MQTTGWPacket.h" #include "MQTTSNGWClient.h" #include "MQTTSNGWProcess.h" +#include "MQTTSNGWAdapterManager.h" #include "MQTTGWConnectionHandler.h" #include "MQTTGWPublishHandler.h" #include "MQTTGWSubscribeHandler.h" #include "MQTTSNGWConnectionHandler.h" #include "MQTTSNGWPublishHandler.h" #include "MQTTSNGWSubscribeHandler.h" +#include "Timer.h" +#include "MQTTSNAggregateConnectionHandler.h" + #include using namespace std; @@ -48,6 +52,8 @@ PacketHandleTask::PacketHandleTask(Gateway* gateway) _mqttsnConnection = new MQTTSNConnectionHandler(_gateway); _mqttsnPublish = new MQTTSNPublishHandler(_gateway); _mqttsnSubscribe = new MQTTSNSubscribeHandler(_gateway); + + _mqttsnAggrConnection = new MQTTSNAggregateConnectionHandler(_gateway); } /** @@ -79,15 +85,22 @@ PacketHandleTask::~PacketHandleTask() { delete _mqttsnSubscribe; } + + if ( _mqttsnAggrConnection ) + { + delete _mqttsnAggrConnection; + } } void PacketHandleTask::run() { - Event* ev = 0; + Event* ev = nullptr; EventQue* eventQue = _gateway->getPacketEventQue(); - Client* client = 0; - MQTTSNPacket* snPacket = 0; - MQTTGWPacket* brPacket = 0; + AdapterManager* adpMgr = _gateway->getAdapterManager(); + + Client* client = nullptr; + MQTTSNPacket* snPacket = nullptr; + MQTTGWPacket* brPacket = nullptr; char msgId[6]; memset(msgId, 0, 6); @@ -114,12 +127,8 @@ void PacketHandleTask::run() _advertiseTimer.start(_gateway->getGWParams()->keepAlive * 1000UL); } - /*------ Check QoS-1 Proxy Connect or PINGREQ ------*/ - QoSm1Proxy* pxy = _gateway->getQoSm1Proxy(); - if ( pxy ) - { - pxy->checkConnection(); - } + /*------ Check Adapters Connect or PINGREQ ------*/ + adpMgr->checkConnection(); } /*------ Handle SEARCHGW Message ---------*/ @@ -137,101 +146,221 @@ void PacketHandleTask::run() DEBUGLOG(" PacketHandleTask gets %s %s from the client.\n", snPacket->getName(), snPacket->getMsgId(msgId)); - switch (snPacket->getType()) + if ( adpMgr->isAggregatedClient(client) ) { - 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; - case MQTTSN_PUBREC: - _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: - _mqttsnPublish->handleRegAck(client, snPacket); - break; - case MQTTSN_SUBSCRIBE: - _mqttsnSubscribe->handleSubscribe(client, snPacket); - break; - case MQTTSN_UNSUBSCRIBE: - _mqttsnSubscribe->handleUnsubscribe(client, snPacket); - break; - default: - break; + aggregatePacketHandler(client, snPacket); } + else + { + transparentPacketHandler(client, snPacket); + } + /* Reset the Timer for PINGREQ. */ client->updateStatus(snPacket); } - /*------ Handle Messages form Broker ---------*/ - else if (ev->getEventType() == EtBrokerRecv) + 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()) + + + if ( client->isAggregater() ) { - case CONNACK: - _mqttConnection->handleConnack(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; + aggregatePacketHandler(client, brPacket); + } + else + { + transparentPacketHandler(client, brPacket); } } delete ev; } } + + +void PacketHandleTask::aggregatePacketHandler(Client*client, MQTTSNPacket* packet) +{ + switch (packet->getType()) + { + case MQTTSN_CONNECT: + _mqttsnAggrConnection->handleConnect(client, packet); + break; + case MQTTSN_WILLTOPIC: + _mqttsnConnection->handleWilltopic(client, packet); + break; + case MQTTSN_WILLMSG: + _mqttsnAggrConnection->handleWillmsg(client, packet); + break; + case MQTTSN_DISCONNECT: + _mqttsnAggrConnection->handleDisconnect(client, packet); + break; + case MQTTSN_WILLMSGUPD: + _mqttsnConnection->handleWillmsgupd(client, packet); + break; + case MQTTSN_PINGREQ: + _mqttsnAggrConnection->handlePingreq(client, packet); + break; + case MQTTSN_PUBLISH: + _mqttsnPublish->handleAggregatePublish(client, packet); + break; + case MQTTSN_PUBACK: + _mqttsnPublish->handleAggregateAck(client, packet, MQTTSN_PUBACK); + break; + case MQTTSN_PUBREC: + _mqttsnPublish->handleAggregateAck(client, packet, MQTTSN_PUBREC); + break; + case MQTTSN_PUBREL: + _mqttsnPublish->handleAggregateAck(client, packet, MQTTSN_PUBREL); + break; + case MQTTSN_PUBCOMP: + _mqttsnPublish->handleAggregateAck(client, packet, MQTTSN_PUBCOMP); + break; + case MQTTSN_REGISTER: + _mqttsnPublish->handleRegister(client, packet); + break; + case MQTTSN_REGACK: + _mqttsnPublish->handleRegAck(client, packet); + break; + case MQTTSN_SUBSCRIBE: + _mqttsnSubscribe->handleAggregateSubscribe(client, packet); + break; + case MQTTSN_UNSUBSCRIBE: + _mqttsnSubscribe->handleAggregateUnsubscribe(client, packet); + break; + default: + break; + } +} + + +void PacketHandleTask::aggregatePacketHandler(Client*client, MQTTGWPacket* packet) +{ + switch (packet->getType()) + { + case CONNACK: + _mqttConnection->handleConnack(client, packet); + break; + case PINGRESP: + _mqttConnection->handlePingresp(client, packet); + break; + case PUBLISH: + _mqttPublish->handleAggregatePublish(client, packet); + break; + case PUBACK: + _mqttPublish->handleAggregatePuback(client, packet); + break; + case PUBREC: + _mqttPublish->handleAggregateAck(client, packet, PUBREC); + break; + case PUBREL: + _mqttPublish->handleAggregatePubrel(client, packet); + break; + case PUBCOMP: + _mqttPublish->handleAggregateAck(client, packet, PUBCOMP); + break; + case SUBACK: + _mqttSubscribe->handleAggregateSuback(client, packet); + break; + case UNSUBACK: + _mqttSubscribe->handleAggregateUnsuback(client, packet); + break; + default: + break; + } +} + +void PacketHandleTask::transparentPacketHandler(Client*client, MQTTSNPacket* packet) +{ + switch (packet->getType()) + { + case MQTTSN_CONNECT: + _mqttsnConnection->handleConnect(client, packet); + break; + case MQTTSN_WILLTOPIC: + _mqttsnConnection->handleWilltopic(client, packet); + break; + case MQTTSN_WILLMSG: + _mqttsnConnection->handleWillmsg(client, packet); + break; + case MQTTSN_DISCONNECT: + _mqttsnConnection->handleDisconnect(client, packet); + break; + case MQTTSN_WILLMSGUPD: + _mqttsnConnection->handleWillmsgupd(client, packet); + break; + case MQTTSN_PINGREQ: + _mqttsnConnection->handlePingreq(client, packet); + break; + case MQTTSN_PUBLISH: + _mqttsnPublish->handlePublish(client, packet); + break; + case MQTTSN_PUBACK: + _mqttsnPublish->handlePuback(client, packet); + break; + case MQTTSN_PUBREC: + _mqttsnPublish->handleAck(client, packet, PUBREC); + break; + case MQTTSN_PUBREL: + _mqttsnPublish->handleAck(client, packet, PUBREL); + break; + case MQTTSN_PUBCOMP: + _mqttsnPublish->handleAck(client, packet, PUBCOMP); + break; + case MQTTSN_REGISTER: + _mqttsnPublish->handleRegister(client, packet); + break; + case MQTTSN_REGACK: + _mqttsnPublish->handleRegAck(client, packet); + break; + case MQTTSN_SUBSCRIBE: + _mqttsnSubscribe->handleSubscribe(client, packet); + break; + case MQTTSN_UNSUBSCRIBE: + _mqttsnSubscribe->handleUnsubscribe(client, packet); + break; + default: + break; + } +} + + +void PacketHandleTask::transparentPacketHandler(Client*client, MQTTGWPacket* packet) +{ + switch (packet->getType()) + { + case CONNACK: + _mqttConnection->handleConnack(client, packet); + break; + case PINGRESP: + _mqttConnection->handlePingresp(client, packet); + break; + case PUBLISH: + _mqttPublish->handlePublish(client, packet); + break; + case PUBACK: + _mqttPublish->handlePuback(client, packet); + break; + case PUBREC: + _mqttPublish->handleAck(client, packet, PUBREC); + break; + case PUBREL: + _mqttPublish->handleAck(client, packet, PUBREL); + break; + case PUBCOMP: + _mqttPublish->handleAck(client, packet, PUBCOMP); + break; + case SUBACK: + _mqttSubscribe->handleSuback(client, packet); + break; + case UNSUBACK: + _mqttSubscribe->handleUnsuback(client, packet); + break; + default: + break; + } +} + diff --git a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.h b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.h index 7114605..a77eb65 100644 --- a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.h +++ b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.h @@ -17,46 +17,60 @@ #ifndef MQTTSNGWPACKETHANDLETASK_H_ #define MQTTSNGWPACKETHANDLETASK_H_ -#include -#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 "Timer.h" +#include "MQTTSNGWProcess.h" namespace MQTTSNGW { +class Gateway; +class Client; +class MQTTSNPacket; +class MQTTGWPacket; +class Timer; +class MQTTGWConnectionHandler; +class MQTTGWPublishHandler; +class MQTTGWSubscribeHandler; +class MQTTSNConnectionHandler; +class MQTTSNPublishHandler; +class MQTTSNSubscribeHandler; + +class MQTTSNAggregateConnectionHandler; #define ERRNO_APL_01 11 // Task Initialize Error +class Thread; +class Timer; /*===================================== Class PacketHandleTask =====================================*/ class PacketHandleTask : public Thread { MAGIC_WORD_FOR_THREAD; + friend class MQTTGWAggregatePublishHandler; + friend class MQTTGWAggregateSubscribeHandler; + friend class MQTTSNAggregateConnectionHandler; + friend class MQTTSNAggregatePublishHandler; + friend class MQTTSNAggregateSubscribeHandler; public: PacketHandleTask(Gateway* gateway); ~PacketHandleTask(); void run(); private: - Gateway* _gateway; + void aggregatePacketHandler(Client*client, MQTTSNPacket* packet); + void aggregatePacketHandler(Client*client, MQTTGWPacket* packet); + void transparentPacketHandler(Client*client, MQTTSNPacket* packet); + void transparentPacketHandler(Client*client, MQTTGWPacket* packet); + + Gateway* _gateway {nullptr}; Timer _advertiseTimer; Timer _sendUnixTimer; - MQTTGWConnectionHandler* _mqttConnection; - MQTTGWPublishHandler* _mqttPublish; - MQTTGWSubscribeHandler* _mqttSubscribe; - MQTTSNConnectionHandler* _mqttsnConnection; - MQTTSNPublishHandler* _mqttsnPublish; - MQTTSNSubscribeHandler* _mqttsnSubscribe; + MQTTGWConnectionHandler* _mqttConnection {nullptr}; + MQTTGWPublishHandler* _mqttPublish {nullptr}; + MQTTGWSubscribeHandler* _mqttSubscribe {nullptr}; + MQTTSNConnectionHandler* _mqttsnConnection {nullptr}; + MQTTSNPublishHandler* _mqttsnPublish {nullptr}; + MQTTSNSubscribeHandler* _mqttsnSubscribe {nullptr}; + + MQTTSNAggregateConnectionHandler* _mqttsnAggrConnection {nullptr}; }; diff --git a/MQTTSNGateway/src/MQTTSNGWProcess.cpp b/MQTTSNGateway/src/MQTTSNGWProcess.cpp index 549b439..88ba292 100644 --- a/MQTTSNGateway/src/MQTTSNGWProcess.cpp +++ b/MQTTSNGateway/src/MQTTSNGWProcess.cpp @@ -34,8 +34,8 @@ char* currentDateTime(void); /*===================================== Global Variables & Functions ======================================*/ -Process* MQTTSNGW::theProcess = 0; -MultiTaskProcess* MQTTSNGW::theMultiTaskProcess = 0; +Process* MQTTSNGW::theProcess = nullptr; +MultiTaskProcess* MQTTSNGW::theMultiTaskProcess = nullptr; /* * Save the type of signal @@ -359,8 +359,8 @@ Exception::Exception(const int exNo, const string& message) { _message = message; _exNo = exNo; - _fileName = 0; - _functionName = 0; + _fileName = nullptr; + _functionName = nullptr; _line = 0; } diff --git a/MQTTSNGateway/src/MQTTSNGWProcess.h b/MQTTSNGateway/src/MQTTSNGWProcess.h index 1ff48da..1fb02a9 100644 --- a/MQTTSNGateway/src/MQTTSNGWProcess.h +++ b/MQTTSNGateway/src/MQTTSNGWProcess.h @@ -132,8 +132,8 @@ public: QueElement(T* t) { _element = t; - _next = 0; - _prev = 0; + _next = nullptr; + _prev = nullptr; } ~QueElement() @@ -155,8 +155,8 @@ class Que public: Que() { - _head = 0; - _tail = 0; + _head = nullptr; + _tail = nullptr; _cnt = 0; _maxSize = 0; } @@ -180,12 +180,12 @@ public: QueElement* head = _head; if ( _head == _tail ) { - _head = _tail = 0; + _head = _tail = nullptr; } else { _head = head->_next; - head->_prev = 0; + head->_prev = nullptr; } delete head; _cnt--; @@ -861,13 +861,13 @@ class ListElm public: ListElm() { - _elm = 0; - _prev = _next = 0; + _elm = nullptr; + _prev = _next = nullptr; } ListElm(T* elm) { _elm = elm; - _prev = _next = 0; + _prev = _next = nullptr; } T* getContent(void) { @@ -888,7 +888,7 @@ class List{ public: List() { - _head = _tail = 0; + _head = _tail = nullptr; _size = 0; } ~List() @@ -899,11 +899,11 @@ public: int add(T* t) { ListElm* elm = new ListElm(t); - if ( elm == 0 ) + if ( elm == nullptr ) { return 0; } - if ( _head == 0 ) + if ( _head == nullptr ) { _head = elm; _tail = elm; @@ -929,7 +929,7 @@ public: else if ( _tail == elm ) { _tail = elm->_prev; - elm->_prev->_next = 0; + elm->_prev->_next = nullptr; _size--; delete elm; } @@ -950,8 +950,8 @@ public: delete p; p = q; } - _head = 0; - _tail = 0; + _head = nullptr; + _tail = nullptr; _size = 0; } diff --git a/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp b/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp index aedb5df..26b1816 100644 --- a/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp @@ -20,6 +20,7 @@ #include "MQTTGWPacket.h" #include "MQTTSNGateway.h" #include "MQTTSNGWClient.h" +#include "MQTTSNGWQoSm1Proxy.h" #include using namespace std; using namespace MQTTSNGW; @@ -34,7 +35,7 @@ MQTTSNPublishHandler::~MQTTSNPublishHandler() } -void MQTTSNPublishHandler::handlePublish(Client* client, MQTTSNPacket* packet) +MQTTGWPacket* MQTTSNPublishHandler::handlePublish(Client* client, MQTTSNPacket* packet) { uint8_t dup; int qos; @@ -47,34 +48,26 @@ void MQTTSNPublishHandler::handlePublish(Client* client, MQTTSNPacket* packet) char shortTopic[2]; - if ( !client->isActive() ) + if ( !_gateway->getAdapterManager()->getQoSm1Proxy()->isActive() ) { - if ( client->isProxy() ) + if ( client->isQoSm1() ) { - client->setProxyPacket(packet); + _gateway->getAdapterManager()->getQoSm1Proxy()->savePacket(client, packet); + + return nullptr; } - else - { - /* Reply DISCONNECT to the client */ - Event* ev = new Event(); - MQTTSNPacket* disconnect = new MQTTSNPacket(); - disconnect->setDISCONNECT(0); - ev->setClientSendEvent(client, disconnect); - _gateway->getClientSendQue()->post(ev); - } - return; } if ( packet->getPUBLISH(&dup, &qos, &retained, &msgId, &topicid, &payload, &payloadlen) ==0 ) { - return; + return nullptr; } pub.msgId = msgId; pub.header.bits.dup = dup; pub.header.bits.qos = ( qos == 3 ? 0 : qos ); pub.header.bits.retain = retained; - Topic* topic = 0; + Topic* topic = nullptr; if( topicid.type == MQTTSN_TOPIC_TYPE_SHORT ) { @@ -90,7 +83,7 @@ void MQTTSNPublishHandler::handlePublish(Client* client, MQTTSNPacket* packet) if( !topic && qos == 3 ) { WRITELOG("%s Invali TopicId.%s %s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); - return; + return nullptr; } if( !topic && msgId && qos > 0 && qos < 3 ) @@ -101,7 +94,7 @@ void MQTTSNPublishHandler::handlePublish(Client* client, MQTTSNPacket* packet) Event* ev1 = new Event(); ev1->setClientSendEvent(client, pubAck); _gateway->getClientSendQue()->post(ev1); - return; + return nullptr; } if ( topic ) { @@ -120,14 +113,17 @@ void MQTTSNPublishHandler::handlePublish(Client* client, MQTTSNPacket* packet) MQTTGWPacket* publish = new MQTTGWPacket(); publish->setPUBLISH(&pub); - Event* ev1 = new Event(); - ev1->setBrokerSendEvent(client, publish); - _gateway->getBrokerSendQue()->post(ev1); - /* reset PINGREQ of ClientProxy */ - if ( qos == 3 ) + if ( !_gateway->getAdapterManager()->isAggregaterActive() ) { - _gateway->getQoSm1Proxy()->resetPingTimer(); + Event* ev1 = new Event(); + ev1->setBrokerSendEvent(client, publish); + _gateway->getBrokerSendQue()->post(ev1); + return nullptr; + } + else + { + return publish; } } @@ -146,11 +142,14 @@ void MQTTSNPublishHandler::handlePuback(Client* client, MQTTSNPacket* packet) if ( rc == MQTTSN_RC_ACCEPTED) { - MQTTGWPacket* pubAck = new MQTTGWPacket(); - pubAck->setAck(PUBACK, msgId); - Event* ev1 = new Event(); - ev1->setBrokerSendEvent(client, pubAck); - _gateway->getBrokerSendQue()->post(ev1); + if ( !_gateway->getAdapterManager()->getAggregater()->isActive() ) + { + MQTTGWPacket* pubAck = new MQTTGWPacket(); + 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) { @@ -219,7 +218,7 @@ void MQTTSNPublishHandler::handleRegAck( Client* client, MQTTSNPacket* packet) MQTTSNPacket* regAck = client->getWaitREGACKPacketList()->getPacket(msgId); - if ( regAck != 0 ) + if ( regAck != nullptr ) { client->getWaitREGACKPacketList()->erase(msgId); Event* ev = new Event(); @@ -239,3 +238,49 @@ void MQTTSNPublishHandler::handleRegAck( Client* client, MQTTSNPacket* packet) } } + + + + +void MQTTSNPublishHandler::handleAggregatePublish(Client* client, MQTTSNPacket* packet) +{ + int msgId = 0; + MQTTGWPacket* publish = handlePublish(client, packet); + if ( publish != nullptr ) + { + if ( publish->getMsgId() > 0 ) + { + if ( packet->isDuplicate() ) + { + msgId = _gateway->getAdapterManager()->getAggregater()->getMsgId(client, packet->getMsgId()); + } + else + { + msgId = _gateway->getAdapterManager()->getAggregater()->addMessageIdTable(client, packet->getMsgId()); + } + publish->setMsgId(msgId); + } + Event* ev1 = new Event(); + ev1->setBrokerSendEvent(client, publish); + _gateway->getBrokerSendQue()->post(ev1); + } +} + +void MQTTSNPublishHandler::handleAggregateAck(Client* client, MQTTSNPacket* packet, int type) +{ + if ( type == MQTTSN_PUBREC ) + { + uint16_t msgId; + + if ( packet->getACK(&msgId) == 0 ) + { + return; + } + MQTTSNPacket* ackPacket = new MQTTSNPacket(); + ackPacket->setPUBREL(msgId); + Event* ev = new Event(); + ev->setClientSendEvent(client, ackPacket); + _gateway->getClientSendQue()->post(ev); + } + return; +} diff --git a/MQTTSNGateway/src/MQTTSNGWPublishHandler.h b/MQTTSNGateway/src/MQTTSNGWPublishHandler.h index f7fc2d8..85efeb8 100644 --- a/MQTTSNGateway/src/MQTTSNGWPublishHandler.h +++ b/MQTTSNGateway/src/MQTTSNGWPublishHandler.h @@ -27,11 +27,15 @@ class MQTTSNPublishHandler public: MQTTSNPublishHandler(Gateway* gateway); ~MQTTSNPublishHandler(); - void handlePublish(Client* client, MQTTSNPacket* packet); + MQTTGWPacket* 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); void handleRegAck( Client* client, MQTTSNPacket* packet); + + void handleAggregatePublish(Client* client, MQTTSNPacket* packet); + void handleAggregateAck(Client* client, MQTTSNPacket* packet, int type); + private: Gateway* _gateway; }; diff --git a/MQTTSNGateway/src/MQTTSNGWQoS-1Proxy.cpp b/MQTTSNGateway/src/MQTTSNGWQoS-1Proxy.cpp deleted file mode 100644 index 67e98ce..0000000 --- a/MQTTSNGateway/src/MQTTSNGWQoS-1Proxy.cpp +++ /dev/null @@ -1,275 +0,0 @@ -/************************************************************************************** - * Copyright (c) 2018, 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 "MQTTSNGWQoS-1Proxy.h" - -#include "MQTTSNGWDefines.h" -#include "MQTTSNGateway.h" -#include "SensorNetwork.h" -#include -#include -#include - -#define QOSM1_PROXY_KEEPALIVE_DURATION 900 // Secs -#define QOSM1_PROXY_RESPONSE_DURATION 10 // Secs -#define QOSM1_PROXY_MAX_RETRY_CNT 3 - -using namespace MQTTSNGW; - -/* - * Class ClientProxyElement - */ - -QoSm1ProxyElement::QoSm1ProxyElement(void) - : _clientId{0} - , _next{0} -{ - -} - -QoSm1ProxyElement::QoSm1ProxyElement(SensorNetAddress* addr, string* clientId) - : _next{0} -{ - _clientId = *clientId; - _sensorNetAddr = *addr; -} - -QoSm1ProxyElement::~QoSm1ProxyElement(void) -{ - -} - -/* - * Class ClientProxy - */ - -QoSm1Proxy:: QoSm1Proxy(void) - : _head{0} - , _isWaitingResp{false} - , _retryCnt{0} -{ - _gateway = 0; - _client = 0; -} - -QoSm1Proxy:: QoSm1Proxy(Gateway* gw) - : _head{0} -, _isWaitingResp{false} -, _retryCnt{0} -{ - _gateway = gw; - _client = 0; -} - - -QoSm1Proxy::~QoSm1Proxy(void) -{ - if ( _head ) - { - QoSm1ProxyElement* p = _head; - while ( p ) - { - QoSm1ProxyElement* next = p->_next; - delete p; - p = next; - } - } -} - -void QoSm1Proxy::setGateway(Gateway* gw) -{ - _gateway = gw; -} - -QoSm1ProxyElement* QoSm1Proxy::add(SensorNetAddress* addr, string* clientId) -{ - QoSm1ProxyElement* elm = new QoSm1ProxyElement(addr, clientId); - if ( _head == 0 ) - { - _head = elm; - } - else - { - QoSm1ProxyElement* p = _head; - while ( p ) - { - if ( p->_next == 0 ) - { - p->_next = elm; - break; - } - else - { - p = p->_next; - } - } - } - return elm; -} - -const char* QoSm1Proxy::getClientId(SensorNetAddress* addr) -{ - QoSm1ProxyElement* p = _head; - while ( p ) - { - if ( p->_sensorNetAddr.isMatch(addr) ) - { - return p->_clientId.c_str(); - break; - } - p = p->_next; - } - return 0; -} - -void QoSm1Proxy::setClient(Client* client) -{ - _client = client; -} - -Client* QoSm1Proxy::getClient(void) -{ - return _client; -} - -bool QoSm1Proxy::setClientProxy(const char* fileName) -{ - FILE* fp; - char buf[MAX_CLIENTID_LENGTH + 256]; - size_t pos; - - SensorNetAddress netAddr; - - if ((fp = fopen(fileName, "r")) != 0) - { - while (fgets(buf, MAX_CLIENTID_LENGTH + 254, 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); - string addr = data.substr(pos + 1); - - if (netAddr.setAddress(&addr) == 0) - { - add(&netAddr, &id); - } - else - { - WRITELOG("Invalid address %s\n", data.c_str()); - return false; - } - } - fclose(fp); - } - else - { - WRITELOG("Can not open the QoS_1Client List. %s\n", fileName); - return false; - } - return true; -} - - -void QoSm1Proxy::checkConnection(void) -{ - if ( _client->isDisconnect() || ( _client->isConnecting() && _responseTimer.isTimeup()) ) - { - _client->connectSended(); - _responseTimer.start(QOSM1_PROXY_RESPONSE_DURATION * 1000UL); - MQTTSNPacket_connectData options = MQTTSNPacket_connectData_initializer; - options.clientID.cstring = _client->getClientId(); - options.duration = QOSM1_PROXY_KEEPALIVE_DURATION; - - MQTTSNPacket* packet = new MQTTSNPacket(); - packet->setCONNECT(&options); - Event* ev = new Event(); - ev->setClientRecvEvent(_client, packet); - _gateway->getPacketEventQue()->post(ev); - } - else if ( (_client->isActive() && _keepAliveTimer.isTimeup() ) || (_isWaitingResp && _responseTimer.isTimeup() ) ) - { - MQTTSNPacket* packet = new MQTTSNPacket(); - MQTTSNString clientId = MQTTSNString_initializer; - packet->setPINGREQ(&clientId); - Event* ev = new Event(); - ev->setClientRecvEvent(_client, packet); - _gateway->getPacketEventQue()->post(ev); - _responseTimer.start(QOSM1_PROXY_RESPONSE_DURATION * 1000UL); - _isWaitingResp = true; - - if ( ++_retryCnt > QOSM1_PROXY_MAX_RETRY_CNT ) - { - _client->disconnected(); - } - resetPingTimer(); - } -} - -void QoSm1Proxy::resetPingTimer(void) -{ - _keepAliveTimer.start(QOSM1_PROXY_KEEPALIVE_DURATION * 1000UL); -} - -void QoSm1Proxy::send(MQTTSNPacket* packet) -{ - if ( packet->getType() == MQTTSN_CONNACK ) - { - resetPingTimer(); - _responseTimer.stop(); - _retryCnt = 0; - sendStoredPublish(); - } - else if ( packet->getType() == MQTTSN_PINGRESP ) - { - _responseTimer.stop(); - _isWaitingResp = false; - _retryCnt = 0; - - resetPingTimer(); - } - else if ( packet->getType() == MQTTSN_DISCONNECT ) - { - // blank - } -} - -void QoSm1Proxy::sendStoredPublish(void) -{ - MQTTSNPacket* msg = 0; - - while ( ( msg = _client->getProxyPacket() ) != 0 ) - { - _client->deleteFirstProxyPacket(); // pop the que to delete element. - - Event* ev = new Event(); - ev->setClientRecvEvent(_client, msg); - _gateway->getPacketEventQue()->post(ev); - } -} diff --git a/MQTTSNGateway/src/MQTTSNGWQoS-1Proxy.h b/MQTTSNGateway/src/MQTTSNGWQoS-1Proxy.h deleted file mode 100644 index 9960668..0000000 --- a/MQTTSNGateway/src/MQTTSNGWQoS-1Proxy.h +++ /dev/null @@ -1,79 +0,0 @@ -/************************************************************************************** - * Copyright (c) 2018, 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 MQTTSNGATEWAY_SRC_MQTTSNGWQOS_1PROXY_H_ -#define MQTTSNGATEWAY_SRC_MQTTSNGWQOS_1PROXY_H_ - -#include "MQTTSNGateway.h" -#include "MQTTGWPacket.h" -#include "MQTTSNGWClient.h" -#include "SensorNetwork.h" -#include "MQTTSNGWProcess.h" - - - -namespace MQTTSNGW -{ -class Gateway; - -class QoSm1ProxyElement -{ - friend class QoSm1Proxy; -public: - QoSm1ProxyElement(void); - QoSm1ProxyElement(SensorNetAddress* addr, string* clientId); - ~QoSm1ProxyElement(void); -private: - SensorNetAddress _sensorNetAddr; - string _clientId; - QoSm1ProxyElement* _next; -}; - -class QoSm1Proxy -{ -public: - QoSm1Proxy(void); - QoSm1Proxy(Gateway* gw); - ~QoSm1Proxy(void); - bool setClientProxy(const char* fileName); - QoSm1ProxyElement* add(SensorNetAddress* addr, string* clientId); - const char* getClientId(SensorNetAddress* addr); - void setClient(Client*); - Client* getClient(void); - void setGateway(Gateway* gw); - void setKeepAlive(uint16_t secs); - - void checkConnection(void); - void resetPingTimer(void); - void send(MQTTSNPacket* packet); - -private: - void sendStoredPublish(void); - - Gateway* _gateway; - Client* _client; - QoSm1ProxyElement* _head; - Timer _keepAliveTimer; - Timer _responseTimer; - bool _isWaitingResp; - int _retryCnt; -}; - -} - - - -#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWQOS_1PROXY_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.cpp b/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.cpp new file mode 100644 index 0000000..2021e17 --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.cpp @@ -0,0 +1,75 @@ +/************************************************************************************** + * Copyright (c) 2018, 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 "MQTTSNGWQoSm1Proxy.h" +#include "MQTTSNGateway.h" +#include "SensorNetwork.h" +#include "MQTTSNGWClientList.h" +#include +#include + + +using namespace MQTTSNGW; + +/*===================================== + Class QoSm1Proxy + =====================================*/ +QoSm1Proxy:: QoSm1Proxy(Gateway* gw) : Adapter(gw) +{ + _gateway = gw; +} + +QoSm1Proxy::~QoSm1Proxy(void) +{ + +} + + +void QoSm1Proxy::initialize(void) +{ + char param[MQTTSNGW_PARAM_MAX]; + + if ( _gateway->hasSecureConnection() ) + { + _isSecure = true; + } + + if (_gateway->getParam("QoS-1", param) == 0 ) + { + if (strcasecmp(param, "YES") == 0 ) + { + /* Create QoS-1 Clients */ + _gateway->getClientList()->setClientList(_gateway, QOSM1PROXY_TYPE); + + /* set ClientId of this Proxy */ + const char* name = CLIENTPROXY; + if (_gateway->getParam("QoS-1ProxyName", param) == 0 ) + { + name = param; + } + /* initialize Adapter */ + setup(name, Atype_QoSm1Proxy); + _isActive = true; + } + } +} + + +bool QoSm1Proxy::isActive(void) +{ + return _isActive; +} + diff --git a/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.h b/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.h new file mode 100644 index 0000000..d3dfcf5 --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.h @@ -0,0 +1,53 @@ +/************************************************************************************** + * Copyright (c) 2018, 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 MQTTSNGATEWAY_SRC_MQTTSNGWQOSM1PROXY_H_ +#define MQTTSNGATEWAY_SRC_MQTTSNGWQOSM1PROXY_H_ + +#include "MQTTSNGWAdapter.h" +namespace MQTTSNGW +{ +class Gateway; +class Adapter; +class Client; +class SensorNetAddress; +class MQTTSNPacket; + +/*===================================== + Class QoSm1Proxy + =====================================*/ +class QoSm1Proxy : public Adapter +{ +public: + QoSm1Proxy(Gateway* gw); + ~QoSm1Proxy(void); + + void initialize(void); + bool isActive(void); + +private: + Gateway* _gateway; + + bool _isActive {false}; + bool _isSecure {false}; +}; + + +} + + + +#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWQOSM1PROXY_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp index fd192a5..6bca10f 100644 --- a/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp @@ -34,13 +34,13 @@ MQTTSNSubscribeHandler::~MQTTSNSubscribeHandler() } -void MQTTSNSubscribeHandler::handleSubscribe(Client* client, MQTTSNPacket* packet) +MQTTGWPacket* MQTTSNSubscribeHandler::handleSubscribe(Client* client, MQTTSNPacket* packet) { uint8_t dup; int qos; uint16_t msgId; MQTTSN_topicid topicFilter; - Topic* topic = 0; + Topic* topic = nullptr; uint16_t topicId = 0; MQTTGWPacket* subscribe; Event* ev1; @@ -48,12 +48,12 @@ void MQTTSNSubscribeHandler::handleSubscribe(Client* client, MQTTSNPacket* packe if ( packet->getSUBSCRIBE(&dup, &qos, &msgId, &topicFilter) == 0 ) { - return; + return nullptr; } if ( msgId == 0 ) { - return; + return nullptr; } if ( topicFilter.type == MQTTSN_TOPIC_TYPE_PREDEFINED ) @@ -73,13 +73,13 @@ void MQTTSNSubscribeHandler::handleSubscribe(Client* client, MQTTSNPacket* packe else if (topicFilter.type == MQTTSN_TOPIC_TYPE_NORMAL) { topic = client->getTopics()->getTopicByName(&topicFilter); - if ( topic == 0 ) + if ( topic == nullptr ) { topic = client->getTopics()->add(&topicFilter); - if ( topic == 0 ) + if ( topic == nullptr ) { WRITELOG("%s Client(%s) can't add the Topic.%s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); - return; + return nullptr; } } topicId = topic->getTopicId(); @@ -100,10 +100,17 @@ void MQTTSNSubscribeHandler::handleSubscribe(Client* client, MQTTSNPacket* packe client->setWaitedSubTopicId(msgId, topicId, topicFilter.type); - ev1 = new Event(); - ev1->setBrokerSendEvent(client, subscribe); - _gateway->getBrokerSendQue()->post(ev1); - return; + if ( !client->isAggregated() ) + { + ev1 = new Event(); + ev1->setBrokerSendEvent(client, subscribe); + _gateway->getBrokerSendQue()->post(ev1); + return nullptr; + } + else + { + return subscribe; + } RespExit: @@ -112,22 +119,23 @@ RespExit: evsuback = new Event(); evsuback->setClientSendEvent(client, sSuback); _gateway->getClientSendQue()->post(evsuback); + return nullptr; } -void MQTTSNSubscribeHandler::handleUnsubscribe(Client* client, MQTTSNPacket* packet) +MQTTGWPacket* MQTTSNSubscribeHandler::handleUnsubscribe(Client* client, MQTTSNPacket* packet) { uint16_t msgId; MQTTSN_topicid topicFilter; - MQTTGWPacket* unsubscribe = 0;; + MQTTGWPacket* unsubscribe = nullptr; if ( packet->getUNSUBSCRIBE(&msgId, &topicFilter) == 0 ) { - return; + return nullptr; } if ( msgId == 0 ) { - return; + return nullptr; } Topic* topic = client->getTopics()->getTopicById(&topicFilter); @@ -143,14 +151,14 @@ void MQTTSNSubscribeHandler::handleUnsubscribe(Client* client, MQTTSNPacket* pac } else { - if ( topic == 0 ) + if ( topic == nullptr ) { MQTTSNPacket* sUnsuback = new MQTTSNPacket(); sUnsuback->setUNSUBACK(msgId); Event* evsuback = new Event(); evsuback->setClientSendEvent(client, sUnsuback); _gateway->getClientSendQue()->post(evsuback); - return; + return nullptr; } else { @@ -159,8 +167,81 @@ void MQTTSNSubscribeHandler::handleUnsubscribe(Client* client, MQTTSNPacket* pac } } - Event* ev1 = new Event(); - ev1->setBrokerSendEvent(client, unsubscribe); - _gateway->getBrokerSendQue()->post(ev1); + if ( !client->isAggregated() ) + { + Event* ev1 = new Event(); + ev1->setBrokerSendEvent(client, unsubscribe); + _gateway->getBrokerSendQue()->post(ev1); + return nullptr; + } + else + { + return unsubscribe; + } } +void MQTTSNSubscribeHandler::handleAggregateSubscribe(Client* client, MQTTSNPacket* packet) +{ + MQTTGWPacket* subscribe = handleSubscribe(client, packet); + + if ( subscribe != nullptr ) + { + UTF8String str = subscribe->getTopic(); + string* topicName = new string(str.data, str.len); + Topic topic = Topic(topicName, MQTTSN_TOPIC_TYPE_NORMAL); + _gateway->getAdapterManager()->addAggregateTopic(&topic, client); + + int msgId = 0; + if ( packet->isDuplicate() ) + { + msgId = _gateway->getAdapterManager()->getAggregater()->getMsgId(client, packet->getMsgId()); + } + else + { + msgId = _gateway->getAdapterManager()->getAggregater()->addMessageIdTable(client, packet->getMsgId()); + } + + if ( msgId == 0 ) + { + WRITELOG("%s MQTTSNSubscribeHandler can't create MessageIdTableElement %s%s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); + return; + } +WRITELOG("msgId=%d\n",msgId); + subscribe->setMsgId(msgId); + Event* ev = new Event(); + ev->setBrokerSendEvent(client, subscribe); + _gateway->getBrokerSendQue()->post(ev); + } +} + +void MQTTSNSubscribeHandler::handleAggregateUnsubscribe(Client* client, MQTTSNPacket* packet) +{ + MQTTGWPacket* unsubscribe = handleUnsubscribe(client, packet); + if ( unsubscribe != nullptr ) + { + UTF8String str = unsubscribe->getTopic(); + string* topicName = new string(str.data, str.len); + Topic topic = Topic(topicName, MQTTSN_TOPIC_TYPE_NORMAL); + _gateway->getAdapterManager()->removeAggregateTopic(&topic, client); + + int msgId = 0; + if ( packet->isDuplicate() ) + { + msgId = _gateway->getAdapterManager()->getAggregater()->getMsgId(client, packet->getMsgId()); + } + else + { + msgId = _gateway->getAdapterManager()->getAggregater()->addMessageIdTable(client, packet->getMsgId()); + } + + if ( msgId == 0 ) + { + WRITELOG("%s MQTTSNUnsubscribeHandler can't create MessageIdTableElement %s%s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); + return; + } + unsubscribe->setMsgId(msgId); + Event* ev = new Event(); + ev->setBrokerSendEvent(client, unsubscribe); + _gateway->getBrokerSendQue()->post(ev); + } +} diff --git a/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.h b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.h index 21410d5..5b2202a 100644 --- a/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.h +++ b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.h @@ -31,8 +31,10 @@ class MQTTSNSubscribeHandler public: MQTTSNSubscribeHandler(Gateway* gateway); ~MQTTSNSubscribeHandler(); - void handleSubscribe(Client* client, MQTTSNPacket* packet); - void handleUnsubscribe(Client* client, MQTTSNPacket* packet); + MQTTGWPacket* handleSubscribe(Client* client, MQTTSNPacket* packet); + MQTTGWPacket* handleUnsubscribe(Client* client, MQTTSNPacket* packet); + void handleAggregateSubscribe(Client* client, MQTTSNPacket* packet); + void handleAggregateUnsubscribe(Client* client, MQTTSNPacket* packet); private: Gateway* _gateway; diff --git a/MQTTSNGateway/src/MQTTSNGWTopic.cpp b/MQTTSNGateway/src/MQTTSNGWTopic.cpp new file mode 100644 index 0000000..7777a2c --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWTopic.cpp @@ -0,0 +1,519 @@ +/************************************************************************************** + * 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 + * Tieto Poland Sp. z o.o. - Gateway improvements + **************************************************************************************/ +#include "MQTTSNGWTopic.h" +#include "MQTTSNGWDefines.h" +#include "MQTTSNGateway.h" +#include + +using namespace MQTTSNGW; + +/*===================================== + Class Topic + ======================================*/ +Topic::Topic() +{ + _type = MQTTSN_TOPIC_TYPE_NORMAL; + _topicName = nullptr; + _topicId = 0; + _next = nullptr; +} + +Topic::Topic(string* topic, MQTTSN_topicTypes type) +{ + _type = type; + _topicName = topic; + _topicId = 0; + _next = nullptr; +} + +Topic::~Topic() +{ + if ( _topicName ) + { + delete _topicName; + } +} + +string* Topic::getTopicName(void) +{ + return _topicName; +} + +uint16_t Topic::getTopicId(void) +{ + return _topicId; +} + +MQTTSN_topicTypes Topic::getType(void) +{ + return _type; +} + +bool Topic::isMatch(string* topicName) +{ + string::size_type tlen = _topicName->size(); + + string::size_type tpos = 0; + string::size_type tloc = 0; + string::size_type pos = 0; + string::size_type loc = 0; + string wildcard = "#"; + string wildcards = "+"; + + while(true) + { + loc = topicName->find('/', pos); + tloc = _topicName->find('/', tpos); + + if ( loc != string::npos && tloc != string::npos ) + { + string subtopic = topicName->substr(pos, loc - pos); + string subtopict = _topicName->substr(tpos, tloc - tpos); + if (subtopict == wildcard) + { + return true; + } + else if (subtopict == wildcards) + { + if ( (tpos = tloc + 1 ) > tlen ) + { + pos = loc + 1; + loc = topicName->find('/', pos); + if ( loc == string::npos ) + { + return true; + } + else + { + return false; + } + } + pos = loc + 1; + } + else if ( subtopic != subtopict ) + { + return false; + } + else + { + if ( (tpos = tloc + 1) > tlen ) + { + return false; + } + + pos = loc + 1; + } + } + else if ( loc == string::npos && tloc == string::npos ) + { + string subtopic = topicName->substr(pos); + string subtopict = _topicName->substr(tpos); + if ( subtopict == wildcard || subtopict == wildcards) + { + return true; + } + else if ( subtopic == subtopict ) + { + return true; + } + else + { + return false; + } + } + else if ( loc == string::npos && tloc != string::npos ) + { + string subtopic = topicName->substr(pos); + string subtopict = _topicName->substr(tpos, tloc - tpos); + if ( subtopic != subtopict) + { + return false; + } + + tpos = tloc + 1; + + return _topicName->substr(tpos) == wildcard; + } + else if ( loc != string::npos && tloc == string::npos ) + { + return _topicName->substr(tpos) == wildcard; + } + } +} + +void Topic::print(void) +{ + WRITELOG("TopicName=%s ID=%d Type=%d\n", _topicName->c_str(), _topicId, _type); +} + +/*===================================== + Class Topics + ======================================*/ +Topics::Topics() +{ + _first = nullptr; + _nextTopicId = 0; + _cnt = 0; +} + +Topics::~Topics() +{ + Topic* p = _first; + while (p) + { + Topic* q = p->_next; + delete p; + p = q; + } +} + +Topic* Topics::getTopicByName(const MQTTSN_topicid* topicid) +{ + Topic* p = _first; + char* ch = topicid->data.long_.name; + + string sname = string(ch, ch + topicid->data.long_.len); + while (p) + { + if ( p->_topicName->compare(sname) == 0 ) + { + return p; + } + p = p->_next; + } + return 0; +} + +Topic* Topics::getTopicById(const MQTTSN_topicid* topicid) +{ + Topic* p = _first; + + while (p) + { + if ( p->_type == topicid->type && p->_topicId == topicid->data.id ) + { + return p; + } + p = p->_next; + } + return 0; +} + +// For MQTTSN_TOPIC_TYPE_NORMAL */ +Topic* Topics::add(const MQTTSN_topicid* topicid) +{ + if (topicid->type != MQTTSN_TOPIC_TYPE_NORMAL ) + { + return 0; + } + + Topic* topic = getTopicByName(topicid); + + if ( topic ) + { + return topic; + } + string name(topicid->data.long_.name, topicid->data.long_.len); + return add(name.c_str(), 0); +} + +Topic* Topics::add(const char* topicName, uint16_t id) +{ + MQTTSN_topicid topicId; + + if ( _cnt >= MAX_TOPIC_PAR_CLIENT ) + { + return 0; + } + + topicId.data.long_.name = (char*)const_cast(topicName); + topicId.data.long_.len = strlen(topicName); + + + Topic* topic = getTopicByName(&topicId); + + if ( topic ) + { + return topic; + } + + topic = new Topic(); + + if (topic == nullptr) + { + return nullptr; + } + + string* name = new string(topicName); + topic->_topicName = name; + + if ( id == 0 ) + { + topic->_type = MQTTSN_TOPIC_TYPE_NORMAL; + topic->_topicId = getNextTopicId(); + } + else + { + topic->_type = MQTTSN_TOPIC_TYPE_PREDEFINED; + topic->_topicId = id; + } + + _cnt++; + + if ( _first == nullptr) + { + _first = topic; + } + else + { + Topic* tp = _first; + while (tp) + { + if (tp->_next == nullptr) + { + tp->_next = topic; + break; + } + else + { + tp = tp->_next; + } + } + } + return topic; +} + +uint16_t Topics::getNextTopicId() +{ + return ++_nextTopicId == 0xffff ? _nextTopicId += 2 : _nextTopicId; +} + +Topic* Topics::match(const 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; +} + + +void Topics::eraseNormal(void) +{ + Topic* topic = _first; + Topic* next = nullptr; + Topic* prev = nullptr; + + while (topic) + { + if ( topic->_type == MQTTSN_TOPIC_TYPE_NORMAL ) + { + next = topic->_next; + if ( _first == topic ) + { + _first = next; + } + if ( prev ) + { + prev->_next = next; + } + delete topic; + _cnt--; + topic = next; + } + else + { + prev = topic; + topic = topic->_next; + } + } +} + +void Topics::print(void) +{ + Topic* topic = _first; + if (topic == nullptr ) + { + WRITELOG("No Topic.\n"); + } + else + { + while (topic) + { + topic->print(); + topic = topic->_next; + } + } +} + +uint8_t Topics::getCount(void) +{ + return _cnt; +} + +/*===================================== + Class TopicIdMap + =====================================*/ +TopicIdMapElement::TopicIdMapElement(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type) +{ + _msgId = msgId; + _topicId = topicId; + _type = type; + _next = nullptr; + _prev = nullptr; +} + +TopicIdMapElement::~TopicIdMapElement() +{ + +} + +MQTTSN_topicTypes TopicIdMapElement::getTopicType(void) +{ + return _type; +} + +uint16_t TopicIdMapElement::getTopicId(void) +{ + return _topicId; +} + +TopicIdMap::TopicIdMap() +{ + _maxInflight = MAX_INFLIGHTMESSAGES; + _msgIds = 0; + _first = nullptr; + _end = nullptr; + _cnt = 0; +} + +TopicIdMap::~TopicIdMap() +{ + TopicIdMapElement* p = _first; + while ( p ) + { + TopicIdMapElement* q = p->_next; + delete p; + p = q; + } +} + +TopicIdMapElement* TopicIdMap::getElement(uint16_t msgId) +{ + TopicIdMapElement* p = _first; + while ( p ) + { + if ( p->_msgId == msgId ) + { + return p; + } + p = p->_next; + } + return 0; +} + +TopicIdMapElement* TopicIdMap::add(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type) +{ + if ( _cnt > _maxInflight * 2 || ( topicId == 0 && type != MQTTSN_TOPIC_TYPE_SHORT ) ) + { + return 0; + } + if ( getElement(msgId) > 0 ) + { + erase(msgId); + } + + TopicIdMapElement* elm = new TopicIdMapElement(msgId, topicId, type); + if ( elm == 0 ) + { + return 0; + } + if ( _first == nullptr ) + { + _first = elm; + _end = elm; + } + else + { + elm->_prev = _end; + _end->_next = elm; + _end = elm; + } + _cnt++; + return elm; +} + +void TopicIdMap::erase(uint16_t msgId) +{ + TopicIdMapElement* p = _first; + while ( p ) + { + if ( p->_msgId == msgId ) + { + if ( p->_prev == nullptr ) + { + _first = p->_next; + } + else + { + p->_prev->_next = p->_next; + } + + if ( p->_next == nullptr ) + { + _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 = nullptr; + _end = nullptr; + _cnt = 0; +} + + + diff --git a/MQTTSNGateway/src/MQTTSNGWTopic.h b/MQTTSNGateway/src/MQTTSNGWTopic.h new file mode 100644 index 0000000..5c3cc77 --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWTopic.h @@ -0,0 +1,115 @@ +/************************************************************************************** + * 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 + * Tieto Poland Sp. z o.o. - Gateway improvements + **************************************************************************************/ + +#ifndef MQTTSNGATEWAY_SRC_MQTTSNGWTOPIC_H_ +#define MQTTSNGATEWAY_SRC_MQTTSNGWTOPIC_H_ + +#include "MQTTSNGWPacket.h" +#include "MQTTSNPacket.h" + +namespace MQTTSNGW +{ + + +/*===================================== + Class Topic + ======================================*/ +class Topic +{ + friend class Topics; +public: + Topic(); + Topic(string* topic, MQTTSN_topicTypes type); + ~Topic(); + string* getTopicName(void); + uint16_t getTopicId(void); + MQTTSN_topicTypes getType(void); + bool isMatch(string* topicName); + void print(void); +private: + MQTTSN_topicTypes _type; + uint16_t _topicId; + string* _topicName; + Topic* _next; +}; + +/*===================================== + Class Topics + ======================================*/ +class Topics +{ +public: + Topics(); + ~Topics(); + Topic* add(const MQTTSN_topicid* topicid); + Topic* add(const char* topicName, uint16_t id = 0); + Topic* getTopicByName(const MQTTSN_topicid* topic); + Topic* getTopicById(const MQTTSN_topicid* topicid); + Topic* match(const MQTTSN_topicid* topicid); + void eraseNormal(void); + uint16_t getNextTopicId(); + void print(void); + uint8_t getCount(void); +private: + uint16_t _nextTopicId; + Topic* _first; + uint8_t _cnt; +}; + +/*===================================== + Class TopicIdMapElement + =====================================*/ +class TopicIdMapElement +{ + friend class TopicIdMap; +public: + TopicIdMapElement(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type); + ~TopicIdMapElement(); + MQTTSN_topicTypes getTopicType(void); + uint16_t getTopicId(void); + +private: + uint16_t _msgId; + uint16_t _topicId; + MQTTSN_topicTypes _type; + TopicIdMapElement* _next; + TopicIdMapElement* _prev; +}; + +class TopicIdMap +{ +public: + TopicIdMap(); + ~TopicIdMap(); + TopicIdMapElement* getElement(uint16_t msgId); + TopicIdMapElement* add(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type); + void erase(uint16_t msgId); + void clear(void); +private: + uint16_t* _msgIds; + TopicIdMapElement* _first; + TopicIdMapElement* _end; + int _cnt; + int _maxInflight; +}; + + +} + + + +#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWTOPIC_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWVersion.h b/MQTTSNGateway/src/MQTTSNGWVersion.h index 2e458a2..1fd764c 100644 --- a/MQTTSNGateway/src/MQTTSNGWVersion.h +++ b/MQTTSNGateway/src/MQTTSNGWVersion.h @@ -17,6 +17,6 @@ #ifndef MQTTSNGWVERSION_H_IN_ #define MQTTSNGWVERSION_H_IN_ -#define PAHO_GATEWAY_VERSION "1.2.1" +#define PAHO_GATEWAY_VERSION "1.3.0" #endif /* MQTTSNGWVERSION_H_IN_ */ diff --git a/MQTTSNGateway/src/MQTTSNGateway.cpp b/MQTTSNGateway/src/MQTTSNGateway.cpp index 069ac5a..2192850 100644 --- a/MQTTSNGateway/src/MQTTSNGateway.cpp +++ b/MQTTSNGateway/src/MQTTSNGateway.cpp @@ -18,6 +18,8 @@ #include "SensorNetwork.h" #include "MQTTSNGWProcess.h" #include "MQTTSNGWVersion.h" +#include "MQTTSNGWQoSm1Proxy.h" +#include "MQTTSNGWClient.h" #include using namespace MQTTSNGW; @@ -26,32 +28,13 @@ char* currentDateTime(void); /*===================================== Class Gateway =====================================*/ -Gateway::Gateway() +Gateway::Gateway(void) { - theMultiTaskProcess = this; - theProcess = this; - _qosm1Proxy = 0; - _params.loginId = 0; - _params.password = 0; - _params.keepAlive = 0; - _params.gatewayId = 0; - _params.mqttVersion = 0; - _params.maxInflightMsgs = 0; - _params.gatewayName = 0; - _params.brokerName = 0; - _params.port = 0; - _params.portSecure = 0; - _params.rootCApath = 0; - _params.rootCAfile = 0; - _params.certKey = 0; - _params.privateKey = 0; - _params.clientListName = 0; - _params.configName = 0; - _params.predefinedTopicFileName = 0; - _params.forwarderListName = 0; - _params.qosMinusClientListName = 0; - _params.qosm1proxyName = 0; - _packetEventQue.setMaxSize(MAX_INFLIGHTMESSAGES * MAX_CLIENTS); + theMultiTaskProcess = this; + theProcess = this; + _packetEventQue.setMaxSize(MAX_INFLIGHTMESSAGES * MAX_CLIENTS); + _clientList = new ClientList(); + _adapterManager = new AdapterManager(this); } Gateway::~Gateway() @@ -116,25 +99,34 @@ Gateway::~Gateway() { free(_params.qosMinusClientListName); } - if ( _params.qosm1proxyName ) - { - free(_params.qosm1proxyName); - } - if ( _qosm1Proxy ) + if ( _adapterManager ) { - delete _qosm1Proxy; + delete _adapterManager; } + if ( _clientList ) + { + delete _clientList; + } +} + +int Gateway::getParam(const char* parameter, char* value) +{ + return MultiTaskProcess::getParam(parameter, value); } void Gateway::initialize(int argc, char** argv) { char param[MQTTSNGW_PARAM_MAX]; string fileName; - bool secure = false; + MultiTaskProcess::initialize(argc, argv); resetRingBuffer(); + _params.configDir = *getConfigDirName(); + fileName = _params.configDir + *getConfigFileName(); + _params.configName = strdup(fileName.c_str()); + if (getParam("BrokerName", param) == 0) { _params.brokerName = strdup(param); @@ -180,6 +172,11 @@ void Gateway::initialize(int argc, char** argv) _params.gatewayName = strdup(param); } + if (_params.gatewayName == 0 ) + { + throw Exception( "Gateway::initialize: Gateway Name is missing."); + } + _params.mqttVersion = DEFAULT_MQTT_VERSION; if (getParam("MQTTVersion", param) == 0) { @@ -193,7 +190,6 @@ void Gateway::initialize(int argc, char** argv) } _params.keepAlive = DEFAULT_KEEP_ALIVE_TIME; - if (getParam("KeepAlive", param) == 0) { _params.keepAlive = atoi(param); @@ -218,113 +214,23 @@ void Gateway::initialize(int argc, char** argv) { if (!strcasecmp(param, "YES")) { - secure = true; - if (getParam("ClientsList", param) == 0) - { - fileName = string(param); - } - else - { - fileName = *getConfigDirName() + string(CLIENT_LIST); - } - - if (!_clientList.authorize(fileName.c_str())) - { - throw Exception("Gateway::initialize: No client list defined by the configuration."); - } - _params.clientListName = strdup(fileName.c_str()); + _params.clientAuthentication = true; } } - /* Set QoSm1Proxy's Client */ + /* ClientList and Adapters Initialize */ + _adapterManager->initialize(); - if (getParam("QoS-1", param) == 0 ) - { - if (!strcasecmp(param, "YES") ) - { - /* Set QoSm1Proxy's Client */ - - _qosm1Proxy = new QoSm1Proxy(this); - MQTTSNString id = MQTTSNString_initializer; - - if (getParam("QoS-1ProxyName", param) == 0 ) - { - string name = string(param); - id.cstring = const_cast(name.c_str()); - } - else - { - id.cstring = const_cast(CLIENTPROXY); - } - Client* client = _clientList.createClient(0, &id, true, secure); - _qosm1Proxy->setClient(client); - client->setPorxy(true); - _qosm1Proxy->setGateway(this); - - - if (getParam("QoS-1ClientsList", param) == 0) - { - fileName = string(param); - } - else - { - fileName = *getConfigDirName() + string(QOS_1CLIENT_LIST); - } - if ( !_qosm1Proxy->setClientProxy(fileName.c_str()) ) - { - throw Exception("Gateway::initialize: No QoS-1ClientsList file defined by the configuration.."); - } - _params.qosMinusClientListName = strdup(fileName.c_str()); - } - } - - if (getParam("PredefinedTopic", param) == 0 ) - { - if (!strcasecmp(param, "YES") ) - { - if (getParam("PredefinedTopicList", param) == 0) - { - fileName = string(param); - } - else - { - fileName = *getConfigDirName() + string(PREDEFINEDTOPIC_FILE); - } - if (!_clientList.setPredefinedTopics(fileName.c_str())) - { - throw Exception("Gateway::initialize: No PredefinedTopic file defined by the configuration.."); - } - _params.predefinedTopicFileName = strdup(fileName.c_str()); - } - } - - if (getParam("Forwarder", param) == 0 ) - { - if (!strcasecmp(param, "YES") ) - { - if (getParam("ForwardersList", param) == 0) - { - fileName = string(param); - } - else - { - fileName = *getConfigDirName() + string(FORWARDER_LIST); - } - if ( !_forwarderList.setFowerder(fileName.c_str()) ) - { - throw Exception("Gateway::initialize: No ForwardersList file defined by the configuration.."); - } - _params.forwarderListName = strdup(fileName.c_str()); - } - } - - fileName = *getConfigDirName() + *getConfigFileName(); - _params.configName = strdup(fileName.c_str()); + bool aggregate = _adapterManager->isAggregaterActive(); + _clientList->initialize(this, aggregate); + /* Setup predefined topics */ + _clientList->setPredefinedTopics(this, aggregate); } void Gateway::run(void) { + /* write prompts */ _lightIndicator.redLight(true); WRITELOG("\n%s", PAHO_COPYRIGHT4); WRITELOG("\n%s\n", PAHO_COPYRIGHT0); @@ -335,30 +241,36 @@ void Gateway::run(void) WRITELOG("%s\n", PAHO_COPYRIGHT4); WRITELOG("\n%s %s has been started.\n\n", currentDateTime(), _params.gatewayName); WRITELOG(" ConfigFile: %s\n", _params.configName); + if ( getClientList()->isAuthorized() ) { WRITELOG(" ClientList: %s\n", _params.clientListName); } + if ( _params.predefinedTopicFileName ) { WRITELOG(" PreDefFile: %s\n", _params.predefinedTopicFileName); } + if ( _params.forwarderListName ) { WRITELOG(" Forwarders: %s\n", _params.forwarderListName); } + if ( _params.qosMinusClientListName ) { WRITELOG(" QoS-1File: %s\n", _params.qosMinusClientListName); } + WRITELOG(" SensorN/W: %s\n", _sensorNetwork.getDescription()); WRITELOG(" Broker: %s : %s, %s\n", _params.brokerName, _params.port, _params.portSecure); - WRITELOG(" RootCApath: %s\n", _params.rootCApath); WRITELOG(" RootCAfile: %s\n", _params.rootCAfile); WRITELOG(" CertKey: %s\n", _params.certKey); WRITELOG(" PrivateKey: %s\n\n\n", _params.privateKey); + + /* Run Tasks until CTRL+C entred */ MultiTaskProcess::run(); /* stop Tasks */ @@ -396,12 +308,7 @@ EventQue* Gateway::getBrokerSendQue() ClientList* Gateway::getClientList() { - return &_clientList; -} - -ForwarderList* Gateway::getForwarderList(void) -{ - return &_forwarderList; + return _clientList; } SensorNetwork* Gateway::getSensorNetwork() @@ -419,11 +326,18 @@ GatewayParams* Gateway::getGWParams(void) return &_params; } -QoSm1Proxy* Gateway::getQoSm1Proxy(void) +AdapterManager* Gateway::getAdapterManager(void) { - return _qosm1Proxy; + return _adapterManager; } +bool Gateway::hasSecureConnection(void) +{ + return ( _params.certKey + && _params.privateKey + && _params.rootCApath + && _params.rootCAfile ); +} /*===================================== Class EventQue =====================================*/ @@ -450,9 +364,9 @@ void EventQue::setMaxSize(uint16_t maxSize) Event* EventQue::wait(void) { - Event* ev = 0; + Event* ev = nullptr; - while(ev == 0) + while(ev == nullptr) { if ( _que.size() == 0 ) { @@ -520,11 +434,7 @@ int EventQue::size() =====================================*/ Event::Event() { - _eventType = Et_NA; - _client = 0; - _sensorNetAddr = 0; - _mqttSNPacket = 0; - _mqttGWPacket = 0; + } Event::~Event() @@ -620,3 +530,5 @@ MQTTGWPacket* Event::getMQTTGWPacket(void) { return _mqttGWPacket; } + + diff --git a/MQTTSNGateway/src/MQTTSNGateway.h b/MQTTSNGateway/src/MQTTSNGateway.h index b547e0a..2507de5 100644 --- a/MQTTSNGateway/src/MQTTSNGateway.h +++ b/MQTTSNGateway/src/MQTTSNGateway.h @@ -16,12 +16,10 @@ #ifndef MQTTSNGATEWAY_H_ #define MQTTSNGATEWAY_H_ -#include "MQTTSNGWClient.h" +#include #include "MQTTSNGWProcess.h" #include "MQTTSNPacket.h" - -#include "MQTTSNGWForwarder.h" -#include "MQTTSNGWQoS-1Proxy.h" +#include "MQTTSNGWClient.h" namespace MQTTSNGW { @@ -46,6 +44,7 @@ namespace MQTTSNGW #define CLIENTS "Clients" #define UNKNOWNCL "Unknown Client !" #define CLIENTPROXY "ClientProxy" +#define CLIENTPROXY_SECURE "ClientProxyS" #define LEFTARROW "<---" #define RIGHTARROW "--->" @@ -77,6 +76,8 @@ namespace MQTTSNGW /*===================================== Class Event ====================================*/ +class Client; + enum EventType{ Et_NA = 0, EtStop, @@ -109,13 +110,14 @@ public: MQTTGWPacket* getMQTTGWPacket(void); private: - EventType _eventType; - Client* _client; - SensorNetAddress* _sensorNetAddr; - MQTTSNPacket* _mqttSNPacket; - MQTTGWPacket* _mqttGWPacket; + EventType _eventType {Et_NA}; + Client* _client {nullptr}; + SensorNetAddress* _sensorNetAddr {nullptr}; + MQTTSNPacket* _mqttSNPacket {nullptr}; + MQTTGWPacket* _mqttGWPacket {nullptr}; }; + /*===================================== Class EventQue ====================================*/ @@ -136,41 +138,48 @@ private: Semaphore _sem; }; -/* - * GatewayParams - */ -typedef struct + + +/*===================================== + Class GatewayParams + ====================================*/ +class GatewayParams { - char* configName; - char* clientListName; - char* loginId; - char* password; - uint16_t keepAlive; - uint8_t gatewayId; - uint8_t mqttVersion; - uint16_t maxInflightMsgs; - char* gatewayName; - char* brokerName; - char* port; - char* portSecure; - char* rootCApath; - char* rootCAfile; - char* certKey; - char* privateKey; - char* predefinedTopicFileName; - char* forwarderListName; - char* qosm1proxyName; - char* qosMinusClientListName; -}GatewayParams; +public: + string configDir; + char* configName {nullptr}; + char* clientListName {nullptr}; + char* loginId {nullptr}; + char* password {nullptr}; + uint16_t keepAlive {0}; + uint8_t gatewayId {0}; + uint8_t mqttVersion {0}; + uint16_t maxInflightMsgs {0}; + char* gatewayName {nullptr}; + char* brokerName {nullptr}; + char* port {nullptr}; + char* portSecure {nullptr}; + char* rootCApath {nullptr}; + char* rootCAfile {nullptr}; + char* certKey {nullptr}; + char* privateKey {nullptr}; + char* predefinedTopicFileName {nullptr}; + char* forwarderListName {nullptr}; + char* qosMinusClientListName {nullptr}; + bool clientAuthentication {false}; +}; + + /*===================================== Class Gateway =====================================*/ -class QoSm1Proxy; +class AdapterManager; +class ClientList; class Gateway: public MultiTaskProcess{ public: - Gateway(); + Gateway(void); ~Gateway(); virtual void initialize(int argc, char** argv); void run(void); @@ -179,22 +188,22 @@ public: EventQue* getClientSendQue(void); EventQue* getBrokerSendQue(void); ClientList* getClientList(void); - ForwarderList* getForwarderList(void); SensorNetwork* getSensorNetwork(void); LightIndicator* getLightIndicator(void); GatewayParams* getGWParams(void); - QoSm1Proxy* getQoSm1Proxy(void); + AdapterManager* getAdapterManager(void); + int getParam(const char* parameter, char* value); + bool hasSecureConnection(void); private: - ClientList _clientList; - QoSm1Proxy* _qosm1Proxy; - ForwarderList _forwarderList; + GatewayParams _params; + ClientList* _clientList {nullptr}; EventQue _packetEventQue; EventQue _brokerSendQue; EventQue _clientSendQue; LightIndicator _lightIndicator; - GatewayParams _params; SensorNetwork _sensorNetwork; + AdapterManager* _adapterManager {nullptr}; }; } diff --git a/MQTTSNGateway/src/linux/Threading.cpp b/MQTTSNGateway/src/linux/Threading.cpp index c214a44..b0b3ac4 100644 --- a/MQTTSNGateway/src/linux/Threading.cpp +++ b/MQTTSNGateway/src/linux/Threading.cpp @@ -30,6 +30,20 @@ using namespace std; using namespace MQTTSNGW; +#if defined(OSX) +int sem_timedwait(sem_type sem, const struct timespec *timeout) +{ + int rc = -1; + int64_t tout = timeout->tv_sec * 1000L + tv_nsec * 1000000L + rc = (int)dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, tout)); + if (rc != 0) + { + rc = ETIMEDOUT; + } + return rc; +} +#endif + /*===================================== Class Mutex =====================================*/ diff --git a/MQTTSNGateway/src/mainGateway.cpp b/MQTTSNGateway/src/mainGateway.cpp index 227f9c8..6fcbbc4 100644 --- a/MQTTSNGateway/src/mainGateway.cpp +++ b/MQTTSNGateway/src/mainGateway.cpp @@ -23,19 +23,18 @@ using namespace MQTTSNGW; /* - * Gateway Process + * Gateway Application */ -Gateway* gw = new Gateway(); -PacketHandleTask task1(gw); -ClientRecvTask task2(gw); -ClientSendTask task3(gw); -BrokerRecvTask task4(gw); -BrokerSendTask task5(gw); +Gateway gateway; +PacketHandleTask task1(&gateway); +ClientRecvTask task2(&gateway); +ClientSendTask task3(&gateway); +BrokerRecvTask task4(&gateway); +BrokerSendTask task5(&gateway); int main(int argc, char** argv) { - gw->initialize(argc, argv); - gw->run(); - delete gw; + gateway.initialize(argc, argv); + gateway.run(); return 0; } diff --git a/MQTTSNGateway/src/tests/TestTopicIdMap.cpp b/MQTTSNGateway/src/tests/TestTopicIdMap.cpp index dea9b47..ce3ecb3 100644 --- a/MQTTSNGateway/src/tests/TestTopicIdMap.cpp +++ b/MQTTSNGateway/src/tests/TestTopicIdMap.cpp @@ -34,7 +34,7 @@ TestTopicIdMap::~TestTopicIdMap() bool TestTopicIdMap::testGetElement(uint16_t msgid, uint16_t id, MQTTSN_topicTypes type) { - TopicIdMapelement* elm = _map->getElement((uint16_t)msgid ); + TopicIdMapElement* elm = _map->getElement((uint16_t)msgid ); if ( elm ) { //printf("msgid=%d id=%d type=%d\n", msgid, elm->getTopicId(), elm->getTopicType());