diff --git a/.cproject b/.cproject index c3137e8..f52491d 100644 --- a/.cproject +++ b/.cproject @@ -14,7 +14,7 @@ - + @@ -66,7 +66,7 @@ - + @@ -136,8 +136,8 @@ - - + + 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/GatewayTester/Makefile b/MQTTSNGateway/GatewayTester/Makefile index 7ce0f29..0ed4a27 100644 --- a/MQTTSNGateway/GatewayTester/Makefile +++ b/MQTTSNGateway/GatewayTester/Makefile @@ -7,9 +7,13 @@ PUBAPPL := mainPub PRGSUB := MQTT-SNSub SUBAPPL := mainSub +PRGQOS := MQTT-SNPubQoS-1 +QOSAPPL := mainPubQoS-1 + SRCDIR := samples SRCPUB := ClientPub SRCSUB := ClientSub +SRCQOS := ClientPubQoS-1 SUBDIR := src CPPSRCS := \ @@ -46,10 +50,11 @@ DEPS := $(CPPSRCS:%.cpp=$(OUTDIR)/%.d) PROGPUB := $(OUTDIR)/$(PRGPUB) PROGSUB := $(OUTDIR)/$(PRGSUB) +PROGQOS := $(OUTDIR)/$(PRGQOS) .PHONY: install clean -all: $(PROG) $(PROGPUB) $(PROGSUB) +all: $(PROG) $(PROGPUB) $(PROGSUB) $(PROGQOS) @@ -64,6 +69,9 @@ $(PROGPUB): $(OBJS) $(OUTDIR)/$(SRCDIR)/$(SRCPUB)/$(PUBAPPL).o $(PROGSUB): $(OBJS) $(OUTDIR)/$(SRCDIR)/$(SRCSUB)/$(SUBAPPL).o $(CXX) $(LDFLAGS) -o $(PROGSUB) $(OUTDIR)/$(SRCDIR)/$(SRCSUB)/$(SUBAPPL).o $(OBJS) $(LIBS) $(LDADD) +$(PROGQOS): $(OBJS) $(OUTDIR)/$(SRCDIR)/$(SRCQOS)/$(QOSAPPL).o + $(CXX) $(LDFLAGS) -o $(PROGQOS) $(OUTDIR)/$(SRCDIR)/$(SRCQOS)/$(QOSAPPL).o $(OBJS) $(LIBS) $(LDADD) + $(OUTDIR)/$(SUBDIR)/%.o:$(SUBDIR)/%.cpp @if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi @@ -80,6 +88,10 @@ $(OUTDIR)/$(SRCDIR)/$(SRCPUB)/%.o:$(SRCDIR)/$(SRCPUB)%.cpp $(OUTDIR)/$(SRCDIR)/$(SRCSUB)/%.o:$(SRCDIR)/$(SRCSUB)%.cpp @if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) $(DEFS) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $< + +$(OUTDIR)/$(SRCDIR)/$(SRCQOS)/%.o:$(SRCDIR)/$(SRCQOS)%.cpp + @if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi + $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) $(DEFS) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $< clean: rm -rf $(OUTDIR) @@ -88,4 +100,5 @@ install: cp -pf $(PROG) ../../../ cp -pf $(PROGPUB) ../../../ cp -pf $(PROGSUB) ../../../ - + cp -pf $(PROGQOS) ../../../ + \ No newline at end of file diff --git a/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp b/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp index 816dba7..c9a571c 100644 --- a/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp +++ b/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp @@ -52,10 +52,10 @@ extern LScreen* theScreen; * UDP Configuration (theNetcon) *------------------------------------------------------*/ UDPCONF = { - "GatewayTestPubClient", // ClientId + "ClientPUB", // ClientId {225,1,1,1}, // Multicast group IP 1883, // Multicast group Port - 20001, // Local PortNo + 20010, // Local PortNo }; /*------------------------------------------------------ @@ -159,7 +159,7 @@ TASK_LIST = {// e.g. TASK( task, executing duration in second), *------------------------------------------------------*/ void setup(void) { - + SetForwarderMode(false); } diff --git a/MQTTSNGateway/GatewayTester/samples/ClientPubQoS-1/mainPubQoS-1.cpp b/MQTTSNGateway/GatewayTester/samples/ClientPubQoS-1/mainPubQoS-1.cpp new file mode 100644 index 0000000..34151ed --- /dev/null +++ b/MQTTSNGateway/GatewayTester/samples/ClientPubQoS-1/mainPubQoS-1.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** + * 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. + * + *--------------------------------------------------------------------------- + * + * MQTT-SN GATEWAY TEST CLIENT + * + * Supported functions. + * + * void PUBLISH ( const char* topicName, uint8_t* payload, uint16_t len, uint8_t qos, bool retain = false ); + * + * void PUBLISH ( uint16_t topicId, uint8_t* payload, uint16_t len, uint8_t qos, bool retain = false ); + * + * void SUBSCRIBE ( const char* topicName, TopicCallback onPublish, uint8_t qos ); + * + * void SUBSCRIBE ( uint16_t topicId, TopicCallback onPublish, uint8_t qos ); + * + * void UNSUBSCRIBE ( const char* topicName ); + * + * void UNSUBSCRIBE ( uint16_t topicId ); + * + * void DISCONNECT ( uint16_t sleepInSecs ); + * + * void CONNECT ( void ); + * + * void DISPLAY( format, .....); <== instead of printf() + * + * + * Contributors: + * Tomoaki Yamaguchi - initial API and implementation + ***************************************************************************/ + +#include "LMqttsnClientApp.h" +#include "LMqttsnClient.h" +#include "LScreen.h" + +using namespace std; +using namespace linuxAsyncClient; +extern LMqttsnClient* theClient; +extern LScreen* theScreen; + +/*------------------------------------------------------ + * UDP Configuration (theNetcon) + *------------------------------------------------------*/ +UDPCONF = { + "QoS-1_Client01", // ClientId + {225,1,1,1}, // Multicast group IP + 1883, // Multicast group Port + 20001, // Local PortNo +}; + +/*------------------------------------------------------ + * Client Configuration (theMqcon) + *------------------------------------------------------*/ +MQTTSNCONF = { + 300, //KeepAlive [seconds] + true, //Clean session + 300, //Sleep duration [seconds] + "", //WillTopic + "", //WillMessage + 0, //WillQos + false //WillRetain +}; + +/*------------------------------------------------------ + * Define Topics + *------------------------------------------------------*/ + + +/*------------------------------------------------------ + * Callback routines for Subscribed Topics + *------------------------------------------------------*/ + +/*------------------------------------------------------ + * A Link list of Callback routines and Topics + *------------------------------------------------------*/ +SUBSCRIBE_LIST = {// e.g. SUB(TopicType, topicName, TopicId, callback, QoSx), + + END_OF_SUBSCRIBE_LIST + }; + +/*------------------------------------------------------ + * Test functions + *------------------------------------------------------*/ + +void publishTopic1(void) +{ + char payload[300]; + sprintf(payload, "publish \"ty4tw/Topic1\" \n"); + uint8_t qos = 3; + PUBLISH(1,(uint8_t*)payload, strlen(payload), qos); +} + +void publishTopic2(void) +{ + char payload[300]; + sprintf(payload, "publish \"ty4tw/topic2\" \n"); + uint8_t qos = 3; + PUBLISH(2,(uint8_t*)payload, strlen(payload), qos); +} + +void publishTopic57(void) +{ + char payload[300]; + sprintf(payload, "publish \"ty4tw/topic57\" \n"); + uint8_t qos = 3; + PUBLISH(5,(uint8_t*)payload, strlen(payload), qos); +} + + +void disconnect(void) +{ + DISCONNECT(0); +} + + +/*------------------------------------------------------ + * A List of Test functions is valid in case of + * line 23 of LMqttsnClientApp.h is commented out. + * //#define CLIENT_MODE + *------------------------------------------------------*/ + +TEST_LIST = {// e.g. TEST( Label, Test), + TEST("Step1:Publish topic1", publishTopic1), + TEST("Step2:Publish topic57", publishTopic57), + TEST("Step3:Publish topic2", publishTopic2), + END_OF_TEST_LIST + }; + + +/*------------------------------------------------------ + * List of tasks is invalid in case of line23 of + * LMqttsnClientApp.h is commented out. + * #define CLIENT_MODE + *------------------------------------------------------*/ +TASK_LIST = {// e.g. TASK( task, executing duration in second), + TASK(publishTopic1, 4), // publishTopic1() is executed every 4 seconds + TASK(publishTopic2, 7), // publishTopic2() is executed every 7 seconds + END_OF_TASK_LIST + }; + + +/*------------------------------------------------------ + * Initialize function + *------------------------------------------------------*/ +void setup(void) +{ + SetQoSMinus1Mode(true); +} + + +/***************** END OF PROGRAM ********************/ diff --git a/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp b/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp index 585c8ec..9bf8c1b 100644 --- a/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp +++ b/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp @@ -52,10 +52,10 @@ extern LScreen* theScreen; * UDP Configuration (theNetcon) *------------------------------------------------------*/ UDPCONF = { - "ty4twGatewaySubClient", // ClientId + "ClientSUB", // ClientId {225,1,1,1}, // Multicast group IP 1883, // Multicast group Port - 20002, // Local PortNo + 20011, // Local PortNo }; /*------------------------------------------------------ @@ -199,7 +199,7 @@ TASK_LIST = {// e.g. TASK( task, executing duration in second), *------------------------------------------------------*/ void setup(void) { - + SetForwarderMode(false); } diff --git a/MQTTSNGateway/GatewayTester/samples/mainTest.cpp b/MQTTSNGateway/GatewayTester/samples/mainTest.cpp index 34db1c5..06aa565 100644 --- a/MQTTSNGateway/GatewayTester/samples/mainTest.cpp +++ b/MQTTSNGateway/GatewayTester/samples/mainTest.cpp @@ -55,7 +55,7 @@ UDPCONF = { "GatewayTestClient", // ClientId {225,1,1,1}, // Multicast group IP 1883, // Multicast group Port - 20001, // Local PortNo + 20020, // Local PortNo }; /*------------------------------------------------------ @@ -220,7 +220,7 @@ TASK_LIST = {// e.g. TASK( task, executing duration in second), *------------------------------------------------------*/ void setup(void) { - //SetForwarderMode(); + SetForwarderMode(false); } diff --git a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp index 78cc726..cdacac1 100644 --- a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp +++ b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp @@ -30,21 +30,16 @@ extern uint16_t getUint16(const uint8_t* pos); extern LMqttsnClient* theClient; extern LScreen* theScreen; - /*===================================== - Class GwProxy + Class GwProxy ======================================*/ -static const char* packet_names[] = -{ - "ADVERTISE", "SEARCHGW", "GWINFO", "RESERVED", "CONNECT", "CONNACK", - "WILLTOPICREQ", "WILLTOPIC", "WILLMSGREQ", "WILLMSG", "REGISTER", "REGACK", - "PUBLISH", "PUBACK", "PUBCOMP", "PUBREC", "PUBREL", "RESERVED", - "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK", "PINGREQ", "PINGRESP", - "DISCONNECT", "RESERVED", "WILLTOPICUPD", "WILLTOPICRESP", "WILLMSGUPD", - "WILLMSGRESP" -}; +static const char* packet_names[] = { "ADVERTISE", "SEARCHGW", "GWINFO", "RESERVED", "CONNECT", "CONNACK", + "WILLTOPICREQ", "WILLTOPIC", "WILLMSGREQ", "WILLMSG", "REGISTER", "REGACK", "PUBLISH", "PUBACK", "PUBCOMP", + "PUBREC", "PUBREL", "RESERVED", "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK", "PINGREQ", "PINGRESP", + "DISCONNECT", "RESERVED", "WILLTOPICUPD", "WILLTOPICRESP", "WILLMSGUPD", "WILLMSGRESP" }; -LGwProxy::LGwProxy(){ +LGwProxy::LGwProxy() +{ _nextMsgId = 0; _status = GW_LOST; _gwId = 0; @@ -61,13 +56,16 @@ LGwProxy::LGwProxy(){ _tWake = 0; _initialized = 0; _isForwarderMode = false; + _isQoSMinus1Mode = false; } -LGwProxy::~LGwProxy(){ +LGwProxy::~LGwProxy() +{ _topicTbl.clearTopic(); } -void LGwProxy::initialize(LUdpConfig netconf, LMqttsnConfig mqconf){ +void LGwProxy::initialize(LUdpConfig netconf, LMqttsnConfig mqconf) +{ _network.initialize(netconf); _clientId = netconf.clientId; _willTopic = mqconf.willTopic; @@ -79,78 +77,105 @@ void LGwProxy::initialize(LUdpConfig netconf, LMqttsnConfig mqconf){ _initialized = 1; } -void LGwProxy::connect(){ +void LGwProxy::connect() +{ char* pos; - while (_status != GW_CONNECTED){ + while (_status != GW_CONNECTED) + { pos = _msg; - if (_status == GW_SEND_WILLMSG){ - *pos++ = 2 + (uint8_t)strlen(_willMsg); - *pos++ = MQTTSN_TYPE_WILLMSG; - strcpy(pos,_willMsg); // WILLMSG - _status = GW_WAIT_CONNACK; - writeGwMsg(); - }else if (_status == GW_SEND_WILLTOPIC){ - *pos++ = 3 + (uint8_t)strlen(_willTopic); - *pos++ = MQTTSN_TYPE_WILLTOPIC; - *pos++ = _qosWill | _retainWill; - strcpy(pos,_willTopic); // WILLTOPIC - _status = GW_WAIT_WILLMSGREQ; - writeGwMsg(); - }else if (_status == GW_CONNECTING || _status == GW_DISCONNECTED || _status == GW_SLEPT ){ - uint8_t clientIdLen = uint8_t(strlen(_clientId) > 23 ? 23 : strlen(_clientId)); - *pos++ = 6 + clientIdLen; - *pos++ = MQTTSN_TYPE_CONNECT; - pos++; - if (_cleanSession){ - _msg[2] = MQTTSN_FLAG_CLEAN; - } - *pos++ = MQTTSN_PROTOCOL_ID; - setUint16((uint8_t*)pos, _tkeepAlive); - pos += 2; - strncpy(pos, _clientId, clientIdLen); - _msg[ 6 + clientIdLen] = 0; - _status = GW_WAIT_CONNACK; - if ( _willMsg && _willTopic && _status != GW_SLEPT ){ - if (strlen(_willMsg) && strlen(_willTopic)){ - _msg[2] = _msg[2] | MQTTSN_FLAG_WILL; // CONNECT - _status = GW_WAIT_WILLTOPICREQ; - } - } - writeGwMsg(); - _connectRetry = MQTTSN_RETRY_COUNT; - }else if (_status == GW_LOST){ + if (_status == GW_LOST) + { *pos++ = 3; *pos++ = MQTTSN_TYPE_SEARCHGW; *pos = 0; // SERCHGW _status = GW_SEARCHING; writeGwMsg(); - + } + else if (_status == GW_SEND_WILLMSG) + { + *pos++ = 2 + (uint8_t) strlen(_willMsg); + *pos++ = MQTTSN_TYPE_WILLMSG; + strcpy(pos, _willMsg); // WILLMSG + _status = GW_WAIT_CONNACK; + writeGwMsg(); + } + else if (_status == GW_SEND_WILLTOPIC) + { + *pos++ = 3 + (uint8_t) strlen(_willTopic); + *pos++ = MQTTSN_TYPE_WILLTOPIC; + *pos++ = _qosWill | _retainWill; + strcpy(pos, _willTopic); // WILLTOPIC + _status = GW_WAIT_WILLMSGREQ; + writeGwMsg(); + } + else if (_status == GW_CONNECTING || _status == GW_DISCONNECTED || _status == GW_SLEPT) + { + uint8_t clientIdLen = uint8_t(strlen(_clientId) > 23 ? 23 : strlen(_clientId)); + if (_isQoSMinus1Mode) + { + _status = GW_CONNECTED; + } + else + { + *pos++ = 6 + clientIdLen; + *pos++ = MQTTSN_TYPE_CONNECT; + pos++; + if (_cleanSession) + { + _msg[2] = MQTTSN_FLAG_CLEAN; + } + *pos++ = MQTTSN_PROTOCOL_ID; + setUint16((uint8_t*) pos, _tkeepAlive); + pos += 2; + strncpy(pos, _clientId, clientIdLen); + _msg[6 + clientIdLen] = 0; + _status = GW_WAIT_CONNACK; + if (_willMsg && _willTopic && _status != GW_SLEPT) + { + if (strlen(_willMsg) && strlen(_willTopic)) + { + _msg[2] = _msg[2] | MQTTSN_FLAG_WILL; // CONNECT + _status = GW_WAIT_WILLTOPICREQ; + } + } + writeGwMsg(); + _connectRetry = MQTTSN_RETRY_COUNT; + } } getConnectResponce(); } return; } -int LGwProxy::getConnectResponce(void){ +int LGwProxy::getConnectResponce(void) +{ int len = readMsg(); - if (len == 0){ - if (_sendUTC + MQTTSN_TIME_RETRY < time(NULL)){ + if (len == 0) + { + if (_sendUTC + MQTTSN_TIME_RETRY < time(NULL)) + { if (_msg[1] == MQTTSN_TYPE_CONNECT) { _connectRetry--; } - if (--_retryCount > 0){ - writeMsg((const uint8_t*)_msg); // Not writeGwMsg() : not to reset the counter. + if (--_retryCount > 0) + { + writeMsg((const uint8_t*) _msg); // Not writeGwMsg() : not to reset the counter. _sendUTC = time(NULL); - }else{ + } + else + { _sendUTC = 0; - if ( _status > GW_SEARCHING && _connectRetry > 0){ + if (_status > GW_SEARCHING && _connectRetry > 0) + { _status = GW_CONNECTING; - }else{ + } + else + { _status = GW_LOST; _gwId = 0; } @@ -158,66 +183,87 @@ int LGwProxy::getConnectResponce(void){ } } return 0; - }else if (_mqttsnMsg[0] == MQTTSN_TYPE_GWINFO && _status == GW_SEARCHING){ + } + else if (_mqttsnMsg[0] == MQTTSN_TYPE_GWINFO && _status == GW_SEARCHING) + { _network.setGwAddress(); _gwId = _mqttsnMsg[1]; _status = GW_CONNECTING; - }else if (_mqttsnMsg[0] == MQTTSN_TYPE_WILLTOPICREQ && _status == GW_WAIT_WILLTOPICREQ){ + } + else if (_mqttsnMsg[0] == MQTTSN_TYPE_WILLTOPICREQ && _status == GW_WAIT_WILLTOPICREQ) + { _status = GW_SEND_WILLTOPIC; - }else if (_mqttsnMsg[0] == MQTTSN_TYPE_WILLMSGREQ && _status == GW_WAIT_WILLMSGREQ){ + } + else if (_mqttsnMsg[0] == MQTTSN_TYPE_WILLMSGREQ && _status == GW_WAIT_WILLMSGREQ) + { _status = GW_SEND_WILLMSG; - }else if (_mqttsnMsg[0] == MQTTSN_TYPE_CONNACK && _status == GW_WAIT_CONNACK){ - if (_mqttsnMsg[1] == MQTTSN_RC_ACCEPTED){ + } + else if (_mqttsnMsg[0] == MQTTSN_TYPE_CONNACK && _status == GW_WAIT_CONNACK) + { + if (_mqttsnMsg[1] == MQTTSN_RC_ACCEPTED) + { _status = GW_CONNECTED; _connectRetry = MQTTSN_RETRY_COUNT; setPingReqTimer(); - if ( _tSleep ){ + if (_tSleep) + { _tSleep = 0; - }else{ + } + else + { DISPLAY("\033[0m\033[0;32m\n\n Connected to the Broker\033[0m\033[0;37m\n\n"); - if ( _cleanSession || _initialized == 1 ) + if (_cleanSession || _initialized == 1) { _topicTbl.clearTopic(); _initialized = 0; theClient->onConnect(); // SUBSCRIBEs are conducted } } - }else{ + } + else + { _status = GW_CONNECTING; } } return 1; } -void LGwProxy::reconnect(void){ +void LGwProxy::reconnect(void) +{ D_MQTTLOG("...Gateway reconnect\r\n"); _status = GW_DISCONNECTED; connect(); } -void LGwProxy::disconnect(uint16_t secs){ +void LGwProxy::disconnect(uint16_t secs) +{ _tSleep = secs; _tWake = 0; _msg[1] = MQTTSN_TYPE_DISCONNECT; - if (secs){ + if (secs) + { _msg[0] = 4; setUint16((uint8_t*) _msg + 2, secs); _status = GW_SLEEPING; - }else{ + } + else + { _msg[0] = 2; _keepAliveTimer.stop(); _status = GW_DISCONNECTING; } _retryCount = MQTTSN_RETRY_COUNT; - writeMsg((const uint8_t*)_msg); + writeMsg((const uint8_t*) _msg); _sendUTC = time(NULL); - while ( _status != GW_DISCONNECTED && _status != GW_SLEPT){ - if (getDisconnectResponce() < 0){ + while (_status != GW_DISCONNECTED && _status != GW_SLEPT) + { + if (getDisconnectResponce() < 0) + { _status = GW_LOST; DISPLAY("\033[0m\033[0;31m\n\n!!!!!! DISCONNECT Error !!!!!\033[0m\033[0;37m \n\n"); return; @@ -225,48 +271,63 @@ void LGwProxy::disconnect(uint16_t secs){ } } -int LGwProxy::getDisconnectResponce(void){ +int LGwProxy::getDisconnectResponce(void) +{ int len = readMsg(); - if (len == 0){ - if (_sendUTC + MQTTSN_TIME_RETRY < time(NULL)){ - if (--_retryCount >= 0){ - writeMsg((const uint8_t*)_msg); + if (len == 0) + { + if (_sendUTC + MQTTSN_TIME_RETRY < time(NULL)) + { + if (--_retryCount >= 0) + { + writeMsg((const uint8_t*) _msg); _sendUTC = time(NULL); - }else{ + } + else + { _status = GW_LOST; _gwId = 0; return -1; } } return 0; - }else if (_mqttsnMsg[0] == MQTTSN_TYPE_DISCONNECT){ - if (_status == GW_SLEEPING ){ + } + else if (_mqttsnMsg[0] == MQTTSN_TYPE_DISCONNECT) + { + if (_status == GW_SLEEPING) + { _status = GW_SLEPT; uint32_t remain = _keepAliveTimer.getRemain(); theClient->setSleepMode(remain); /* Wake up and starts from this point. */ - }else{ + } + else + { _status = GW_DISCONNECTED; } } return 0; } -int LGwProxy::getMessage(void){ +int LGwProxy::getMessage(void) +{ int len = readMsg(); - if (len < 0){ + if (len < 0) + { return len; //error } #ifdef DEBUG_MQTTSN - if (len){ + if (len) + { D_MQTTLOG(" recved msgType %x\n", _mqttsnMsg[0]); } #endif - if (len == 0){ + if (len == 0) + { // Check PINGREQ required checkPingReq(); @@ -282,87 +343,115 @@ int LGwProxy::getMessage(void){ // Check Timeout of SUBSCRIBEs, theClient->getSubscribeManager()->checkTimeout(); - }else if (_mqttsnMsg[0] == MQTTSN_TYPE_PUBLISH){ + } + else if (_mqttsnMsg[0] == MQTTSN_TYPE_PUBLISH) + { theClient->getPublishManager()->published(_mqttsnMsg, len); - }else if (_mqttsnMsg[0] == MQTTSN_TYPE_PUBACK || _mqttsnMsg[0] == MQTTSN_TYPE_PUBCOMP || - _mqttsnMsg[0] == MQTTSN_TYPE_PUBREC || _mqttsnMsg[0] == MQTTSN_TYPE_PUBREL ){ - theClient->getPublishManager()->responce(_mqttsnMsg, (uint16_t)len); + } + else if (_mqttsnMsg[0] == MQTTSN_TYPE_PUBACK || _mqttsnMsg[0] == MQTTSN_TYPE_PUBCOMP + || _mqttsnMsg[0] == MQTTSN_TYPE_PUBREC || _mqttsnMsg[0] == MQTTSN_TYPE_PUBREL) + { + theClient->getPublishManager()->responce(_mqttsnMsg, (uint16_t) len); - }else if (_mqttsnMsg[0] == MQTTSN_TYPE_SUBACK || _mqttsnMsg[0] == MQTTSN_TYPE_UNSUBACK){ + } + else if (_mqttsnMsg[0] == MQTTSN_TYPE_SUBACK || _mqttsnMsg[0] == MQTTSN_TYPE_UNSUBACK) + { theClient->getSubscribeManager()->responce(_mqttsnMsg); - }else if (_mqttsnMsg[0] == MQTTSN_TYPE_REGISTER){ + } + else if (_mqttsnMsg[0] == MQTTSN_TYPE_REGISTER) + { _regMgr.responceRegister(_mqttsnMsg, len); - }else if (_mqttsnMsg[0] == MQTTSN_TYPE_REGACK){ + } + else if (_mqttsnMsg[0] == MQTTSN_TYPE_REGACK) + { _regMgr.responceRegAck(getUint16(_mqttsnMsg + 3), getUint16(_mqttsnMsg + 1)); - }else if (_mqttsnMsg[0] == MQTTSN_TYPE_PINGRESP){ - if (_pingStatus == GW_WAIT_PINGRESP){ + } + else if (_mqttsnMsg[0] == MQTTSN_TYPE_PINGRESP) + { + if (_pingStatus == GW_WAIT_PINGRESP) + { _pingStatus = 0; setPingReqTimer(); - if ( _tSleep > 0 ){ + if (_tSleep > 0) + { _tWake += _tkeepAlive; - if ( _tWake < _tSleep ){ + if (_tWake < _tSleep) + { theClient->setSleepMode(_tkeepAlive * 1000UL); - }else{ + } + else + { DISPLAY("\033[0m\033[0;32m\n\n Get back to ACTIVE.\033[0m\033[0;37m\n\n"); _tWake = 0; connect(); } } } - }else if (_mqttsnMsg[0] == MQTTSN_TYPE_DISCONNECT){ + } + else if (_mqttsnMsg[0] == MQTTSN_TYPE_DISCONNECT) + { _status = GW_LOST; _gwAliveTimer.stop(); _keepAliveTimer.stop(); - }else if (_mqttsnMsg[0] == MQTTSN_TYPE_ADVERTISE){ - if (getUint16((const uint8_t*)(_mqttsnMsg + 2)) < 61){ - _tAdv = getUint16((const uint8_t*)(_mqttsnMsg + 2)) * 1500; - }else{ - _tAdv = getUint16((const uint8_t*)(_mqttsnMsg + 2)) * 1100; + } + else if (_mqttsnMsg[0] == MQTTSN_TYPE_ADVERTISE) + { + if (getUint16((const uint8_t*) (_mqttsnMsg + 2)) < 61) + { + _tAdv = getUint16((const uint8_t*) (_mqttsnMsg + 2)) * 1500; + } + else + { + _tAdv = getUint16((const uint8_t*) (_mqttsnMsg + 2)) * 1100; } _gwAliveTimer.start(_tAdv); } return 0; } - - - -uint16_t LGwProxy::registerTopic(char* topicName, uint16_t topicId){ +uint16_t LGwProxy::registerTopic(char* topicName, uint16_t topicId) +{ uint16_t id = topicId; - if (id == 0){ + if (id == 0) + { id = _topicTbl.getTopicId(topicName); _regMgr.registerTopic(topicName); } return id; } - -int LGwProxy::writeMsg(const uint8_t* msg){ +int LGwProxy::writeMsg(const uint8_t* msg) +{ uint16_t len; uint8_t pos; - uint8_t rc = 0; + uint8_t rc = 0; - if (msg[0] == 0x01){ + if (msg[0] == 0x01) + { len = getUint16(msg + 1); pos = 2; - }else{ + } + else + { len = msg[0]; pos = 1; } - if (msg[0] == 3 && msg[1] == MQTTSN_TYPE_SEARCHGW){ - rc = _network.broadcast(msg,len); - }else + if (msg[0] == 3 && msg[1] == MQTTSN_TYPE_SEARCHGW) { - if ( _isForwarderMode ) + rc = _network.broadcast(msg, len); + } + else + { + if (_isForwarderMode) { // create a forwarder encapsulation message WirelessNodeId is a 4bytes fake data - uint8_t* buf = (uint8_t*)malloc(len + 7); + uint8_t* buf = (uint8_t*) malloc(len + 7); buf[0] = 7; buf[1] = MQTTSN_TYPE_ENCAPSULATED; buf[2] = 1; @@ -371,16 +460,19 @@ int LGwProxy::writeMsg(const uint8_t* msg){ buf[5] = 'I'; buf[6] = 'd'; memcpy(buf + 7, msg, len); - if ( buf) - rc = _network.unicast(buf, len + 7); + if (buf) + rc = _network.unicast(buf, len + 7); free(buf); DISPLAY(" Encapsulated\n "); - }else{ - rc = _network.unicast(msg,len); + } + else + { + rc = _network.unicast(msg, len); } - if (rc > 0){ - if ( msg[pos] >= MQTTSN_TYPE_ADVERTISE && msg[pos] <= MQTTSN_TYPE_WILLMSGRESP ) + if (rc > 0) + { + if (msg[pos] >= MQTTSN_TYPE_ADVERTISE && msg[pos] <= MQTTSN_TYPE_WILLMSGRESP) { DISPLAY(" send %s\n", packet_names[msg[pos]]); } @@ -389,105 +481,139 @@ int LGwProxy::writeMsg(const uint8_t* msg){ return rc; } -void LGwProxy::writeGwMsg(void){ +void LGwProxy::writeGwMsg(void) +{ _retryCount = MQTTSN_RETRY_COUNT; - writeMsg((const uint8_t*)_msg); + writeMsg((const uint8_t*) _msg); _sendUTC = time(NULL); } -int LGwProxy::readMsg(void){ +int LGwProxy::readMsg(void) +{ int len = 0; uint8_t* msg = _network.getMessage(&len); _mqttsnMsg = msg; - if (len == 0){ + if (len == 0) + { return 0; } - if (_mqttsnMsg[0] == 0x01){ - int msgLen = (int) getUint16((const uint8_t*)_mqttsnMsg + 1); - if (len != msgLen){ + if (_mqttsnMsg[0] == 0x01) + { + int msgLen = (int) getUint16((const uint8_t*) _mqttsnMsg + 1); + if (len != msgLen) + { _mqttsnMsg += 3; len = msgLen - 3; } - }else{ + } + else + { _mqttsnMsg += 1; len -= 1; } - if ( *_mqttsnMsg == MQTTSN_TYPE_ENCAPSULATED ) + if (*_mqttsnMsg == MQTTSN_TYPE_ENCAPSULATED) { int lenEncap = len + 1; - if (msg[lenEncap] == 0x01){ - int msgLen = (int) getUint16((const uint8_t*)(msg + lenEncap + 1)); + if (msg[lenEncap] == 0x01) + { + int msgLen = (int) getUint16((const uint8_t*) (msg + lenEncap + 1)); msg += (lenEncap + 3); len = msgLen - 3; - }else{ + } + else + { msg += (lenEncap + 1); len = *(msg - 1); } _mqttsnMsg = msg; - DISPLAY(" recv encapslated message\n" ); + DISPLAY(" recv encapslated message\n"); } - if ( *_mqttsnMsg >= MQTTSN_TYPE_ADVERTISE && *_mqttsnMsg <= MQTTSN_TYPE_WILLMSGRESP ) + if (*_mqttsnMsg >= MQTTSN_TYPE_ADVERTISE && *_mqttsnMsg <= MQTTSN_TYPE_WILLMSGRESP) { DISPLAY(" recv %s\n", packet_names[*_mqttsnMsg]); } return len; } -void LGwProxy::setWillTopic(const char* willTopic, uint8_t qos, bool retain){ +void LGwProxy::setWillTopic(const char* willTopic, uint8_t qos, bool retain) +{ _willTopic = willTopic; _retainWill = _qosWill = 0; - if (qos == 1){ + if (qos == 1) + { _qosWill = MQTTSN_FLAG_QOS_1; - }else if (qos == 2){ + } + else if (qos == 2) + { _qosWill = MQTTSN_FLAG_QOS_2; } - if (retain){ + if (retain) + { _retainWill = MQTTSN_FLAG_RETAIN; } } -void LGwProxy::setWillMsg(const char* willMsg){ +void LGwProxy::setWillMsg(const char* willMsg) +{ _willMsg = willMsg; } - -void LGwProxy::setCleanSession(bool flg){ - if (flg){ +void LGwProxy::setCleanSession(bool flg) +{ + if (flg) + { _cleanSession = MQTTSN_FLAG_CLEAN; - }else{ + } + else + { _cleanSession = 0; } } -uint16_t LGwProxy::getNextMsgId(void){ +uint16_t LGwProxy::getNextMsgId(void) +{ _nextMsgId++; - if (_nextMsgId == 0){ + if (_nextMsgId == 0) + { _nextMsgId = 1; } return _nextMsgId; } -void LGwProxy::checkPingReq(void){ +void LGwProxy::checkPingReq(void) +{ + if ( _isQoSMinus1Mode ) + { + return; + } + uint8_t msg[2]; msg[0] = 0x02; msg[1] = MQTTSN_TYPE_PINGREQ; - - if ( (_status == GW_CONNECTED || _status == GW_SLEPT) && isPingReqRequired() && _pingStatus != GW_WAIT_PINGRESP){ + + if ((_status == GW_CONNECTED || _status == GW_SLEPT) && isPingReqRequired() && _pingStatus != GW_WAIT_PINGRESP) + { _pingStatus = GW_WAIT_PINGRESP; _pingRetryCount = MQTTSN_RETRY_COUNT; - writeMsg((const uint8_t*)msg); + writeMsg((const uint8_t*) msg); _pingSendUTC = time(NULL); - }else if (_pingStatus == GW_WAIT_PINGRESP){ - if (_pingSendUTC + MQTTSN_TIME_RETRY < time(NULL)){ - if (--_pingRetryCount > 0){ - writeMsg((const uint8_t*)msg); + } + else if (_pingStatus == GW_WAIT_PINGRESP) + { + if (_pingSendUTC + MQTTSN_TIME_RETRY < time(NULL)) + { + if (--_pingRetryCount > 0) + { + writeMsg((const uint8_t*) msg); _pingSendUTC = time(NULL); - }else{ + } + else + { _status = GW_LOST; _gwId = 0; _pingStatus = 0; @@ -498,8 +624,10 @@ void LGwProxy::checkPingReq(void){ } } -void LGwProxy::checkAdvertise(void){ - if ( _gwAliveTimer.isTimeUp()){ +void LGwProxy::checkAdvertise(void) +{ + if (_gwAliveTimer.isTimeUp()) + { _status = GW_LOST; _gwId = 0; _pingStatus = 0; @@ -509,27 +637,37 @@ void LGwProxy::checkAdvertise(void){ } } -LTopicTable* LGwProxy::getTopicTable(void){ +LTopicTable* LGwProxy::getTopicTable(void) +{ return &_topicTbl; } -LRegisterManager* LGwProxy::getRegisterManager(void){ +LRegisterManager* LGwProxy::getRegisterManager(void) +{ return &_regMgr; } -bool LGwProxy::isPingReqRequired(void){ +bool LGwProxy::isPingReqRequired(void) +{ return _keepAliveTimer.isTimeUp(_tkeepAlive * 1000UL); } -void LGwProxy::setPingReqTimer(void){ +void LGwProxy::setPingReqTimer(void) +{ _keepAliveTimer.start(_tkeepAlive * 1000UL); } -const char* LGwProxy::getClientId(void) { +const char* LGwProxy::getClientId(void) +{ return _clientId; } -void LGwProxy::setForwarderMode(void) +void LGwProxy::setForwarderMode(bool valid) { - _isForwarderMode = true; + _isForwarderMode = valid; +} + +void LGwProxy::setQoSMinus1Mode(bool valid) +{ + _isQoSMinus1Mode = valid; } diff --git a/MQTTSNGateway/GatewayTester/src/LGwProxy.h b/MQTTSNGateway/GatewayTester/src/LGwProxy.h index a34be1f..814affc 100644 --- a/MQTTSNGateway/GatewayTester/src/LGwProxy.h +++ b/MQTTSNGateway/GatewayTester/src/LGwProxy.h @@ -65,7 +65,8 @@ public: void setCleanSession(bool); void setKeepAliveDuration(uint16_t duration); void setAdvertiseDuration(uint16_t duration); - void setForwarderMode(void); + void setForwarderMode(bool valid); + void setQoSMinus1Mode(bool valid); void reconnect(void); int writeMsg(const uint8_t* msg); void setPingReqTimer(void); @@ -109,6 +110,7 @@ private: uint16_t _tSleep; uint16_t _tWake; bool _isForwarderMode; + bool _isQoSMinus1Mode; char _msg[MQTTSN_MAX_MSG_LENGTH + 1]; }; diff --git a/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h b/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h index 9891921..b848e4c 100644 --- a/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h +++ b/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h @@ -27,7 +27,6 @@ ======================================*/ //#define DEBUG_NW //#define DEBUG_MQTTSN -//#define DEBUG_OTA /**************************************** MQTT-SN Parameters @@ -105,7 +104,9 @@ typedef enum #define END_OF_SUBSCRIBE_LIST {MQTTSN_TOPIC_TYPE_NORMAL,0,0,0, 0} #define UDPCONF LUdpConfig theNetcon #define MQTTSNCONF LMqttsnConfig theMqcon -#define SetForwarderMode theClient->getGwProxy()->setForwarderMode +#define SetForwarderMode(...) theClient->getGwProxy()->setForwarderMode(__VA_ARGS__) +#define SetQoSMinus1Mode(...) theClient->getGwProxy()->setQoSMinus1Mode(__VA_ARGS__) + #ifdef CLIENT_MODE #define DISPLAY(...) #define PROMPT(...) @@ -142,6 +143,7 @@ typedef enum #define QoS0 0 #define QoS1 1 #define QoS2 2 +#define Q0Sm1 3 #define MQTTSN_TYPE_ADVERTISE 0x00 #define MQTTSN_TYPE_SEARCHGW 0x01 #define MQTTSN_TYPE_GWINFO 0x02 @@ -177,7 +179,7 @@ typedef enum #define MQTTSN_FLAG_QOS_0 0x0 #define MQTTSN_FLAG_QOS_1 0x20 #define MQTTSN_FLAG_QOS_2 0x40 -#define MQTTSN_FLAG_QOS_N1 0xc0 +#define MQTTSN_FLAG_QOS_M1 0x60 #define MQTTSN_FLAG_RETAIN 0x10 #define MQTTSN_FLAG_WILL 0x08 #define MQTTSN_FLAG_CLEAN 0x04 diff --git a/MQTTSNGateway/GatewayTester/src/LPublishManager.cpp b/MQTTSNGateway/GatewayTester/src/LPublishManager.cpp index 4e20c8d..918cddb 100644 --- a/MQTTSNGateway/GatewayTester/src/LPublishManager.cpp +++ b/MQTTSNGateway/GatewayTester/src/LPublishManager.cpp @@ -40,351 +40,351 @@ const char* NULLCHAR = ""; LPublishManager::LPublishManager() { - _first = 0; - _last = 0; - _elmCnt = 0; - _publishedFlg = SAVE_TASK_INDEX; + _first = 0; + _last = 0; + _elmCnt = 0; + _publishedFlg = SAVE_TASK_INDEX; } LPublishManager::~LPublishManager() { - PubElement* elm = _first; - PubElement* sav = 0; - while (elm) - { - sav = elm->next; - if (elm != 0) - { - delElement(elm); - } - elm = sav; - } + PubElement* elm = _first; + PubElement* sav = 0; + while (elm) + { + sav = elm->next; + if (elm != 0) + { + delElement(elm); + } + elm = sav; + } } void LPublishManager::publish(const char* topicName, Payload* payload, uint8_t qos, bool retain) { - publish(topicName, payload->getRowData(), payload->getLen(), qos, retain); + publish(topicName, payload->getRowData(), payload->getLen(), qos, retain); } void LPublishManager::publish(const char* topicName, uint8_t* payload, uint16_t len, uint8_t qos, bool retain) { - uint16_t msgId = 0; - uint8_t topicType = MQTTSN_TOPIC_TYPE_SHORT; + uint16_t msgId = 0; + uint8_t topicType = MQTTSN_TOPIC_TYPE_SHORT; if ( strlen(topicName) > 2 ) { topicType = MQTTSN_TOPIC_TYPE_NORMAL; } - if ( qos > 0 ) - { - msgId = theClient->getGwProxy()->getNextMsgId(); - } + if ( qos > 0 && qos < 3 ) + { + msgId = theClient->getGwProxy()->getNextMsgId(); + } - PubElement* elm = add(topicName, 0, payload, len, qos, retain, msgId, topicType); + PubElement* elm = add(topicName, 0, payload, len, qos, retain, msgId, topicType); - if (elm->status == TOPICID_IS_READY) - { - sendPublish(elm); - } - else - { - theClient->getGwProxy()->registerTopic((char*) topicName, 0); - } + if (elm->status == TOPICID_IS_READY) + { + sendPublish(elm); + } + else + { + theClient->getGwProxy()->registerTopic((char*) topicName, 0); + } } void LPublishManager::publish(uint16_t topicId, Payload* payload, uint8_t qos, bool retain) { - publish(topicId, payload->getRowData(), payload->getLen(), qos, retain); + publish(topicId, payload->getRowData(), payload->getLen(), qos, retain); } void LPublishManager::publish(uint16_t topicId, uint8_t* payload, uint16_t len, uint8_t qos, bool retain) { - uint16_t msgId = 0; - if ( qos > 0 ) - { - msgId = theClient->getGwProxy()->getNextMsgId(); - } - PubElement* elm = add(NULLCHAR, topicId, payload, len, qos, retain, msgId, MQTTSN_TOPIC_TYPE_PREDEFINED); - sendPublish(elm); + uint16_t msgId = 0; + if ( qos > 0 && qos < 3 ) + { + msgId = theClient->getGwProxy()->getNextMsgId(); + } + PubElement* elm = add(NULLCHAR, topicId, payload, len, qos, retain, msgId, MQTTSN_TOPIC_TYPE_PREDEFINED); + sendPublish(elm); } void LPublishManager::sendPublish(PubElement* elm) { - if (elm == 0) - { - return; - } + if (elm == 0) + { + return; + } - theClient->getGwProxy()->connect(); + theClient->getGwProxy()->connect(); - uint8_t msg[MQTTSN_MAX_MSG_LENGTH + 1]; - uint8_t org = 0; - if (elm->payloadlen > 128) - { - msg[0] = 0x01; - setUint16(msg + 1, elm->payloadlen + 9); - org = 2; - } - else - { - msg[0] = (uint8_t) elm->payloadlen + 7; - } - msg[org + 1] = MQTTSN_TYPE_PUBLISH; - msg[org + 2] = elm->flag; - if ((elm->retryCount < MQTTSN_RETRY_COUNT)) - { - msg[org + 2] = msg[org + 2] | MQTTSN_FLAG_DUP; - } - if ((elm->flag & 0x03) == MQTTSN_TOPIC_TYPE_SHORT ) - { - memcpy(msg + org + 3, elm->topicName, 2); - } - else - { - setUint16(msg + org + 3, elm->topicId); - } - setUint16(msg + org + 5, elm->msgId); - memcpy(msg + org + 7, elm->payload, elm->payloadlen); + uint8_t msg[MQTTSN_MAX_MSG_LENGTH + 1]; + uint8_t org = 0; + if (elm->payloadlen > 128) + { + msg[0] = 0x01; + setUint16(msg + 1, elm->payloadlen + 9); + org = 2; + } + else + { + msg[0] = (uint8_t) elm->payloadlen + 7; + } + msg[org + 1] = MQTTSN_TYPE_PUBLISH; + msg[org + 2] = elm->flag; + if ((elm->retryCount < MQTTSN_RETRY_COUNT)) + { + msg[org + 2] = msg[org + 2] | MQTTSN_FLAG_DUP; + } + if ((elm->flag & 0x03) == MQTTSN_TOPIC_TYPE_SHORT ) + { + memcpy(msg + org + 3, elm->topicName, 2); + } + else + { + setUint16(msg + org + 3, elm->topicId); + } + setUint16(msg + org + 5, elm->msgId); + memcpy(msg + org + 7, elm->payload, elm->payloadlen); - theClient->getGwProxy()->writeMsg(msg); - theClient->getGwProxy()->setPingReqTimer(); - if ((elm->flag & 0x60) == MQTTSN_FLAG_QOS_0) - { - DISPLAY("\033[0m\033[0;32m Topic \"%s\" was Published. \033[0m\033[0;37m\n\n", elm->topicName); - remove(elm); // PUBLISH Done - return; - } - else if ((elm->flag & 0x60) == MQTTSN_FLAG_QOS_1) - { - elm->status = WAIT_PUBACK; - } - else if ((elm->flag & 0x60) == MQTTSN_FLAG_QOS_2) - { - elm->status = WAIT_PUBREC; - } + theClient->getGwProxy()->writeMsg(msg); + theClient->getGwProxy()->setPingReqTimer(); + if ( ((elm->flag & 0x60) == MQTTSN_FLAG_QOS_0 ) || ( (elm->flag & 0x60) == MQTTSN_FLAG_QOS_M1) ) + { + DISPLAY("\033[0m\033[0;32m Topic \"%s\" was Published. \033[0m\033[0;37m\n\n", elm->topicName); + remove(elm); // PUBLISH Done + return; + } + else if ((elm->flag & 0x60) == MQTTSN_FLAG_QOS_1) + { + elm->status = WAIT_PUBACK; + } + else if ((elm->flag & 0x60) == MQTTSN_FLAG_QOS_2) + { + elm->status = WAIT_PUBREC; + } - elm->sendUTC = time(NULL); - elm->retryCount--; + elm->sendUTC = time(NULL); + elm->retryCount--; } void LPublishManager::sendSuspend(const char* topicName, uint16_t topicId, uint8_t topicType) { - PubElement* elm = _first; - while (elm) - { - if (strcmp(elm->topicName, topicName) == 0 && elm->status == TOPICID_IS_SUSPEND) - { - elm->topicId = topicId; - elm->flag |= topicType; - elm->status = TOPICID_IS_READY; - sendPublish(elm); - elm = 0; - } - else - { - elm = elm->next; - } - } + PubElement* elm = _first; + while (elm) + { + if (strcmp(elm->topicName, topicName) == 0 && elm->status == TOPICID_IS_SUSPEND) + { + elm->topicId = topicId; + elm->flag |= topicType; + elm->status = TOPICID_IS_READY; + sendPublish(elm); + elm = 0; + } + else + { + elm = elm->next; + } + } } void LPublishManager::sendPubAck(uint16_t topicId, uint16_t msgId, uint8_t rc) { - uint8_t msg[7]; - msg[0] = 7; - msg[1] = MQTTSN_TYPE_PUBACK; - setUint16(msg + 2, topicId); - setUint16(msg + 4, msgId); - msg[6] = rc; - theClient->getGwProxy()->writeMsg(msg); + uint8_t msg[7]; + msg[0] = 7; + msg[1] = MQTTSN_TYPE_PUBACK; + setUint16(msg + 2, topicId); + setUint16(msg + 4, msgId); + msg[6] = rc; + theClient->getGwProxy()->writeMsg(msg); } void LPublishManager::sendPubRel(PubElement* elm) { - uint8_t msg[4]; - msg[0] = 4; - msg[1] = MQTTSN_TYPE_PUBREL; - setUint16(msg + 2, elm->msgId); - theClient->getGwProxy()->writeMsg(msg); + uint8_t msg[4]; + msg[0] = 4; + msg[1] = MQTTSN_TYPE_PUBREL; + setUint16(msg + 2, elm->msgId); + theClient->getGwProxy()->writeMsg(msg); } bool LPublishManager::isDone(void) { - return (_first == 0); + return (_first == 0); } bool LPublishManager::isMaxFlight(void) { - return (_elmCnt > MAX_INFLIGHT_MSG / 2); + return (_elmCnt > MAX_INFLIGHT_MSG / 2); } void LPublishManager::responce(const uint8_t* msg, uint16_t msglen) { - if (msg[0] == MQTTSN_TYPE_PUBACK) - { - uint16_t msgId = getUint16(msg + 3); - PubElement* elm = getElement(msgId); - if (elm == 0) - { - return; - } - if (msg[5] == MQTTSN_RC_ACCEPTED) - { - if (elm->status == WAIT_PUBACK) - { - DISPLAY("\033[0m\033[0;32m Topic \"%s\" Id : %d was Published. \033[0m\033[0;37m\n\n", elm->topicName, elm->topicId); - remove(elm); // PUBLISH Done - } - } - else if (msg[5] == MQTTSN_RC_REJECTED_INVALID_TOPIC_ID) - { - elm->status = TOPICID_IS_SUSPEND; - elm->topicId = 0; - elm->retryCount = MQTTSN_RETRY_COUNT; - elm->sendUTC = 0; - theClient->getGwProxy()->registerTopic((char*) elm->topicName, 0); - } - } - else if (msg[0] == MQTTSN_TYPE_PUBREC) - { - PubElement* elm = getElement(getUint16(msg + 1)); - if (elm == 0) - { - return; - } - if (elm->status == WAIT_PUBREC || elm->status == WAIT_PUBCOMP) - { - sendPubRel(elm); - elm->status = WAIT_PUBCOMP; - elm->sendUTC = time(NULL); - } - } - else if (msg[0] == MQTTSN_TYPE_PUBCOMP) - { - PubElement* elm = getElement(getUint16(msg + 1)); - if (elm == 0) - { - return; - } - if (elm->status == WAIT_PUBCOMP) - { - DISPLAY("\033[0m\033[0;32m Topic \"%s\" Id : %d was Published. \033[0m\033[0;37m\n\n", elm->topicName, elm->topicId); - remove(elm); // PUBLISH Done - } - } + if (msg[0] == MQTTSN_TYPE_PUBACK) + { + uint16_t msgId = getUint16(msg + 3); + PubElement* elm = getElement(msgId); + if (elm == 0) + { + return; + } + if (msg[5] == MQTTSN_RC_ACCEPTED) + { + if (elm->status == WAIT_PUBACK) + { + DISPLAY("\033[0m\033[0;32m Topic \"%s\" Id : %d was Published. \033[0m\033[0;37m\n\n", elm->topicName, elm->topicId); + remove(elm); // PUBLISH Done + } + } + else if (msg[5] == MQTTSN_RC_REJECTED_INVALID_TOPIC_ID) + { + elm->status = TOPICID_IS_SUSPEND; + elm->topicId = 0; + elm->retryCount = MQTTSN_RETRY_COUNT; + elm->sendUTC = 0; + theClient->getGwProxy()->registerTopic((char*) elm->topicName, 0); + } + } + else if (msg[0] == MQTTSN_TYPE_PUBREC) + { + PubElement* elm = getElement(getUint16(msg + 1)); + if (elm == 0) + { + return; + } + if (elm->status == WAIT_PUBREC || elm->status == WAIT_PUBCOMP) + { + sendPubRel(elm); + elm->status = WAIT_PUBCOMP; + elm->sendUTC = time(NULL); + } + } + else if (msg[0] == MQTTSN_TYPE_PUBCOMP) + { + PubElement* elm = getElement(getUint16(msg + 1)); + if (elm == 0) + { + return; + } + if (elm->status == WAIT_PUBCOMP) + { + DISPLAY("\033[0m\033[0;32m Topic \"%s\" Id : %d was Published. \033[0m\033[0;37m\n\n", elm->topicName, elm->topicId); + remove(elm); // PUBLISH Done + } + } } void LPublishManager::published(uint8_t* msg, uint16_t msglen) { - uint16_t topicId = getUint16(msg + 2); + uint16_t topicId = getUint16(msg + 2); - if (msg[1] & MQTTSN_FLAG_QOS_1) - { - sendPubAck(topicId, getUint16(msg + 4), MQTTSN_RC_ACCEPTED); - } + if (msg[1] & MQTTSN_FLAG_QOS_1) + { + sendPubAck(topicId, getUint16(msg + 4), MQTTSN_RC_ACCEPTED); + } - _publishedFlg = NEG_TASK_INDEX; - theClient->getTopicTable()->execCallback(topicId, msg + 6, msglen - 6, (MQTTSN_topicTypes)(msg[1] & MQTTSN_TOPIC_TYPE)); - _publishedFlg = SAVE_TASK_INDEX; + _publishedFlg = NEG_TASK_INDEX; + theClient->getTopicTable()->execCallback(topicId, msg + 6, msglen - 6, (MQTTSN_topicTypes)(msg[1] & MQTTSN_TOPIC_TYPE)); + _publishedFlg = SAVE_TASK_INDEX; } void LPublishManager::checkTimeout(void) { - PubElement* elm = _first; - while (elm) - { - if (elm->sendUTC > 0 && elm->sendUTC + MQTTSN_TIME_RETRY < time(NULL)) - { - if (elm->retryCount >= 0) - { - sendPublish(elm); - D_MQTTLOG("...Timeout retry\r\n"); - } - else - { - theClient->getGwProxy()->reconnect(); - elm->retryCount = MQTTSN_RETRY_COUNT; - break; - } - } - elm = elm->next; - } + PubElement* elm = _first; + while (elm) + { + if (elm->sendUTC > 0 && elm->sendUTC + MQTTSN_TIME_RETRY < time(NULL)) + { + if (elm->retryCount >= 0) + { + sendPublish(elm); + D_MQTTLOG("...Timeout retry\r\n"); + } + else + { + theClient->getGwProxy()->reconnect(); + elm->retryCount = MQTTSN_RETRY_COUNT; + break; + } + } + elm = elm->next; + } } PubElement* LPublishManager::getElement(uint16_t msgId) { - PubElement* elm = _first; - while (elm) - { - if (elm->msgId == msgId) - { - break; - } - else - { - elm = elm->next; - } - } - return elm; + PubElement* elm = _first; + while (elm) + { + if (elm->msgId == msgId) + { + break; + } + else + { + elm = elm->next; + } + } + return elm; } PubElement* LPublishManager::getElement(const char* topicName) { - PubElement* elm = _first; - while (elm) - { - if (strcmp(elm->topicName, topicName) == 0) - { - break; - } - else - { - elm = elm->next; - } - } - return elm; + PubElement* elm = _first; + while (elm) + { + if (strcmp(elm->topicName, topicName) == 0) + { + break; + } + else + { + elm = elm->next; + } + } + return elm; } void LPublishManager::remove(PubElement* elm) { - if (elm) - { - if (elm->prev == 0) - { - _first = elm->next; - if (elm->next == 0) - { - _last = 0; - } - else - { - elm->next->prev = 0; - _last = elm->next; - } - } - else - { - if ( elm->next == 0 ) - { - _last = elm->prev; - } - elm->prev->next = elm->next; - } - delElement(elm); - } + if (elm) + { + if (elm->prev == 0) + { + _first = elm->next; + if (elm->next == 0) + { + _last = 0; + } + else + { + elm->next->prev = 0; + _last = elm->next; + } + } + else + { + if ( elm->next == 0 ) + { + _last = elm->prev; + } + elm->prev->next = elm->next; + } + delElement(elm); + } } void LPublishManager::delElement(PubElement* elm) { - if (elm->taskIndex >= 0) - { - theClient->getTaskManager()->done(elm->taskIndex); - } - _elmCnt--; - if ( elm->payload ) - { - free(elm->payload); - } - free(elm); + if (elm->taskIndex >= 0) + { + theClient->getTaskManager()->done(elm->taskIndex); + } + _elmCnt--; + if ( elm->payload ) + { + free(elm->payload); + } + free(elm); } /* @@ -393,84 +393,88 @@ void LPublishManager::delElement(PubElement* elm) }*/ PubElement* LPublishManager::add(const char* topicName, uint16_t topicId, uint8_t* payload, uint16_t len, uint8_t qos, - uint8_t retain, uint16_t msgId, uint8_t topicType) + uint8_t retain, uint16_t msgId, uint8_t topicType) { - PubElement* elm = (PubElement*) calloc(1, sizeof(PubElement)); + PubElement* elm = (PubElement*) calloc(1, sizeof(PubElement)); - if (elm == 0) - { - return elm; - } - if (_last == 0) - { - _first = elm; - _last = elm; - } - else - { - elm->prev = _last; - _last->next = elm; - _last = elm; - } + if (elm == 0) + { + return elm; + } + if (_last == 0) + { + _first = elm; + _last = elm; + } + else + { + elm->prev = _last; + _last->next = elm; + _last = elm; + } - elm->topicName = topicName; - elm->flag |= topicType; + elm->topicName = topicName; + elm->flag |= topicType; - if (qos == 0) - { - elm->flag |= MQTTSN_FLAG_QOS_0; - } - else if (qos == 1) - { - elm->flag |= MQTTSN_FLAG_QOS_1; - } - else if (qos == 2) - { - elm->flag |= MQTTSN_FLAG_QOS_2; - } - if (retain) - { - elm->flag |= MQTTSN_FLAG_RETAIN; - } + if (qos == 0) + { + elm->flag |= MQTTSN_FLAG_QOS_0; + } + else if (qos == 1) + { + elm->flag |= MQTTSN_FLAG_QOS_1; + } + else if (qos == 2) + { + elm->flag |= MQTTSN_FLAG_QOS_2; + } + else if (qos == 3) + { + elm->flag |= MQTTSN_FLAG_QOS_M1; + } + if (retain) + { + elm->flag |= MQTTSN_FLAG_RETAIN; + } - if (topicId) - { - elm->status = TOPICID_IS_READY; - elm->topicId = topicId; - } - else - { - uint16_t id = theClient->getTopicId(topicName); + if (topicId) + { + elm->status = TOPICID_IS_READY; + elm->topicId = topicId; + } + else + { + uint16_t id = theClient->getTopicId(topicName); if ( id ) { elm->status = TOPICID_IS_READY; elm->topicId = id; } - } + } - elm->payloadlen = len; - elm->msgId = msgId; - elm->retryCount = MQTTSN_RETRY_COUNT; - elm->sendUTC = 0; + elm->payloadlen = len; + elm->msgId = msgId; + elm->retryCount = MQTTSN_RETRY_COUNT; + elm->sendUTC = 0; - if (_publishedFlg == NEG_TASK_INDEX) - { - elm->taskIndex = -1; - } - else - { - elm->taskIndex = theClient->getTaskManager()->getIndex(); - theClient->getTaskManager()->suspend(elm->taskIndex); - } + if (_publishedFlg == NEG_TASK_INDEX) + { + elm->taskIndex = -1; + } + else + { + elm->taskIndex = theClient->getTaskManager()->getIndex(); + theClient->getTaskManager()->suspend(elm->taskIndex); + } - elm->payload = (uint8_t*) malloc(len); - if (elm->payload == 0) - { - delElement(elm); - return 0; - } - memcpy(elm->payload, payload, len); + elm->payload = (uint8_t*) malloc(len); + if (elm->payload == 0) + { + delElement(elm); + return 0; + } + memcpy(elm->payload, payload, len); - ++_elmCnt; - return elm; + ++_elmCnt; + return elm; } diff --git a/MQTTSNGateway/Makefile b/MQTTSNGateway/Makefile index cfc9283..4015b85 100644 --- a/MQTTSNGateway/Makefile +++ b/MQTTSNGateway/Makefile @@ -10,7 +10,6 @@ TESTAPPL := mainTestProcess CONFIG := gateway.conf CLIENTS := clients.conf PREDEFTOPIC := predefinedTopic.conf -FORWARDERS := forwarders.conf SRCDIR := src SUBDIR := ../MQTTSNPacket/src @@ -39,6 +38,15 @@ $(SRCDIR)/MQTTSNGWPublishHandler.cpp \ $(SRCDIR)/MQTTSNGWSubscribeHandler.cpp \ $(SRCDIR)/MQTTSNGWEncapsulatedPacket.cpp \ $(SRCDIR)/MQTTSNGWForwarder.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 \ @@ -140,7 +148,6 @@ install: cp -pf $(CONFIG) ../../ cp -pf $(CLIENTS) ../../ cp -pf $(PREDEFTOPIC) ../../ - cp -pf $(FORWARDERS) ../../ exectest: diff --git a/MQTTSNGateway/README.md b/MQTTSNGateway/README.md index 28e149c..e04ffa6 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,57 +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  
+#
 
 ClientAuthentication=NO
-ClientsList=/path/to/your_clients.conf    
+AggregateGateway=NO
+QoS-1=NO
+Forwarder=NO
+
+#ClientsList=/path/to/your_clients.conf
 
 PredefinedTopic=NO
-PredefinedTopicList=/path/to/your_predefinedTopic.conf
+#PredefinedTopicList=/path/to/your_predefinedTopic.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
 
-Forwarder=NO
-ForwardersList=/home/tomoaki/tmp/forwarders.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 **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 **QoS-1** is **YES**, QoS-1 PUBLISH is available. All clients which send QoS-1 PUBLISH must be specified by Client.conf file. +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 **YES**, Forwarder Encapsulation Message is available. Connectable Forwarders must be declared by a **ClientsList** file. - - ### ** How to monitor the gateway from remote. ** Uncomment line32 in MQTTSNGWDefined.h. diff --git a/MQTTSNGateway/clients.conf b/MQTTSNGateway/clients.conf index 16d128a..ddb2310 100644 --- a/MQTTSNGateway/clients.conf +++ b/MQTTSNGateway/clients.conf @@ -11,8 +11,37 @@ # 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 is a forwarder, "forwarder" is required. +# 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.52,unstableLine,secureConnection +# ClientID5,41000@192.168.200.53,unstableLine,secureConnection,QoS-1 +# ClientID6,41000@192.168.200.54,unstableLine,secureConnection,forwarder +# # 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 +GatewayTester, 172.16.1.11:20020 +ClientPUB,172.16.1.11:2010 +Client01,172.16.1.11:12001 +Client02,172.16.1.11:12002 +Client03,172.16.1.11:13003 + +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 + +Forwarder01,172.16.1.11:22002,forwarder +Forwarder02,172.16.1.11:22003,forwarder +Forwarder03,172.16.1.11:22004,forwarder + diff --git a/MQTTSNGateway/forwarders.conf b/MQTTSNGateway/forwarders.conf deleted file mode 100644 index 3275924..0000000 --- a/MQTTSNGateway/forwarders.conf +++ /dev/null @@ -1,16 +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. -#*********************************************************************** -# -# SensorNetwork address format is defined by SensorNetAddress::setAddress(string* data) function. -# -Forwarder01,172.16.1.7:12002 diff --git a/MQTTSNGateway/gateway.conf b/MQTTSNGateway/gateway.conf index 10e02a4..52481de 100644 --- a/MQTTSNGateway/gateway.conf +++ b/MQTTSNGateway/gateway.conf @@ -10,21 +10,28 @@ # 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 +# + ClientAuthentication=NO -ClientsList=/path/to/your_clients.conf +AggregateGateway=NO +QoS-1=NO +Forwarder=NO + +#ClientsList=/path/to/your_clients.conf PredefinedTopic=NO -PredefinedTopicList=/path/to/your_predefinedTopic.conf - -Forwarder=NO -ForwardersList=/path/to/your_forwarers.conf +#PredefinedTopicList=/path/to/your_predefinedTopic.conf #RootCAfile=/etc/ssl/certs/ca-certificates.crt #RootCApath=/etc/ssl/certs/ @@ -37,6 +44,7 @@ KeepAlive=900 #LoginID=your_ID #Password=your_Password + # UDP GatewayPortNo=10000 MulticastIP=225.1.1.1 diff --git a/MQTTSNGateway/predefinedTopic.conf b/MQTTSNGateway/predefinedTopic.conf index 9b50801..95d23ea 100644 --- a/MQTTSNGateway/predefinedTopic.conf +++ b/MQTTSNGateway/predefinedTopic.conf @@ -11,9 +11,36 @@ # http://www.eclipse.org/org/documents/edl-v10.php. #*********************************************************************** # -# ClientID, TopicName, TopicID +# pre-defined-topics are defined by this file. +# A format of this file is in CSV as follows: +# +# ClientID, TopicName, TopicID +# +# This file is consist from two sections. +# One for QoS-1 PUBLISH Clients, the other for another clients. + +# +# pre-defined-topics for Clients # GatewayTestClient,ty4tw/predefinedTopic1, 1 GatewayTestClient,ty4tw/predefinedTopic2, 2 -GatewayTestClient,ty4tw/predefinedTopic3, 3 \ No newline at end of file +GatewayTestClient,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 + + diff --git a/MQTTSNGateway/src/MQTTGWPacket.cpp b/MQTTSNGateway/src/MQTTGWPacket.cpp index 55532fc..45cb9d8 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; + + switch ( type ) + { + case PUBLISH: + Publish pub; + pub.topiclen = 0; + 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 b29fea0..ce5625d 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) @@ -131,8 +131,7 @@ void MQTTGWPublishHandler::handlePublish(Client* client, MQTTGWPacket* packet) /* create REGISTER */ MQTTSNPacket* regPacket = new MQTTSNPacket(); - MQTTSNString topicName; - topicName.cstring = 0; + MQTTSNString topicName = MQTTSNString_initializer; topicName.lenstring.len = topicId.data.long_.len; topicName.lenstring.data = topicId.data.long_.name; @@ -182,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(); @@ -235,3 +234,90 @@ 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); + } + + + + string* topicName = new string(pub.topic, pub.topiclen); + 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 ) + { + 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; + break; + } + Event* ev = new Event(); + ev->setBrokerRecvEvent(devClient, msg); + _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..935d58d --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp @@ -0,0 +1,188 @@ +/************************************************************************************** + * 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(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(); + } + + 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..510d02f --- /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 Forwarder; +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(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..1eceedd --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWAggregater.cpp @@ -0,0 +1,145 @@ +/************************************************************************************** + * Copyright (c) 2016, Tomoaki Yamaguchi + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Tomoaki Yamaguchi - initial API and implementation and/or initial documentation + **************************************************************************************/ +#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(AGGREGATER_TYPE); + + string name = _gateway->getGWParams()->gatewayName; + setup(name.c_str(), 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 0a81ef8..f524d0b 100644 --- a/MQTTSNGateway/src/MQTTSNGWClient.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClient.cpp @@ -16,369 +16,18 @@ **************************************************************************************/ #include "MQTTSNGWDefines.h" -#include "MQTTSNGWClient.h" +#include "MQTTSNGWClientList.h" #include "MQTTSNGateway.h" #include "SensorNetwork.h" -#include "MQTTSNGWForwarder.h" -#include "Network.h" #include #include #include +#include "MQTTSNGWForwarder.h" + 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; - - clientId.cstring = 0; - clientId.lenstring.data = 0; - clientId.lenstring.len = 0; - - 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; - bool rc = false; - - clientId.cstring = 0; - clientId.lenstring.data = 0; - clientId.lenstring.len = 0; - - 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; - dummyId.cstring = strdup(""); - dummyId.lenstring.len = 0; - 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); - return client; -} - -uint16_t ClientList::getClientCount() -{ - return _clientCnt; -} - -bool ClientList::isAuthorized() -{ - return _authorize; -} /*===================================== Class Client @@ -392,30 +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; - _otaClient = 0; - _prevClient = 0; - _nextClient = 0; + _prevClient = nullptr; + _nextClient = nullptr; _clientSleepPacketQue.setMaxSize(MAX_SAVED_PUBLISH); + _proxyPacketQue.setMaxSize(MAX_SAVED_PUBLISH); _hasPredefTopic = false; _holdPingRequest = false; - _forwarder = 0; + _forwarder = nullptr; + _clientType = Ctype_Regular; } Client::~Client() @@ -451,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); } @@ -485,6 +128,30 @@ int Client::setClientSleepPacket(MQTTGWPacket* packet) return rc; } +MQTTSNPacket* Client::getProxyPacket(void) +{ + return _proxyPacketQue.getPacket(); +} + +void Client::deleteFirstProxyPacket() +{ + _proxyPacketQue.pop(); +} + +int Client::setProxyPacket(MQTTSNPacket* packet) +{ + int rc = _proxyPacketQue.post(packet); + if ( rc ) + { + WRITELOG("%s %s is Disconnected. the packet was saved.\n", currentDateTime(), _clientId); + } + else + { + WRITELOG("%s %s is Disconnected and discard the packet.\n", currentDateTime(), _clientId); + } + return rc; +} + Connect* Client::getConnectData(void) { return &_connectData; @@ -537,6 +204,7 @@ void Client::setKeepAlive(MQTTSNPacket* packet) void Client::setForwarder(Forwarder* forwarder) { _forwarder = forwarder; + _clientType = Ctype_Forwarded; } Forwarder* Client::getForwarder(void) @@ -551,7 +219,7 @@ void Client::setSessionStatus(bool status) bool Client::erasable(void) { - return _sessionStatus || !_hasPredefTopic; + return _sessionStatus && !_hasPredefTopic && _forwarder == nullptr; } void Client::updateStatus(MQTTSNPacket* packet) @@ -572,7 +240,10 @@ void Client::updateStatus(MQTTSNPacket* packet) case MQTTSN_PUBCOMP: case MQTTSN_PUBREL: case MQTTSN_PUBREC: - _keepAliveTimer.start(_keepAliveMsec * 1.5); + if ( _clientType != Ctype_Proxy ) + { + _keepAliveTimer.start(_keepAliveMsec * 1.5); + } break; case MQTTSN_DISCONNECT: uint16_t duration; @@ -641,9 +312,14 @@ void Client::disconnected(void) _waitWillMsgFlg = false; } +void Client::tryConnect(void) +{ + _status = Cstat_TryConnecting; +} + bool Client::isConnectSendable(void) { - if (_status == Cstat_Lost || _status == Cstat_TryConnecting) + if ( _status == Cstat_Lost || _status == Cstat_TryConnecting ) { return false; } @@ -703,6 +379,11 @@ void Client::setTopics(Topics* topics) _topics = topics; } +ClientStatus Client::getClientStatus(void) +{ + return _status; +} + void Client::setWaitWillMsgFlg(bool flg) { _waitWillMsgFlg = flg; @@ -733,6 +414,11 @@ bool Client::isAwake(void) return (_status == Cstat_Awake); } +bool Client::isConnecting(void) +{ + return (_status == Cstat_Connecting); +} + bool Client::isSecureNetwork(void) { return _secureNetwork; @@ -760,10 +446,18 @@ void Client::setClientId(MQTTSNString id) free(_clientId); } - /* save clientId into (char*)_clientId NULL terminated */ - _clientId = (char*)calloc(MQTTSNstrlen(id) + 1, 1); - unsigned char* ptr = (unsigned char*)_clientId; - writeMQTTSNString((unsigned char**)&ptr, id); + if ( id.cstring ) + { + _clientId = (char*)calloc(strlen(id.cstring) + 1, 1); + memcpy(_clientId, id.cstring, strlen(id.cstring)); + } + else + { + /* save clientId into (char*)_clientId NULL terminated */ + _clientId = (char*)calloc(MQTTSNstrlen(id) + 1, 1); + unsigned char* ptr = (unsigned char*)_clientId; + writeMQTTSNString((unsigned char**)&ptr, id); + } } void Client::setWillTopic(MQTTSNString willTopic) @@ -812,14 +506,60 @@ const char* Client::getStatus(void) return theClientStatus[_status]; } -Client* Client::getOTAClient(void) +bool Client::isQoSm1Proxy(void) { - return _otaClient; + return _clientType == Ctype_Proxy; } -void Client::setOTAClient(Client* cl) +bool Client::isForwarded(void) { - _otaClient =cl; + 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) @@ -837,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 @@ -1338,8 +586,8 @@ waitREGACKPacket::waitREGACKPacket(MQTTSNPacket* packet, uint16_t REGACKMsgId) { _packet = packet; _msgId = REGACKMsgId; - _next = 0; - _prev = 0; + _next = nullptr; + _prev = nullptr; } waitREGACKPacket::~waitREGACKPacket() @@ -1353,8 +601,8 @@ waitREGACKPacket::~waitREGACKPacket() WaitREGACKPacketList::WaitREGACKPacketList() { - _first = 0; - _end = 0; + _first = nullptr; + _end = nullptr; _cnt = 0; } @@ -1372,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; @@ -1403,7 +651,7 @@ MQTTSNPacket* WaitREGACKPacketList::getPacket(uint16_t REGACKMsgId) } p = p->_next; } - return 0; + return nullptr; } void WaitREGACKPacketList::erase(uint16_t REGACKMsgId) @@ -1413,7 +661,7 @@ void WaitREGACKPacketList::erase(uint16_t REGACKMsgId) { if (p->_msgId == REGACKMsgId) { - if (p->_prev == 0) + if (p->_prev == nullptr) { _first = p->_next; @@ -1422,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 8900656..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,10 +177,13 @@ 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); + + MQTTSNPacket* getProxyPacket(void); + void deleteFirstProxyPacket(void); WaitREGACKPacketList* getWaitREGACKPacketList(void); void eraseWaitedPubTopicId(uint16_t msgId); @@ -261,6 +192,7 @@ public: void clearWaitedSubTopicId(void); int setClientSleepPacket(MQTTGWPacket*); + int setProxyPacket(MQTTSNPacket* packet); void setWaitedPubTopicId(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type); void setWaitedSubTopicId(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type); @@ -271,6 +203,8 @@ public: void connackSended(int rc); void disconnected(void); bool isConnectSendable(void); + void tryConnect(void); + ClientStatus getClientStatus(void); uint16_t getNextPacketId(void); uint8_t getNextSnMsgId(void); @@ -286,6 +220,16 @@ public: Forwarder* getForwarder(void); void setForwarder(Forwarder* forwader); + 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); void setWillMsg(MQTTSNString willmsg); @@ -298,6 +242,7 @@ public: bool erasable(void); bool isDisconnect(void); + bool isConnecting(void); bool isActive(void); bool isSleep(void); bool isAwake(void); @@ -310,11 +255,11 @@ public: bool isHoldPringReqest(void); Client* getNextClient(void); - Client* getOTAClient(void); - void setOTAClient(Client* cl); private: PacketQue _clientSleepPacketQue; + PacketQue _proxyPacketQue; + WaitREGACKPacketList _waitREGACKList; Topics* _topics; @@ -345,40 +290,13 @@ private: SensorNetAddress _sensorNetAddr; Forwarder* _forwarder; - + ClientType _clientType; bool _sessionStatus; bool _hasPredefTopic; Client* _nextClient; Client* _prevClient; - Client* _otaClient; -}; - -/*===================================== - 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..488944b --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWClientList.cpp @@ -0,0 +1,473 @@ +/************************************************************************************** + * 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 "MQTTSNGateway.h" +#include +#include + +using namespace MQTTSNGW; +extern Gateway* theGateway; +/*===================================== + 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(bool aggregate) +{ + if (theGateway->getGWParams()->clientAuthentication ) + { + int type = TRANSPEARENT_TYPE; + if ( aggregate ) + { + type = AGGREGATER_TYPE; + } + setClientList(type); + _authorize = true; + } +} + +void ClientList::setClientList(int type) +{ + char param[MQTTSNGW_PARAM_MAX]; + string fileName; + GatewayParams* params = theGateway->getGWParams(); + if (theGateway->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."); + } + + if ( params->clientListName == nullptr ) + { + params->clientListName = strdup(fileName.c_str()); + } +} + +void ClientList::setPredefinedTopics(bool aggrecate) +{ + char param[MQTTSNGW_PARAM_MAX]; + + string fileName; + GatewayParams* params = theGateway->getGWParams(); + + if (theGateway->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 forwarder; + 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); + forwarder = (data.find("forwarder") != 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 if ( forwarder && type == FORWARDER_TYPE) + { + theGateway->getAdapterManager()->getForwarderList()->addForwarder(&netAddr, &clientId); + } + else if (type == TRANSPEARENT_TYPE ) + { + createClient(&netAddr, &clientId, stable, secure, 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..135f365 --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWClientList.h @@ -0,0 +1,72 @@ +/************************************************************************************** + * Copyright (c) 2016, Tomoaki Yamaguchi + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Tomoaki Yamaguchi - initial API and implementation 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 +#define FORWARDER_TYPE 3 + +class Client; + +/*===================================== + Class ClientList + =====================================*/ +class ClientList +{ +public: + ClientList(); + ~ClientList(); + + void initialize(bool aggregate); + void setClientList(int type); + void setPredefinedTopics(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); + Gateway* _gateway {nullptr}; + 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 9b74341..b927532 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp @@ -15,12 +15,13 @@ **************************************************************************************/ #include "MQTTSNGWClientRecvTask.h" -#include "MQTTSNGateway.h" #include "MQTTSNPacket.h" -#include "MQTTSNGWForwarder.h" +#include "MQTTSNGWQoSm1Proxy.h" #include "MQTTSNGWEncapsulatedPacket.h" #include +//#include "MQTTSNGWForwarder.h" + using namespace MQTTSNGW; char* currentDateTime(void); /*===================================== @@ -56,14 +57,19 @@ void ClientRecvTask::initialize(int argc, char** argv) */ void ClientRecvTask::run() { - Event* ev = 0; - Client* client = 0; - char buf[128]; + Event* ev = nullptr; + AdapterManager* adpMgr = _gateway->getAdapterManager(); + QoSm1Proxy* qosm1Proxy = adpMgr->getQoSm1Proxy(); + bool isAggrActive = adpMgr->isAggregaterActive(); + ClientList* clientList = _gateway->getClientList(); + EventQue* packetEventQue = _gateway->getPacketEventQue(); + char buf[128]; while (true) { - Forwarder* fwd = 0; + Client* client = nullptr; + Forwarder* fwd = nullptr; WirelessNodeId nodeId; MQTTSNPacket* packet = new MQTTSNPacket(); @@ -91,53 +97,65 @@ void ClientRecvTask::run() if ( packet->getType() == MQTTSN_SEARCHGW ) { /* write log and post Event */ - log(0, packet); + log(0, packet, 0); ev = new Event(); ev->setBrodcastEvent(packet); - _gateway->getPacketEventQue()->post(ev); + packetEventQue->post(ev); continue; } + + SensorNetAddress* senderAddr = _gateway->getSensorNetwork()->getSenderAddress(); + if ( packet->getType() == MQTTSN_ENCAPSULATED ) { - fwd = _gateway->getForwarderList()->getForwarder(_sensorNetwork->getSenderAddress()); + fwd = _gateway->getAdapterManager()->getForwarderList()->getForwarder(senderAddr); - if ( fwd == 0 ) - { - log(0, packet); - WRITELOG("%s Forwarder %s is not authorized.%s\n", ERRMSG_HEADER, _sensorNetwork->getSenderAddress()->sprint(buf), ERRMSG_FOOTER); - delete packet; - continue; - } - else - { - MQTTSNString fwdName; - fwdName.lenstring.data = const_cast( fwd->getName() ); - fwdName.lenstring.len = strlen(fwdName.lenstring.data); - log(0, packet, &fwdName); + if ( fwd != nullptr ) + { + MQTTSNString fwdName = MQTTSNString_initializer; + fwdName.cstring = const_cast( fwd->getName() ); + log(0, packet, &fwdName); - MQTTSNGWEncapsulatedPacket encap; - encap.desirialize(packet->getPacketData(), packet->getPacketLength()); - nodeId.setId( encap.getWirelessNodeId() ); - client = fwd->getClient(&nodeId); - delete packet; - packet = encap.getMQTTSNPacket(); - } + /* get the packet from the encapsulation message */ + MQTTSNGWEncapsulatedPacket encap; + encap.desirialize(packet->getPacketData(), packet->getPacketLength()); + nodeId.setId( encap.getWirelessNodeId() ); + client = fwd->getClient(&nodeId); + packet = encap.getMQTTSNPacket(); + } } else { - /* get client from the ClientList of Gateway by sensorNetAddress. */ - client = _gateway->getClientList()->getClient(_sensorNetwork->getSenderAddress()); + /* Check the client belonging to QoS-1Proxy ? */ + + if ( qosm1Proxy->isActive() ) + { + const char* clientName = qosm1Proxy->getClientId(senderAddr); + + if ( clientName ) + { + if ( !packet->isQoSMinusPUBLISH() ) + { + client = qosm1Proxy->getClient(); + 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; + continue; + } + } + } } + client = _gateway->getClientList()->getClient(senderAddr); if ( client ) { /* write log and post Event */ - log(client, packet); + log(client, packet, 0); ev = new Event(); ev->setClientRecvEvent(client,packet); - _gateway->getPacketEventQue()->post(ev); + packetEventQue->post(ev); } else { @@ -149,19 +167,19 @@ void ClientRecvTask::run() if ( !packet->getCONNECT(&data) ) { log(0, packet, &data.clientID); - WRITELOG("%s CONNECT message form %s is incorrect.%s\n", ERRMSG_HEADER, _sensorNetwork->getSenderAddress()->sprint(buf), ERRMSG_FOOTER); + WRITELOG("%s CONNECT message form %s is incorrect.%s\n", ERRMSG_HEADER, senderAddr->sprint(buf), ERRMSG_FOOTER); delete packet; 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); @@ -171,12 +189,12 @@ void ClientRecvTask::run() if ( client ) { /* Client exists. Set SensorNet Address of it. */ - client->setClientAddress(_sensorNetwork->getSenderAddress()); + client->setClientAddress(senderAddr); } else { /* create a new client */ - client = _gateway->getClientList()->createClient(_sensorNetwork->getSenderAddress(), &data.clientID, false, false); + client = clientList->createClient(senderAddr, &data.clientID, isAggrActive); } } @@ -184,7 +202,7 @@ void ClientRecvTask::run() if (!client) { - WRITELOG("%s Client(%s) was rejected. CONNECT message has been discarded.%s\n", ERRMSG_HEADER, _sensorNetwork->getSenderAddress()->sprint(buf), ERRMSG_FOOTER); + WRITELOG("%s Client(%s) was rejected. CONNECT message has been discarded.%s\n", ERRMSG_HEADER, senderAddr->sprint(buf), ERRMSG_FOOTER); delete packet; continue; } @@ -192,23 +210,20 @@ void ClientRecvTask::run() /* post Client RecvEvent */ ev = new Event(); ev->setClientRecvEvent(client, packet); - _gateway->getPacketEventQue()->post(ev); + packetEventQue->post(ev); } - else + else { - log(client, packet); - WRITELOG("%s Client(%s) is not connecting. message has been discarded.%s\n", ERRMSG_HEADER, _sensorNetwork->getSenderAddress()->sprint(buf), ERRMSG_FOOTER); - delete packet; - - /* Send DISCONNECT */ - if ( fwd == 0 ) - { - packet = new MQTTSNPacket(); - packet->setDISCONNECT(0); - ev = new Event(); - ev->setClientSendEvent(_sensorNetwork->getSenderAddress(), packet); - _gateway->getClientSendQue()->post(ev); - } + log(client, packet, 0); + if ( packet->getType() == MQTTSN_ENCAPSULATED ) + { + WRITELOG("%s Forwarder(%s) is not declared by ClientList file. message has been discarded.%s\n", ERRMSG_HEADER, _sensorNetwork->getSenderAddress()->sprint(buf), ERRMSG_FOOTER); + } + else + { + WRITELOG("%s Client(%s) is not connecting. message has been discarded.%s\n", ERRMSG_HEADER, senderAddr->sprint(buf), ERRMSG_FOOTER); + } + delete packet; } } } @@ -216,16 +231,22 @@ void ClientRecvTask::run() void ClientRecvTask::log(Client* client, MQTTSNPacket* packet, MQTTSNString* id) { - char pbuf[SIZE_OF_LOG_PACKET * 3]; const char* clientId; char cstr[MAX_CLIENTID_LENGTH + 1]; - char msgId[6]; if ( id ) { - memset((void*)cstr, 0, id->lenstring.len + 1); - strncpy(cstr, id->lenstring.data, id->lenstring.len) ; - clientId = cstr; + if ( id->cstring ) + { + strncpy(cstr, id->cstring, strlen(id->cstring) ); + clientId = cstr; + } + else + { + memset((void*)cstr, 0, id->lenstring.len + 1); + strncpy(cstr, id->lenstring.data, id->lenstring.len ); + clientId = cstr; + } } else if ( client ) { @@ -236,40 +257,48 @@ void ClientRecvTask::log(Client* client, MQTTSNPacket* packet, MQTTSNString* id) clientId = UNKNOWNCL; } - switch (packet->getType()) - { - case MQTTSN_SEARCHGW: - WRITELOG(FORMAT_Y_G_G_NL, currentDateTime(), packet->getName(), LEFTARROW, CLIENT, packet->print(pbuf)); - break; - case MQTTSN_CONNECT: - case MQTTSN_PINGREQ: - WRITELOG(FORMAT_Y_G_G_NL, currentDateTime(), packet->getName(), LEFTARROW, clientId, packet->print(pbuf)); - break; - case MQTTSN_DISCONNECT: - case MQTTSN_WILLTOPICUPD: - case MQTTSN_WILLMSGUPD: - case MQTTSN_WILLTOPIC: - case MQTTSN_WILLMSG: - WRITELOG(FORMAT_Y_G_G, currentDateTime(), packet->getName(), LEFTARROW, clientId, packet->print(pbuf)); - break; - case MQTTSN_PUBLISH: - case MQTTSN_REGISTER: - case MQTTSN_SUBSCRIBE: - case MQTTSN_UNSUBSCRIBE: - WRITELOG(FORMAT_G_MSGID_G_G_NL, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROW, clientId, packet->print(pbuf)); - break; - case MQTTSN_REGACK: - case MQTTSN_PUBACK: - case MQTTSN_PUBREC: - case MQTTSN_PUBREL: - case MQTTSN_PUBCOMP: - WRITELOG(FORMAT_G_MSGID_G_G, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROW, clientId, packet->print(pbuf)); - break; - case MQTTSN_ENCAPSULATED: - WRITELOG(FORMAT_Y_G_G, currentDateTime(), packet->getName(), LEFTARROW, clientId, packet->print(pbuf)); - break; - default: - WRITELOG(FORMAT_W_NL, currentDateTime(), packet->getName(), LEFTARROW, clientId, packet->print(pbuf)); - break; - } + log(clientId, packet); +} + +void ClientRecvTask::log(const char* clientId, MQTTSNPacket* packet) +{ + char pbuf[SIZE_OF_LOG_PACKET * 3]; + char msgId[6]; + + switch (packet->getType()) + { + case MQTTSN_SEARCHGW: + WRITELOG(FORMAT_Y_G_G_NL, currentDateTime(), packet->getName(), LEFTARROW, CLIENT, packet->print(pbuf)); + break; + case MQTTSN_CONNECT: + case MQTTSN_PINGREQ: + WRITELOG(FORMAT_Y_G_G_NL, currentDateTime(), packet->getName(), LEFTARROW, clientId, packet->print(pbuf)); + break; + case MQTTSN_DISCONNECT: + case MQTTSN_WILLTOPICUPD: + case MQTTSN_WILLMSGUPD: + case MQTTSN_WILLTOPIC: + case MQTTSN_WILLMSG: + WRITELOG(FORMAT_Y_G_G, currentDateTime(), packet->getName(), LEFTARROW, clientId, packet->print(pbuf)); + break; + case MQTTSN_PUBLISH: + case MQTTSN_REGISTER: + case MQTTSN_SUBSCRIBE: + case MQTTSN_UNSUBSCRIBE: + WRITELOG(FORMAT_G_MSGID_G_G_NL, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROW, clientId, packet->print(pbuf)); + break; + case MQTTSN_REGACK: + case MQTTSN_PUBACK: + case MQTTSN_PUBREC: + case MQTTSN_PUBREL: + case MQTTSN_PUBCOMP: + WRITELOG(FORMAT_G_MSGID_G_G, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROW, clientId, packet->print(pbuf)); + break; + case MQTTSN_ENCAPSULATED: + WRITELOG(FORMAT_Y_G_G, currentDateTime(), packet->getName(), LEFTARROW, clientId, packet->print(pbuf)); + break; + default: + WRITELOG(FORMAT_W_NL, currentDateTime(), packet->getName(), LEFTARROW, clientId, packet->print(pbuf)); + break; + } } diff --git a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.h b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.h index 295c0ee..30a63e9 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.h +++ b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.h @@ -21,6 +21,7 @@ namespace MQTTSNGW { +class AdapterManager; /*===================================== Class ClientRecvTask @@ -28,14 +29,16 @@ 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 = 0); + 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 87de924..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,22 +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); - rc = packet->unicast(_sensorNetwork, client->getSensorNetAddress()); - } + rc = adpMgr->unicastToClient(client, packet, this); } else if (ev->getEventType() == EtBroadcast) { @@ -135,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 06b8d43..33b3ef8 100644 --- a/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp @@ -90,7 +90,10 @@ void MQTTSNConnectionHandler::handleConnect(Client* client, MQTTSNPacket* packet //* clear ConnectData of Client */ Connect* connectData = client->getConnectData(); memset(connectData, 0, sizeof(Connect)); - client->disconnected(); + if ( !client->isAdapter() ) + { + client->disconnected(); + } Topics* topics = client->getTopics(); @@ -101,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; @@ -153,7 +156,7 @@ void MQTTSNConnectionHandler::handleWilltopic(Client* client, MQTTSNPacket* pack { int willQos; uint8_t willRetain; - MQTTSNString willTopic; + MQTTSNString willTopic = MQTTSNString_initializer; if ( packet->getWILLTOPIC(&willQos, &willRetain, &willTopic) == 0 ) { @@ -187,7 +190,7 @@ void MQTTSNConnectionHandler::handleWillmsg(Client* client, MQTTSNPacket* packet return; } - MQTTSNString willmsg; + MQTTSNString willmsg = MQTTSNString_initializer; Connect* connectData = client->getConnectData(); if( client->isConnectSendable() ) @@ -288,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 8f7f837..0cc22b6 100644 --- a/MQTTSNGateway/src/MQTTSNGWDefines.h +++ b/MQTTSNGateway/src/MQTTSNGWDefines.h @@ -40,11 +40,15 @@ 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) #define SIZE_OF_LOG_PACKET (500) // Length of the packet log in bytes +#define QOSM1_PROXY_KEEPALIVE_DURATION 900 // Secs +#define QOSM1_PROXY_RESPONSE_DURATION 10 // Secs +#define QOSM1_PROXY_MAX_RETRY_CNT 3 /*================================= * Data Type ==================================*/ 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 0bad175..5fa2a49 100644 --- a/MQTTSNGateway/src/MQTTSNGWForwarder.cpp +++ b/MQTTSNGateway/src/MQTTSNGWForwarder.cpp @@ -13,19 +13,21 @@ * Contributors: * Tomoaki Yamaguchi - initial API and implementation and/or initial documentation **************************************************************************************/ -#include #include "MQTTSNGWForwarder.h" +#include "SensorNetwork.h" + +#include using namespace MQTTSNGW; using namespace std; -/* - * Class ForwarderList - */ +/*===================================== + Class ForwarderList + =====================================*/ ForwarderList::ForwarderList() { - _head = 0; + _head = nullptr; } ForwarderList::~ForwarderList() @@ -42,6 +44,22 @@ ForwarderList::~ForwarderList() } } + +void ForwarderList::initialize(Gateway* gw) +{ + char param[MQTTSNGW_PARAM_MAX]; + string fileName; + + if (gw->getParam("Forwarder", param) == 0 ) + { + if (!strcasecmp(param, "YES") ) + { + gw->getClientList()->setClientList(FORWARDER_TYPE); + } + } +} + + Forwarder* ForwarderList::getForwarder(SensorNetAddress* addr) { Forwarder* p = _head; @@ -56,61 +74,10 @@ Forwarder* ForwarderList::getForwarder(SensorNetAddress* addr) return p; } -bool ForwarderList::setFowerder(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) - { - addForwarder(&netAddr, &id); - } - else - { - WRITELOG("Invalid address %s\n", data.c_str()); - return false; - } - } - fclose(fp); - } - else - { - WRITELOG("Can not open the forwarders List. %s\n", fileName); - return false; - } - return true; -} - - -Forwarder* ForwarderList::addForwarder(SensorNetAddress* addr, string* forwarderId) +Forwarder* ForwarderList::addForwarder(SensorNetAddress* addr, MQTTSNString* forwarderId) { Forwarder* fdr = new Forwarder(addr, forwarderId); - if ( _head == 0 ) + if ( _head == nullptr ) { _head = fdr; } @@ -119,7 +86,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; @@ -135,30 +102,30 @@ 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) +Forwarder::Forwarder(SensorNetAddress* addr, MQTTSNString* forwarderId) { - _forwarderName = *forwarderId; + _forwarderName = string(forwarderId->cstring); _sensorNetAddr = *addr; - _headClient = 0; - _next = 0; + _headClient = nullptr; + _next = nullptr; } Forwarder::~Forwarder(void) { if ( _headClient ) { - ForwardedClient* p = _headClient; + ForwarderElement* p = _headClient; while ( p ) { - ForwardedClient* next = p->_next; + ForwarderElement* next = p->_next; delete p; p = next; } @@ -172,12 +139,12 @@ const char* Forwarder::getId(void) void Forwarder::addClient(Client* client, WirelessNodeId* id) { - ForwardedClient* p = _headClient; - ForwardedClient* prev = 0; + ForwarderElement* p = _headClient; + ForwarderElement* prev = nullptr; client->setForwarder(this); - if ( p != 0 ) + if ( p != nullptr ) { while ( p ) { @@ -191,7 +158,7 @@ void Forwarder::addClient(Client* client, WirelessNodeId* id) } } - ForwardedClient* fclient = new ForwardedClient(); + ForwarderElement* fclient = new ForwarderElement(); fclient->setClient(client); fclient->setWirelessNodeId(id); @@ -208,9 +175,9 @@ void Forwarder::addClient(Client* client, WirelessNodeId* id) Client* Forwarder::getClient(WirelessNodeId* id) { - Client* cl = 0; + Client* cl = nullptr; _mutex.lock(); - ForwardedClient* p = _headClient; + ForwarderElement* p = _headClient; while ( p ) { if ( *(p->_wirelessNodeId) == *id ) @@ -234,9 +201,9 @@ const char* Forwarder::getName(void) WirelessNodeId* Forwarder::getWirelessNodeId(Client* client) { - WirelessNodeId* nodeId = 0; + WirelessNodeId* nodeId = nullptr; _mutex.lock(); - ForwardedClient* p = _headClient; + ForwarderElement* p = _headClient; while ( p ) { if ( p->_client == client ) @@ -255,9 +222,9 @@ WirelessNodeId* Forwarder::getWirelessNodeId(Client* client) void Forwarder::eraseClient(Client* client) { - ForwardedClient* prev = 0; + ForwarderElement* prev = nullptr; _mutex.lock(); - ForwardedClient* p = _headClient; + ForwarderElement* p = _headClient; while ( p ) { @@ -291,14 +258,14 @@ SensorNetAddress* Forwarder::getSensorNetAddr(void) * Class ForwardedClient */ -ForwardedClient::ForwardedClient() +ForwarderElement::ForwarderElement() : _client{0} , _wirelessNodeId{0} , _next{0} { } -ForwardedClient::~ForwardedClient() +ForwarderElement::~ForwarderElement() { if (_wirelessNodeId) { @@ -306,14 +273,14 @@ ForwardedClient::~ForwardedClient() } } -void ForwardedClient::setClient(Client* client) +void ForwarderElement::setClient(Client* client) { _client = client; } -void ForwardedClient::setWirelessNodeId(WirelessNodeId* id) +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 db6d099..a7279d2 100644 --- a/MQTTSNGateway/src/MQTTSNGWForwarder.h +++ b/MQTTSNGateway/src/MQTTSNGWForwarder.h @@ -18,39 +18,47 @@ #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 ForwardedClient +/*===================================== + Class ForwarderElement + =====================================*/ +class ForwarderElement { friend class Forwarder; public: - ForwardedClient(); - ~ForwardedClient(); + ForwarderElement(); + ~ForwarderElement(); + void setClient(Client* client); void setWirelessNodeId(WirelessNodeId* id); private: Client* _client; WirelessNodeId* _wirelessNodeId; - ForwardedClient* _next; + ForwarderElement* _next; }; - +/*===================================== + Class Forwarder + =====================================*/ class Forwarder { friend class ForwarderList; public: - Forwarder(); - Forwarder(SensorNetAddress* addr, string* forwarderId); + Forwarder(void); + Forwarder(SensorNetAddress* addr, MQTTSNString* forwarderId); ~Forwarder(); + void initialize(void); const char* getId(void); void addClient(Client* client, WirelessNodeId* id); Client* getClient(WirelessNodeId* id); @@ -62,20 +70,23 @@ public: private: string _forwarderName; SensorNetAddress _sensorNetAddr; - ForwardedClient* _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); + Forwarder* addForwarder(SensorNetAddress* addr, MQTTSNString* forwarderId); private: Forwarder* _head; 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 74c00fb..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) @@ -101,6 +119,17 @@ int MQTTSNPacket::getType(void) return _buf[p]; } +bool MQTTSNPacket::isQoSMinusPUBLISH(void) +{ + if ( _bufLen == 0 ) + { + return false;; + } + int value = 0; + int p = MQTTSNPacket_decode(_buf, _bufLen, &value); + return ( (_buf[p] == MQTTSN_PUBLISH) && ((_buf[p + 1] & 0x60 ) == 0x60 )); +} + unsigned char* MQTTSNPacket::getPacketData(void) { return _buf; @@ -119,7 +148,8 @@ const char* MQTTSNPacket::getName() int MQTTSNPacket::setADVERTISE(uint8_t gatewayid, uint16_t duration) { unsigned char buf[5]; - int len = MQTTSNSerialize_advertise(buf, 5, (unsigned char) gatewayid, + int buflen = sizeof(buf); + int len = MQTTSNSerialize_advertise(buf, buflen, (unsigned char) gatewayid, (unsigned short) duration); return desirialize(buf, len); } @@ -127,44 +157,55 @@ int MQTTSNPacket::setADVERTISE(uint8_t gatewayid, uint16_t duration) int MQTTSNPacket::setGWINFO(uint8_t gatewayId) { unsigned char buf[3]; - int len = MQTTSNSerialize_gwinfo(buf, 3, (unsigned char) gatewayId, 0, 0); + int buflen = sizeof(buf); + int len = MQTTSNSerialize_gwinfo(buf, buflen, (unsigned char) gatewayId, 0, 0); return desirialize(buf, len); } int MQTTSNPacket::setConnect(void) { unsigned char buf[40]; + int buflen = sizeof(buf); MQTTSNPacket_connectData data; data.clientID.cstring = (char*)"client01"; - int len = MQTTSNSerialize_connect(buf, 40, &data); + int len = MQTTSNSerialize_connect(buf, buflen, &data); 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]; - int len = MQTTSNSerialize_connack(buf, 3, (int) returnCode); + int buflen = sizeof(buf); + int len = MQTTSNSerialize_connack(buf, buflen, (int) returnCode); return desirialize(buf, len); } int MQTTSNPacket::setWILLTOPICREQ(void) { unsigned char buf[2]; - int len = MQTTSNSerialize_willtopicreq(buf, 2); + int buflen = sizeof(buf); + int len = MQTTSNSerialize_willtopicreq(buf, buflen); return desirialize(buf, len); } int MQTTSNPacket::setWILLMSGREQ(void) { unsigned char buf[2]; - int len = MQTTSNSerialize_willmsgreq(buf, 2); + int buflen = sizeof(buf); + int len = MQTTSNSerialize_willmsgreq(buf, buflen); return desirialize(buf, len); } int MQTTSNPacket::setREGISTER(uint16_t topicId, uint16_t msgId, MQTTSNString* topicName) { unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE]; - int len = MQTTSNSerialize_register(buf, MQTTSNGW_MAX_PACKET_SIZE, (unsigned short) topicId, (unsigned short) msgId, + int buflen = sizeof(buf); + int len = MQTTSNSerialize_register(buf, buflen, (unsigned short) topicId, (unsigned short) msgId, topicName); return desirialize(buf, len); } @@ -172,7 +213,8 @@ int MQTTSNPacket::setREGISTER(uint16_t topicId, uint16_t msgId, MQTTSNString* to int MQTTSNPacket::setREGACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode) { unsigned char buf[7]; - int len = MQTTSNSerialize_regack(buf, 7, (unsigned short) topicId, (unsigned short) msgId, + int buflen = sizeof(buf); + int len = MQTTSNSerialize_regack(buf, buflen, (unsigned short) topicId, (unsigned short) msgId, (unsigned char) returnCode); return desirialize(buf, len); } @@ -181,7 +223,8 @@ int MQTTSNPacket::setPUBLISH(uint8_t dup, int qos, uint8_t retained, uint16_t ms uint8_t* payload, uint16_t payloadlen) { unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE]; - int len = MQTTSNSerialize_publish(buf, MQTTSNGW_MAX_PACKET_SIZE, (unsigned char) dup, qos, (unsigned char) retained, + int buflen = sizeof(buf); + int len = MQTTSNSerialize_publish(buf, buflen, (unsigned char) dup, qos, (unsigned char) retained, (unsigned short) msgId, topic, (unsigned char*) payload, (int) payloadlen); return desirialize(buf, len); } @@ -189,7 +232,8 @@ int MQTTSNPacket::setPUBLISH(uint8_t dup, int qos, uint8_t retained, uint16_t ms int MQTTSNPacket::setPUBACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode) { unsigned char buf[7]; - int len = MQTTSNSerialize_puback(buf, 7, (unsigned short) topicId, (unsigned short) msgId, + int buflen = sizeof(buf); + int len = MQTTSNSerialize_puback(buf, buflen, (unsigned short) topicId, (unsigned short) msgId, (unsigned char) returnCode); return desirialize(buf, len); } @@ -197,28 +241,32 @@ int MQTTSNPacket::setPUBACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode int MQTTSNPacket::setPUBREC(uint16_t msgId) { unsigned char buf[4]; - int len = MQTTSNSerialize_pubrec(buf, 4, (unsigned short) msgId); + int buflen = sizeof(buf); + int len = MQTTSNSerialize_pubrec(buf, buflen, (unsigned short) msgId); return desirialize(buf, len); } int MQTTSNPacket::setPUBREL(uint16_t msgId) { unsigned char buf[4]; - int len = MQTTSNSerialize_pubrel(buf, 4, (unsigned short) msgId); + int buflen = sizeof(buf); + int len = MQTTSNSerialize_pubrel(buf, buflen, (unsigned short) msgId); return desirialize(buf, len); } int MQTTSNPacket::setPUBCOMP(uint16_t msgId) { unsigned char buf[4]; - int len = MQTTSNSerialize_pubcomp(buf, 4, (unsigned short) msgId); + int buflen = sizeof(buf); + int len = MQTTSNSerialize_pubcomp(buf, buflen, (unsigned short) msgId); return desirialize(buf, len); } int MQTTSNPacket::setSUBACK(int qos, uint16_t topicId, uint16_t msgId, uint8_t returnCode) { unsigned char buf[8]; - int len = MQTTSNSerialize_suback(buf, 8, qos, (unsigned short) topicId, + int buflen = sizeof(buf); + int len = MQTTSNSerialize_suback(buf, buflen, qos, (unsigned short) topicId, (unsigned short) msgId, (unsigned char) returnCode); return desirialize(buf, len); } @@ -226,38 +274,59 @@ int MQTTSNPacket::setSUBACK(int qos, uint16_t topicId, uint16_t msgId, uint8_t r int MQTTSNPacket::setUNSUBACK(uint16_t msgId) { unsigned char buf[4]; - int len = MQTTSNSerialize_unsuback(buf, 4, (unsigned short) msgId); + int buflen = sizeof(buf); + int len = MQTTSNSerialize_unsuback(buf, buflen, (unsigned short) msgId); return desirialize(buf, len); } int MQTTSNPacket::setPINGRESP(void) { unsigned char buf[32]; - int len = MQTTSNSerialize_pingresp(buf, 32); + int buflen = sizeof(buf); + int len = MQTTSNSerialize_pingresp(buf, buflen); return desirialize(buf, len); } int MQTTSNPacket::setDISCONNECT(uint16_t duration) { unsigned char buf[4]; - int len = MQTTSNSerialize_disconnect(buf, 4, (int) duration); + int buflen = sizeof(buf); + int len = MQTTSNSerialize_disconnect(buf, buflen, (int) duration); return desirialize(buf, len); } int MQTTSNPacket::setWILLTOPICRESP(uint8_t returnCode) { unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE]; - int len = MQTTSNSerialize_willtopicresp(buf, MQTTSNGW_MAX_PACKET_SIZE, (int) returnCode); + int buflen = sizeof(buf); + int len = MQTTSNSerialize_willtopicresp(buf, buflen, (int) returnCode); return desirialize(buf, len); } int MQTTSNPacket::setWILLMSGRESP(uint8_t returnCode) { unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE]; - int len = MQTTSNSerialize_willmsgresp(buf, MQTTSNGW_MAX_PACKET_SIZE, (int) returnCode); + int buflen = sizeof(buf); + int len = MQTTSNSerialize_willmsgresp(buf, buflen, (int) returnCode); return desirialize(buf, len); } +int MQTTSNPacket::setCONNECT(MQTTSNPacket_connectData* options) +{ + unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE]; + int buflen = sizeof(buf); + int len = MQTTSNSerialize_connect(buf, buflen, options); + return desirialize(buf, len); +} + +int MQTTSNPacket::setPINGREQ(MQTTSNString* clientId) +{ + unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE]; + int buflen = sizeof(buf); + int len = MQTTSNSerialize_pingreq( buf, buflen, *clientId); + return desirialize(buf, len); +} + int MQTTSNPacket::getSERCHGW(uint8_t* radius) { return MQTTSNDeserialize_searchgw((unsigned char*) radius, (unsigned char*) _buf, _bufLen); @@ -409,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 5cd7578..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); @@ -59,6 +60,9 @@ public: int setWILLTOPICRESP(uint8_t returnCode); int setWILLMSGRESP(uint8_t returnCode); + int setCONNECT(MQTTSNPacket_connectData* options); + int setPINGREQ(MQTTSNString* clientId); + int getSERCHGW(uint8_t* radius); int getCONNECT(MQTTSNPacket_connectData* option); int getCONNACK(uint8_t* returnCode); @@ -76,7 +80,13 @@ public: int getDISCONNECT(uint16_t* duration); 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 02dd9ab..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); @@ -113,6 +126,9 @@ void PacketHandleTask::run() _mqttsnConnection->sendADVERTISE(); _advertiseTimer.start(_gateway->getGWParams()->keepAlive * 1000UL); } + + /*------ Check Adapters Connect or PINGREQ ------*/ + adpMgr->checkConnection(); } /*------ Handle SEARCHGW Message ---------*/ @@ -130,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 4f0adc4..53bbb43 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; @@ -43,30 +44,30 @@ void MQTTSNPublishHandler::handlePublish(Client* client, MQTTSNPacket* packet) uint8_t* payload; MQTTSN_topicid topicid; int payloadlen; - Publish pub; + Publish pub = {0, 0, 0, 0, 0, 0}; + char shortTopic[2]; - if ( !client->isActive() ) + if ( !_gateway->getAdapterManager()->getQoSm1Proxy()->isActive() ) { - /* 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 ( client->isQoSm1() ) + { + _gateway->getAdapterManager()->getQoSm1Proxy()->savePacket(client, packet); + + return nullptr; + } } 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; + 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 ) { @@ -79,7 +80,13 @@ void MQTTSNPublishHandler::handlePublish(Client* client, MQTTSNPacket* packet) { topic = client->getTopics()->getTopicById(&topicid); - if( !topic && msgId && qos > 0 ) + if( !topic && qos == 3 ) + { + WRITELOG("%s Invali TopicId.%s %s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); + return nullptr; + } + + if( !topic && msgId && qos > 0 && qos < 3 ) { /* Reply PubAck with INVALID_TOPIC_ID to the client */ MQTTSNPacket* pubAck = new MQTTSNPacket(); @@ -87,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 ) { @@ -96,7 +103,7 @@ void MQTTSNPublishHandler::handlePublish(Client* client, MQTTSNPacket* packet) } } /* Save a msgId & a TopicId pare for PUBACK */ - if( msgId && qos > 0 ) + if( msgId && qos > 0 && qos < 3) { client->setWaitedPubTopicId(msgId, topicid.data.id, topicid.type); } @@ -106,9 +113,18 @@ 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); + + if ( _gateway->getAdapterManager()->isAggregaterActive() && client->isAggregated() ) + { + return publish; + } + else + { + Event* ev1 = new Event(); + ev1->setBrokerSendEvent(client, publish); + _gateway->getBrokerSendQue()->post(ev1); + return nullptr; + } } void MQTTSNPublishHandler::handlePuback(Client* client, MQTTSNPacket* packet) @@ -126,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) { @@ -161,7 +180,7 @@ void MQTTSNPublishHandler::handleRegister(Client* client, MQTTSNPacket* packet) { uint16_t id; uint16_t msgId; - MQTTSNString topicName; + MQTTSNString topicName = MQTTSNString_initializer;; MQTTSN_topicid topicid; if ( client->isActive() || client->isAwake()) @@ -199,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(); @@ -219,3 +238,48 @@ 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); + } +} 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/MQTTSNGWQoSm1Proxy.cpp b/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.cpp new file mode 100644 index 0000000..50ff56c --- /dev/null +++ b/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.cpp @@ -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 + **************************************************************************************/ + +#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(QOSM1PROXY_TYPE); + + /* initialize Adapter */ + string name = string(_gateway->getGWParams()->gatewayName) + "QoS-1"; + setup(name.c_str(), 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 04c55ce..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.0" +#define PAHO_GATEWAY_VERSION "1.3.0" #endif /* MQTTSNGWVERSION_H_IN_ */ diff --git a/MQTTSNGateway/src/MQTTSNGateway.cpp b/MQTTSNGateway/src/MQTTSNGateway.cpp index c6029ce..25ab87f 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,29 +28,15 @@ char* currentDateTime(void); /*===================================== Class Gateway =====================================*/ -Gateway::Gateway() +MQTTSNGW::Gateway* theGateway = nullptr; + +Gateway::Gateway(void) { - theMultiTaskProcess = this; - theProcess = this; - _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; - _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() @@ -101,23 +89,40 @@ Gateway::~Gateway() { free(_params.configName); } - if ( _params.predefinedTopicFileName ) + + if ( _params.qosMinusClientListName ) { - free(_params.predefinedTopicFileName); + free(_params.qosMinusClientListName); } - if ( _params.forwarderListName ) + + if ( _adapterManager ) { - free(_params.forwarderListName); + 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; + theGateway = this; + 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); @@ -163,6 +168,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) { @@ -176,7 +186,6 @@ void Gateway::initialize(int argc, char** argv) } _params.keepAlive = DEFAULT_KEEP_ALIVE_TIME; - if (getParam("KeepAlive", param) == 0) { _params.keepAlive = atoi(param); @@ -201,79 +210,23 @@ void Gateway::initialize(int argc, char** argv) { if (!strcasecmp(param, "YES")) { - 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; } } + /* ClientList and Adapters Initialize */ + _adapterManager->initialize(); + bool aggregate = _adapterManager->isAggregaterActive(); + _clientList->initialize(aggregate); - 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()); - } - else - { - _params.predefinedTopicFileName = 0; - } - } - - 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()); - } - else - { - _params.forwarderListName = 0; - } - } - - fileName = *getConfigDirName() + *getConfigFileName(); - _params.configName = strdup(fileName.c_str()); + /* Setup predefined topics */ + _clientList->setPredefinedTopics(aggregate); } void Gateway::run(void) { + /* write prompts */ _lightIndicator.redLight(true); WRITELOG("\n%s", PAHO_COPYRIGHT4); WRITELOG("\n%s\n", PAHO_COPYRIGHT0); @@ -284,26 +237,26 @@ 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() ) + + if ( _params.clientListName ) { - WRITELOG(" ClientList: %s\n", _params.clientListName); + WRITELOG(" ClientList: %s\n", _params.clientListName); } + if ( _params.predefinedTopicFileName ) { WRITELOG(" PreDefFile: %s\n", _params.predefinedTopicFileName); } - if ( _params.forwarderListName ) - { - WRITELOG(" Forwarders: %s\n", _params.forwarderListName); - } + 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", _params.privateKey); + WRITELOG(" PrivateKey: %s\n\n\n", _params.privateKey); + + /* Run Tasks until CTRL+C entred */ MultiTaskProcess::run(); /* stop Tasks */ @@ -341,12 +294,7 @@ EventQue* Gateway::getBrokerSendQue() ClientList* Gateway::getClientList() { - return &_clientList; -} - -ForwarderList* Gateway::getForwarderList(void) -{ - return &_forwarderList; + return _clientList; } SensorNetwork* Gateway::getSensorNetwork() @@ -364,6 +312,18 @@ GatewayParams* Gateway::getGWParams(void) return &_params; } +AdapterManager* Gateway::getAdapterManager(void) +{ + return _adapterManager; +} + +bool Gateway::hasSecureConnection(void) +{ + return ( _params.certKey + && _params.privateKey + && _params.rootCApath + && _params.rootCAfile ); +} /*===================================== Class EventQue =====================================*/ @@ -390,9 +350,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 ) { @@ -460,11 +420,7 @@ int EventQue::size() =====================================*/ Event::Event() { - _eventType = Et_NA; - _client = 0; - _sensorNetAddr = 0; - _mqttSNPacket = 0; - _mqttGWPacket = 0; + } Event::~Event() @@ -560,3 +516,5 @@ MQTTGWPacket* Event::getMQTTGWPacket(void) { return _mqttGWPacket; } + + diff --git a/MQTTSNGateway/src/MQTTSNGateway.h b/MQTTSNGateway/src/MQTTSNGateway.h index d219d6f..b4c0f5c 100644 --- a/MQTTSNGateway/src/MQTTSNGateway.h +++ b/MQTTSNGateway/src/MQTTSNGateway.h @@ -16,10 +16,10 @@ #ifndef MQTTSNGATEWAY_H_ #define MQTTSNGATEWAY_H_ -#include "MQTTSNGWClient.h" -#include "MQTTSNGWForwarder.h" +#include #include "MQTTSNGWProcess.h" #include "MQTTSNPacket.h" +#include "MQTTSNGWClient.h" namespace MQTTSNGW { @@ -74,6 +74,8 @@ namespace MQTTSNGW /*===================================== Class Event ====================================*/ +class Client; + enum EventType{ Et_NA = 0, EtStop, @@ -106,13 +108,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 ====================================*/ @@ -133,37 +136,47 @@ 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; -}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* qosMinusClientListName {nullptr}; + bool clientAuthentication {false}; +}; + + /*===================================== Class Gateway =====================================*/ +class AdapterManager; +class ClientList; + class Gateway: public MultiTaskProcess{ public: - Gateway(); + Gateway(void); ~Gateway(); virtual void initialize(int argc, char** argv); void run(void); @@ -172,20 +185,22 @@ public: EventQue* getClientSendQue(void); EventQue* getBrokerSendQue(void); ClientList* getClientList(void); - ForwarderList* getForwarderList(void); SensorNetwork* getSensorNetwork(void); LightIndicator* getLightIndicator(void); GatewayParams* getGWParams(void); + AdapterManager* getAdapterManager(void); + int getParam(const char* parameter, char* value); + bool hasSecureConnection(void); private: - ClientList _clientList; - 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());