From 69b229daae9c2229999e4c834afb83d5062662b6 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 16 Feb 2021 15:51:54 +0900 Subject: [PATCH 01/67] Change TAB to 4spaces Signed-off-by: tomoaki --- MQTTSNGateway/src/MQTTGWConnectionHandler.cpp | 123 +- MQTTSNGateway/src/MQTTGWConnectionHandler.h | 12 +- MQTTSNGateway/src/MQTTGWPacket.cpp | 829 +++++---- MQTTSNGateway/src/MQTTGWPacket.h | 250 +-- MQTTSNGateway/src/MQTTGWPublishHandler.cpp | 425 +++-- MQTTSNGateway/src/MQTTGWPublishHandler.h | 24 +- MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp | 108 +- MQTTSNGateway/src/MQTTGWSubscribeHandler.h | 14 +- .../src/MQTTSNAggregateConnectionHandler.cpp | 230 +-- .../src/MQTTSNAggregateConnectionHandler.h | 16 +- MQTTSNGateway/src/MQTTSNGWAdapter.cpp | 257 +-- MQTTSNGateway/src/MQTTSNGWAdapter.h | 39 +- MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp | 205 +- MQTTSNGateway/src/MQTTSNGWAdapterManager.h | 18 +- .../src/MQTTSNGWAggregateTopicTable.cpp | 406 ++-- .../src/MQTTSNGWAggregateTopicTable.h | 49 +- MQTTSNGateway/src/MQTTSNGWAggregater.cpp | 118 +- MQTTSNGateway/src/MQTTSNGWAggregater.h | 46 +- MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp | 324 ++-- MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.h | 17 +- MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp | 245 +-- MQTTSNGateway/src/MQTTSNGWBrokerSendTask.h | 24 +- MQTTSNGateway/src/MQTTSNGWClient.cpp | 618 ++++--- MQTTSNGateway/src/MQTTSNGWClient.h | 39 +- MQTTSNGateway/src/MQTTSNGWClientList.cpp | 246 +-- MQTTSNGateway/src/MQTTSNGWClientList.h | 16 +- MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp | 406 ++-- MQTTSNGateway/src/MQTTSNGWClientRecvTask.h | 24 +- MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp | 176 +- MQTTSNGateway/src/MQTTSNGWClientSendTask.h | 16 +- .../src/MQTTSNGWConnectionHandler.cpp | 340 ++-- MQTTSNGateway/src/MQTTSNGWConnectionHandler.h | 26 +- MQTTSNGateway/src/MQTTSNGWDefines.h | 5 +- .../src/MQTTSNGWEncapsulatedPacket.cpp | 52 +- .../src/MQTTSNGWEncapsulatedPacket.h | 2 - MQTTSNGateway/src/MQTTSNGWForwarder.cpp | 66 +- MQTTSNGateway/src/MQTTSNGWForwarder.h | 17 +- MQTTSNGateway/src/MQTTSNGWLogmonitor.cpp | 26 +- MQTTSNGateway/src/MQTTSNGWLogmonitor.h | 6 +- MQTTSNGateway/src/MQTTSNGWMessageIdTable.cpp | 285 +-- MQTTSNGateway/src/MQTTSNGWMessageIdTable.h | 32 +- MQTTSNGateway/src/MQTTSNGWPacket.cpp | 673 +++---- MQTTSNGateway/src/MQTTSNGWPacket.h | 125 +- .../src/MQTTSNGWPacketHandleTask.cpp | 577 +++--- MQTTSNGateway/src/MQTTSNGWPacketHandleTask.h | 53 +- MQTTSNGateway/src/MQTTSNGWProcess.cpp | 452 ++--- MQTTSNGateway/src/MQTTSNGWProcess.h | 1647 +++++++++-------- MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp | 451 ++--- MQTTSNGateway/src/MQTTSNGWPublishHandler.h | 20 +- MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.cpp | 24 +- MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.h | 13 +- .../src/MQTTSNGWSubscribeHandler.cpp | 284 +-- MQTTSNGateway/src/MQTTSNGWSubscribeHandler.h | 17 +- MQTTSNGateway/src/MQTTSNGWTopic.cpp | 278 +-- MQTTSNGateway/src/MQTTSNGWTopic.h | 11 +- MQTTSNGateway/src/MQTTSNGWVersion.h | 2 +- MQTTSNGateway/src/MQTTSNGateway.cpp | 652 ++++--- MQTTSNGateway/src/MQTTSNGateway.h | 209 ++- MQTTSNGateway/src/mainGateway.cpp | 25 +- MQTTSNGateway/src/mainLogmonitor.cpp | 9 +- 60 files changed, 5973 insertions(+), 5726 deletions(-) diff --git a/MQTTSNGateway/src/MQTTGWConnectionHandler.cpp b/MQTTSNGateway/src/MQTTGWConnectionHandler.cpp index 0e5d85e..f3bb526 100644 --- a/MQTTSNGateway/src/MQTTGWConnectionHandler.cpp +++ b/MQTTSNGateway/src/MQTTGWConnectionHandler.cpp @@ -22,7 +22,7 @@ using namespace MQTTSNGW; MQTTGWConnectionHandler::MQTTGWConnectionHandler(Gateway* gateway) { - _gateway = gateway; + _gateway = gateway; } MQTTGWConnectionHandler::~MQTTGWConnectionHandler() @@ -30,70 +30,79 @@ MQTTGWConnectionHandler::~MQTTGWConnectionHandler() } -void MQTTGWConnectionHandler::handleConnack(Client* client, MQTTGWPacket* packet) +void MQTTGWConnectionHandler::handleConnack(Client* client, + MQTTGWPacket* packet) { - uint8_t rc = MQTT_SERVER_UNAVAILABLE; - Connack resp; - packet->getCONNACK(&resp); + uint8_t rc = MQTT_SERVER_UNAVAILABLE; + Connack resp; + packet->getCONNACK(&resp); - /* convert MQTT ReturnCode to MQTT-SN one */ - if (resp.rc == MQTT_CONNECTION_ACCEPTED) - { - rc = MQTTSN_RC_ACCEPTED; - } - else if (resp.rc == MQTT_UNACCEPTABLE_PROTOCOL_VERSION) - { - rc = MQTTSN_RC_NOT_SUPPORTED; - WRITELOG(" ClientID : %s Requested Protocol version is not supported.\n", client->getClientId()); - } - else if (resp.rc == MQTT_IDENTIFIER_REJECTED) - { - rc = MQTTSN_RC_NOT_SUPPORTED; - WRITELOG(" ClientID : %s ClientID is collect UTF-8 but not allowed by the Server.\n", - client->getClientId()); - } - else if (resp.rc == MQTT_SERVER_UNAVAILABLE) - { - rc = MQTTSN_RC_REJECTED_CONGESTED; - WRITELOG(" ClientID : %s The Network Connection has been made but the MQTT service is unavailable.\n", - client->getClientId()); - } - else if (resp.rc == MQTT_BAD_USERNAME_OR_PASSWORD) - { - rc = MQTTSN_RC_NOT_SUPPORTED; - WRITELOG(" Gateway Configuration Error: The data in the user name or password is malformed.\n"); - } - else if (resp.rc == MQTT_NOT_AUTHORIZED) - { - rc = MQTTSN_RC_NOT_SUPPORTED; - WRITELOG(" Gateway Configuration Error: The Client is not authorized to connect.\n"); - } + /* convert MQTT ReturnCode to MQTT-SN one */ + if (resp.rc == MQTT_CONNECTION_ACCEPTED) + { + rc = MQTTSN_RC_ACCEPTED; + } + else if (resp.rc == MQTT_UNACCEPTABLE_PROTOCOL_VERSION) + { + rc = MQTTSN_RC_NOT_SUPPORTED; + WRITELOG( + " ClientID : %s Requested Protocol version is not supported.\n", + client->getClientId()); + } + else if (resp.rc == MQTT_IDENTIFIER_REJECTED) + { + rc = MQTTSN_RC_NOT_SUPPORTED; + WRITELOG( + " ClientID : %s ClientID is collect UTF-8 but not allowed by the Server.\n", + client->getClientId()); + } + else if (resp.rc == MQTT_SERVER_UNAVAILABLE) + { + rc = MQTTSN_RC_REJECTED_CONGESTED; + WRITELOG( + " ClientID : %s The Network Connection has been made but the MQTT service is unavailable.\n", + client->getClientId()); + } + else if (resp.rc == MQTT_BAD_USERNAME_OR_PASSWORD) + { + rc = MQTTSN_RC_NOT_SUPPORTED; + WRITELOG( + " Gateway Configuration Error: The data in the user name or password is malformed.\n"); + } + else if (resp.rc == MQTT_NOT_AUTHORIZED) + { + rc = MQTTSN_RC_NOT_SUPPORTED; + WRITELOG( + " Gateway Configuration Error: The Client is not authorized to connect.\n"); + } - MQTTSNPacket* snPacket = new MQTTSNPacket(); - snPacket->setCONNACK(rc); + MQTTSNPacket* snPacket = new MQTTSNPacket(); + snPacket->setCONNACK(rc); - Event* ev1 = new Event(); - ev1->setClientSendEvent(client, snPacket); - client->connackSended(rc); // update the client's status - _gateway->getClientSendQue()->post(ev1); + Event* ev1 = new Event(); + ev1->setClientSendEvent(client, snPacket); + client->connackSended(rc); // update the client's status + _gateway->getClientSendQue()->post(ev1); } -void MQTTGWConnectionHandler::handlePingresp(Client* client, MQTTGWPacket* packet) +void MQTTGWConnectionHandler::handlePingresp(Client* client, + MQTTGWPacket* packet) { - MQTTSNPacket* snPacket = new MQTTSNPacket(); - snPacket->setPINGRESP(); - Event* ev1 = new Event(); - ev1->setClientSendEvent(client, snPacket); - client->updateStatus(snPacket); - _gateway->getClientSendQue()->post(ev1); + MQTTSNPacket* snPacket = new MQTTSNPacket(); + snPacket->setPINGRESP(); + Event* ev1 = new Event(); + ev1->setClientSendEvent(client, snPacket); + client->updateStatus(snPacket); + _gateway->getClientSendQue()->post(ev1); } -void MQTTGWConnectionHandler::handleDisconnect(Client* client, MQTTGWPacket* packet) +void MQTTGWConnectionHandler::handleDisconnect(Client* client, + MQTTGWPacket* packet) { - MQTTSNPacket* snPacket = new MQTTSNPacket(); - snPacket->setDISCONNECT(0); - client->disconnected(); - client->getNetwork()->close(); - Event* ev1 = new Event(); - ev1->setClientSendEvent(client, snPacket); + MQTTSNPacket* snPacket = new MQTTSNPacket(); + snPacket->setDISCONNECT(0); + client->disconnected(); + client->getNetwork()->close(); + Event* ev1 = new Event(); + ev1->setClientSendEvent(client, snPacket); } diff --git a/MQTTSNGateway/src/MQTTGWConnectionHandler.h b/MQTTSNGateway/src/MQTTGWConnectionHandler.h index 125350d..d736c61 100644 --- a/MQTTSNGateway/src/MQTTGWConnectionHandler.h +++ b/MQTTSNGateway/src/MQTTGWConnectionHandler.h @@ -26,13 +26,13 @@ namespace MQTTSNGW class MQTTGWConnectionHandler { public: - MQTTGWConnectionHandler(Gateway* gateway); - ~MQTTGWConnectionHandler(); - void handleConnack(Client* client, MQTTGWPacket* packet); - void handlePingresp(Client* client, MQTTGWPacket* packet); - void handleDisconnect(Client* client, MQTTGWPacket* packet); + MQTTGWConnectionHandler(Gateway* gateway); + ~MQTTGWConnectionHandler(); + void handleConnack(Client* client, MQTTGWPacket* packet); + void handlePingresp(Client* client, MQTTGWPacket* packet); + void handleDisconnect(Client* client, MQTTGWPacket* packet); private: - Gateway* _gateway; + Gateway* _gateway; }; } diff --git a/MQTTSNGateway/src/MQTTGWPacket.cpp b/MQTTSNGateway/src/MQTTGWPacket.cpp index 45cb9d8..e3277db 100644 --- a/MQTTSNGateway/src/MQTTGWPacket.cpp +++ b/MQTTSNGateway/src/MQTTGWPacket.cpp @@ -29,8 +29,9 @@ void writeInt(unsigned char** pptr, int msgId); * List of the predefined MQTT v3 packet names. */ static const char* mqtt_packet_names[] = -{ "RESERVED", "CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL", "PUBCOMP", "SUBSCRIBE", "SUBACK", - "UNSUBSCRIBE", "UNSUBACK", "PINGREQ", "PINGRESP", "DISCONNECT" }; +{ "RESERVED", "CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL", + "PUBCOMP", "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK", "PINGREQ", + "PINGRESP", "DISCONNECT" }; /** * Encodes the message length according to the MQTT algorithm @@ -40,17 +41,17 @@ static const char* mqtt_packet_names[] = */ int MQTTPacket_encode(char* buf, int length) { - int rc = 0; - do - { - char d = length % 128; - length /= 128; - /* if there are more digits to encode, set the top bit of this digit */ - if (length > 0) - d |= 0x80; - buf[rc++] = d; - } while (length > 0); - return rc; + int rc = 0; + do + { + char d = length % 128; + length /= 128; + /* if there are more digits to encode, set the top bit of this digit */ + if (length > 0) + d |= 0x80; + buf[rc++] = d; + } while (length > 0); + return rc; } /** @@ -60,10 +61,10 @@ int MQTTPacket_encode(char* buf, int length) */ int readInt(char** pptr) { - char* ptr = *pptr; - int len = 256 * ((unsigned char) (*ptr)) + (unsigned char) (*(ptr + 1)); - *pptr += 2; - return len; + char* ptr = *pptr; + int len = 256 * ((unsigned char) (*ptr)) + (unsigned char) (*(ptr + 1)); + *pptr += 2; + return len; } /** @@ -80,20 +81,20 @@ int readInt(char** pptr) */ char* readUTFlen(char** pptr, char* enddata, int* len) { - char* string = NULL; + char* string = NULL; - if (enddata - (*pptr) > 1) /* enough length to read the integer? */ - { - *len = readInt(pptr); - if (&(*pptr)[*len] <= enddata) - { - string = (char*)calloc(*len + 1, 1); - memcpy(string, *pptr, (size_t)*len); - string[*len] = '\0'; - *pptr += *len; - } - } - return string; + if (enddata - (*pptr) > 1) /* enough length to read the integer? */ + { + *len = readInt(pptr); + if (&(*pptr)[*len] <= enddata) + { + string = (char*) calloc(*len + 1, 1); + memcpy(string, *pptr, (size_t) *len); + string[*len] = '\0'; + *pptr += *len; + } + } + return string; } /** @@ -108,8 +109,8 @@ char* readUTFlen(char** pptr, char* enddata, int* len) */ char* readUTF(char** pptr, char* enddata) { - int len; - return readUTFlen(pptr, enddata, &len); + int len; + return readUTFlen(pptr, enddata, &len); } /** @@ -119,9 +120,9 @@ char* readUTF(char** pptr, char* enddata) */ unsigned char readChar(char** pptr) { - unsigned char c = **pptr; - (*pptr)++; - return c; + unsigned char c = **pptr; + (*pptr)++; + return c; } /** @@ -131,8 +132,8 @@ unsigned char readChar(char** pptr) */ void writeChar(unsigned char** pptr, char c) { - **pptr = c; - (*pptr)++; + **pptr = c; + (*pptr)++; } /** @@ -142,10 +143,10 @@ void writeChar(unsigned char** pptr, char c) */ void writeInt(unsigned char** pptr, int anInt) { - **pptr = (unsigned char)(anInt / 256); - (*pptr)++; - **pptr = (unsigned char)(anInt % 256); - (*pptr)++; + **pptr = (unsigned char) (anInt / 256); + (*pptr)++; + **pptr = (unsigned char) (anInt % 256); + (*pptr)++; } /** @@ -155,10 +156,10 @@ void writeInt(unsigned char** pptr, int anInt) */ void writeUTF(unsigned char** pptr, const char* string) { - int len = (int)strlen(string); - writeInt(pptr, len); - memcpy(*pptr, string, (size_t)len); - *pptr += len; + int len = (int) strlen(string); + writeInt(pptr, len); + memcpy(*pptr, string, (size_t) len); + *pptr += len; } /** @@ -167,479 +168,485 @@ void writeUTF(unsigned char** pptr, const char* string) */ MQTTGWPacket::MQTTGWPacket() { - _data = 0; - _header.byte = 0; - _remainingLength = 0; + _data = 0; + _header.byte = 0; + _remainingLength = 0; } MQTTGWPacket::~MQTTGWPacket() { - if (_data) - { - free(_data); - } + if (_data) + { + free(_data); + } } int MQTTGWPacket::recv(Network* network) { - int len = 0; - int multiplier = 1; - unsigned char c; + int len = 0; + int multiplier = 1; + unsigned char c; - /* read First Byte of Packet */ - int rc = network->recv((unsigned char*)&_header.byte, 1); - if ( rc <= 0) - { - return rc; - } - /* read RemainingLength */ - do - { - if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) - { - return -2; - } - if (network->recv(&c, 1) == -1) - { - return -1; - } - _remainingLength += (c & 127) * multiplier; - multiplier *= 128; - } while ((c & 128) != 0); + /* read First Byte of Packet */ + int rc = network->recv((unsigned char*) &_header.byte, 1); + if (rc <= 0) + { + return rc; + } + /* read RemainingLength */ + do + { + if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) + { + return -2; + } + if (network->recv(&c, 1) == -1) + { + return -1; + } + _remainingLength += (c & 127) * multiplier; + multiplier *= 128; + } while ((c & 128) != 0); - if ( _remainingLength > 0 ) - { - /* allocate buffer */ - _data = (unsigned char*)calloc(_remainingLength, 1); - if ( !_data ) - { - return -3; - } + if (_remainingLength > 0) + { + /* allocate buffer */ + _data = (unsigned char*) calloc(_remainingLength, 1); + if (!_data) + { + return -3; + } - /* read Payload */ - int remlen = network->recv(_data, _remainingLength); + /* read Payload */ + int remlen = network->recv(_data, _remainingLength); - if (remlen == -1 ) - { - return -1; - } - else if ( remlen != _remainingLength ) - { - return -2; - } - } - return 1 + len + _remainingLength; + if (remlen == -1) + { + return -1; + } + else if (remlen != _remainingLength) + { + return -2; + } + } + return 1 + len + _remainingLength; } int MQTTGWPacket::send(Network* network) { - unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE]; - memset(buf, 0, MQTTSNGW_MAX_PACKET_SIZE); - int len = getPacketData(buf); - return network->send(buf, len); + unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE]; + memset(buf, 0, MQTTSNGW_MAX_PACKET_SIZE); + int len = getPacketData(buf); + return network->send(buf, len); } int MQTTGWPacket::getAck(Ack* ack) { - if (PUBACK != _header.bits.type && PUBREC != _header.bits.type && PUBREL != _header.bits.type - && PUBCOMP != _header.bits.type && UNSUBACK != _header.bits.type) - { - return 0; - } - char* ptr = (char*) _data; - ack->header.byte = _header.byte; - ack->msgId = readInt((char**) &ptr); - return 1; + if (PUBACK != _header.bits.type && PUBREC != _header.bits.type + && PUBREL != _header.bits.type && PUBCOMP != _header.bits.type + && UNSUBACK != _header.bits.type) + { + return 0; + } + char* ptr = (char*) _data; + ack->header.byte = _header.byte; + ack->msgId = readInt((char**) &ptr); + return 1; } int MQTTGWPacket::getCONNACK(Connack* resp) { - if (_header.bits.type != CONNACK) - { - return 0; - } - char* ptr = (char*) _data; - resp->header.byte = _header.byte; - resp->flags.all = *ptr++; - resp->rc = readChar(&ptr); - return 1; + if (_header.bits.type != CONNACK) + { + return 0; + } + char* ptr = (char*) _data; + resp->header.byte = _header.byte; + resp->flags.all = *ptr++; + resp->rc = readChar(&ptr); + return 1; } int MQTTGWPacket::getSUBACK(unsigned short* msgId, unsigned char* rc) { - if (_header.bits.type != SUBACK) - { - return 0; - } - char *ptr = (char*) _data; - *msgId = readInt((char**) &ptr); - *rc = readChar(&ptr); - return 1; + if (_header.bits.type != SUBACK) + { + return 0; + } + char *ptr = (char*) _data; + *msgId = readInt((char**) &ptr); + *rc = readChar(&ptr); + return 1; } int MQTTGWPacket::getPUBLISH(Publish* pub) { - if (_header.bits.type != PUBLISH) - { - return 0; - } - char* ptr = (char*) _data; - pub->header = _header; - pub->topiclen = readInt((char**) &ptr); - pub->topic = (char*) _data + 2; - ptr += pub->topiclen; - if (_header.bits.qos > 0) - { - pub->msgId = readInt(&ptr); - pub->payloadlen = _remainingLength - pub->topiclen - 4; - } - else - { - pub->msgId = 0; - pub->payloadlen = _remainingLength - pub->topiclen - 2; - } - pub->payload = ptr; - return 1; + if (_header.bits.type != PUBLISH) + { + return 0; + } + char* ptr = (char*) _data; + pub->header = _header; + pub->topiclen = readInt((char**) &ptr); + pub->topic = (char*) _data + 2; + ptr += pub->topiclen; + if (_header.bits.qos > 0) + { + pub->msgId = readInt(&ptr); + pub->payloadlen = _remainingLength - pub->topiclen - 4; + } + else + { + pub->msgId = 0; + pub->payloadlen = _remainingLength - pub->topiclen - 2; + } + pub->payload = ptr; + return 1; } -int MQTTGWPacket::setCONNECT(Connect* connect, unsigned char* username, unsigned char* password) +int MQTTGWPacket::setCONNECT(Connect* connect, unsigned char* username, + unsigned char* password) { - clearData(); - _header = connect->header; + clearData(); + _header = connect->header; - _remainingLength = ((connect->version == 3) ? 12 : 10) + (int)strlen(connect->clientID) + 2; - if (connect->flags.bits.will) - { - _remainingLength += (int)strlen(connect->willTopic) + 2 + (int)strlen(connect->willMsg) + 2; - } - if ( connect->flags.bits.username ) - { - _remainingLength += (int)strlen((char*) username) + 2; - } - if (connect->flags.bits.password) - { - _remainingLength += (int)strlen((char*) password) + 2; - } + _remainingLength = ((connect->version == 3) ? 12 : 10) + + (int) strlen(connect->clientID) + 2; + if (connect->flags.bits.will) + { + _remainingLength += (int) strlen(connect->willTopic) + 2 + + (int) strlen(connect->willMsg) + 2; + } + if (connect->flags.bits.username) + { + _remainingLength += (int) strlen((char*) username) + 2; + } + if (connect->flags.bits.password) + { + _remainingLength += (int) strlen((char*) password) + 2; + } - _data = (unsigned char*)calloc(_remainingLength, 1); - unsigned char* ptr = _data; + _data = (unsigned char*) calloc(_remainingLength, 1); + unsigned char* ptr = _data; - if (connect->version == 3) - { - writeUTF(&ptr, "MQIsdp"); - writeChar(&ptr, (char) 3); - } - else if (connect->version == 4) - { - writeUTF(&ptr, "MQTT"); - writeChar(&ptr, (char) 4); - } - else - { - return 0; - } + if (connect->version == 3) + { + writeUTF(&ptr, "MQIsdp"); + writeChar(&ptr, (char) 3); + } + else if (connect->version == 4) + { + writeUTF(&ptr, "MQTT"); + writeChar(&ptr, (char) 4); + } + else + { + return 0; + } - writeChar(&ptr, connect->flags.all); - writeInt(&ptr, connect->keepAliveTimer); - writeUTF(&ptr, connect->clientID); - if (connect->flags.bits.will) - { - writeUTF(&ptr, connect->willTopic); - writeUTF(&ptr, connect->willMsg); - } + writeChar(&ptr, connect->flags.all); + writeInt(&ptr, connect->keepAliveTimer); + writeUTF(&ptr, connect->clientID); + if (connect->flags.bits.will) + { + writeUTF(&ptr, connect->willTopic); + writeUTF(&ptr, connect->willMsg); + } - if (connect->flags.bits.username) - { - writeUTF(&ptr, (const char*) username); - } - if (connect->flags.bits.password) - { - writeUTF(&ptr, (const char*) password); - } - return 1; + if (connect->flags.bits.username) + { + writeUTF(&ptr, (const char*) username); + } + if (connect->flags.bits.password) + { + writeUTF(&ptr, (const char*) password); + } + return 1; } -int MQTTGWPacket::setSUBSCRIBE(const char* topic, unsigned char qos, unsigned short msgId) +int MQTTGWPacket::setSUBSCRIBE(const char* topic, unsigned char qos, + unsigned short msgId) { - clearData(); - _header.byte = 0; - _header.bits.type = SUBSCRIBE; - _header.bits.qos = 1; // Reserved - _remainingLength = (int)strlen(topic) + 5; - _data = (unsigned char*)calloc(_remainingLength, 1); - if (_data) - { - unsigned char* ptr = _data; - writeInt(&ptr, msgId); - writeUTF(&ptr, topic); - writeChar(&ptr, (char) qos); - return 1; - } - clearData(); - return 0; + clearData(); + _header.byte = 0; + _header.bits.type = SUBSCRIBE; + _header.bits.qos = 1; // Reserved + _remainingLength = (int) strlen(topic) + 5; + _data = (unsigned char*) calloc(_remainingLength, 1); + if (_data) + { + unsigned char* ptr = _data; + writeInt(&ptr, msgId); + writeUTF(&ptr, topic); + writeChar(&ptr, (char) qos); + return 1; + } + clearData(); + return 0; } int MQTTGWPacket::setUNSUBSCRIBE(const char* topic, unsigned short msgid) { - clearData(); - _header.byte = 0; - _header.bits.type = UNSUBSCRIBE; - _header.bits.qos = 1; - _remainingLength = (int)strlen(topic) + 4; - _data = (unsigned char*)calloc(_remainingLength, 1); - if (_data) - { - unsigned char* ptr = _data; - writeInt(&ptr, msgid); - writeUTF(&ptr, topic); - return 1; - } - clearData(); - return 0; + clearData(); + _header.byte = 0; + _header.bits.type = UNSUBSCRIBE; + _header.bits.qos = 1; + _remainingLength = (int) strlen(topic) + 4; + _data = (unsigned char*) calloc(_remainingLength, 1); + if (_data) + { + unsigned char* ptr = _data; + writeInt(&ptr, msgid); + writeUTF(&ptr, topic); + return 1; + } + clearData(); + return 0; } int MQTTGWPacket::setPUBLISH(Publish* pub) { - clearData(); - _header.byte = pub->header.byte; - _header.bits.type = PUBLISH; - _remainingLength = 4 + pub->topiclen + pub->payloadlen; - _data = (unsigned char*)calloc(_remainingLength, 1); - if (_data) - { - unsigned char* ptr = _data; - writeInt(&ptr, pub->topiclen); - memcpy(ptr, pub->topic, pub->topiclen); - ptr += pub->topiclen; - if ( _header.bits.qos > 0 ) - { - writeInt(&ptr, pub->msgId); - } - else - { - _remainingLength -= 2; - } - memcpy(ptr, pub->payload, pub->payloadlen); - return 1; - } - else - { - clearData(); - return 0; - } + clearData(); + _header.byte = pub->header.byte; + _header.bits.type = PUBLISH; + _remainingLength = 4 + pub->topiclen + pub->payloadlen; + _data = (unsigned char*) calloc(_remainingLength, 1); + if (_data) + { + unsigned char* ptr = _data; + writeInt(&ptr, pub->topiclen); + memcpy(ptr, pub->topic, pub->topiclen); + ptr += pub->topiclen; + if (_header.bits.qos > 0) + { + writeInt(&ptr, pub->msgId); + } + else + { + _remainingLength -= 2; + } + memcpy(ptr, pub->payload, pub->payloadlen); + return 1; + } + else + { + clearData(); + return 0; + } } int MQTTGWPacket::setAck(unsigned char msgType, unsigned short msgid) { - clearData(); - _remainingLength = 2; - _header.bits.type = msgType; - _header.bits.qos = (msgType == PUBREL) ? 1 : 0; + clearData(); + _remainingLength = 2; + _header.bits.type = msgType; + _header.bits.qos = (msgType == PUBREL) ? 1 : 0; - _data = (unsigned char*)calloc(_remainingLength, 1); - if (_data) - { - unsigned char* data = _data; - writeInt(&data, msgid); - return 1; - } - return 0; + _data = (unsigned char*) calloc(_remainingLength, 1); + if (_data) + { + unsigned char* data = _data; + writeInt(&data, msgid); + return 1; + } + return 0; } int MQTTGWPacket::setHeader(unsigned char msgType) { - clearData(); - if (msgType < CONNECT || msgType > DISCONNECT) - { - return 0; - } - _header.bits.type = msgType; - return 0; + clearData(); + if (msgType < CONNECT || msgType > DISCONNECT) + { + return 0; + } + _header.bits.type = msgType; + return 0; } int MQTTGWPacket::getType(void) { - return _header.bits.type; + return _header.bits.type; } const char* MQTTGWPacket::getName(void) { - return getType() > DISCONNECT ? "UNKNOWN" : mqtt_packet_names[getType()]; + return getType() > DISCONNECT ? "UNKNOWN" : mqtt_packet_names[getType()]; } int MQTTGWPacket::getPacketData(unsigned char* buf) { - unsigned char* ptr = buf; - *ptr++ = _header.byte; - int len = MQTTPacket_encode((char*)ptr, _remainingLength); - ptr += len; - memcpy(ptr, _data, _remainingLength); - return 1 + len + _remainingLength; + unsigned char* ptr = buf; + *ptr++ = _header.byte; + int len = MQTTPacket_encode((char*) ptr, _remainingLength); + ptr += len; + memcpy(ptr, _data, _remainingLength); + return 1 + len + _remainingLength; } int MQTTGWPacket::getPacketLength(void) { - char buf[4]; - return 1 + MQTTPacket_encode(buf, _remainingLength) + _remainingLength; + char buf[4]; + return 1 + MQTTPacket_encode(buf, _remainingLength) + _remainingLength; } void MQTTGWPacket::clearData(void) { - if (_data) - { - free(_data); - } - _header.byte = 0; - _remainingLength = 0; + if (_data) + { + free(_data); + } + _header.byte = 0; + _remainingLength = 0; } char* MQTTGWPacket::getMsgId(char* pbuf) { - int type = getType(); + int type = getType(); - switch ( type ) - { - case PUBLISH: - Publish pub; - pub.msgId = 0; - getPUBLISH(&pub); - if ( _header.bits.dup ) - { - sprintf(pbuf, "+%04X", pub.msgId); - } - else - { - sprintf(pbuf, " %04X", pub.msgId); - } - break; - case SUBSCRIBE: - case UNSUBSCRIBE: - case PUBACK: - case PUBREC: - case PUBREL: - case PUBCOMP: - case SUBACK: - case UNSUBACK: - sprintf(pbuf, " %02X%02X", _data[0], _data[1]); - break; - default: - sprintf(pbuf, " "); - break; - } - if ( strcmp(pbuf, " 0000") == 0 ) - { - sprintf(pbuf, " "); - } - return pbuf; + switch (type) + { + case PUBLISH: + Publish pub; + pub.msgId = 0; + getPUBLISH(&pub); + if (_header.bits.dup) + { + sprintf(pbuf, "+%04X", pub.msgId); + } + else + { + sprintf(pbuf, " %04X", pub.msgId); + } + break; + case SUBSCRIBE: + case UNSUBSCRIBE: + case PUBACK: + case PUBREC: + case PUBREL: + case PUBCOMP: + case SUBACK: + case UNSUBACK: + sprintf(pbuf, " %02X%02X", _data[0], _data[1]); + break; + default: + sprintf(pbuf, " "); + break; + } + if (strcmp(pbuf, " 0000") == 0) + { + sprintf(pbuf, " "); + } + return pbuf; } int MQTTGWPacket::getMsgId(void) { - int type = getType(); - int msgId = 0; + 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; + switch (type) + { + case PUBLISH: + Publish pub; + pub.msgId = 0; + getPUBLISH(&pub); + msgId = pub.msgId; + break; + case PUBACK: + case PUBREC: + case PUBREL: + case PUBCOMP: + case SUBSCRIBE: + case UNSUBSCRIBE: + case SUBACK: + case UNSUBACK: + msgId = 256 * (unsigned char) _data[0] + (unsigned char) _data[1]; + break; + default: + break; + } + return msgId; } void MQTTGWPacket::setMsgId(int msgId) { - int type = getType(); - unsigned char* ptr = 0; + int 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; - } + 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]; - char* ptr = pbuf; - char** pptr = &pbuf; - int len = getPacketData(packetData); - int size = len > SIZE_OF_LOG_PACKET ? SIZE_OF_LOG_PACKET : len; - for (int i = 0; i < size; i++) - { - sprintf(*pptr, " %02X", packetData[i]); - *pptr += 3; - } - **pptr = 0; - return ptr; + uint8_t packetData[MQTTSNGW_MAX_PACKET_SIZE]; + char* ptr = pbuf; + char** pptr = &pbuf; + int len = getPacketData(packetData); + int size = len > SIZE_OF_LOG_PACKET ? SIZE_OF_LOG_PACKET : len; + for (int i = 0; i < size; i++) + { + sprintf(*pptr, " %02X", packetData[i]); + *pptr += 3; + } + **pptr = 0; + return ptr; } MQTTGWPacket& MQTTGWPacket::operator =(MQTTGWPacket& packet) { - clearData(); - this->_header.byte = packet._header.byte; - this->_remainingLength = packet._remainingLength; - _data = (unsigned char*)calloc(_remainingLength, 1); - if (_data) - { - memcpy(this->_data, packet._data, _remainingLength); - } - else - { - clearData(); - } - return *this; + clearData(); + this->_header.byte = packet._header.byte; + this->_remainingLength = packet._remainingLength; + _data = (unsigned char*) calloc(_remainingLength, 1); + if (_data) + { + memcpy(this->_data, packet._data, _remainingLength); + } + else + { + clearData(); + } + 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; + 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 fb2ad86..46df326 100644 --- a/MQTTSNGateway/src/MQTTGWPacket.h +++ b/MQTTSNGateway/src/MQTTGWPacket.h @@ -31,89 +31,100 @@ typedef void* (*pf)(unsigned char, char*, size_t); enum msgTypes { - CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL, - PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, - PINGREQ, PINGRESP, DISCONNECT + CONNECT = 1, + CONNACK, + PUBLISH, + PUBACK, + PUBREC, + PUBREL, + PUBCOMP, + SUBSCRIBE, + SUBACK, + UNSUBSCRIBE, + UNSUBACK, + PINGREQ, + PINGRESP, + DISCONNECT }; - /** * Bitfields for the MQTT header byte. */ typedef union { - /*unsigned*/ char byte; /**< the whole byte */ + /*unsigned*/ + char byte; /**< the whole byte */ #if defined(REVERSED) - struct - { - unsigned int type : 4; /**< message type nibble */ - bool dup : 1; /**< DUP flag bit */ - unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */ - bool retain : 1; /**< retained flag bit */ - } bits; + struct + { + unsigned int type : 4; /**< message type nibble */ + bool dup : 1; /**< DUP flag bit */ + unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */ + bool retain : 1; /**< retained flag bit */ + }bits; #else - struct - { - bool retain : 1; /**< retained flag bit */ - unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */ - bool dup : 1; /**< DUP flag bit */ - unsigned int type : 4; /**< message type nibble */ - } bits; + struct + { + bool retain :1; /**< retained flag bit */ + unsigned int qos :2; /**< QoS value, 0, 1 or 2 */ + bool dup :1; /**< DUP flag bit */ + unsigned int type :4; /**< message type nibble */ + } bits; #endif } Header; - /** * Data for a connect packet. */ -enum MQTT_connackCodes{ - MQTT_CONNECTION_ACCEPTED , - MQTT_UNACCEPTABLE_PROTOCOL_VERSION, - MQTT_IDENTIFIER_REJECTED, - MQTT_SERVER_UNAVAILABLE, - MQTT_BAD_USERNAME_OR_PASSWORD, - MQTT_NOT_AUTHORIZED +enum MQTT_connackCodes +{ + MQTT_CONNECTION_ACCEPTED, + MQTT_UNACCEPTABLE_PROTOCOL_VERSION, + MQTT_IDENTIFIER_REJECTED, + MQTT_SERVER_UNAVAILABLE, + MQTT_BAD_USERNAME_OR_PASSWORD, + MQTT_NOT_AUTHORIZED }; typedef struct { - Header header; /**< MQTT header byte */ - union - { - unsigned char all; /**< all connect flags */ + Header header; /**< MQTT header byte */ + union + { + unsigned char all; /**< all connect flags */ #if defined(REVERSED) - struct - { - bool username : 1; /**< 3.1 user name */ - bool password : 1; /**< 3.1 password */ - bool willRetain : 1; /**< will retain setting */ - unsigned int willQoS : 2; /**< will QoS value */ - bool will : 1; /**< will flag */ - bool cleanstart : 1; /**< cleansession flag */ - int : 1; /**< unused */ - } bits; + struct + { + bool username : 1; /**< 3.1 user name */ + bool password : 1; /**< 3.1 password */ + bool willRetain : 1; /**< will retain setting */ + unsigned int willQoS : 2; /**< will QoS value */ + bool will : 1; /**< will flag */ + bool cleanstart : 1; /**< cleansession flag */ + int : 1; /**< unused */ + }bits; #else - struct - { - int : 1; /**< unused */ - bool cleanstart : 1; /**< cleansession flag */ - bool will : 1; /**< will flag */ - unsigned int willQoS : 2; /**< will QoS value */ - bool willRetain : 1; /**< will retain setting */ - bool password : 1; /**< 3.1 password */ - bool username : 1; /**< 3.1 user name */ - } bits; + struct + { + int :1; /**< unused */ + bool cleanstart :1; /**< cleansession flag */ + bool will :1; /**< will flag */ + unsigned int willQoS :2; /**< will QoS value */ + bool willRetain :1; /**< will retain setting */ + bool password :1; /**< 3.1 password */ + bool username :1; /**< 3.1 user name */ + } bits; #endif - } flags; /**< connect flags byte */ + } flags; /**< connect flags byte */ - char *Protocol, /**< MQTT protocol name */ - *clientID, /**< string client id */ - *willTopic, /**< will topic */ - *willMsg; /**< will payload */ + char *Protocol, /**< MQTT protocol name */ + *clientID, /**< string client id */ + *willTopic, /**< will topic */ + *willMsg; /**< will payload */ - int keepAliveTimer; /**< keepalive timeout value in seconds */ - unsigned char version; /**< MQTT version number */ + int keepAliveTimer; /**< keepalive timeout value in seconds */ + unsigned char version; /**< MQTT version number */ } Connect; #define MQTTPacket_Connect_Initializer {{0}, {0}, nullptr, nullptr, nullptr, nullptr, 0, 0} @@ -121,57 +132,54 @@ typedef struct #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. */ typedef struct { - char* topic; - char* msg; - int retained; - int qos; -}willMessages; + char* topic; + char* msg; + int retained; + int qos; +} willMessages; /** * Data for a connack packet. */ typedef struct { - Header header; /**< MQTT header byte */ - union - { - unsigned char all; /**< all connack flags */ + Header header; /**< MQTT header byte */ + union + { + unsigned char all; /**< all connack flags */ #if defined(REVERSED) - struct - { - unsigned int reserved : 7; /**< message type nibble */ - bool sessionPresent : 1; /**< was a session found on the server? */ - } bits; + struct + { + unsigned int reserved : 7; /**< message type nibble */ + bool sessionPresent : 1; /**< was a session found on the server? */ + }bits; #else - struct - { - bool sessionPresent : 1; /**< was a session found on the server? */ - unsigned int reserved : 7; /**< message type nibble */ - } bits; + struct + { + bool sessionPresent :1; /**< was a session found on the server? */ + unsigned int reserved :7; /**< message type nibble */ + } bits; #endif - } flags; /**< connack flags byte */ - char rc; /**< connack return code */ + } flags; /**< connack flags byte */ + char rc; /**< connack return code */ } Connack; - /** * Data for a publish packet. */ typedef struct { - Header header; /**< MQTT header byte */ - char* topic; /**< topic string */ - int topiclen; - int msgId; /**< MQTT message id */ - char* payload; /**< binary payload, length delimited */ - int payloadlen; /**< payload length */ + Header header; /**< MQTT header byte */ + char* topic; /**< topic string */ + int topiclen; + int msgId; /**< MQTT message id */ + char* payload; /**< binary payload, length delimited */ + int payloadlen; /**< payload length */ } Publish; #define MQTTPacket_Publish_Initializer {{0}, nullptr, 0, 0, nullptr, 0} @@ -181,8 +189,8 @@ typedef struct */ typedef struct { - Header header; /**< MQTT header byte */ - int msgId; /**< MQTT message id */ + Header header; /**< MQTT header byte */ + int msgId; /**< MQTT message id */ } Ack; /** @@ -190,8 +198,8 @@ typedef struct */ typedef struct { - unsigned char len; - char* data; + unsigned char len; + char* data; } UTF8String; /** @@ -200,39 +208,41 @@ typedef struct class MQTTGWPacket { public: - MQTTGWPacket(); - ~MQTTGWPacket(); - int recv(Network* network); - int send(Network* network); - int getType(void); - int getPacketData(unsigned char* buf); - int getPacketLength(void); - const char* getName(void); + MQTTGWPacket(); + ~MQTTGWPacket(); + int recv(Network* network); + int send(Network* network); + int getType(void); + int getPacketData(unsigned char* buf); + int getPacketLength(void); + const char* getName(void); - int getAck(Ack* ack); - int getCONNACK(Connack* resp); - int getSUBACK(unsigned short* msgId, unsigned char* rc); - int getPUBLISH(Publish* pub); + int getAck(Ack* ack); + int getCONNACK(Connack* resp); + int getSUBACK(unsigned short* msgId, unsigned char* rc); + int getPUBLISH(Publish* pub); - int setCONNECT(Connect* conect, unsigned char* username, unsigned char* password); - int setPUBLISH(Publish* pub); - int setAck(unsigned char msgType, unsigned short msgid); - int setHeader(unsigned char msgType); - int setSUBSCRIBE(const char* topic, unsigned char qos, unsigned short msgId); - int setUNSUBSCRIBE(const char* topics, unsigned short msgid); + int setCONNECT(Connect* conect, unsigned char* username, + unsigned char* password); + int setPUBLISH(Publish* pub); + int setAck(unsigned char msgType, unsigned short msgid); + int setHeader(unsigned char msgType); + int setSUBSCRIBE(const char* topic, unsigned char qos, + unsigned short msgId); + int setUNSUBSCRIBE(const char* topics, unsigned short msgid); - UTF8String getTopic(void); - char* getMsgId(char* buf); - int getMsgId(void); - void setMsgId(int msgId); - char* print(char* buf); - MQTTGWPacket& operator =(MQTTGWPacket& packet); + UTF8String getTopic(void); + char* getMsgId(char* buf); + int getMsgId(void); + void setMsgId(int msgId); + char* print(char* buf); + MQTTGWPacket& operator =(MQTTGWPacket& packet); private: - void clearData(void); - Header _header; - int _remainingLength; - unsigned char* _data; + void clearData(void); + Header _header; + int _remainingLength; + unsigned char* _data; }; } diff --git a/MQTTSNGateway/src/MQTTGWPublishHandler.cpp b/MQTTSNGateway/src/MQTTGWPublishHandler.cpp index e3abc79..e73a7cc 100644 --- a/MQTTSNGateway/src/MQTTGWPublishHandler.cpp +++ b/MQTTSNGateway/src/MQTTGWPublishHandler.cpp @@ -27,7 +27,7 @@ char* currentDateTime(void); MQTTGWPublishHandler::MQTTGWPublishHandler(Gateway* gateway) { - _gateway = gateway; + _gateway = gateway; } MQTTGWPublishHandler::~MQTTGWPublishHandler() @@ -37,266 +37,285 @@ MQTTGWPublishHandler::~MQTTGWPublishHandler() void MQTTGWPublishHandler::handlePublish(Client* client, MQTTGWPacket* packet) { - if ( !client->isActive() && !client->isSleep() && !client->isAwake()) - { - WRITELOG("%s The client is neither active nor sleep %s%s\n", ERRMSG_HEADER, client->getStatus(), ERRMSG_FOOTER); - return; - } + if (!client->isActive() && !client->isSleep() && !client->isAwake()) + { + WRITELOG("%s The client is neither active nor sleep %s%s\n", + ERRMSG_HEADER, client->getStatus(), ERRMSG_FOOTER); + return; + } - /* client is sleeping. save PUBLISH */ - if ( client->isSleep() ) - { - Publish pub; - packet->getPUBLISH(&pub); + /* client is sleeping. save PUBLISH */ + if (client->isSleep()) + { + Publish pub; + packet->getPUBLISH(&pub); - WRITELOG(FORMAT_Y_G_G, currentDateTime(), packet->getName(), - RIGHTARROW, client->getClientId(), "is sleeping. a message was saved."); + 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); - } + if (pub.header.bits.qos == 1) + { + replyACK(client, &pub, PUBACK); + } + else if (pub.header.bits.qos == 2) + { + replyACK(client, &pub, PUBREC); + } - MQTTGWPacket* msg = new MQTTGWPacket(); - *msg = *packet; - if ( msg->getType() == 0 ) - { - WRITELOG("%s MQTTGWPublishHandler::handlePublish can't allocate memories for Packet.%s\n", ERRMSG_HEADER,ERRMSG_FOOTER); - delete msg; - return; - } - client->setClientSleepPacket(msg); - return; - } + MQTTGWPacket* msg = new MQTTGWPacket(); + *msg = *packet; + if (msg->getType() == 0) + { + WRITELOG( + "%s MQTTGWPublishHandler::handlePublish can't allocate memories for Packet.%s\n", + ERRMSG_HEADER, ERRMSG_FOOTER); + delete msg; + return; + } + client->setClientSleepPacket(msg); + return; + } - Publish pub; - packet->getPUBLISH(&pub); + Publish pub; + packet->getPUBLISH(&pub); - MQTTSNPacket* snPacket = new MQTTSNPacket(); + MQTTSNPacket* snPacket = new MQTTSNPacket(); - /* create MQTTSN_topicid */ - MQTTSN_topicid topicId; - uint16_t id = 0; + /* create MQTTSN_topicid */ + MQTTSN_topicid topicId; + uint16_t id = 0; - if (pub.topiclen <= 2) - { - topicId.type = MQTTSN_TOPIC_TYPE_SHORT; - *(topicId.data.short_name) = *pub.topic; - *(topicId.data.short_name + 1) = *(pub.topic + 1); - } - else - { + if (pub.topiclen <= 2) + { + topicId.type = MQTTSN_TOPIC_TYPE_SHORT; + *(topicId.data.short_name) = *pub.topic; + *(topicId.data.short_name + 1) = *(pub.topic + 1); + } + else + { topicId.data.long_.len = pub.topiclen; topicId.data.long_.name = pub.topic; Topic* tp = client->getTopics()->getTopicByName(&topicId); - if ( tp ) + if (tp) { topicId.type = tp->getType(); topicId.data.long_.len = pub.topiclen; topicId.data.long_.name = pub.topic; topicId.data.id = tp->getTopicId(); } - else - { - /* This message might be subscribed with wild card. */ - topicId.type = MQTTSN_TOPIC_TYPE_NORMAL; - Topic* topic = client->getTopics()->match(&topicId); - if (topic == nullptr) - { - WRITELOG(" Invalid Topic. PUBLISH message is canceled.\n"); - if (pub.header.bits.qos == 1) - { - replyACK(client, &pub, PUBACK); - } - else if ( pub.header.bits.qos == 2 ) - { - replyACK(client, &pub, PUBREC); - } + else + { + /* This message might be subscribed with wild card. */ + topicId.type = MQTTSN_TOPIC_TYPE_NORMAL; + Topic* topic = client->getTopics()->match(&topicId); + if (topic == nullptr) + { + WRITELOG(" Invalid Topic. PUBLISH message is canceled.\n"); + if (pub.header.bits.qos == 1) + { + replyACK(client, &pub, PUBACK); + } + else if (pub.header.bits.qos == 2) + { + replyACK(client, &pub, PUBREC); + } - delete snPacket; - return; - } + delete snPacket; + return; + } - /* add the Topic and get a TopicId */ - topic = client->getTopics()->add(&topicId); - id = topic->getTopicId(); + /* add the Topic and get a TopicId */ + topic = client->getTopics()->add(&topicId); + id = topic->getTopicId(); - if (id > 0) - { - /* create REGISTER */ - MQTTSNPacket* regPacket = new MQTTSNPacket(); + if (id > 0) + { + /* create REGISTER */ + MQTTSNPacket* regPacket = new MQTTSNPacket(); - MQTTSNString topicName = MQTTSNString_initializer; - topicName.lenstring.len = topicId.data.long_.len; - topicName.lenstring.data = topicId.data.long_.name; + MQTTSNString topicName = MQTTSNString_initializer; + topicName.lenstring.len = topicId.data.long_.len; + topicName.lenstring.data = topicId.data.long_.name; - uint16_t regackMsgId = client->getNextSnMsgId(); - regPacket->setREGISTER(id, regackMsgId, &topicName); + uint16_t regackMsgId = client->getNextSnMsgId(); + regPacket->setREGISTER(id, regackMsgId, &topicName); - /* send REGISTER */ - Event* evrg = new Event(); - evrg->setClientSendEvent(client, regPacket); - _gateway->getClientSendQue()->post(evrg); + /* send REGISTER */ + Event* evrg = new Event(); + evrg->setClientSendEvent(client, regPacket); + _gateway->getClientSendQue()->post(evrg); - /* send PUBLISH */ - topicId.data.id = id; - snPacket->setPUBLISH((uint8_t) pub.header.bits.dup, (int) pub.header.bits.qos, - (uint8_t) pub.header.bits.retain, (uint16_t) pub.msgId, topicId, (uint8_t*) pub.payload, - pub.payloadlen); - client->getWaitREGACKPacketList()->setPacket(snPacket, regackMsgId); - return; - } - else - { - WRITELOG("%sMQTTGWPublishHandler Can't create a Topic.%s\n", ERRMSG_HEADER,ERRMSG_FOOTER); - delete snPacket; - return; - } - } - } + /* send PUBLISH */ + topicId.data.id = id; + snPacket->setPUBLISH((uint8_t) pub.header.bits.dup, + (int) pub.header.bits.qos, + (uint8_t) pub.header.bits.retain, (uint16_t) pub.msgId, + topicId, (uint8_t*) pub.payload, pub.payloadlen); + client->getWaitREGACKPacketList()->setPacket(snPacket, + regackMsgId); + return; + } + else + { + WRITELOG("%sMQTTGWPublishHandler Can't create a Topic.%s\n", + ERRMSG_HEADER, ERRMSG_FOOTER); + delete snPacket; + return; + } + } + } - snPacket->setPUBLISH((uint8_t) pub.header.bits.dup, (int) pub.header.bits.qos, (uint8_t) pub.header.bits.retain, - (uint16_t) pub.msgId, topicId, (uint8_t*) pub.payload, pub.payloadlen); - Event* ev1 = new Event(); - ev1->setClientSendEvent(client, snPacket); - _gateway->getClientSendQue()->post(ev1); + snPacket->setPUBLISH((uint8_t) pub.header.bits.dup, + (int) pub.header.bits.qos, (uint8_t) pub.header.bits.retain, + (uint16_t) pub.msgId, topicId, (uint8_t*) pub.payload, + pub.payloadlen); + Event* ev1 = new Event(); + ev1->setClientSendEvent(client, snPacket); + _gateway->getClientSendQue()->post(ev1); } void MQTTGWPublishHandler::replyACK(Client* client, Publish* pub, int type) { - MQTTGWPacket* pubAck = new MQTTGWPacket(); - pubAck->setAck(type, (uint16_t)pub->msgId); - Event* ev1 = new Event(); - ev1->setBrokerSendEvent(client, pubAck); - _gateway->getBrokerSendQue()->post(ev1); + MQTTGWPacket* pubAck = new MQTTGWPacket(); + pubAck->setAck(type, (uint16_t) pub->msgId); + Event* ev1 = new Event(); + ev1->setBrokerSendEvent(client, pubAck); + _gateway->getBrokerSendQue()->post(ev1); } void MQTTGWPublishHandler::handlePuback(Client* client, MQTTGWPacket* packet) { - Ack ack; - packet->getAck(&ack); - TopicIdMapElement* topicId = client->getWaitedPubTopicId((uint16_t)ack.msgId); - if (topicId) - { - MQTTSNPacket* mqttsnPacket = new MQTTSNPacket(); - mqttsnPacket->setPUBACK(topicId->getTopicId(), (uint16_t)ack.msgId, 0); + Ack ack; + packet->getAck(&ack); + TopicIdMapElement* topicId = client->getWaitedPubTopicId( + (uint16_t) ack.msgId); + if (topicId) + { + MQTTSNPacket* mqttsnPacket = new MQTTSNPacket(); + mqttsnPacket->setPUBACK(topicId->getTopicId(), (uint16_t) ack.msgId, 0); - client->eraseWaitedPubTopicId((uint16_t)ack.msgId); - Event* ev1 = new Event(); - ev1->setClientSendEvent(client, mqttsnPacket); - _gateway->getClientSendQue()->post(ev1); - return; - } - WRITELOG(" PUBACK from the Broker is invalid. PacketID : %04X ClientID : %s \n", (uint16_t)ack.msgId, client->getClientId()); + client->eraseWaitedPubTopicId((uint16_t) ack.msgId); + Event* ev1 = new Event(); + ev1->setClientSendEvent(client, mqttsnPacket); + _gateway->getClientSendQue()->post(ev1); + return; + } + WRITELOG( + " PUBACK from the Broker is invalid. PacketID : %04X ClientID : %s \n", + (uint16_t) ack.msgId, client->getClientId()); } -void MQTTGWPublishHandler::handleAck(Client* client, MQTTGWPacket* packet, int type) +void MQTTGWPublishHandler::handleAck(Client* client, MQTTGWPacket* packet, + int type) { - Ack ack; - packet->getAck(&ack); + Ack ack; + packet->getAck(&ack); - if ( client->isActive() || client->isAwake() ) - { - MQTTSNPacket* mqttsnPacket = new MQTTSNPacket(); - if (type == PUBREC) - { - mqttsnPacket->setPUBREC((uint16_t) ack.msgId); - } - else if (type == PUBREL) - { - mqttsnPacket->setPUBREL((uint16_t) ack.msgId); - } - else if (type == PUBCOMP) - { - mqttsnPacket->setPUBCOMP((uint16_t) ack.msgId); - } + if (client->isActive() || client->isAwake()) + { + MQTTSNPacket* mqttsnPacket = new MQTTSNPacket(); + if (type == PUBREC) + { + mqttsnPacket->setPUBREC((uint16_t) ack.msgId); + } + else if (type == PUBREL) + { + mqttsnPacket->setPUBREL((uint16_t) ack.msgId); + } + else if (type == PUBCOMP) + { + mqttsnPacket->setPUBCOMP((uint16_t) ack.msgId); + } - Event* ev1 = new Event(); - ev1->setClientSendEvent(client, mqttsnPacket); - _gateway->getClientSendQue()->post(ev1); - } - else if ( client->isSleep() ) - { - if (type == PUBREL) - { - MQTTGWPacket* pubComp = new MQTTGWPacket(); - pubComp->setAck(PUBCOMP, (uint16_t)ack.msgId); - Event* ev1 = new Event(); - ev1->setBrokerSendEvent(client, pubComp); - _gateway->getBrokerSendQue()->post(ev1); - } - } + Event* ev1 = new Event(); + ev1->setClientSendEvent(client, mqttsnPacket); + _gateway->getClientSendQue()->post(ev1); + } + else if (client->isSleep()) + { + if (type == PUBREL) + { + MQTTGWPacket* pubComp = new MQTTGWPacket(); + pubComp->setAck(PUBCOMP, (uint16_t) ack.msgId); + Event* ev1 = new Event(); + ev1->setBrokerSendEvent(client, pubComp); + _gateway->getBrokerSendQue()->post(ev1); + } + } } - - -void MQTTGWPublishHandler::handleAggregatePuback(Client* client, MQTTGWPacket* packet) +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); - } + 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) +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); - } + 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) +void MQTTGWPublishHandler::handleAggregatePubrel(Client* client, + MQTTGWPacket* packet) { - Publish pub; - packet->getPUBLISH(&pub); - replyACK(client, &pub, PUBCOMP); + Publish pub; + packet->getPUBLISH(&pub); + replyACK(client, &pub, PUBCOMP); } -void MQTTGWPublishHandler::handleAggregatePublish(Client* client, MQTTGWPacket* packet) +void MQTTGWPublishHandler::handleAggregatePublish(Client* client, + MQTTGWPacket* packet) { - Publish pub; - packet->getPUBLISH(&pub); + Publish pub; + packet->getPUBLISH(&pub); + string* topicName = new string(pub.topic, pub.topiclen); // topic deletes topicName when the topic is deleted + Topic topic = Topic(topicName, MQTTSN_TOPIC_TYPE_NORMAL); - string* topicName = new string(pub.topic, pub.topiclen); // topic deletes topicName when the topic is deleted - Topic topic = Topic(topicName, MQTTSN_TOPIC_TYPE_NORMAL); + // ToDo: need to refactor + ClientTopicElement* elm = + _gateway->getAdapterManager()->getAggregater()->getClientElement( + &topic); - // ToDo: need to refactor - ClientTopicElement* elm = _gateway->getAdapterManager()->getAggregater()->getClientElement(&topic); + while (elm != nullptr) + { + Client* devClient = elm->getClient(); + MQTTGWPacket* msg = new MQTTGWPacket(); + *msg = *packet; - while ( elm != nullptr ) - { - Client* devClient = elm->getClient(); - 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; + } - 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); - Event* ev = new Event(); - ev->setBrokerRecvEvent(devClient, msg); - _gateway->getPacketEventQue()->post(ev); - - elm = elm->getNextClientElement(); - } + elm = elm->getNextClientElement(); + } } diff --git a/MQTTSNGateway/src/MQTTGWPublishHandler.h b/MQTTSNGateway/src/MQTTGWPublishHandler.h index fee60e8..c32faee 100644 --- a/MQTTSNGateway/src/MQTTGWPublishHandler.h +++ b/MQTTSNGateway/src/MQTTGWPublishHandler.h @@ -26,25 +26,23 @@ namespace MQTTSNGW class MQTTGWPublishHandler { public: - MQTTGWPublishHandler(Gateway* gateway); - ~MQTTGWPublishHandler(); - void handlePublish(Client* client, MQTTGWPacket* packet); - void handlePuback(Client* client, MQTTGWPacket* packet); - void handleAck(Client* client, MQTTGWPacket* packet, int type); + MQTTGWPublishHandler(Gateway* gateway); + ~MQTTGWPublishHandler(); + void handlePublish(Client* client, MQTTGWPacket* packet); + 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); + 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); + void replyACK(Client* client, Publish* pub, int type); - Gateway* _gateway; + Gateway* _gateway; }; } - - #endif /* MQTTGWPUBLISHHANDLER_H_ */ diff --git a/MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp b/MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp index 2df4815..dd7425b 100644 --- a/MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp +++ b/MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp @@ -22,7 +22,7 @@ using namespace MQTTSNGW; MQTTGWSubscribeHandler::MQTTGWSubscribeHandler(Gateway* gateway) { - _gateway = gateway; + _gateway = gateway; } MQTTGWSubscribeHandler::~MQTTGWSubscribeHandler() @@ -32,68 +32,74 @@ MQTTGWSubscribeHandler::~MQTTGWSubscribeHandler() void MQTTGWSubscribeHandler::handleSuback(Client* client, MQTTGWPacket* packet) { - uint16_t msgId; - uint8_t rc; - uint8_t returnCode; - int qos = 0; + uint16_t msgId; + uint8_t rc; + uint8_t returnCode; + int qos = 0; - packet->getSUBACK(&msgId, &rc); - TopicIdMapElement* topicId = client->getWaitedSubTopicId(msgId); + packet->getSUBACK(&msgId, &rc); + TopicIdMapElement* topicId = client->getWaitedSubTopicId(msgId); - if (topicId) - { - MQTTSNPacket* snPacket = new MQTTSNPacket(); + if (topicId) + { + MQTTSNPacket* snPacket = new MQTTSNPacket(); - if (rc == 0x80) - { - returnCode = MQTTSN_RC_REJECTED_INVALID_TOPIC_ID; - } - else - { - returnCode = MQTTSN_RC_ACCEPTED; - qos = rc; - } - snPacket->setSUBACK(qos, topicId->getTopicId(), msgId, returnCode); - Event* evt = new Event(); - evt->setClientSendEvent(client, snPacket); - _gateway->getClientSendQue()->post(evt); + if (rc == 0x80) + { + returnCode = MQTTSN_RC_REJECTED_INVALID_TOPIC_ID; + } + else + { + returnCode = MQTTSN_RC_ACCEPTED; + qos = rc; + } + snPacket->setSUBACK(qos, topicId->getTopicId(), msgId, returnCode); + Event* evt = new Event(); + evt->setClientSendEvent(client, snPacket); + _gateway->getClientSendQue()->post(evt); client->eraseWaitedSubTopicId(msgId); - } + } } -void MQTTGWSubscribeHandler::handleUnsuback(Client* client, MQTTGWPacket* packet) +void MQTTGWSubscribeHandler::handleUnsuback(Client* client, + MQTTGWPacket* packet) { - Ack ack; - packet->getAck(&ack); - MQTTSNPacket* snPacket = new MQTTSNPacket(); - snPacket->setUNSUBACK(ack.msgId); - Event* evt = new Event(); - evt->setClientSendEvent(client, snPacket); - _gateway->getClientSendQue()->post(evt); + Ack ack; + packet->getAck(&ack); + MQTTSNPacket* snPacket = new MQTTSNPacket(); + snPacket->setUNSUBACK(ack.msgId); + Event* evt = new Event(); + evt->setClientSendEvent(client, snPacket); + _gateway->getClientSendQue()->post(evt); } -void MQTTGWSubscribeHandler::handleAggregateSuback(Client* client, MQTTGWPacket* packet) +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); - } + 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) +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); - } + 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 d52b70f..7d86a3f 100644 --- a/MQTTSNGateway/src/MQTTGWSubscribeHandler.h +++ b/MQTTSNGateway/src/MQTTGWSubscribeHandler.h @@ -27,15 +27,15 @@ namespace MQTTSNGW class MQTTGWSubscribeHandler { public: - MQTTGWSubscribeHandler(Gateway* gateway); - ~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); + MQTTGWSubscribeHandler(Gateway* gateway); + ~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; + Gateway* _gateway; }; } diff --git a/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.cpp b/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.cpp index 90672bf..b7a3a71 100644 --- a/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.cpp @@ -26,9 +26,10 @@ using namespace MQTTSNGW; /*===================================== Class MQTTSNAggregateConnectionHandler =====================================*/ -MQTTSNAggregateConnectionHandler::MQTTSNAggregateConnectionHandler(Gateway* gateway) +MQTTSNAggregateConnectionHandler::MQTTSNAggregateConnectionHandler( + Gateway* gateway) { - _gateway = gateway; + _gateway = gateway; } MQTTSNAggregateConnectionHandler::~MQTTSNAggregateConnectionHandler() @@ -36,130 +37,131 @@ MQTTSNAggregateConnectionHandler::~MQTTSNAggregateConnectionHandler() } - /* * CONNECT */ -void MQTTSNAggregateConnectionHandler::handleConnect(Client* client, MQTTSNPacket* packet) +void MQTTSNAggregateConnectionHandler::handleConnect(Client* client, + MQTTSNPacket* packet) { - MQTTSNPacket_connectData data; - if ( packet->getCONNECT(&data) == 0 ) - { - return; - } + 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; - } + /* 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)); + //* clear ConnectData of Client */ + Connect* connectData = client->getConnectData(); + memset(connectData, 0, sizeof(Connect)); - client->disconnected(); + client->disconnected(); - Topics* topics = client->getTopics(); + Topics* topics = client->getTopics(); - /* CONNECT was not sent yet. prepare Connect data */ + /* 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(); - client->setSessionStatus(false); - if (data.cleansession) - { - /* reset the table of msgNo and TopicId pare */ - client->clearWaitedPubTopicId(); - client->clearWaitedSubTopicId(); + /* renew the TopicList */ + if (topics) + { + Topic* tp = topics->getFirstTopic(); + while (tp != nullptr) + { + if (tp->getType() == MQTTSN_TOPIC_TYPE_NORMAL) + { + _gateway->getAdapterManager()->getAggregater()->removeAggregateTopic( + tp, client); + } + tp = topics->getNextTopic(tp); + } + topics->eraseNormal(); + } + client->setSessionStatus(true); + } - /* renew the TopicList */ - if (topics) - { - Topic* tp = topics->getFirstTopic(); - while( tp != nullptr ) - { - if ( tp->getType() == MQTTSN_TOPIC_TYPE_NORMAL ) - { - _gateway->getAdapterManager()->getAggregater()->removeAggregateTopic(tp, client); - } - tp = topics->getNextTopic(tp); - } - 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); - 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; - } + /* 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) +void MQTTSNAggregateConnectionHandler::handleWillmsg(Client* client, + MQTTSNPacket* packet) { - if ( !client->isWaitWillMsg() ) - { - DEBUGLOG(" MQTTSNConnectionHandler::handleWillmsg WaitWillMsgFlg is off.\n"); - return; - } + if (!client->isWaitWillMsg()) + { + DEBUGLOG(" MQTTSNConnectionHandler::handleWillmsg WaitWillMsgFlg is off.\n"); + return; + } - MQTTSNString willmsg = MQTTSNString_initializer; - //Connect* connectData = client->getConnectData(); + 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); + 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); + /* 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; - } + sendStoredPublish(client); + return; + } } /* * DISCONNECT */ -void MQTTSNAggregateConnectionHandler::handleDisconnect(Client* client, MQTTSNPacket* packet) +void MQTTSNAggregateConnectionHandler::handleDisconnect(Client* client, + MQTTSNPacket* packet) { MQTTSNPacket* snMsg = new MQTTSNPacket(); snMsg->setDISCONNECT(0); @@ -171,33 +173,35 @@ void MQTTSNAggregateConnectionHandler::handleDisconnect(Client* client, MQTTSNPa /* * PINGREQ */ -void MQTTSNAggregateConnectionHandler::handlePingreq(Client* client, MQTTSNPacket* packet) +void MQTTSNAggregateConnectionHandler::handlePingreq(Client* client, + MQTTSNPacket* packet) { - if ( ( client->isSleep() || client->isAwake() ) && client->getClientSleepPacket() ) - { - sendStoredPublish(client); - client->holdPingRequest(); - } + if ((client->isSleep() || client->isAwake()) + && client->getClientSleepPacket()) + { + sendStoredPublish(client); + client->holdPingRequest(); + } - /* create and send PINGRESP to the PacketHandler */ - client->resetPingRequest(); + /* create and send PINGRESP to the PacketHandler */ + client->resetPingRequest(); - MQTTGWPacket* pingresp = new MQTTGWPacket(); + MQTTGWPacket* pingresp = new MQTTGWPacket(); - pingresp->setHeader(PINGRESP); + pingresp->setHeader(PINGRESP); - Event* evt = new Event(); - evt->setBrokerRecvEvent(client, pingresp); - _gateway->getPacketEventQue()->post(evt); + 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 ) + while ((msg = client->getClientSleepPacket()) != nullptr) { - client->deleteFirstClientSleepPacket(); // pop the que to delete element. + client->deleteFirstClientSleepPacket(); // pop the que to delete element. Event* ev = new Event(); ev->setBrokerRecvEvent(client, msg); diff --git a/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.h b/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.h index 53282b3..15001b7 100644 --- a/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.h +++ b/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.h @@ -28,18 +28,18 @@ class MQTTSNPacket; class MQTTSNAggregateConnectionHandler { public: - MQTTSNAggregateConnectionHandler(Gateway* gateway); - ~MQTTSNAggregateConnectionHandler(void); + 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); + 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); + void sendStoredPublish(Client* client); - Gateway* _gateway; + Gateway* _gateway; }; } diff --git a/MQTTSNGateway/src/MQTTSNGWAdapter.cpp b/MQTTSNGateway/src/MQTTSNGWAdapter.cpp index 2fa37b3..78994bf 100644 --- a/MQTTSNGateway/src/MQTTSNGWAdapter.cpp +++ b/MQTTSNGateway/src/MQTTSNGWAdapter.cpp @@ -24,116 +24,115 @@ #include using namespace MQTTSNGW; - /*===================================== - Class Adapter + Class Adapter =====================================*/ -Adapter:: Adapter(Gateway* gw) +Adapter::Adapter(Gateway* gw) { - _gateway = gw; - _proxy = new Proxy(gw); - _proxySecure = new Proxy(gw); + _gateway = gw; + _proxy = new Proxy(gw); + _proxySecure = new Proxy(gw); } Adapter::~Adapter(void) { - if ( _proxy ) + if (_proxy) { delete _proxy; } - if ( _proxySecure ) - { - delete _proxySecure; - } + if (_proxySecure) + { + delete _proxySecure; + } } - void Adapter::setup(const char* adpterName, AdapterType adapterType) { _isSecure = false; - if ( _gateway->hasSecureConnection() ) + if (_gateway->hasSecureConnection()) { - _isSecure = true; + _isSecure = true; } MQTTSNString id = MQTTSNString_initializer; - MQTTSNString idSecure = 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()); + 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* 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 = _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 ) + Client* client = _gateway->getClientList()->getClient(addr); + if (!client) { - return nullptr; + return nullptr; } - else if ( client->isQoSm1() ) + else if (client->isQoSm1()) { - return client->getClientId(); + return client; } else { - return nullptr; + 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; - } + Client* client = getClient(addr); + if (!client) + { + return false; + } + else if (client->isSecureNetwork()) + { + return true; + } + else + { + return false; + } } bool Adapter::isSecure(void) { - return _isSecure; + return _isSecure; } void Adapter::setClient(Client* client, bool secure) { - if ( secure ) + if (secure) { _clientSecure = client; } @@ -157,7 +156,7 @@ void Adapter::checkConnection(void) { _proxy->checkConnection(_client); - if ( _isSecure ) + if (_isSecure) { _proxySecure->checkConnection(_clientSecure); } @@ -166,15 +165,17 @@ void Adapter::checkConnection(void) void Adapter::send(MQTTSNPacket* packet, Client* client) { Proxy* proxy = _proxy; - if ( client->isSecureNetwork() && !_isSecure ) + if (client->isSecureNetwork() && !_isSecure) { - if ( _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); + WRITELOG( + "%s %s No Secure connections %s 's packet is discarded.%s\n", + ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); return; } } @@ -185,13 +186,13 @@ void Adapter::send(MQTTSNPacket* packet, Client* client) void Adapter::resetPingTimer(bool secure) { - if ( secure ) + if (secure) { - _proxySecure->resetPingTimer(); + _proxySecure->resetPingTimer(); } else { - _proxy->resetPingTimer(); + _proxy->resetPingTimer(); } } @@ -202,48 +203,48 @@ bool Adapter::isActive(void) void Adapter::savePacket(Client* client, MQTTSNPacket* packet) { - if ( client->isSecureNetwork()) - { - _proxySecure->savePacket(client, packet); - } - else - { - _proxy->savePacket(client, packet); - } + if (client->isSecureNetwork()) + { + _proxySecure->savePacket(client, packet); + } + else + { + _proxy->savePacket(client, packet); + } } - Client* Adapter::getAdapterClient(Client* client) { - if ( client->isSecureNetwork() ) - { - return _clientSecure; - } - else - { - return _client; - } + if (client->isSecureNetwork()) + { + return _clientSecure; + } + else + { + return _client; + } } /*===================================== - Class Proxy + Class Proxy =====================================*/ Proxy::Proxy(Gateway* gw) { - _gateway = gw; - _suspendedPacketEventQue = new EventQue(); + _gateway = gw; + _suspendedPacketEventQue = new EventQue(); } Proxy::~Proxy(void) { - if ( _suspendedPacketEventQue ) - { - delete _suspendedPacketEventQue; - } + if (_suspendedPacketEventQue) + { + delete _suspendedPacketEventQue; + } } void Proxy::checkConnection(Client* client) { - if ( client->isDisconnect() || ( client->isConnecting() && _responseTimer.isTimeup()) ) + if (client->isDisconnect() + || (client->isConnecting() && _responseTimer.isTimeup())) { client->connectSended(); _responseTimer.start(PROXY_RESPONSE_DURATION * 1000UL); @@ -257,26 +258,26 @@ void Proxy::checkConnection(Client* client) ev->setClientRecvEvent(client, packet); _gateway->getPacketEventQue()->post(ev); } - else if ( (client->isActive() && _keepAliveTimer.isTimeup() ) || (_isWaitingResp && _responseTimer.isTimeup() ) ) + 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(PROXY_RESPONSE_DURATION * 1000UL); - _isWaitingResp = true; + 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(PROXY_RESPONSE_DURATION * 1000UL); + _isWaitingResp = true; - if ( ++_retryCnt > PROXY_MAX_RETRY_CNT ) - { - client->disconnected(); - } - resetPingTimer(); + if (++_retryCnt > PROXY_MAX_RETRY_CNT) + { + client->disconnected(); + } + resetPingTimer(); } } - void Proxy::resetPingTimer(void) { _keepAliveTimer.start(PROXY_KEEPALIVE_DURATION * 1000UL); @@ -284,24 +285,24 @@ void Proxy::resetPingTimer(void) void Proxy::recv(MQTTSNPacket* packet, Client* client) { - if ( packet->getType() == MQTTSN_CONNACK ) + if (packet->getType() == MQTTSN_CONNACK) { - if ( packet->isAccepted() ) - { + if (packet->isAccepted()) + { _responseTimer.stop(); _retryCnt = 0; resetPingTimer(); sendSuspendedPacket(); - } + } } - else if ( packet->getType() == MQTTSN_PINGRESP ) + else if (packet->getType() == MQTTSN_PINGRESP) { _isWaitingResp = false; _responseTimer.stop(); - _retryCnt = 0; - resetPingTimer(); + _retryCnt = 0; + resetPingTimer(); } - else if ( packet->getType() == MQTTSN_DISCONNECT ) + else if (packet->getType() == MQTTSN_DISCONNECT) { // blank } @@ -309,18 +310,18 @@ void Proxy::recv(MQTTSNPacket* packet, Client* client) void Proxy::savePacket(Client* client, MQTTSNPacket* packet) { - MQTTSNPacket* pk = new MQTTSNPacket(*packet); - Event* ev = new Event(); - ev->setClientRecvEvent(client, pk); - _suspendedPacketEventQue->post(ev); + 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); - } + while (_suspendedPacketEventQue->size()) + { + Event* ev = _suspendedPacketEventQue->wait(); + _gateway->getPacketEventQue()->post(ev); + } } diff --git a/MQTTSNGateway/src/MQTTSNGWAdapter.h b/MQTTSNGateway/src/MQTTSNGWAdapter.h index f126bf1..20c9a87 100644 --- a/MQTTSNGateway/src/MQTTSNGWAdapter.h +++ b/MQTTSNGateway/src/MQTTSNGWAdapter.h @@ -31,17 +31,18 @@ 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; +typedef enum +{ + Atype_QoSm1Proxy, Atype_Aggregater +} AdapterType; /*===================================== - Class Adapter + Class Adapter =====================================*/ class Adapter { public: - Adapter(Gateway* gw); + Adapter(Gateway* gw); ~Adapter(void); void setup(const char* adpterName, AdapterType adapterType); @@ -60,18 +61,17 @@ public: 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}; + 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 =====================================*/ class Proxy { @@ -88,11 +88,12 @@ public: private: void sendSuspendedPacket(void); Gateway* _gateway; - EventQue* _suspendedPacketEventQue {nullptr}; - Timer _keepAliveTimer; - Timer _responseTimer; - bool _isWaitingResp {false}; - int _retryCnt {0}; + EventQue* _suspendedPacketEventQue + { nullptr }; + Timer _keepAliveTimer; + Timer _responseTimer; + bool _isWaitingResp { false }; + int _retryCnt { 0 }; }; } diff --git a/MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp b/MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp index 0d5fa55..5061ed7 100644 --- a/MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp +++ b/MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp @@ -33,42 +33,42 @@ char* currentDateTime(void); =====================================*/ AdapterManager::AdapterManager(Gateway* gw) { - _gateway = gw; - _forwarders = new ForwarderList(); - _qosm1Proxy = new QoSm1Proxy(gw); - _aggregater = new Aggregater(gw); + _gateway = gw; + _forwarders = new ForwarderList(); + _qosm1Proxy = new QoSm1Proxy(gw); + _aggregater = new Aggregater(gw); } - -void AdapterManager::initialize(char* gwName, bool aggregate, bool forwarder, bool qosM1) +void AdapterManager::initialize(char* gwName, bool aggregate, bool forwarder, + bool qosM1) { - if ( aggregate ) + if (aggregate) { - _aggregater->initialize(gwName); + _aggregater->initialize(gwName); } - if ( qosM1 ) + if (qosM1) { - _qosm1Proxy->initialize(gwName); + _qosm1Proxy->initialize(gwName); } - if ( forwarder ) + if (forwarder) { - _forwarders->initialize(_gateway); + _forwarders->initialize(_gateway); } } AdapterManager::~AdapterManager(void) { - if ( _forwarders ) + if (_forwarders) { delete _forwarders; } - if ( _qosm1Proxy ) + if (_qosm1Proxy) { delete _qosm1Proxy; } - if ( _aggregater ) + if (_aggregater) { delete _aggregater; } @@ -91,119 +91,124 @@ Aggregater* AdapterManager::getAggregater(void) bool AdapterManager::isAggregatedClient(Client* client) { - if ( !_aggregater->isActive() || client->isQoSm1() || client->isAggregater() || client->isQoSm1Proxy()) - { - return false; - } - else - { - return true; - } + 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; + 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); - } - else if ( client->isQoSm1Proxy() ) - { - _qosm1Proxy->resetPingTimer(secure); - } - else if ( client->isAggregater() ) - { - _aggregater->resetPingTimer(secure); - } - return newClient; + if (client->isQoSm1()) + { + newClient = _qosm1Proxy->getAdapterClient(client); + _qosm1Proxy->resetPingTimer(secure); + } + else if (client->isAggregated()) + { + newClient = _aggregater->getAdapterClient(client); + _aggregater->resetPingTimer(secure); + } + else if (client->isQoSm1Proxy()) + { + _qosm1Proxy->resetPingTimer(secure); + } + else if (client->isAggregater()) + { + _aggregater->resetPingTimer(secure); + } + return newClient; } -int AdapterManager::unicastToClient(Client* client, MQTTSNPacket* packet, ClientSendTask* task) +int AdapterManager::unicastToClient(Client* client, MQTTSNPacket* packet, + ClientSendTask* task) { - char pbuf[SIZE_OF_LOG_PACKET * 3]; - Forwarder* fwd = client->getForwarder(); - int rc = 0; + 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); - task->log(client, packet); - WRITELOG(FORMAT_Y_W_G, currentDateTime(), encap.getName(), RIGHTARROW, fwd->getId(), encap.print(pbuf)); - 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; + if (fwd) + { + MQTTSNGWEncapsulatedPacket encap(packet); + WirelessNodeId* wnId = fwd->getWirelessNodeId(client); + encap.setWirelessNodeId(wnId); + task->log(client, packet); + WRITELOG(FORMAT_Y_W_G, currentDateTime(), encap.getName(), RIGHTARROW, + fwd->getId(), encap.print(pbuf)); + 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 (_aggregater->isActive()) + { + _aggregater->checkConnection(); + } - if ( _qosm1Proxy->isActive()) - { - _qosm1Proxy->checkConnection(); - } + if (_qosm1Proxy->isActive()) + { + _qosm1Proxy->checkConnection(); + } } Client* AdapterManager::convertClient(uint16_t msgId, uint16_t* clientMsgId) { - return _aggregater->convertClient(msgId, clientMsgId); + return _aggregater->convertClient(msgId, clientMsgId); } bool AdapterManager::isAggregaterActive(void) { - return _aggregater->isActive(); + return _aggregater->isActive(); } /* -AggregateTopicElement* AdapterManager::findTopic(Topic* topic) -{ - return _aggregater->findTopic(topic); -} + AggregateTopicElement* AdapterManager::findTopic(Topic* topic) + { + return _aggregater->findTopic(topic); + } -AggregateTopicElement* AdapterManager::addAggregateTopic(Topic* topic, Client* client) -{ - return _aggregater->addAggregateTopic(topic, client); -} + AggregateTopicElement* AdapterManager::addAggregateTopic(Topic* topic, Client* client) + { + return _aggregater->addAggregateTopic(topic, client); + } -void AdapterManager::removeAggregateTopic(Topic* topic, Client* client) -{ - //_aggregater->removeAggregateTopic(topic, client); -} + void AdapterManager::removeAggregateTopic(Topic* topic, Client* client) + { + //_aggregater->removeAggregateTopic(topic, client); + } -void AdapterManager::removeAggregateTopicList(Topics* topics, Client* client) -{ + void AdapterManager::removeAggregateTopicList(Topics* topics, Client* client) + { -} -*/ + } + */ diff --git a/MQTTSNGateway/src/MQTTSNGWAdapterManager.h b/MQTTSNGateway/src/MQTTSNGWAdapterManager.h index 58e5a03..42674be 100644 --- a/MQTTSNGateway/src/MQTTSNGWAdapterManager.h +++ b/MQTTSNGateway/src/MQTTSNGWAdapterManager.h @@ -33,12 +33,12 @@ class ClientRecvTask; class ClientSendTask; /*===================================== - Class AdapterManager + Class AdapterManager =====================================*/ class AdapterManager { public: - AdapterManager(Gateway* gw); + AdapterManager(Gateway* gw); ~AdapterManager(void); void initialize(char* gwName, bool aggregater, bool fowarder, bool qosM1); ForwarderList* getForwarderList(void); @@ -49,18 +49,16 @@ public: bool isAggregatedClient(Client* client); Client* getClient(Client* client); Client* convertClient(uint16_t msgId, uint16_t* clientMsgId); - int unicastToClient(Client* client, MQTTSNPacket* packet, ClientSendTask* task); + int unicastToClient(Client* client, MQTTSNPacket* packet, + ClientSendTask* task); bool isAggregaterActive(void); private: - Gateway* _gateway {nullptr}; - ForwarderList* _forwarders {nullptr}; - QoSm1Proxy* _qosm1Proxy {nullptr}; - Aggregater* _aggregater {nullptr}; + 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 index 24dd23f..ed912eb 100644 --- a/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.cpp +++ b/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.cpp @@ -21,7 +21,7 @@ =====================================*/ ClientTopicElement::ClientTopicElement(Client* client) { - _client = client; + _client = client; } ClientTopicElement::~ClientTopicElement() @@ -31,12 +31,12 @@ ClientTopicElement::~ClientTopicElement() Client* ClientTopicElement::getClient(void) { - return _client; + return _client; } ClientTopicElement* ClientTopicElement::getNextClientElement(void) { - return _next; + return _next; } /*===================================== @@ -49,122 +49,123 @@ AggregateTopicElement::AggregateTopicElement(void) AggregateTopicElement::AggregateTopicElement(Topic* topic, Client* client) { - _topic = topic; - ClientTopicElement* elm = new ClientTopicElement(client); - if ( elm != nullptr ) - { - _head = elm; - _tail = elm; - } + _topic = topic; + 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(); + _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; - } + ClientTopicElement* elm = new ClientTopicElement(client); + if (elm == nullptr) + { + return nullptr; + } - _mutex.lock(); + _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 = p; - } - } - _mutex.unlock(); - return elm; + 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 = p; + } + } + _mutex.unlock(); + return elm; } ClientTopicElement* AggregateTopicElement::find(Client* client) { - ClientTopicElement* p = _head; - while ( p != nullptr ) - { - if ( p->_client == client) - { - break; - } - p = p->_next; - } - return p; + ClientTopicElement* p = _head; + while (p != nullptr) + { + if (p->_client == client) + { + break; + } + p = p->_next; + } + return p; } ClientTopicElement* AggregateTopicElement::getFirstClientTopicElement(void) { - return _head; + return _head; } -ClientTopicElement* AggregateTopicElement::getNextClientTopicElement(ClientTopicElement* elmClient) +ClientTopicElement* AggregateTopicElement::getNextClientTopicElement( + ClientTopicElement* elmClient) { - return elmClient->_next; + return elmClient->_next; } void AggregateTopicElement::eraseClient(Client* client) { - _mutex.lock(); + _mutex.lock(); - ClientTopicElement* p = find(client); - if ( p != nullptr ) - { - if ( p->_prev == nullptr ) // head element - { - _head = p->_next; - if ( p->_next == nullptr ) // head & only one - { - _tail = nullptr; - } - else - { - p->_next->_prev = nullptr; // head & midle - } - } - else if ( p->_next != nullptr ) // middle - { - p->_prev->_next = p->_next; - } - else // tail - { - p->_prev->_next = nullptr; - _tail = p->_prev; - } - delete p; - } - _mutex.unlock(); + ClientTopicElement* p = find(client); + if (p != nullptr) + { + if (p->_prev == nullptr) // head element + { + _head = p->_next; + if (p->_next == nullptr) // head & only one + { + _tail = nullptr; + } + else + { + p->_next->_prev = nullptr; // head & midle + } + } + else if (p->_next != nullptr) // middle + { + p->_prev->_next = p->_next; + } + else // tail + { + p->_prev->_next = nullptr; + _tail = p->_prev; + } + delete p; + } + _mutex.unlock(); } /*===================================== @@ -183,138 +184,139 @@ AggregateTopicTable::~AggregateTopicTable() AggregateTopicElement* AggregateTopicTable::add(Topic* topic, Client* client) { - AggregateTopicElement* elm = nullptr; - _mutex.lock(); - elm = getAggregateTopicElement(topic); - if ( elm != nullptr ) - { - if ( elm->find(client) == nullptr ) - { - elm->add(client); - } - } - else - { - Topic* newTopic = topic->duplicate(); - elm = new AggregateTopicElement(newTopic, client); - if ( _head == nullptr ) - { - _head = elm; - _tail = elm; - } - else - { - elm->_prev = _tail; - _tail->_next = elm; - _tail = elm; - } - } - _mutex.unlock(); - return elm; + AggregateTopicElement* elm = nullptr; + _mutex.lock(); + elm = getAggregateTopicElement(topic); + if (elm != nullptr) + { + if (elm->find(client) == nullptr) + { + elm->add(client); + } + } + else + { + Topic* newTopic = topic->duplicate(); + elm = new AggregateTopicElement(newTopic, client); + if (_head == nullptr) + { + _head = elm; + _tail = elm; + } + else + { + elm->_prev = _tail; + _tail->_next = elm; + _tail = elm; + } + } + _mutex.unlock(); + return elm; } void AggregateTopicTable::erase(Topic* topic, Client* client) { - AggregateTopicElement* elm = nullptr; + AggregateTopicElement* elm = nullptr; - _mutex.lock(); - elm = getAggregateTopicElement(topic); + _mutex.lock(); + elm = getAggregateTopicElement(topic); - if ( elm != nullptr ) - { - elm->eraseClient(client); - } - if ( elm->_head == nullptr ) - { - erase(elm); - } - _mutex.unlock(); - return; + if (elm != nullptr) + { + elm->eraseClient(client); + } + if (elm->_head == nullptr) + { + erase(elm); + } + _mutex.unlock(); + return; } void AggregateTopicTable::erase(AggregateTopicElement* elmTopic) { - if ( elmTopic != nullptr ) - { - if ( elmTopic->_prev == nullptr ) // head element - { - _head = elmTopic->_next; - if ( elmTopic->_next == nullptr ) // head & only one - { - _tail = nullptr; - } - else - { - elmTopic->_next->_prev = nullptr; // head & midle - } - } - else if ( elmTopic->_next != nullptr ) // middle - { - elmTopic->_prev->_next = elmTopic->_next; - } - else // tail - { - elmTopic->_prev->_next = nullptr; - _tail = elmTopic->_prev; - } - delete elmTopic; - } + if (elmTopic != nullptr) + { + if (elmTopic->_prev == nullptr) // head element + { + _head = elmTopic->_next; + if (elmTopic->_next == nullptr) // head & only one + { + _tail = nullptr; + } + else + { + elmTopic->_next->_prev = nullptr; // head & midle + } + } + else if (elmTopic->_next != nullptr) // middle + { + elmTopic->_prev->_next = elmTopic->_next; + } + else // tail + { + elmTopic->_prev->_next = nullptr; + _tail = elmTopic->_prev; + } + delete elmTopic; + } } -AggregateTopicElement* AggregateTopicTable::getAggregateTopicElement(Topic* topic) +AggregateTopicElement* AggregateTopicTable::getAggregateTopicElement( + Topic* topic) { - AggregateTopicElement* elm = _head; + AggregateTopicElement* elm = _head; - while( elm != nullptr ) - { - if ( elm->_topic->isMatch(topic->_topicName) ) - { - break; - } - elm = elm->_next; - } - return elm; + while (elm != nullptr) + { + if (elm->_topic->isMatch(topic->_topicName)) + { + break; + } + elm = elm->_next; + } + return elm; } ClientTopicElement* AggregateTopicTable::getClientElement(Topic* topic) { - AggregateTopicElement* elm = getAggregateTopicElement(topic); - if ( elm != nullptr ) - { - return elm->_head; - } - else - { - return nullptr; - } + AggregateTopicElement* elm = getAggregateTopicElement(topic); + if (elm != nullptr) + { + return elm->_head; + } + else + { + return nullptr; + } } void AggregateTopicTable::print(void) { - AggregateTopicElement* elm = _head; + AggregateTopicElement* elm = _head; - printf("Beginning of AggregateTopicTable\n"); - while( elm != nullptr ) - { - printf("%s\n", elm->_topic->getTopicName()->c_str()); + printf("Beginning of AggregateTopicTable\n"); + while (elm != nullptr) + { + printf("%s\n", elm->_topic->getTopicName()->c_str()); - ClientTopicElement* clElm = elm->getFirstClientTopicElement(); - Client* client = clElm->getClient(); + ClientTopicElement* clElm = elm->getFirstClientTopicElement(); + Client* client = clElm->getClient(); - while ( client != nullptr ) - { - printf(" %s\n", client->getClientId()); - clElm = clElm->getNextClientElement(); - if ( clElm != nullptr ) - { - client = clElm->getClient(); - } - else - { - client = nullptr; - } - } - elm = elm->_next; - } - printf("End of AggregateTopicTable\n"); + while (client != nullptr) + { + printf(" %s\n", client->getClientId()); + clElm = clElm->getNextClientElement(); + if (clElm != nullptr) + { + client = clElm->getClient(); + } + else + { + client = nullptr; + } + } + elm = elm->_next; + } + printf("End of AggregateTopicTable\n"); } diff --git a/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.h b/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.h index 87d9e82..6293c0d 100644 --- a/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.h +++ b/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.h @@ -35,24 +35,24 @@ class Mutex; class AggregateTopicTable { public: - AggregateTopicTable(); - ~AggregateTopicTable(); + AggregateTopicTable(); + ~AggregateTopicTable(); - AggregateTopicElement* add(Topic* topic, Client* client); - AggregateTopicElement* getAggregateTopicElement(Topic* topic); - ClientTopicElement* getClientElement(Topic* topic); - void erase(Topic* topic, Client* client); - void clear(void); + AggregateTopicElement* add(Topic* topic, Client* client); + AggregateTopicElement* getAggregateTopicElement(Topic* topic); + ClientTopicElement* getClientElement(Topic* topic); + void erase(Topic* topic, Client* client); + void clear(void); - void print(void); + void print(void); private: - void erase(AggregateTopicElement* elmTopic); - Mutex _mutex; - AggregateTopicElement* _head {nullptr}; - AggregateTopicElement* _tail {nullptr}; - int _cnt {0}; - int _maxSize {MAX_MESSAGEID_TABLE_SIZE}; + void erase(AggregateTopicElement* elmTopic); + Mutex _mutex; + AggregateTopicElement* _head { nullptr }; + AggregateTopicElement* _tail { nullptr }; + int _cnt { 0 }; + int _maxSize { MAX_MESSAGEID_TABLE_SIZE }; }; /*===================================== @@ -68,17 +68,18 @@ public: ClientTopicElement* add(Client* client); ClientTopicElement* getFirstClientTopicElement(void); - ClientTopicElement* getNextClientTopicElement(ClientTopicElement* elmClient); + ClientTopicElement* getNextClientTopicElement( + ClientTopicElement* elmClient); void eraseClient(Client* client); ClientTopicElement* find(Client* client); private: Mutex _mutex; - Topic* _topic {nullptr}; - AggregateTopicElement* _next {nullptr}; - AggregateTopicElement* _prev {nullptr}; - ClientTopicElement* _head {nullptr}; - ClientTopicElement* _tail {nullptr}; + Topic* _topic { nullptr }; + AggregateTopicElement* _next { nullptr }; + AggregateTopicElement* _prev { nullptr }; + ClientTopicElement* _head { nullptr }; + ClientTopicElement* _tail { nullptr }; }; /*===================================== @@ -96,13 +97,11 @@ public: Client* getClient(void); private: - Client* _client {nullptr}; - ClientTopicElement* _next {nullptr}; - ClientTopicElement* _prev {nullptr}; + 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 index 93718db..79bdc61 100644 --- a/MQTTSNGateway/src/MQTTSNGWAggregater.cpp +++ b/MQTTSNGateway/src/MQTTSNGWAggregater.cpp @@ -26,9 +26,10 @@ using namespace MQTTSNGW; -Aggregater::Aggregater(Gateway* gw) : Adapter(gw) +Aggregater::Aggregater(Gateway* gw) : + Adapter(gw) { - _gateway = gw; + _gateway = gw; } Aggregater::~Aggregater(void) @@ -38,10 +39,10 @@ Aggregater::~Aggregater(void) void Aggregater::initialize(char* gwName) { - /* Create Aggregater Client */ - string name = string(gwName) + string("_Aggregater"); - setup(name.c_str(), Atype_Aggregater); - _isActive = true; + /* Create Aggregater Client */ + string name = string(gwName) + string("_Aggregater"); + setup(name.c_str(), Atype_Aggregater); + _isActive = true; //testMessageIdTable(); @@ -49,100 +50,99 @@ void Aggregater::initialize(char* gwName) bool Aggregater::isActive(void) { - return _isActive; + return _isActive; } uint16_t Aggregater::msgId(void) { - // Only SecureClient generates msgId to avoid duplication of msgId. Client does not generate it. - return Adapter::getSecureClient()->getNextPacketId(); + // Only SecureClient generates msgId to avoid duplication of msgId. Client does not generate it. + return Adapter::getSecureClient()->getNextPacketId(); } Client* Aggregater::convertClient(uint16_t msgId, uint16_t* clientMsgId) { - return _msgIdTable.getClientMsgId(msgId, 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.*/ + /* 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; - } + 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); + return _msgIdTable.getMsgId(client, clientMsgId); } -AggregateTopicElement* Aggregater::addAggregateTopic(Topic* topic, Client* client) +AggregateTopicElement* Aggregater::addAggregateTopic(Topic* topic, + Client* client) { - return _topicTable.add(topic, client); + return _topicTable.add(topic, client); } - void Aggregater::removeAggregateTopic(Topic* topic, Client* client) { - _topicTable.erase(topic, client); + _topicTable.erase(topic, client); } AggregateTopicElement* Aggregater::findTopic(Topic* topic) { - return _topicTable.getAggregateTopicElement(topic); + return _topicTable.getAggregateTopicElement(topic); } ClientTopicElement* Aggregater::getClientElement(Topic* topic) { - AggregateTopicElement* elm = findTopic(topic); - if ( elm != nullptr ) - { - return elm->getFirstClientTopicElement(); - } - else - { - return nullptr; - } + AggregateTopicElement* elm = findTopic(topic); + if (elm != nullptr) + { + return elm->getFirstClientTopicElement(); + } + else + { + return nullptr; + } } void Aggregater::printAggregateTopicTable(void) { - _topicTable.print(); + _topicTable.print(); } bool Aggregater::testMessageIdTable(void) { - Client* client = new Client(); - uint16_t msgId = 0; + 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)); + 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; + 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 index 959ff87..490b71f 100644 --- a/MQTTSNGateway/src/MQTTSNGWAggregater.h +++ b/MQTTSNGateway/src/MQTTSNGWAggregater.h @@ -32,11 +32,11 @@ class AggregateTopicTable; class Topics; /*===================================== - Class Aggregater + Class Aggregater =====================================*/ -class Aggregater : public Adapter +class Aggregater: public Adapter { - friend class MessageIdTable; + friend class MessageIdTable; public: Aggregater(Gateway* gw); ~Aggregater(void); @@ -44,39 +44,35 @@ public: void initialize(char* gwName); 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); + 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); - ClientTopicElement* getClientElement(Topic* topic); - ClientTopicElement* getNextClientElement(ClientTopicElement* clientElement); - Client* getClient(ClientTopicElement* clientElement); + ClientTopicElement* getClientElement(Topic* topic); + ClientTopicElement* getNextClientElement(ClientTopicElement* clientElement); + Client* getClient(ClientTopicElement* clientElement); - AggregateTopicElement* findTopic(Topic* topic); - AggregateTopicElement* addAggregateTopic(Topic* topic, Client* client); + AggregateTopicElement* findTopic(Topic* topic); + AggregateTopicElement* addAggregateTopic(Topic* topic, Client* client); - void removeAggregateTopic(Topic* topic, Client* client); - void removeAggregateAllTopic(Client* client); - bool isActive(void); + void removeAggregateTopic(Topic* topic, Client* client); + void removeAggregateAllTopic(Client* client); + bool isActive(void); - void printAggregateTopicTable(void); - bool testMessageIdTable(void); + void printAggregateTopicTable(void); + bool testMessageIdTable(void); private: - uint16_t msgId(void); - Gateway* _gateway {nullptr}; + uint16_t msgId(void); + Gateway* _gateway { nullptr }; MessageIdTable _msgIdTable; AggregateTopicTable _topicTable; - bool _isActive {false}; - bool _isSecure {false}; + bool _isActive { false }; + bool _isSecure { false }; }; - - } - - #endif /* MQTTSNGATEWAY_SRC_MQTTSNGWAGGREGATER_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp index 99b0ce5..9a570b6 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp @@ -29,9 +29,9 @@ char* currentDateTime(void); =====================================*/ BrokerRecvTask::BrokerRecvTask(Gateway* gateway) { - _gateway = gateway; - _gateway->attach((Thread*)this); - _light = nullptr; + _gateway = gateway; + _gateway->attach((Thread*) this); + _light = nullptr; } BrokerRecvTask::~BrokerRecvTask() @@ -44,7 +44,7 @@ BrokerRecvTask::~BrokerRecvTask() */ void BrokerRecvTask::initialize(int argc, char** argv) { - _light = _gateway->getLightIndicator(); + _light = _gateway->getLightIndicator(); } /** @@ -52,133 +52,147 @@ void BrokerRecvTask::initialize(int argc, char** argv) */ void BrokerRecvTask::run(void) { - struct timeval timeout; - MQTTGWPacket* packet = nullptr; - int rc; - Event* ev = nullptr; - fd_set rset; - fd_set wset; + struct timeval timeout; + MQTTGWPacket* packet = nullptr; + int rc; + Event* ev = nullptr; + fd_set rset; + fd_set wset; - while (true) - { - _light->blueLight(false); - if (CHK_SIGINT) - { - WRITELOG("\n%s BrokerRecvTask stopped.", currentDateTime()); - return; - } - timeout.tv_sec = 0; - timeout.tv_usec = 500000; // 500 msec - FD_ZERO(&rset); - FD_ZERO(&wset); - int maxSock = 0; - int sockfd = 0; + while (true) + { + _light->blueLight(false); + if (CHK_SIGINT) + { + WRITELOG("\n%s BrokerRecvTask stopped.", currentDateTime()); + return; + } + timeout.tv_sec = 0; + timeout.tv_usec = 500000; // 500 msec + FD_ZERO(&rset); + FD_ZERO(&wset); + int maxSock = 0; + int sockfd = 0; - /* Prepare sockets list to read */ - Client* client = _gateway->getClientList()->getClient(0); + /* Prepare sockets list to read */ + Client* client = _gateway->getClientList()->getClient(0); - while ( client ) - { - if (client->getNetwork()->isValid()) - { - sockfd = client->getNetwork()->getSock(); - FD_SET(sockfd, &rset); - FD_SET(sockfd, &wset); - if (sockfd > maxSock) - { - maxSock = sockfd; - } - } - client = client->getNextClient(); - } + while (client) + { + if (client->getNetwork()->isValid()) + { + sockfd = client->getNetwork()->getSock(); + FD_SET(sockfd, &rset); + FD_SET(sockfd, &wset); + if (sockfd > maxSock) + { + maxSock = sockfd; + } + } + client = client->getNextClient(); + } - if (maxSock == 0) - { - usleep(500 * 1000); - } - else - { - /* Check sockets is ready to read */ - int activity = select(maxSock + 1, &rset, 0, 0, &timeout); - if (activity > 0) - { - client = _gateway->getClientList()->getClient(0); + if (maxSock == 0) + { + usleep(500 * 1000); + } + else + { + /* Check sockets is ready to read */ + int activity = select(maxSock + 1, &rset, 0, 0, &timeout); + if (activity > 0) + { + client = _gateway->getClientList()->getClient(0); - while ( client ) - { - _light->blueLight(false); - if (client->getNetwork()->isValid()) - { - int sockfd = client->getNetwork()->getSock(); - if (FD_ISSET(sockfd, &rset)) - { - packet = new MQTTGWPacket(); - rc = 0; - /* read sockets */ - _light->blueLight(true); - rc = packet->recv(client->getNetwork()); - if ( rc > 0 ) - { - if ( log(client, packet) == -1 ) - { - delete packet; - goto nextClient; - } + while (client) + { + _light->blueLight(false); + if (client->getNetwork()->isValid()) + { + int sockfd = client->getNetwork()->getSock(); + if (FD_ISSET(sockfd, &rset)) + { + packet = new MQTTGWPacket(); + rc = 0; + /* read sockets */ + _light->blueLight(true); + rc = packet->recv(client->getNetwork()); + if (rc > 0) + { + if (log(client, packet) == -1) + { + delete packet; + goto nextClient; + } - /* post a BrokerRecvEvent */ - ev = new Event(); - ev->setBrokerRecvEvent(client, packet); - _gateway->getPacketEventQue()->post(ev); - } - else - { - if ( rc == 0 ) // Disconnected - { - client->getNetwork()->close(); - delete packet; + /* post a BrokerRecvEvent */ + ev = new Event(); + ev->setBrokerRecvEvent(client, packet); + _gateway->getPacketEventQue()->post(ev); + } + else + { + if (rc == 0) // Disconnected + { + client->getNetwork()->close(); + delete packet; - /* delete client when the client is not authorized & session is clean */ - _gateway->getClientList()->erase(client); + /* delete client when the client is not authorized & session is clean */ + _gateway->getClientList()->erase(client); - if ( client ) - { - client = client->getNextClient(); - } - continue; - } - else if (rc == -1) - { - WRITELOG("%s BrokerRecvTask can't receive a packet from the broker errno=%d %s%s\n", ERRMSG_HEADER, errno, client->getClientId(), ERRMSG_FOOTER); - } - else if ( rc == -2 ) - { - WRITELOG("%s BrokerRecvTask receive invalid length of packet from the broker. DISCONNECT %s %s\n", ERRMSG_HEADER, client->getClientId(),ERRMSG_FOOTER); - } - else if ( rc == -3 ) - { - WRITELOG("%s BrokerRecvTask can't get memories for the packet %s%s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); - } + if (client) + { + client = client->getNextClient(); + } + continue; + } + else if (rc == -1) + { + WRITELOG( + "%s BrokerRecvTask can't receive a packet from the broker errno=%d %s%s\n", + ERRMSG_HEADER, errno, + client->getClientId(), + ERRMSG_FOOTER); + } + else if (rc == -2) + { + WRITELOG( + "%s BrokerRecvTask receive invalid length of packet from the broker. DISCONNECT %s %s\n", + ERRMSG_HEADER, + client->getClientId(), + ERRMSG_FOOTER); + } + else if (rc == -3) + { + WRITELOG( + "%s BrokerRecvTask can't get memories for the packet %s%s\n", + ERRMSG_HEADER, + client->getClientId(), + ERRMSG_FOOTER); + } - delete packet; + delete packet; - if ( (rc == -1 || rc == -2) && ( client->isActive() || client->isSleep() || client->isAwake() )) - { - /* disconnect the client */ - packet = new MQTTGWPacket(); - packet->setHeader(DISCONNECT); - ev = new Event(); - ev->setBrokerRecvEvent(client, packet); - _gateway->getPacketEventQue()->post(ev); - } - } - } - } - nextClient: - client = client->getNextClient(); - } - } - } - } + if ((rc == -1 || rc == -2) + && (client->isActive() + || client->isSleep() + || client->isAwake())) + { + /* disconnect the client */ + packet = new MQTTGWPacket(); + packet->setHeader(DISCONNECT); + ev = new Event(); + ev->setBrokerRecvEvent(client, packet); + _gateway->getPacketEventQue()->post(ev); + } + } + } + } + nextClient: client = client->getNextClient(); + } + } + } + } } /** @@ -186,35 +200,43 @@ void BrokerRecvTask::run(void) */ int BrokerRecvTask::log(Client* client, MQTTGWPacket* packet) { - char pbuf[(SIZE_OF_LOG_PACKET + 5 )* 3]; - char msgId[6]; - int rc = 0; + char pbuf[(SIZE_OF_LOG_PACKET + 5) * 3]; + char msgId[6]; + int rc = 0; - switch (packet->getType()) - { - case CONNACK: - WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), LEFTARROWB, client->getClientId(), packet->print(pbuf)); - break; - case PUBLISH: - WRITELOG(FORMAT_W_MSGID_Y_W_NL, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROWB, client->getClientId(), packet->print(pbuf)); - break; - case PUBACK: - case PUBREC: - case PUBREL: - case PUBCOMP: - WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROWB, client->getClientId(), packet->print(pbuf)); - break; - case SUBACK: - case UNSUBACK: - WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROWB, client->getClientId(), packet->print(pbuf)); - break; - case PINGRESP: - WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), LEFTARROWB, client->getClientId(), packet->print(pbuf)); - break; - default: - WRITELOG("Type=%x\n", packet->getType()); - rc = -1; - break; - } - return rc; + switch (packet->getType()) + { + case CONNACK: + WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), LEFTARROWB, + client->getClientId(), packet->print(pbuf)); + break; + case PUBLISH: + WRITELOG(FORMAT_W_MSGID_Y_W_NL, currentDateTime(), packet->getName(), + packet->getMsgId(msgId), LEFTARROWB, client->getClientId(), + packet->print(pbuf)); + break; + case PUBACK: + case PUBREC: + case PUBREL: + case PUBCOMP: + WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), + packet->getMsgId(msgId), LEFTARROWB, client->getClientId(), + packet->print(pbuf)); + break; + case SUBACK: + case UNSUBACK: + WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), + packet->getMsgId(msgId), LEFTARROWB, client->getClientId(), + packet->print(pbuf)); + break; + case PINGRESP: + WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), LEFTARROWB, + client->getClientId(), packet->print(pbuf)); + break; + default: + WRITELOG("Type=%x\n", packet->getType()); + rc = -1; + break; + } + return rc; } diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.h b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.h index 4177015..ae532b7 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.h +++ b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.h @@ -28,21 +28,20 @@ namespace MQTTSNGW class BrokerRecvTask: public Thread { MAGIC_WORD_FOR_THREAD; - ; + public: - BrokerRecvTask(Gateway* gateway); - ~BrokerRecvTask(); - void initialize(int argc, char** argv); - void run(void); + BrokerRecvTask(Gateway* gateway); + ~BrokerRecvTask(); + void initialize(int argc, char** argv); + void run(void); private: - int log(Client*, MQTTGWPacket*); + int log(Client*, MQTTGWPacket*); - Gateway* _gateway; - LightIndicator* _light; + Gateway* _gateway; + LightIndicator* _light; }; } - #endif /* MQTTSNGWBROKERRECVTASK_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp index ff58a8d..ebe8a3c 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp @@ -33,10 +33,10 @@ char* currentDateTime(); =====================================*/ BrokerSendTask::BrokerSendTask(Gateway* gateway) { - _gateway = gateway; - _gateway->attach((Thread*)this); - _gwparams = nullptr; - _light = nullptr; + _gateway = gateway; + _gateway->attach((Thread*) this); + _gwparams = nullptr; + _light = nullptr; } BrokerSendTask::~BrokerSendTask() @@ -49,8 +49,8 @@ BrokerSendTask::~BrokerSendTask() */ void BrokerSendTask::initialize(int argc, char** argv) { - _gwparams = _gateway->getGWParams(); - _light = _gateway->getLightIndicator(); + _gwparams = _gateway->getGWParams(); + _light = _gateway->getLightIndicator(); } /** @@ -58,132 +58,149 @@ void BrokerSendTask::initialize(int argc, char** argv) */ void BrokerSendTask::run() { - Event* ev = nullptr; - MQTTGWPacket* packet = nullptr; - Client* client = nullptr; - AdapterManager* adpMgr = _gateway->getAdapterManager(); - int rc = 0; + Event* ev = nullptr; + MQTTGWPacket* packet = nullptr; + Client* client = nullptr; + AdapterManager* adpMgr = _gateway->getAdapterManager(); + int rc = 0; - while (true) - { - ev = _gateway->getBrokerSendQue()->wait(); + while (true) + { + ev = _gateway->getBrokerSendQue()->wait(); - if ( ev->getEventType() == EtStop ) - { - WRITELOG("\n%s BrokerSendTask stopped.", currentDateTime()); - delete ev; - return; - } + if (ev->getEventType() == EtStop) + { + WRITELOG("\n%s BrokerSendTask stopped.", currentDateTime()); + delete ev; + return; + } - if ( ev->getEventType() == EtBrokerSend) - { - client = ev->getClient(); - packet = ev->getMQTTGWPacket(); + if (ev->getEventType() == EtBrokerSend) + { + client = ev->getClient(); + packet = ev->getMQTTGWPacket(); - /* Check Client is managed by Adapters */ - client = adpMgr->getClient(client); + /* Check Client is managed by Adapters */ + client = adpMgr->getClient(client); - if ( packet->getType() == CONNECT && client->getNetwork()->isValid() ) - { - client->getNetwork()->close(); - } + if (packet->getType() == CONNECT && client->getNetwork()->isValid()) + { + client->getNetwork()->close(); + } - if ( !client->getNetwork()->isValid() ) - { - /* connect to the broker and send a packet */ + if (!client->getNetwork()->isValid()) + { + /* connect to the broker and send a packet */ - if (client->isSecureNetwork()) - { - 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((const char*)_gwparams->brokerName, (const char*)_gwparams->port); - } + if (client->isSecureNetwork()) + { + 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( + (const char*) _gwparams->brokerName, + (const char*) _gwparams->port); + } - if ( !rc ) - { - /* disconnect the broker and the client */ - WRITELOG("%s BrokerSendTask: %s can't connect to the broker. errno=%d %s %s\n", - ERRMSG_HEADER, client->getClientId(), errno, strerror(errno), ERRMSG_FOOTER); - delete ev; - client->getNetwork()->close(); - continue; - } - } + if (!rc) + { + /* disconnect the broker and the client */ + WRITELOG( + "%s BrokerSendTask: %s can't connect to the broker. errno=%d %s %s\n", + ERRMSG_HEADER, client->getClientId(), errno, + strerror(errno), ERRMSG_FOOTER); + delete ev; + client->getNetwork()->close(); + continue; + } + } - /* send a packet */ - _light->blueLight(true); - if ( (rc = packet->send(client->getNetwork())) > 0 ) - { - if ( packet->getType() == CONNECT ) - { - client->connectSended(); - } - else if ( packet->getType() == DISCONNECT ) - { - client->getNetwork()->close(); - client->disconnected(); - } - log(client, packet); - } - else - { - WRITELOG("%s BrokerSendTask: %s can't send a packet to the broker. errno=%d %s %s\n", - ERRMSG_HEADER, client->getClientId(), rc == -1 ? errno : 0, strerror(errno), ERRMSG_FOOTER); - if ( errno != EBADF ) - { - client->getNetwork()->close(); - } + /* send a packet */ + _light->blueLight(true); + if ((rc = packet->send(client->getNetwork())) > 0) + { + if (packet->getType() == CONNECT) + { + client->connectSended(); + } + else if (packet->getType() == DISCONNECT) + { + client->getNetwork()->close(); + client->disconnected(); + } + log(client, packet); + } + else + { + WRITELOG( + "%s BrokerSendTask: %s can't send a packet to the broker. errno=%d %s %s\n", + ERRMSG_HEADER, client->getClientId(), + rc == -1 ? errno : 0, strerror(errno), ERRMSG_FOOTER); + if ( errno != EBADF) + { + client->getNetwork()->close(); + } - /* Disconnect the client */ - packet = new MQTTGWPacket(); - packet->setHeader(DISCONNECT); - Event* ev1 = new Event(); - ev1->setBrokerRecvEvent(client, packet); - _gateway->getPacketEventQue()->post(ev1); - } + /* Disconnect the client */ + packet = new MQTTGWPacket(); + packet->setHeader(DISCONNECT); + Event* ev1 = new Event(); + ev1->setBrokerRecvEvent(client, packet); + _gateway->getPacketEventQue()->post(ev1); + } - _light->blueLight(false); - } - delete ev; - } + _light->blueLight(false); + } + delete ev; + } } - /** * write message content into stdout or Ringbuffer */ void BrokerSendTask::log(Client* client, MQTTGWPacket* packet) { - char pbuf[(SIZE_OF_LOG_PACKET + 5 )* 3]; - char msgId[6]; + char pbuf[(SIZE_OF_LOG_PACKET + 5) * 3]; + char msgId[6]; - switch (packet->getType()) - { - case CONNECT: - WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), RIGHTARROWB, client->getClientId(), packet->print(pbuf)); - break; - case PUBLISH: - WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), packet->getMsgId(msgId), RIGHTARROWB, client->getClientId(), packet->print(pbuf)); - break; - case SUBSCRIBE: - case UNSUBSCRIBE: - case PUBACK: - case PUBREC: - case PUBREL: - case PUBCOMP: - WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), packet->getMsgId(msgId), RIGHTARROWB, client->getClientId(), packet->print(pbuf)); - break; - case PINGREQ: - WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), RIGHTARROWB, client->getClientId(), packet->print(pbuf)); - break; - case DISCONNECT: - WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), RIGHTARROWB, client->getClientId(), packet->print(pbuf)); - break; - default: - break; - } + switch (packet->getType()) + { + case CONNECT: + WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), + RIGHTARROWB, client->getClientId(), packet->print(pbuf)); + break; + case PUBLISH: + WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), + packet->getMsgId(msgId), RIGHTARROWB, client->getClientId(), + packet->print(pbuf)); + break; + case SUBSCRIBE: + case UNSUBSCRIBE: + case PUBACK: + case PUBREC: + case PUBREL: + case PUBCOMP: + WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), + packet->getMsgId(msgId), RIGHTARROWB, client->getClientId(), + packet->print(pbuf)); + break; + case PINGREQ: + WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), + RIGHTARROWB, client->getClientId(), packet->print(pbuf)); + break; + case DISCONNECT: + WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), + RIGHTARROWB, client->getClientId(), packet->print(pbuf)); + break; + default: + break; + } } diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.h b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.h index 8244112..7361692 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.h +++ b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.h @@ -25,22 +25,22 @@ namespace MQTTSNGW class Adapter; /*===================================== - Class BrokerSendTask + Class BrokerSendTask =====================================*/ -class BrokerSendTask : public Thread +class BrokerSendTask: public Thread { - MAGIC_WORD_FOR_THREAD; - friend AdapterManager; +MAGIC_WORD_FOR_THREAD; + friend AdapterManager; public: - BrokerSendTask(Gateway* gateway); - ~BrokerSendTask(); - void initialize(int argc, char** argv); - void run(); + BrokerSendTask(Gateway* gateway); + ~BrokerSendTask(); + void initialize(int argc, char** argv); + void run(); private: - void log(Client*, MQTTGWPacket*); - Gateway* _gateway; - GatewayParams* _gwparams; - LightIndicator* _light; + void log(Client*, MQTTGWPacket*); + Gateway* _gateway; + GatewayParams* _gwparams; + LightIndicator* _light; }; } diff --git a/MQTTSNGateway/src/MQTTSNGWClient.cpp b/MQTTSNGateway/src/MQTTSNGWClient.cpp index 746f1af..a971bc2 100644 --- a/MQTTSNGateway/src/MQTTSNGWClient.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClient.cpp @@ -28,104 +28,107 @@ using namespace MQTTSNGW; char* currentDateTime(void); - /*===================================== Class Client =====================================*/ -static const char* theClientStatus[] = { "Disconnected", "TryConnecting", "Connecting", "Active", "Asleep", "Awake", "Lost" }; +static const char* theClientStatus[] = +{ "Disconnected", "TryConnecting", "Connecting", "Active", "Asleep", "Awake", + "Lost" }; Client::Client(bool secure) { - _packetId = 0; - _snMsgId = 0; - _status = Cstat_Disconnected; - _keepAliveMsec = 0; - _topics = new Topics(); - _clientId = nullptr; - _willTopic = nullptr; - _willMsg = nullptr; - _connectData = MQTTPacket_Connect_Initializer; - _network = new Network(secure); - _secureNetwork = secure; - _sensorNetype = true; - _connAck = nullptr; - _waitWillMsgFlg = false; - _sessionStatus = false; - _prevClient = nullptr; - _nextClient = nullptr; - _clientSleepPacketQue.setMaxSize(MAX_SAVED_PUBLISH); - _proxyPacketQue.setMaxSize(MAX_SAVED_PUBLISH); - _hasPredefTopic = false; - _holdPingRequest = false; - _forwarder = nullptr; - _clientType = Ctype_Regular; + _packetId = 0; + _snMsgId = 0; + _status = Cstat_Disconnected; + _keepAliveMsec = 0; + _topics = new Topics(); + _clientId = nullptr; + _willTopic = nullptr; + _willMsg = nullptr; + _connectData = MQTTPacket_Connect_Initializer; + _network = new Network(secure); + _secureNetwork = secure; + _sensorNetype = true; + _connAck = nullptr; + _waitWillMsgFlg = false; + _sessionStatus = false; + _prevClient = nullptr; + _nextClient = nullptr; + _clientSleepPacketQue.setMaxSize(MAX_SAVED_PUBLISH); + _proxyPacketQue.setMaxSize(MAX_SAVED_PUBLISH); + _hasPredefTopic = false; + _holdPingRequest = false; + _forwarder = nullptr; + _clientType = Ctype_Regular; } Client::~Client() { - if ( _topics ) - { - delete _topics; - } + if (_topics) + { + delete _topics; + } - if ( _clientId ) - { - free(_clientId); - } + if (_clientId) + { + free(_clientId); + } - if ( _willTopic ) - { - free(_willTopic); - } + if (_willTopic) + { + free(_willTopic); + } - if ( _willMsg ) - { - free(_willMsg); - } + if (_willMsg) + { + free(_willMsg); + } - if (_connAck) - { - delete _connAck; - } + if (_connAck) + { + delete _connAck; + } - if (_network) - { - delete _network; - } + if (_network) + { + delete _network; + } } TopicIdMapElement* Client::getWaitedPubTopicId(uint16_t msgId) { - return _waitedPubTopicIdMap.getElement(msgId); + return _waitedPubTopicIdMap.getElement(msgId); } TopicIdMapElement* Client::getWaitedSubTopicId(uint16_t msgId) { - return _waitedSubTopicIdMap.getElement(msgId); + return _waitedSubTopicIdMap.getElement(msgId); } MQTTGWPacket* Client::getClientSleepPacket() { - return _clientSleepPacketQue.getPacket(); + return _clientSleepPacketQue.getPacket(); } void Client::deleteFirstClientSleepPacket() { - _clientSleepPacketQue.pop(); + _clientSleepPacketQue.pop(); } int Client::setClientSleepPacket(MQTTGWPacket* packet) { - int rc = _clientSleepPacketQue.post(packet); - if ( rc ) - { - WRITELOG("%s %s is sleeping. the packet was saved.\n", currentDateTime(), _clientId); - } - else - { - WRITELOG("%s %s is sleeping but discard the packet.\n", currentDateTime(), _clientId); - } - return rc; + int rc = _clientSleepPacketQue.post(packet); + if (rc) + { + WRITELOG("%s %s is sleeping. the packet was saved.\n", + currentDateTime(), _clientId); + } + else + { + WRITELOG("%s %s is sleeping but discard the packet.\n", + currentDateTime(), _clientId); + } + return rc; } MQTTSNPacket* Client::getProxyPacket(void) @@ -141,64 +144,68 @@ void Client::deleteFirstProxyPacket() int Client::setProxyPacket(MQTTSNPacket* packet) { int rc = _proxyPacketQue.post(packet); - if ( rc ) + if (rc) { - WRITELOG("%s %s is Disconnected. the packet was saved.\n", currentDateTime(), _clientId); + 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); + WRITELOG("%s %s is Disconnected and discard the packet.\n", + currentDateTime(), _clientId); } return rc; } Connect* Client::getConnectData(void) { - return &_connectData; + return &_connectData; } void Client::eraseWaitedPubTopicId(uint16_t msgId) { - _waitedPubTopicIdMap.erase(msgId); + _waitedPubTopicIdMap.erase(msgId); } void Client::eraseWaitedSubTopicId(uint16_t msgId) { - _waitedSubTopicIdMap.erase(msgId); + _waitedSubTopicIdMap.erase(msgId); } void Client::clearWaitedPubTopicId(void) { - _waitedPubTopicIdMap.clear(); + _waitedPubTopicIdMap.clear(); } void Client::clearWaitedSubTopicId(void) { - _waitedSubTopicIdMap.clear(); + _waitedSubTopicIdMap.clear(); } -void Client::setWaitedPubTopicId(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type) +void Client::setWaitedPubTopicId(uint16_t msgId, uint16_t topicId, + MQTTSN_topicTypes type) { - _waitedPubTopicIdMap.add(msgId, topicId, type); + _waitedPubTopicIdMap.add(msgId, topicId, type); } -void Client::setWaitedSubTopicId(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type) +void Client::setWaitedSubTopicId(uint16_t msgId, uint16_t topicId, + MQTTSN_topicTypes type) { - _waitedSubTopicIdMap.add(msgId, topicId, type); + _waitedSubTopicIdMap.add(msgId, topicId, type); } bool Client::checkTimeover(void) { - return (_status == Cstat_Active && _keepAliveTimer.isTimeup()); + return (_status == Cstat_Active && _keepAliveTimer.isTimeup()); } void Client::setKeepAlive(MQTTSNPacket* packet) { - MQTTSNPacket_connectData param; - if (packet->getCONNECT(¶m)) - { - _keepAliveMsec = param.duration * 1000UL; - _keepAliveTimer.start(_keepAliveMsec * 1.5); - } + MQTTSNPacket_connectData param; + if (packet->getCONNECT(¶m)) + { + _keepAliveMsec = param.duration * 1000UL; + _keepAliveTimer.start(_keepAliveMsec * 1.5); + } } void Client::setForwarder(Forwarder* forwarder) @@ -214,102 +221,102 @@ Forwarder* Client::getForwarder(void) void Client::setSessionStatus(bool status) { - _sessionStatus = status; + _sessionStatus = status; } bool Client::erasable(void) { - return _sessionStatus && !_hasPredefTopic && _forwarder == nullptr; + return _sessionStatus && !_hasPredefTopic && _forwarder == nullptr; } void Client::updateStatus(MQTTSNPacket* packet) { - if (((_status == Cstat_Disconnected) || (_status == Cstat_Lost)) && packet->getType() == MQTTSN_CONNECT) - { - setKeepAlive(packet); - } - else if (_status == Cstat_Active) - { - switch (packet->getType()) - { - case MQTTSN_PINGREQ: - case MQTTSN_PUBLISH: - case MQTTSN_SUBSCRIBE: - case MQTTSN_UNSUBSCRIBE: - case MQTTSN_PUBACK: - case MQTTSN_PUBCOMP: - case MQTTSN_PUBREL: - case MQTTSN_PUBREC: - if ( _clientType != Ctype_Proxy ) - { - _keepAliveTimer.start(_keepAliveMsec * 1.5); - } - break; - case MQTTSN_DISCONNECT: - uint16_t duration; - packet->getDISCONNECT(&duration); - if (duration) - { - _status = Cstat_Asleep; - } - else - { - disconnected(); - } - break; - default: - break; - } - } - else if (_status == Cstat_Awake || _status == Cstat_Asleep) - { - switch (packet->getType()) - { - case MQTTSN_CONNECT: - _status = Cstat_Active; - break; - case MQTTSN_DISCONNECT: - disconnected(); - break; - case MQTTSN_PINGREQ: - _status = Cstat_Awake; - break; - case MQTTSN_PINGRESP: - _status = Cstat_Asleep; - break; - default: - break; - } - } - DEBUGLOG("Client Status = %s\n", theClientStatus[_status]); + if (((_status == Cstat_Disconnected) || (_status == Cstat_Lost)) + && packet->getType() == MQTTSN_CONNECT) + { + setKeepAlive(packet); + } + else if (_status == Cstat_Active) + { + switch (packet->getType()) + { + case MQTTSN_PINGREQ: + case MQTTSN_PUBLISH: + case MQTTSN_SUBSCRIBE: + case MQTTSN_UNSUBSCRIBE: + case MQTTSN_PUBACK: + case MQTTSN_PUBCOMP: + case MQTTSN_PUBREL: + case MQTTSN_PUBREC: + if (_clientType != Ctype_Proxy) + { + _keepAliveTimer.start(_keepAliveMsec * 1.5); + } + break; + case MQTTSN_DISCONNECT: + uint16_t duration; + packet->getDISCONNECT(&duration); + if (duration) + { + _status = Cstat_Asleep; + } + else + { + disconnected(); + } + break; + default: + break; + } + } + else if (_status == Cstat_Awake || _status == Cstat_Asleep) + { + switch (packet->getType()) + { + case MQTTSN_CONNECT: + _status = Cstat_Active; + break; + case MQTTSN_DISCONNECT: + disconnected(); + break; + case MQTTSN_PINGREQ: + _status = Cstat_Awake; + break; + case MQTTSN_PINGRESP: + _status = Cstat_Asleep; + break; + default: + break; + } + } DEBUGLOG("Client Status = %s\n", theClientStatus[_status]); } void Client::updateStatus(ClientStatus stat) { - _status = stat; + _status = stat; } void Client::connectSended() { - _status = Cstat_Connecting; + _status = Cstat_Connecting; } void Client::connackSended(int rc) { - if (rc == MQTTSN_RC_ACCEPTED) - { - _status = Cstat_Active; - } - else - { - disconnected(); - } + if (rc == MQTTSN_RC_ACCEPTED) + { + _status = Cstat_Active; + } + else + { + disconnected(); + } } void Client::disconnected(void) { - _status = Cstat_Disconnected; - _waitWillMsgFlg = false; + _status = Cstat_Disconnected; + _waitWillMsgFlg = false; } void Client::tryConnect(void) @@ -319,64 +326,64 @@ void Client::tryConnect(void) bool Client::isConnectSendable(void) { - if ( _status == Cstat_Lost || _status == Cstat_TryConnecting ) - { - return false; - } - else - { - return true; - } + if (_status == Cstat_Lost || _status == Cstat_TryConnecting) + { + return false; + } + else + { + return true; + } } uint16_t Client::getNextPacketId(void) { - _packetId++; - if ( _packetId == 0xffff ) - { - _packetId = 1; - } - return _packetId; + _packetId++; + if (_packetId == 0xffff) + { + _packetId = 1; + } + return _packetId; } uint8_t Client::getNextSnMsgId(void) { - _snMsgId++; - if (_snMsgId == 0) - { - _snMsgId++; - } - return _snMsgId; + _snMsgId++; + if (_snMsgId == 0) + { + _snMsgId++; + } + return _snMsgId; } Topics* Client::getTopics(void) { - return _topics; + return _topics; } Network* Client::getNetwork(void) { - return _network; + return _network; } void Client::setClientAddress(SensorNetAddress* sensorNetAddr) { - _sensorNetAddr = *sensorNetAddr; + _sensorNetAddr = *sensorNetAddr; } SensorNetAddress* Client::getSensorNetAddress(void) { - return &_sensorNetAddr; + return &_sensorNetAddr; } void Client::setSensorNetType(bool stable) { - _sensorNetype = stable; + _sensorNetype = stable; } void Client::setTopics(Topics* topics) { - _topics = topics; + _topics = topics; } ClientStatus Client::getClientStatus(void) @@ -386,32 +393,32 @@ ClientStatus Client::getClientStatus(void) void Client::setWaitWillMsgFlg(bool flg) { - _waitWillMsgFlg = flg; + _waitWillMsgFlg = flg; } bool Client::isWaitWillMsg(void) { - return _waitWillMsgFlg; + return _waitWillMsgFlg; } bool Client::isDisconnect(void) { - return (_status == Cstat_Disconnected); + return (_status == Cstat_Disconnected); } bool Client::isActive(void) { - return (_status == Cstat_Active); + return (_status == Cstat_Active); } bool Client::isSleep(void) { - return (_status == Cstat_Asleep); + return (_status == Cstat_Asleep); } bool Client::isAwake(void) { - return (_status == Cstat_Awake); + return (_status == Cstat_Awake); } bool Client::isConnecting(void) @@ -421,94 +428,94 @@ bool Client::isConnecting(void) bool Client::isSecureNetwork(void) { - return _secureNetwork; + return _secureNetwork; } bool Client::isSensorNetStable(void) { - return _sensorNetype; + return _sensorNetype; } WaitREGACKPacketList* Client::getWaitREGACKPacketList() { - return &_waitREGACKList; + return &_waitREGACKList; } Client* Client::getNextClient(void) { - return _nextClient; + return _nextClient; } void Client::setClientId(MQTTSNString id) { - if ( _clientId ) - { - free(_clientId); - } + if (_clientId) + { + free(_clientId); + } - if ( id.cstring ) - { - _clientId = (char*)calloc(strlen(id.cstring) + 1, 1); - memcpy(_clientId, id.cstring, strlen(id.cstring)); - } - else - { + 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); - } + _clientId = (char*) calloc(MQTTSNstrlen(id) + 1, 1); + unsigned char* ptr = (unsigned char*) _clientId; + writeMQTTSNString((unsigned char**) &ptr, id); + } } void Client::setWillTopic(MQTTSNString willTopic) { - if ( _willTopic ) - { - free(_willTopic); - } + if (_willTopic) + { + free(_willTopic); + } - _willTopic = (char*)calloc(MQTTSNstrlen(willTopic) + 1, 1); - /* save willTopic into (char*)_willTopic with NULL termination */ - unsigned char* ptr = (unsigned char*)_willTopic; - writeMQTTSNString((unsigned char**)&ptr, willTopic); + _willTopic = (char*) calloc(MQTTSNstrlen(willTopic) + 1, 1); + /* save willTopic into (char*)_willTopic with NULL termination */ + unsigned char* ptr = (unsigned char*) _willTopic; + writeMQTTSNString((unsigned char**) &ptr, willTopic); } void Client::setWillMsg(MQTTSNString willMsg) { - if ( _willMsg) - { - free(_willMsg); - } + if (_willMsg) + { + free(_willMsg); + } - _willMsg = (char*)calloc(MQTTSNstrlen(willMsg) + 1, 1); - /* save willMsg into (char*)_willMsg with NULL termination */ - unsigned char* ptr = (unsigned char*)_willMsg; - writeMQTTSNString((unsigned char**)&ptr, willMsg); + _willMsg = (char*) calloc(MQTTSNstrlen(willMsg) + 1, 1); + /* save willMsg into (char*)_willMsg with NULL termination */ + unsigned char* ptr = (unsigned char*) _willMsg; + writeMQTTSNString((unsigned char**) &ptr, willMsg); } char* Client::getClientId(void) { - return _clientId; + return _clientId; } char* Client::getWillTopic(void) { - return _willTopic; + return _willTopic; } char* Client::getWillMsg(void) { - return _willMsg; + return _willMsg; } const char* Client::getStatus(void) { - return theClientStatus[_status]; + return theClientStatus[_status]; } bool Client::isQoSm1Proxy(void) { - return _clientType == Ctype_Proxy; + return _clientType == Ctype_Proxy; } bool Client::isForwarded(void) @@ -528,23 +535,23 @@ bool Client::isAggregater(void) void Client::setAdapterType(AdapterType type) { - switch ( type ) + switch (type) { case Atype_QoSm1Proxy: - _clientType = Ctype_Proxy; - break; + _clientType = Ctype_Proxy; + break; case Atype_Aggregater: - _clientType = Ctype_Aggregater; - break; + _clientType = Ctype_Aggregater; + break; default: - throw Exception("Client::setAdapterType(): Invalid Type."); - break; + throw Exception("Client::setAdapterType(): Invalid Type."); + break; } } bool Client::isAdapter(void) { - return _clientType == Ctype_Proxy || _clientType == Ctype_Aggregater; + return _clientType == Ctype_Proxy || _clientType == Ctype_Aggregater; } bool Client::isQoSm1(void) @@ -554,12 +561,12 @@ bool Client::isQoSm1(void) void Client::setQoSm1(void) { - _clientType = Ctype_QoS_1; + _clientType = Ctype_QoS_1; } void Client::setAggregated(void) { - _clientType = Ctype_Aggregated; + _clientType = Ctype_Aggregated; } void Client::holdPingRequest(void) @@ -577,22 +584,20 @@ bool Client::isHoldPingReqest(void) return _holdPingRequest; } - - /*===================================== Class WaitREGACKPacket =====================================*/ waitREGACKPacket::waitREGACKPacket(MQTTSNPacket* packet, uint16_t REGACKMsgId) { - _packet = packet; - _msgId = REGACKMsgId; - _next = nullptr; - _prev = nullptr; + _packet = packet; + _msgId = REGACKMsgId; + _next = nullptr; + _prev = nullptr; } waitREGACKPacket::~waitREGACKPacket() { - delete _packet; + delete _packet; } /*===================================== @@ -601,89 +606,89 @@ waitREGACKPacket::~waitREGACKPacket() WaitREGACKPacketList::WaitREGACKPacketList() { - _first = nullptr; - _end = nullptr; - _cnt = 0; + _first = nullptr; + _end = nullptr; + _cnt = 0; } WaitREGACKPacketList::~WaitREGACKPacketList() { - waitREGACKPacket* p = _first; - while (p) - { - waitREGACKPacket* q = p->_next; - delete p; - p = q; - } + waitREGACKPacket* p = _first; + while (p) + { + waitREGACKPacket* q = p->_next; + delete p; + p = q; + } } int WaitREGACKPacketList::setPacket(MQTTSNPacket* packet, uint16_t REGACKMsgId) { - waitREGACKPacket* elm = new waitREGACKPacket(packet, REGACKMsgId); - if (elm == nullptr) - { - return 0; - } + waitREGACKPacket* elm = new waitREGACKPacket(packet, REGACKMsgId); + if (elm == nullptr) + { + return 0; + } - if (_first == nullptr) - { - _first = elm; - _end = elm; - } - else - { - _end->_next = elm; - elm->_prev = _end; - _end = elm; - } - _cnt++; - return 1; + if (_first == nullptr) + { + _first = elm; + _end = elm; + } + else + { + _end->_next = elm; + elm->_prev = _end; + _end = elm; + } + _cnt++; + return 1; } MQTTSNPacket* WaitREGACKPacketList::getPacket(uint16_t REGACKMsgId) { - waitREGACKPacket* p = _first; - while (p) - { - if (p->_msgId == REGACKMsgId) - { - return p->_packet; - } - p = p->_next; - } - return nullptr; + waitREGACKPacket* p = _first; + while (p) + { + if (p->_msgId == REGACKMsgId) + { + return p->_packet; + } + p = p->_next; + } + return nullptr; } void WaitREGACKPacketList::erase(uint16_t REGACKMsgId) { - waitREGACKPacket* p = _first; - while (p) - { - if (p->_msgId == REGACKMsgId) - { - if (p->_prev == nullptr) - { - _first = p->_next; + waitREGACKPacket* p = _first; + while (p) + { + if (p->_msgId == REGACKMsgId) + { + 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; - } - _cnt--; + } + else + { + p->_prev->_next = p->_next; + } + if (p->_next == nullptr) + { + _end = p->_prev; + } + else + { + p->_next->_prev = p->_prev; + } + _cnt--; break; // Do not delete element. Element is deleted after sending to Client. - } - p = p->_next; - } + } + p = p->_next; + } } uint8_t WaitREGACKPacketList::getCount(void) @@ -691,4 +696,3 @@ uint8_t WaitREGACKPacketList::getCount(void) return _cnt; } - diff --git a/MQTTSNGateway/src/MQTTSNGWClient.h b/MQTTSNGateway/src/MQTTSNGWClient.h index 5071710..1774ad9 100644 --- a/MQTTSNGateway/src/MQTTSNGWClient.h +++ b/MQTTSNGateway/src/MQTTSNGWClient.h @@ -49,7 +49,6 @@ public: _que = new Que; } - ~PacketQue() { clear(); @@ -72,8 +71,7 @@ public: } } - int - post(T* packet) + int post(T* packet) { int rc; _mutex.lock(); @@ -113,8 +111,6 @@ private: Mutex _mutex; }; - - /*===================================== Class WaitREGACKPacket =====================================*/ @@ -151,20 +147,29 @@ private: waitREGACKPacket* _end; }; - - /*===================================== Class Client =====================================*/ typedef enum { - Cstat_Disconnected = 0, Cstat_TryConnecting, Cstat_Connecting, Cstat_Active, Cstat_Asleep, Cstat_Awake, Cstat_Lost + 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; + Ctype_Regular = 0, + Ctype_Forwarded, + Ctype_QoS_1, + Ctype_Aggregated, + Ctype_Proxy, + Ctype_Aggregater +} ClientType; class Forwarder; @@ -191,10 +196,12 @@ public: void clearWaitedPubTopicId(void); void clearWaitedSubTopicId(void); - int setClientSleepPacket(MQTTGWPacket*); + 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); + void setWaitedPubTopicId(uint16_t msgId, uint16_t topicId, + MQTTSN_topicTypes type); + void setWaitedSubTopicId(uint16_t msgId, uint16_t topicId, + MQTTSN_topicTypes type); bool checkTimeover(void); void updateStatus(MQTTSNPacket*); @@ -260,7 +267,7 @@ private: PacketQue _clientSleepPacketQue; PacketQue _proxyPacketQue; - WaitREGACKPacketList _waitREGACKList; + WaitREGACKPacketList _waitREGACKList; Topics* _topics; TopicIdMap _waitedPubTopicIdMap; @@ -285,7 +292,7 @@ private: uint8_t _snMsgId; Network* _network; // Broker - bool _secureNetwork; // SSL + bool _secureNetwork; // SSL bool _sensorNetype; // false: unstable network like a G3 SensorNetAddress _sensorNetAddr; @@ -299,7 +306,5 @@ private: Client* _prevClient; }; - - } #endif /* MQTTSNGWCLIENT_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWClientList.cpp b/MQTTSNGateway/src/MQTTSNGWClientList.cpp index f164996..a1e0dfb 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientList.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientList.cpp @@ -51,38 +51,41 @@ ClientList::~ClientList() void ClientList::initialize(bool aggregate) { - if (theGateway->getGWParams()->clientAuthentication ) + if (theGateway->getGWParams()->clientAuthentication) { - int type = TRANSPEARENT_TYPE; - if ( aggregate ) - { - type = AGGREGATER_TYPE; - } - setClientList(type); + int type = TRANSPEARENT_TYPE; + if (aggregate) + { + type = AGGREGATER_TYPE; + } + setClientList(type); _authorize = true; } - if ( theGateway->getGWParams()->predefinedTopic ) + if (theGateway->getGWParams()->predefinedTopic) { - setPredefinedTopics(aggregate); + setPredefinedTopics(aggregate); } } void ClientList::setClientList(int type) { - if (!createList(theGateway->getGWParams()->clientListName, type)) - { - throw Exception("ClientList::setClientList No client list defined by config file."); - } + if (!createList(theGateway->getGWParams()->clientListName, type)) + { + throw Exception( + "ClientList::setClientList No client list defined by config file."); + } } void ClientList::setPredefinedTopics(bool aggrecate) { - if ( !readPredefinedList(theGateway->getGWParams()->predefinedTopicFileName, aggrecate) ) - { - throw Exception("ClientList::setPredefinedTopics No predefindTopi list defined by config file."); + if (!readPredefinedList(theGateway->getGWParams()->predefinedTopicFileName, + aggrecate)) + { + throw Exception( + "ClientList::setPredefinedTopics No predefindTopi list defined by config file."); - } + } } /** @@ -148,17 +151,19 @@ bool ClientList::createList(const char* fileName, int type) 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) ) + if ((qos_1 && type == QOSM1PROXY_TYPE) + || (!qos_1 && type == AGGREGATER_TYPE)) { - createClient(&netAddr, &clientId, stable, secure, type); + createClient(&netAddr, &clientId, stable, secure, type); } - else if ( forwarder && type == FORWARDER_TYPE) + else if (forwarder && type == FORWARDER_TYPE) { - theGateway->getAdapterManager()->getForwarderList()->addForwarder(&netAddr, &clientId); + theGateway->getAdapterManager()->getForwarderList()->addForwarder( + &netAddr, &clientId); } - else if (type == TRANSPEARENT_TYPE ) + else if (type == TRANSPEARENT_TYPE) { - createClient(&netAddr, &clientId, stable, secure, type); + createClient(&netAddr, &clientId, stable, secure, type); } } else @@ -179,7 +184,8 @@ bool ClientList::readPredefinedList(const char* fileName, bool aggregate) FILE* fp; char buf[MAX_CLIENTID_LENGTH + 256]; size_t pos0, pos1; - MQTTSNString clientId = MQTTSNString_initializer;; + MQTTSNString clientId = MQTTSNString_initializer; + ; bool rc = false; if ((fp = fopen(fileName, "r")) != 0) @@ -201,12 +207,12 @@ bool ClientList::readPredefinedList(const char* fileName, bool aggregate) } pos0 = data.find_first_of(","); - pos1 = data.find(",", pos0 + 1) ; + 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); + string topicName = data.substr(pos0 + 1, pos1 - pos0 - 1); uint16_t topicID = stoul(data.substr(pos1 + 1)); - createPredefinedTopic( &clientId, topicName, topicID, aggregate); + createPredefinedTopic(&clientId, topicName, topicID, aggregate); free(clientId.cstring); } fclose(fp); @@ -214,7 +220,8 @@ bool ClientList::readPredefinedList(const char* fileName, bool aggregate) } else { - WRITELOG("ClientList can not open the Predefined Topic List. %s\n", fileName); + WRITELOG("ClientList can not open the Predefined Topic List. %s\n", + fileName); return false; } return rc; @@ -222,7 +229,7 @@ bool ClientList::readPredefinedList(const char* fileName, bool aggregate) void ClientList::erase(Client*& client) { - if ( !_authorize && client->erasable()) + if (!_authorize && client->erasable()) { _mutex.lock(); Client* prev = client->_prevClient; @@ -247,7 +254,7 @@ void ClientList::erase(Client*& client) } _clientCnt--; Forwarder* fwd = client->getForwarder(); - if ( fwd ) + if (fwd) { fwd->eraseClient(client); } @@ -259,14 +266,14 @@ void ClientList::erase(Client*& client) Client* ClientList::getClient(SensorNetAddress* addr) { - if ( addr ) + if (addr) { _mutex.lock(); Client* client = _firstClient; while (client != nullptr) { - if (client->getSensorNetAddress()->isMatch(addr) ) + if (client->getSensorNetAddress()->isMatch(addr)) { _mutex.unlock(); return client; @@ -280,38 +287,38 @@ Client* ClientList::getClient(SensorNetAddress* addr) 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* 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; + const char* clID = clientId->cstring; - if (clID == nullptr ) + if (clID == nullptr) { clID = clientId->lenstring.data; } while (client != nullptr) { - if (strncmp((const char*)client->getClientId(), clID, MQTTSNstrlen(*clientId)) == 0 ) + if (strncmp((const char*) client->getClientId(), clID, + MQTTSNstrlen(*clientId)) == 0) { _mutex.unlock(); return client; @@ -322,51 +329,53 @@ Client* ClientList::getClient(MQTTSNString* clientId) return 0; } -Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, int type) +Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, + int type) { - return createClient(addr, clientId, false, false, type); + return createClient(addr, clientId, false, false, type); } -Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, bool unstableLine, bool secure, int type) +Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, + bool unstableLine, bool secure, int type) { Client* client = nullptr; /* anonimous clients */ - if ( _clientCnt > MAX_CLIENTS ) + if (_clientCnt > MAX_CLIENTS) { return 0; // full of clients } client = getClient(addr); - if ( client ) + if (client) { return client; } /* creat a new client */ client = new Client(secure); - if ( addr ) + if (addr) { client->setClientAddress(addr); } client->setSensorNetType(unstableLine); - if ( MQTTSNstrlen(*clientId) ) + if (MQTTSNstrlen(*clientId)) { client->setClientId(*clientId); } else { - MQTTSNString dummyId MQTTSNString_initializer; + MQTTSNString dummyId MQTTSNString_initializer; dummyId.cstring = strdup(""); client->setClientId(dummyId); - free(dummyId.cstring); + free(dummyId.cstring); } - if ( type == AGGREGATER_TYPE ) + if (type == AGGREGATER_TYPE) { - client->setAggregated(); + client->setAggregated(); } - else if ( type == QOSM1PROXY_TYPE ) + else if (type == QOSM1PROXY_TYPE) { client->setQoSm1(); } @@ -374,7 +383,7 @@ Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, _mutex.lock(); /* add the list */ - if ( _firstClient == nullptr ) + if (_firstClient == nullptr) { _firstClient = client; _endClient = client; @@ -390,66 +399,68 @@ Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, return client; } -Client* ClientList::createPredefinedTopic( MQTTSNString* clientId, string topicName, uint16_t topicId, bool aggregate) +Client* ClientList::createPredefinedTopic(MQTTSNString* clientId, + string topicName, uint16_t topicId, bool aggregate) { - if ( topicId == 0 ) - { - WRITELOG("Invalid TopicId. Predefined Topic %s, TopicId is 0. \n", topicName.c_str()); - return nullptr; - } + if (topicId == 0) + { + WRITELOG("Invalid TopicId. Predefined Topic %s, TopicId is 0. \n", + topicName.c_str()); + return nullptr; + } - if ( strcmp(clientId->cstring, common_topic) == 0 ) - { - theGateway->getTopics()->add((const char*)topicName.c_str(), topicId); - return nullptr; - } - else - { - Client* client = getClient(clientId); + if (strcmp(clientId->cstring, common_topic) == 0) + { + theGateway->getTopics()->add((const char*) topicName.c_str(), topicId); + return nullptr; + } + else + { + Client* client = getClient(clientId); - if ( _authorize && client == nullptr ) - { - return nullptr; - } + if (_authorize && client == nullptr) + { + return nullptr; + } - /* anonimous clients */ - if ( _clientCnt > MAX_CLIENTS ) - { - return nullptr; // full of clients - } + /* 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(); + 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(); - } + /* 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; - } + // create Topic & Add it + client->getTopics()->add((const char*) topicName.c_str(), topicId); + client->_hasPredefTopic = true; + return client; + } } uint16_t ClientList::getClientCount() @@ -462,4 +473,3 @@ bool ClientList::isAuthorized() return _authorize; } - diff --git a/MQTTSNGateway/src/MQTTSNGWClientList.h b/MQTTSNGateway/src/MQTTSNGWClientList.h index 135f365..e3542bb 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientList.h +++ b/MQTTSNGateway/src/MQTTSNGWClientList.h @@ -43,8 +43,10 @@ public: 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); + 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); @@ -55,18 +57,16 @@ public: private: bool readPredefinedList(const char* fileName, bool _aggregate); - Gateway* _gateway {nullptr}; - Client* createPredefinedTopic( MQTTSNString* clientId, string topicName, uint16_t toipcId, 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}; + bool _authorize { false }; }; - } - - #endif /* MQTTSNGATEWAY_SRC_MQTTSNGWCLIENTLIST_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp index 03f3415..49568b5 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp @@ -29,9 +29,9 @@ char* currentDateTime(void); =====================================*/ ClientRecvTask::ClientRecvTask(Gateway* gateway) { - _gateway = gateway; - _gateway->attach((Thread*)this); - _sensorNetwork = _gateway->getSensorNetwork(); + _gateway = gateway; + _gateway->attach((Thread*) this); + _sensorNetwork = _gateway->getSensorNetwork(); } ClientRecvTask::~ClientRecvTask() @@ -44,10 +44,10 @@ ClientRecvTask::~ClientRecvTask() */ void ClientRecvTask::initialize(int argc, char** argv) { - if ( _sensorNetwork->initialize() < 0 ) - { - throw Exception(" Can't open the sensor network.\n"); - } + if (_sensorNetwork->initialize() < 0) + { + throw Exception(" Can't open the sensor network.\n"); + } } /* @@ -57,214 +57,237 @@ void ClientRecvTask::initialize(int argc, char** argv) */ void ClientRecvTask::run() { - Event* ev = nullptr; - AdapterManager* adpMgr = _gateway->getAdapterManager(); - QoSm1Proxy* qosm1Proxy = adpMgr->getQoSm1Proxy(); - int clientType = adpMgr->isAggregaterActive() ? AGGREGATER_TYPE : TRANSPEARENT_TYPE; - ClientList* clientList = _gateway->getClientList(); - EventQue* packetEventQue = _gateway->getPacketEventQue(); + Event* ev = nullptr; + AdapterManager* adpMgr = _gateway->getAdapterManager(); + QoSm1Proxy* qosm1Proxy = adpMgr->getQoSm1Proxy(); + int clientType = + adpMgr->isAggregaterActive() ? AGGREGATER_TYPE : TRANSPEARENT_TYPE; + ClientList* clientList = _gateway->getClientList(); + EventQue* packetEventQue = _gateway->getPacketEventQue(); - char buf[128]; + char buf[128]; - while (true) - { - Client* client = nullptr; - Forwarder* fwd = nullptr; - WirelessNodeId nodeId; + while (true) + { + Client* client = nullptr; + Forwarder* fwd = nullptr; + WirelessNodeId nodeId; - MQTTSNPacket* packet = new MQTTSNPacket(); - int packetLen = packet->recv(_sensorNetwork); + MQTTSNPacket* packet = new MQTTSNPacket(); + int packetLen = packet->recv(_sensorNetwork); - if (CHK_SIGINT) - { - WRITELOG("\n%s ClientRecvTask stopped.", currentDateTime()); - delete packet; - return; - } + if (CHK_SIGINT) + { + WRITELOG("\n%s ClientRecvTask stopped.", currentDateTime()); + delete packet; + return; + } - if (packetLen < 2 ) - { - delete packet; - continue; - } + if (packetLen < 2) + { + delete packet; + continue; + } - if ( packet->getType() <= MQTTSN_ADVERTISE || packet->getType() == MQTTSN_GWINFO ) - { - delete packet; - continue; - } + if (packet->getType() <= MQTTSN_ADVERTISE + || packet->getType() == MQTTSN_GWINFO) + { + delete packet; + continue; + } - if ( packet->getType() == MQTTSN_SEARCHGW ) - { - /* write log and post Event */ - log(0, packet, 0); - ev = new Event(); - ev->setBrodcastEvent(packet); - packetEventQue->post(ev); - continue; - } + if (packet->getType() == MQTTSN_SEARCHGW) + { + /* write log and post Event */ + log(0, packet, 0); + ev = new Event(); + ev->setBrodcastEvent(packet); + packetEventQue->post(ev); + continue; + } + SensorNetAddress* senderAddr = + _gateway->getSensorNetwork()->getSenderAddress(); - SensorNetAddress* senderAddr = _gateway->getSensorNetwork()->getSenderAddress(); + if (packet->getType() == MQTTSN_ENCAPSULATED) + { + fwd = + _gateway->getAdapterManager()->getForwarderList()->getForwarder( + senderAddr); - if ( packet->getType() == MQTTSN_ENCAPSULATED ) - { - fwd = _gateway->getAdapterManager()->getForwarderList()->getForwarder(senderAddr); + if (fwd != nullptr) + { + MQTTSNString fwdName = MQTTSNString_initializer; + fwdName.cstring = const_cast(fwd->getName()); + log(0, packet, &fwdName); - if ( fwd != nullptr ) - { - MQTTSNString fwdName = MQTTSNString_initializer; - fwdName.cstring = const_cast( fwd->getName() ); - log(0, packet, &fwdName); + /* get the packet from the encapsulation message */ + MQTTSNGWEncapsulatedPacket encap; + encap.desirialize(packet->getPacketData(), + packet->getPacketLength()); + nodeId.setId(encap.getWirelessNodeId()); + client = fwd->getClient(&nodeId); + packet = encap.getMQTTSNPacket(); + } + } + else + { + /* Check the client belonging to QoS-1Proxy ? */ - /* 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 - { - /* Check the client belonging to QoS-1Proxy ? */ + if (qosm1Proxy->isActive()) + { + const char* clientName = qosm1Proxy->getClientId(senderAddr); - if ( qosm1Proxy->isActive() ) - { - const char* clientName = qosm1Proxy->getClientId(senderAddr); + if (clientName != nullptr) + { + client = qosm1Proxy->getClient(); - if ( clientName != nullptr ) - { - client = qosm1Proxy->getClient(); + if (!packet->isQoSMinusPUBLISH()) + { + 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; + } + } + } - if ( !packet->isQoSMinusPUBLISH() ) - { - 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; - } - } - } + if (client == nullptr) + { + client = _gateway->getClientList()->getClient(senderAddr); + } + } - if ( client == nullptr ) - { - client = _gateway->getClientList()->getClient(senderAddr); - } - } + if (client != nullptr) + { + /* write log and post Event */ + log(client, packet, 0); + ev = new Event(); + ev->setClientRecvEvent(client, packet); + packetEventQue->post(ev); + } + else + { + /* new client */ + if (packet->getType() == MQTTSN_CONNECT) + { + MQTTSNPacket_connectData data; + memset(&data, 0, sizeof(MQTTSNPacket_connectData)); + if (!packet->getCONNECT(&data)) + { + log(0, packet, &data.clientID); + WRITELOG("%s CONNECT message form %s is incorrect.%s\n", + ERRMSG_HEADER, senderAddr->sprint(buf), + ERRMSG_FOOTER); + delete packet; + continue; + } - if ( client != nullptr ) - { - /* write log and post Event */ - log(client, packet, 0); - ev = new Event(); - ev->setClientRecvEvent(client,packet); - packetEventQue->post(ev); - } - else - { - /* new client */ - if (packet->getType() == MQTTSN_CONNECT) - { - MQTTSNPacket_connectData data; - memset(&data, 0, sizeof(MQTTSNPacket_connectData)); - if ( !packet->getCONNECT(&data) ) - { - log(0, packet, &data.clientID); - WRITELOG("%s CONNECT message form %s is incorrect.%s\n", ERRMSG_HEADER, senderAddr->sprint(buf), ERRMSG_FOOTER); - delete packet; - continue; - } + client = clientList->getClient(&data.clientID); - client = clientList->getClient(&data.clientID); - - if ( fwd != nullptr ) - { - if ( client == nullptr ) - { - /* create a new client */ - client = clientList->createClient(0, &data.clientID, clientType); - } - /* Add to a forwarded client list of forwarder. */ + if (fwd != nullptr) + { + if (client == nullptr) + { + /* create a new client */ + client = clientList->createClient(0, &data.clientID, + clientType); + } + /* Add to a forwarded client list of forwarder. */ fwd->addClient(client, &nodeId); - } - else - { - if ( client ) + } + else + { + if (client) { /* Authentication is not required */ - if ( _gateway->getGWParams()->clientAuthentication == false) - { - client->setClientAddress(senderAddr); - } + if (_gateway->getGWParams()->clientAuthentication + == false) + { + client->setClientAddress(senderAddr); + } } else { /* create a new client */ - client = clientList->createClient(senderAddr, &data.clientID, clientType); + client = clientList->createClient(senderAddr, + &data.clientID, clientType); } - } + } - log(client, packet, &data.clientID); + log(client, packet, &data.clientID); - if ( client == nullptr ) - { - WRITELOG("%s Client(%s) was rejected. CONNECT message has been discarded.%s\n", ERRMSG_HEADER, senderAddr->sprint(buf), ERRMSG_FOOTER); - delete packet; - continue; - } + if (client == nullptr) + { + WRITELOG( + "%s Client(%s) was rejected. CONNECT message has been discarded.%s\n", + ERRMSG_HEADER, senderAddr->sprint(buf), + ERRMSG_FOOTER); + delete packet; + continue; + } - /* post Client RecvEvent */ - ev = new Event(); - ev->setClientRecvEvent(client, packet); - packetEventQue->post(ev); - } - else - { - log(client, packet, 0); - if ( packet->getType() == MQTTSN_ENCAPSULATED ) - { - WRITELOG("%s MQTTSNGWClientRecvTask 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 MQTTSNGWClientRecvTask Client(%s) is not connecting. message has been discarded.%s\n", ERRMSG_HEADER, senderAddr->sprint(buf), ERRMSG_FOOTER); - } - delete packet; - } - } - } + /* post Client RecvEvent */ + ev = new Event(); + ev->setClientRecvEvent(client, packet); + packetEventQue->post(ev); + } + else + { + log(client, packet, 0); + if (packet->getType() == MQTTSN_ENCAPSULATED) + { + WRITELOG( + "%s MQTTSNGWClientRecvTask 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 MQTTSNGWClientRecvTask Client(%s) is not connecting. message has been discarded.%s\n", + ERRMSG_HEADER, senderAddr->sprint(buf), + ERRMSG_FOOTER); + } + delete packet; + } + } + } } void ClientRecvTask::log(Client* client, MQTTSNPacket* packet, MQTTSNString* id) { - const char* clientId; - char cstr[MAX_CLIENTID_LENGTH + 1]; + const char* clientId; + char cstr[MAX_CLIENTID_LENGTH + 1]; - if ( id ) - { - 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 ); + if (id) + { + if (id->cstring) + { + strncpy(cstr, id->cstring, strlen(id->cstring)); clientId = cstr; - } - } - else if ( client ) - { - clientId = client->getClientId(); - } - else - { - clientId = UNKNOWNCL; - } + } + else + { + memset((void*) cstr, 0, id->lenstring.len + 1); + strncpy(cstr, id->lenstring.data, id->lenstring.len); + clientId = cstr; + } + } + else if (client) + { + clientId = client->getClientId(); + } + else + { + clientId = UNKNOWNCL; + } - log(clientId, packet); + log(clientId, packet); } void ClientRecvTask::log(const char* clientId, MQTTSNPacket* packet) @@ -275,37 +298,46 @@ void ClientRecvTask::log(const char* clientId, MQTTSNPacket* packet) switch (packet->getType()) { case MQTTSN_SEARCHGW: - WRITELOG(FORMAT_Y_G_G_NL, currentDateTime(), packet->getName(), LEFTARROW, CLIENT, packet->print(pbuf)); + 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)); + 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)); + 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)); + 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)); + 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; + 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)); + 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 30a63e9..9428d3a 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.h +++ b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.h @@ -24,24 +24,24 @@ namespace MQTTSNGW class AdapterManager; /*===================================== - Class ClientRecvTask + Class ClientRecvTask =====================================*/ -class ClientRecvTask:public Thread +class ClientRecvTask: public Thread { - MAGIC_WORD_FOR_THREAD; - friend AdapterManager; +MAGIC_WORD_FOR_THREAD; + friend AdapterManager; public: - ClientRecvTask(Gateway*); - ~ClientRecvTask(void); - virtual void initialize(int argc, char** argv); - void run(void); + ClientRecvTask(Gateway*); + ~ClientRecvTask(void); + virtual void initialize(int argc, char** argv); + void run(void); private: - void log(Client*, MQTTSNPacket*, MQTTSNString* id); - void log(const char* clientId, MQTTSNPacket* packet); + void log(Client*, MQTTSNPacket*, MQTTSNString* id); + void log(const char* clientId, MQTTSNPacket* packet); - Gateway* _gateway; - SensorNetwork* _sensorNetwork; + Gateway* _gateway; + SensorNetwork* _sensorNetwork; }; } diff --git a/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp index b0af063..0734a5e 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp @@ -28,9 +28,9 @@ char* currentDateTime(void); =====================================*/ ClientSendTask::ClientSendTask(Gateway* gateway) { - _gateway = gateway; - _gateway->attach((Thread*)this); - _sensorNetwork = _gateway->getSensorNetwork(); + _gateway = gateway; + _gateway->attach((Thread*) this); + _sensorNetwork = _gateway->getSensorNetwork(); } ClientSendTask::~ClientSendTask() @@ -40,94 +40,106 @@ ClientSendTask::~ClientSendTask() void ClientSendTask::run() { - Client* client = nullptr; - MQTTSNPacket* packet = nullptr; - AdapterManager* adpMgr = _gateway->getAdapterManager(); - int rc = 0; + Client* client = nullptr; + MQTTSNPacket* packet = nullptr; + AdapterManager* adpMgr = _gateway->getAdapterManager(); + int rc = 0; - while (true) - { - Event* ev = _gateway->getClientSendQue()->wait(); + while (true) + { + Event* ev = _gateway->getClientSendQue()->wait(); - if (ev->getEventType() == EtStop || _gateway->IsStopping() ) - { - WRITELOG("\n%s ClientSendTask stopped.", currentDateTime()); - delete ev; - break; - } + if (ev->getEventType() == EtStop || _gateway->IsStopping()) + { + WRITELOG("\n%s ClientSendTask stopped.", currentDateTime()); + delete ev; + break; + } - if (ev->getEventType() == EtBroadcast) - { - packet = ev->getMQTTSNPacket(); - log(client, packet); + if (ev->getEventType() == EtBroadcast) + { + packet = ev->getMQTTSNPacket(); + log(client, packet); - if ( packet->broadcast(_sensorNetwork) < 0 ) - { - WRITELOG("%s ClientSendTask can't multicast a packet Error=%d%s\n", - ERRMSG_HEADER, errno, ERRMSG_FOOTER); - } - } - else - { - if (ev->getEventType() == EtClientSend) - { - client = ev->getClient(); - packet = ev->getMQTTSNPacket(); - rc = adpMgr->unicastToClient(client, packet, this); - } - else if (ev->getEventType() == EtSensornetSend) - { - packet = ev->getMQTTSNPacket(); - log(client, packet); - rc = packet->unicast(_sensorNetwork, ev->getSensorNetAddress()); - } + if (packet->broadcast(_sensorNetwork) < 0) + { + WRITELOG( + "%s ClientSendTask can't multicast a packet Error=%d%s\n", + ERRMSG_HEADER, errno, ERRMSG_FOOTER); + } + } + else + { + if (ev->getEventType() == EtClientSend) + { + client = ev->getClient(); + packet = ev->getMQTTSNPacket(); + rc = adpMgr->unicastToClient(client, packet, this); + } + else if (ev->getEventType() == EtSensornetSend) + { + packet = ev->getMQTTSNPacket(); + log(client, packet); + rc = packet->unicast(_sensorNetwork, ev->getSensorNetAddress()); + } - if ( rc < 0 ) - { - WRITELOG("%s ClientSendTask can't send a packet to the client %s. Error=%d%s\n", - ERRMSG_HEADER, (client ? (const char*)client->getClientId() : UNKNOWNCL ), errno, ERRMSG_FOOTER); - } - } - delete ev; - } + if (rc < 0) + { + WRITELOG( + "%s ClientSendTask can't send a packet to the client %s. Error=%d%s\n", + ERRMSG_HEADER, + (client ? + (const char*) client->getClientId() : UNKNOWNCL), + errno, ERRMSG_FOOTER); + } + } + delete ev; + } } void ClientSendTask::log(Client* client, MQTTSNPacket* packet) { - char pbuf[SIZE_OF_LOG_PACKET * 3 + 1]; - char msgId[6]; - const char* clientId = client ? (const char*)client->getClientId() : UNKNOWNCL ; + char pbuf[SIZE_OF_LOG_PACKET * 3 + 1]; + char msgId[6]; + const char* clientId = + client ? (const char*) client->getClientId() : UNKNOWNCL; - switch (packet->getType()) - { - case MQTTSN_ADVERTISE: - case MQTTSN_GWINFO: - WRITELOG(FORMAT_Y_W_G, currentDateTime(), packet->getName(), RIGHTARROW, CLIENTS, packet->print(pbuf)); - break; - case MQTTSN_CONNACK: - case MQTTSN_DISCONNECT: - case MQTTSN_WILLTOPICREQ: - case MQTTSN_WILLMSGREQ: - case MQTTSN_WILLTOPICRESP: - case MQTTSN_WILLMSGRESP: - case MQTTSN_PINGRESP: - WRITELOG(FORMAT_Y_W_G, currentDateTime(), packet->getName(), RIGHTARROW, clientId, packet->print(pbuf)); - break; - case MQTTSN_REGISTER: - case MQTTSN_PUBLISH: - WRITELOG(FORMAT_W_MSGID_W_G, currentDateTime(), packet->getName(), packet->getMsgId(msgId), RIGHTARROW, clientId, packet->print(pbuf)); - break; - case MQTTSN_REGACK: - case MQTTSN_PUBACK: - case MQTTSN_PUBREC: - case MQTTSN_PUBREL: - case MQTTSN_PUBCOMP: - case MQTTSN_SUBACK: - case MQTTSN_UNSUBACK: - WRITELOG(FORMAT_W_MSGID_W_G, currentDateTime(), packet->getName(), packet->getMsgId(msgId), RIGHTARROW, clientId, packet->print(pbuf)); - break; - default: - break; - } + switch (packet->getType()) + { + case MQTTSN_ADVERTISE: + case MQTTSN_GWINFO: + WRITELOG(FORMAT_Y_W_G, currentDateTime(), packet->getName(), RIGHTARROW, + CLIENTS, packet->print(pbuf)); + break; + case MQTTSN_CONNACK: + case MQTTSN_DISCONNECT: + case MQTTSN_WILLTOPICREQ: + case MQTTSN_WILLMSGREQ: + case MQTTSN_WILLTOPICRESP: + case MQTTSN_WILLMSGRESP: + case MQTTSN_PINGRESP: + WRITELOG(FORMAT_Y_W_G, currentDateTime(), packet->getName(), RIGHTARROW, + clientId, packet->print(pbuf)); + break; + case MQTTSN_REGISTER: + case MQTTSN_PUBLISH: + WRITELOG(FORMAT_W_MSGID_W_G, currentDateTime(), packet->getName(), + packet->getMsgId(msgId), RIGHTARROW, clientId, + packet->print(pbuf)); + break; + case MQTTSN_REGACK: + case MQTTSN_PUBACK: + case MQTTSN_PUBREC: + case MQTTSN_PUBREL: + case MQTTSN_PUBCOMP: + case MQTTSN_SUBACK: + case MQTTSN_UNSUBACK: + WRITELOG(FORMAT_W_MSGID_W_G, currentDateTime(), packet->getName(), + packet->getMsgId(msgId), RIGHTARROW, clientId, + packet->print(pbuf)); + break; + default: + break; + } } diff --git a/MQTTSNGateway/src/MQTTSNGWClientSendTask.h b/MQTTSNGateway/src/MQTTSNGWClientSendTask.h index 3eaf84f..1e4d14d 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientSendTask.h +++ b/MQTTSNGateway/src/MQTTSNGWClientSendTask.h @@ -28,18 +28,18 @@ class AdapterManager; =====================================*/ class ClientSendTask: public Thread { - MAGIC_WORD_FOR_THREAD; - friend AdapterManager; +MAGIC_WORD_FOR_THREAD; + friend AdapterManager; public: - ClientSendTask(Gateway* gateway); - ~ClientSendTask(void); - void run(void); + ClientSendTask(Gateway* gateway); + ~ClientSendTask(void); + void run(void); private: - void log(Client* client, MQTTSNPacket* packet); + void log(Client* client, MQTTSNPacket* packet); - Gateway* _gateway; - SensorNetwork* _sensorNetwork; + Gateway* _gateway; + SensorNetwork* _sensorNetwork; }; } diff --git a/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp b/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp index 76367ce..f0133ff 100644 --- a/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp @@ -28,7 +28,7 @@ using namespace MQTTSNGW; =====================================*/ MQTTSNConnectionHandler::MQTTSNConnectionHandler(Gateway* gateway) { - _gateway = gateway; + _gateway = gateway; } MQTTSNConnectionHandler::~MQTTSNConnectionHandler() @@ -41,11 +41,12 @@ MQTTSNConnectionHandler::~MQTTSNConnectionHandler() */ void MQTTSNConnectionHandler::sendADVERTISE() { - MQTTSNPacket* adv = new MQTTSNPacket(); - adv->setADVERTISE(_gateway->getGWParams()->gatewayId, _gateway->getGWParams()->keepAlive); - Event* ev1 = new Event(); - ev1->setBrodcastEvent(adv); //broadcast - _gateway->getClientSendQue()->post(ev1); + MQTTSNPacket* adv = new MQTTSNPacket(); + adv->setADVERTISE(_gateway->getGWParams()->gatewayId, + _gateway->getGWParams()->keepAlive); + Event* ev1 = new Event(); + ev1->setBrodcastEvent(adv); //broadcast + _gateway->getClientSendQue()->post(ev1); } /* @@ -53,182 +54,191 @@ void MQTTSNConnectionHandler::sendADVERTISE() */ void MQTTSNConnectionHandler::handleSearchgw(MQTTSNPacket* packet) { - if (packet->getType() == MQTTSN_SEARCHGW) - { - MQTTSNPacket* gwinfo = new MQTTSNPacket(); - gwinfo->setGWINFO(_gateway->getGWParams()->gatewayId); - Event* ev1 = new Event(); - ev1->setBrodcastEvent(gwinfo); - _gateway->getClientSendQue()->post(ev1); - } + if (packet->getType() == MQTTSN_SEARCHGW) + { + MQTTSNPacket* gwinfo = new MQTTSNPacket(); + gwinfo->setGWINFO(_gateway->getGWParams()->gatewayId); + Event* ev1 = new Event(); + ev1->setBrodcastEvent(gwinfo); + _gateway->getClientSendQue()->post(ev1); + } } /* * CONNECT */ -void MQTTSNConnectionHandler::handleConnect(Client* client, MQTTSNPacket* packet) +void MQTTSNConnectionHandler::handleConnect(Client* client, + MQTTSNPacket* packet) { - MQTTSNPacket_connectData data; - if ( packet->getCONNECT(&data) == 0 ) - { - return; - } + 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); + /* 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; - } + sendStoredPublish(client); + return; + } - //* clear ConnectData of Client */ - Connect* connectData = client->getConnectData(); - memset(connectData, 0, sizeof(Connect)); - if ( !client->isAdapter() ) - { - client->disconnected(); - } + //* clear ConnectData of Client */ + Connect* connectData = client->getConnectData(); + memset(connectData, 0, sizeof(Connect)); + if (!client->isAdapter()) + { + client->disconnected(); + } - Topics* topics = client->getTopics(); + Topics* topics = client->getTopics(); - /* CONNECT was not sent yet. prepare Connect data */ - connectData->header.bits.type = CONNECT; - connectData->clientID = client->getClientId(); - connectData->version = _gateway->getGWParams()->mqttVersion; - connectData->keepAliveTimer = data.duration; - connectData->flags.bits.will = data.willFlag; + /* CONNECT was not sent yet. prepare Connect data */ + connectData->header.bits.type = CONNECT; + connectData->clientID = client->getClientId(); + connectData->version = _gateway->getGWParams()->mqttVersion; + connectData->keepAliveTimer = data.duration; + connectData->flags.bits.will = data.willFlag; - if ((const char*) _gateway->getGWParams()->loginId != nullptr) - { - connectData->flags.bits.username = 1; - } + if ((const char*) _gateway->getGWParams()->loginId != nullptr) + { + connectData->flags.bits.username = 1; + } - if ((const char*) _gateway->getGWParams()->password != 0) - { - connectData->flags.bits.password = 1; - } + if ((const char*) _gateway->getGWParams()->password != 0) + { + connectData->flags.bits.password = 1; + } - client->setSessionStatus(false); - if (data.cleansession) - { - connectData->flags.bits.cleanstart = 1; - /* reset the table of msgNo and TopicId pare */ - client->clearWaitedPubTopicId(); - client->clearWaitedSubTopicId(); + client->setSessionStatus(false); + if (data.cleansession) + { + connectData->flags.bits.cleanstart = 1; + /* reset the table of msgNo and TopicId pare */ + client->clearWaitedPubTopicId(); + client->clearWaitedSubTopicId(); - /* renew the TopicList */ - if (topics) - { - topics->eraseNormal();; - } - client->setSessionStatus(true); - } + /* renew the TopicList */ + if (topics) + { + 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); + if (data.willFlag) + { + /* create & send WILLTOPICREQ message to the client */ + MQTTSNPacket* reqTopic = new MQTTSNPacket(); + reqTopic->setWILLTOPICREQ(); + Event* evwr = new Event(); + evwr->setClientSendEvent(client, reqTopic); - /* Send WILLTOPICREQ to the client */ - _gateway->getClientSendQue()->post(evwr); - } - else - { - /* CONNECT message was not qued in. - * create CONNECT message & send it to the broker */ - MQTTGWPacket* mqMsg = new MQTTGWPacket(); - mqMsg->setCONNECT(client->getConnectData(), (unsigned char*)_gateway->getGWParams()->loginId, (unsigned char*)_gateway->getGWParams()->password); - Event* ev1 = new Event(); - ev1->setBrokerSendEvent(client, mqMsg); - _gateway->getBrokerSendQue()->post(ev1); - } + /* Send WILLTOPICREQ to the client */ + _gateway->getClientSendQue()->post(evwr); + } + else + { + /* CONNECT message was not qued in. + * create CONNECT message & send it to the broker */ + MQTTGWPacket* mqMsg = new MQTTGWPacket(); + mqMsg->setCONNECT(client->getConnectData(), + (unsigned char*) _gateway->getGWParams()->loginId, + (unsigned char*) _gateway->getGWParams()->password); + Event* ev1 = new Event(); + ev1->setBrokerSendEvent(client, mqMsg); + _gateway->getBrokerSendQue()->post(ev1); + } } /* * WILLTOPIC */ -void MQTTSNConnectionHandler::handleWilltopic(Client* client, MQTTSNPacket* packet) +void MQTTSNConnectionHandler::handleWilltopic(Client* client, + MQTTSNPacket* packet) { - int willQos; - uint8_t willRetain; - MQTTSNString willTopic = MQTTSNString_initializer; + int willQos; + uint8_t willRetain; + MQTTSNString willTopic = MQTTSNString_initializer; - if ( packet->getWILLTOPIC(&willQos, &willRetain, &willTopic) == 0 ) - { - return; - } - client->setWillTopic(willTopic); - Connect* connectData = client->getConnectData(); + if (packet->getWILLTOPIC(&willQos, &willRetain, &willTopic) == 0) + { + return; + } + client->setWillTopic(willTopic); + Connect* connectData = client->getConnectData(); - /* add the connectData for MQTT CONNECT message */ - connectData->willTopic = client->getWillTopic(); - connectData->flags.bits.willQoS = willQos; - connectData->flags.bits.willRetain = willRetain; + /* add the connectData for MQTT CONNECT message */ + connectData->willTopic = client->getWillTopic(); + connectData->flags.bits.willQoS = willQos; + connectData->flags.bits.willRetain = willRetain; - /* Send WILLMSGREQ to the client */ - client->setWaitWillMsgFlg(true); - MQTTSNPacket* reqMsg = new MQTTSNPacket(); - reqMsg->setWILLMSGREQ(); - Event* evt = new Event(); - evt->setClientSendEvent(client, reqMsg); - _gateway->getClientSendQue()->post(evt); + /* Send WILLMSGREQ to the client */ + client->setWaitWillMsgFlg(true); + MQTTSNPacket* reqMsg = new MQTTSNPacket(); + reqMsg->setWILLMSGREQ(); + Event* evt = new Event(); + evt->setClientSendEvent(client, reqMsg); + _gateway->getClientSendQue()->post(evt); } /* * WILLMSG */ -void MQTTSNConnectionHandler::handleWillmsg(Client* client, MQTTSNPacket* packet) +void MQTTSNConnectionHandler::handleWillmsg(Client* client, + MQTTSNPacket* packet) { - if ( !client->isWaitWillMsg() ) - { - DEBUGLOG(" MQTTSNConnectionHandler::handleWillmsg WaitWillMsgFlg is off.\n"); - return; - } + if (!client->isWaitWillMsg()) + { + DEBUGLOG(" MQTTSNConnectionHandler::handleWillmsg WaitWillMsgFlg is off.\n"); + return; + } - MQTTSNString willmsg = MQTTSNString_initializer; - Connect* connectData = client->getConnectData(); + 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); + if (client->isConnectSendable()) + { + /* save WillMsg in the client */ + if (packet->getWILLMSG(&willmsg) == 0) + { + return; + } + client->setWillMsg(willmsg); - /* create CONNECT message */ - MQTTGWPacket* mqttPacket = new MQTTGWPacket(); - connectData->willMsg = client->getWillMsg(); - mqttPacket->setCONNECT(connectData, (unsigned char*)_gateway->getGWParams()->loginId, (unsigned char*)_gateway->getGWParams()->password); + /* create CONNECT message */ + MQTTGWPacket* mqttPacket = new MQTTGWPacket(); + connectData->willMsg = client->getWillMsg(); + mqttPacket->setCONNECT(connectData, + (unsigned char*) _gateway->getGWParams()->loginId, + (unsigned char*) _gateway->getGWParams()->password); - /* Send CONNECT to the broker */ - Event* evt = new Event(); - evt->setBrokerSendEvent(client, mqttPacket); - client->setWaitWillMsgFlg(false); - _gateway->getBrokerSendQue()->post(evt); - } + /* Send CONNECT to the broker */ + Event* evt = new Event(); + evt->setBrokerSendEvent(client, mqttPacket); + client->setWaitWillMsgFlg(false); + _gateway->getBrokerSendQue()->post(evt); + } } /* * DISCONNECT */ -void MQTTSNConnectionHandler::handleDisconnect(Client* client, MQTTSNPacket* packet) +void MQTTSNConnectionHandler::handleDisconnect(Client* client, + MQTTSNPacket* packet) { uint16_t duration = 0; - if ( packet->getDISCONNECT(&duration) != 0 ) + if (packet->getDISCONNECT(&duration) != 0) { - if ( duration == 0 ) + if (duration == 0) { MQTTGWPacket* mqMsg = new MQTTGWPacket(); mqMsg->setHeader(DISCONNECT); @@ -248,59 +258,63 @@ void MQTTSNConnectionHandler::handleDisconnect(Client* client, MQTTSNPacket* pac /* * WILLTOPICUPD */ -void MQTTSNConnectionHandler::handleWilltopicupd(Client* client, MQTTSNPacket* packet) +void MQTTSNConnectionHandler::handleWilltopicupd(Client* client, + MQTTSNPacket* packet) { - /* send NOT_SUPPORTED responce to the client */ - MQTTSNPacket* respMsg = new MQTTSNPacket(); - respMsg->setWILLTOPICRESP(MQTTSN_RC_NOT_SUPPORTED); - Event* evt = new Event(); - evt->setClientSendEvent(client, respMsg); - _gateway->getClientSendQue()->post(evt); + /* send NOT_SUPPORTED responce to the client */ + MQTTSNPacket* respMsg = new MQTTSNPacket(); + respMsg->setWILLTOPICRESP(MQTTSN_RC_NOT_SUPPORTED); + Event* evt = new Event(); + evt->setClientSendEvent(client, respMsg); + _gateway->getClientSendQue()->post(evt); } /* * WILLMSGUPD */ -void MQTTSNConnectionHandler::handleWillmsgupd(Client* client, MQTTSNPacket* packet) +void MQTTSNConnectionHandler::handleWillmsgupd(Client* client, + MQTTSNPacket* packet) { - /* send NOT_SUPPORTED responce to the client */ - MQTTSNPacket* respMsg = new MQTTSNPacket(); - respMsg->setWILLMSGRESP(MQTTSN_RC_NOT_SUPPORTED); - Event* evt = new Event(); - evt->setClientSendEvent(client, respMsg); - _gateway->getClientSendQue()->post(evt); + /* send NOT_SUPPORTED responce to the client */ + MQTTSNPacket* respMsg = new MQTTSNPacket(); + respMsg->setWILLMSGRESP(MQTTSN_RC_NOT_SUPPORTED); + Event* evt = new Event(); + evt->setClientSendEvent(client, respMsg); + _gateway->getClientSendQue()->post(evt); } /* * PINGREQ */ -void MQTTSNConnectionHandler::handlePingreq(Client* client, MQTTSNPacket* packet) +void MQTTSNConnectionHandler::handlePingreq(Client* client, + MQTTSNPacket* packet) { - if ( ( client->isSleep() || client->isAwake() ) && client->getClientSleepPacket() ) - { - sendStoredPublish(client); - client->holdPingRequest(); - } - else - { + if ((client->isSleep() || client->isAwake()) + && client->getClientSleepPacket()) + { + sendStoredPublish(client); + client->holdPingRequest(); + } + else + { /* send PINGREQ to the broker */ - client->resetPingRequest(); + client->resetPingRequest(); MQTTGWPacket* pingreq = new MQTTGWPacket(); pingreq->setHeader(PINGREQ); Event* evt = new Event(); evt->setBrokerSendEvent(client, pingreq); _gateway->getBrokerSendQue()->post(evt); - } + } } void MQTTSNConnectionHandler::sendStoredPublish(Client* client) { MQTTGWPacket* msg = nullptr; - while ( ( msg = client->getClientSleepPacket() ) != 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. + client->deleteFirstClientSleepPacket(); // pop the que to delete element. Event* ev = new Event(); ev->setBrokerRecvEvent(client, msg); diff --git a/MQTTSNGateway/src/MQTTSNGWConnectionHandler.h b/MQTTSNGateway/src/MQTTSNGWConnectionHandler.h index 6af6113..eb75177 100644 --- a/MQTTSNGateway/src/MQTTSNGWConnectionHandler.h +++ b/MQTTSNGateway/src/MQTTSNGWConnectionHandler.h @@ -25,21 +25,21 @@ namespace MQTTSNGW class MQTTSNConnectionHandler { public: - MQTTSNConnectionHandler(Gateway* gateway); - ~MQTTSNConnectionHandler(); - void sendADVERTISE(void); - void handleSearchgw(MQTTSNPacket* packet); - void handleConnect(Client* client, MQTTSNPacket* packet); - void handleWilltopic(Client* client, MQTTSNPacket* packet); - void handleWillmsg(Client* client, MQTTSNPacket* packet); - void handleDisconnect(Client* client, MQTTSNPacket* packet); - void handleWilltopicupd(Client* client, MQTTSNPacket* packet); - void handleWillmsgupd(Client* client, MQTTSNPacket* packet); - void handlePingreq(Client* client, MQTTSNPacket* packet); + MQTTSNConnectionHandler(Gateway* gateway); + ~MQTTSNConnectionHandler(); + void sendADVERTISE(void); + void handleSearchgw(MQTTSNPacket* packet); + void handleConnect(Client* client, MQTTSNPacket* packet); + void handleWilltopic(Client* client, MQTTSNPacket* packet); + void handleWillmsg(Client* client, MQTTSNPacket* packet); + void handleDisconnect(Client* client, MQTTSNPacket* packet); + void handleWilltopicupd(Client* client, MQTTSNPacket* packet); + void handleWillmsgupd(Client* client, MQTTSNPacket* packet); + void handlePingreq(Client* client, MQTTSNPacket* packet); private: - void sendStoredPublish(Client* client); + void sendStoredPublish(Client* client); - Gateway* _gateway; + Gateway* _gateway; }; } diff --git a/MQTTSNGateway/src/MQTTSNGWDefines.h b/MQTTSNGateway/src/MQTTSNGWDefines.h index d73827d..7a10fcd 100644 --- a/MQTTSNGateway/src/MQTTSNGWDefines.h +++ b/MQTTSNGateway/src/MQTTSNGWDefines.h @@ -53,16 +53,15 @@ namespace MQTTSNGW /*================================= * Data Type ==================================*/ -typedef unsigned char uint8_t; +typedef unsigned char uint8_t; typedef unsigned short uint16_t; -typedef unsigned int uint32_t; +typedef unsigned int uint32_t; /*================================= * Log controls ==================================*/ //#define DEBUG // print out log for debug //#define DEBUG_NWSTACK // print out SensorNetwork log - #ifdef DEBUG #define DEBUGLOG(...) printf(__VA_ARGS__) #else diff --git a/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.cpp b/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.cpp index 750867f..dccde79 100644 --- a/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.cpp +++ b/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.cpp @@ -21,17 +21,17 @@ using namespace MQTTSNGW; using namespace std; -WirelessNodeId::WirelessNodeId() - : - _len{0}, - _nodeId{0} +WirelessNodeId::WirelessNodeId() : + _len + { 0 }, _nodeId + { 0 } { } WirelessNodeId::~WirelessNodeId() { - if ( _nodeId ) + if (_nodeId) { free(_nodeId); } @@ -39,12 +39,12 @@ WirelessNodeId::~WirelessNodeId() void WirelessNodeId::setId(uint8_t* id, uint8_t len) { - if ( _nodeId ) - { - free(_nodeId); - } - uint8_t* buf = (uint8_t*)malloc(len); - if ( buf ) + if (_nodeId) + { + free(_nodeId); + } + uint8_t* buf = (uint8_t*) malloc(len); + if (buf) { memcpy(buf, id, len); _len = len; @@ -64,7 +64,7 @@ void WirelessNodeId::setId(WirelessNodeId* id) bool WirelessNodeId::operator ==(WirelessNodeId& id) { - if ( _len == id._len ) + if (_len == id._len) { return memcmp(_nodeId, id._nodeId, _len) == 0; } @@ -77,16 +77,18 @@ bool WirelessNodeId::operator ==(WirelessNodeId& id) /* * Class MQTTSNGWEncapsulatedPacket */ -MQTTSNGWEncapsulatedPacket::MQTTSNGWEncapsulatedPacket() - : _mqttsn{0}, - _ctrl{0} +MQTTSNGWEncapsulatedPacket::MQTTSNGWEncapsulatedPacket() : + _mqttsn + { 0 }, _ctrl + { 0 } { } -MQTTSNGWEncapsulatedPacket::MQTTSNGWEncapsulatedPacket(MQTTSNPacket* packet) - : _mqttsn{packet}, - _ctrl{0} +MQTTSNGWEncapsulatedPacket::MQTTSNGWEncapsulatedPacket(MQTTSNPacket* packet) : + _mqttsn + { packet }, _ctrl + { 0 } { } @@ -96,7 +98,8 @@ MQTTSNGWEncapsulatedPacket::~MQTTSNGWEncapsulatedPacket() /* Do not delete the MQTTSNPacket. MQTTSNPacket is deleted by delete Event */ } -int MQTTSNGWEncapsulatedPacket::unicast(SensorNetwork* network, SensorNetAddress* sendTo) +int MQTTSNGWEncapsulatedPacket::unicast(SensorNetwork* network, + SensorNetAddress* sendTo) { uint8_t buf[MQTTSNGW_MAX_PACKET_SIZE]; int len = serialize(buf); @@ -109,18 +112,19 @@ int MQTTSNGWEncapsulatedPacket::serialize(uint8_t* buf) buf[0] = _id._len + 3; buf[1] = MQTTSN_ENCAPSULATED; buf[2] = _ctrl; - memcpy( buf + 3, _id._nodeId, _id._len); - if ( _mqttsn ) + memcpy(buf + 3, _id._nodeId, _id._len); + if (_mqttsn) { len = _mqttsn->getPacketLength(); memcpy(buf + buf[0], _mqttsn->getPacketData(), len); } - return buf[0] + len; + return buf[0] + len; } -int MQTTSNGWEncapsulatedPacket::desirialize(unsigned char* buf, unsigned short len) +int MQTTSNGWEncapsulatedPacket::desirialize(unsigned char* buf, + unsigned short len) { - if ( _mqttsn ) + if (_mqttsn) { delete _mqttsn; _mqttsn = nullptr; diff --git a/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.h b/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.h index eb2cba6..080b9ab 100644 --- a/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.h +++ b/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.h @@ -60,6 +60,4 @@ private: } - - #endif /* MQTTSNGATEWAY_SRC_MQTTSNGWENCAPSULATEDPACKET_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWForwarder.cpp b/MQTTSNGateway/src/MQTTSNGWForwarder.cpp index 71b2e83..92875f3 100644 --- a/MQTTSNGateway/src/MQTTSNGWForwarder.cpp +++ b/MQTTSNGateway/src/MQTTSNGWForwarder.cpp @@ -22,7 +22,7 @@ using namespace MQTTSNGW; using namespace std; /*===================================== - Class ForwarderList + Class ForwarderList =====================================*/ ForwarderList::ForwarderList() @@ -32,10 +32,10 @@ ForwarderList::ForwarderList() ForwarderList::~ForwarderList() { - if ( _head ) + if (_head) { Forwarder* p = _head; - while ( p ) + while (p) { Forwarder* next = p->_next; delete p; @@ -44,20 +44,18 @@ ForwarderList::~ForwarderList() } } - void ForwarderList::initialize(Gateway* gw) { - /* Create Fowarders from clients.conf */ - gw->getClientList()->setClientList(FORWARDER_TYPE); + /* Create Fowarders from clients.conf */ + gw->getClientList()->setClientList(FORWARDER_TYPE); } - Forwarder* ForwarderList::getForwarder(SensorNetAddress* addr) { Forwarder* p = _head; - while ( p ) + while (p) { - if ( p->_sensorNetAddr.isMatch(addr) ) + if (p->_sensorNetAddr.isMatch(addr)) { break; } @@ -66,19 +64,20 @@ Forwarder* ForwarderList::getForwarder(SensorNetAddress* addr) return p; } -Forwarder* ForwarderList::addForwarder(SensorNetAddress* addr, MQTTSNString* forwarderId) +Forwarder* ForwarderList::addForwarder(SensorNetAddress* addr, + MQTTSNString* forwarderId) { Forwarder* fdr = new Forwarder(addr, forwarderId); - if ( _head == nullptr ) + if (_head == nullptr) { _head = fdr; } else { Forwarder* p = _head; - while ( p ) + while (p) { - if ( p->_next == nullptr ) + if (p->_next == nullptr) { p->_next = fdr; break; @@ -99,10 +98,10 @@ Forwarder::Forwarder() } /*===================================== - Class ForwarderList + Class ForwarderList =====================================*/ -Forwarder::Forwarder(SensorNetAddress* addr, MQTTSNString* forwarderId) +Forwarder::Forwarder(SensorNetAddress* addr, MQTTSNString* forwarderId) { _forwarderName = string(forwarderId->cstring); _sensorNetAddr = *addr; @@ -112,10 +111,10 @@ Forwarder::Forwarder(SensorNetAddress* addr, MQTTSNString* forwarderId) Forwarder::~Forwarder(void) { - if ( _headClient ) + if (_headClient) { ForwarderElement* p = _headClient; - while ( p ) + while (p) { ForwarderElement* next = p->_next; delete p; @@ -136,11 +135,11 @@ void Forwarder::addClient(Client* client, WirelessNodeId* id) client->setForwarder(this); - if ( p != nullptr ) + if (p != nullptr) { - while ( p ) + while (p) { - if ( p->_client == client ) + if (p->_client == client) { client->setForwarder(this); p->setWirelessNodeId(id); @@ -156,7 +155,7 @@ void Forwarder::addClient(Client* client, WirelessNodeId* id) fclient->setClient(client); fclient->setWirelessNodeId(id); - if ( prev ) + if (prev) { prev->_next = fclient; } @@ -171,9 +170,9 @@ Client* Forwarder::getClient(WirelessNodeId* id) Client* cl = nullptr; _mutex.lock(); ForwarderElement* p = _headClient; - while ( p ) + while (p) { - if ( *(p->_wirelessNodeId) == *id ) + if (*(p->_wirelessNodeId) == *id) { cl = p->_client; break; @@ -197,9 +196,9 @@ WirelessNodeId* Forwarder::getWirelessNodeId(Client* client) WirelessNodeId* nodeId = nullptr; _mutex.lock(); ForwarderElement* p = _headClient; - while ( p ) + while (p) { - if ( p->_client == client ) + if (p->_client == client) { nodeId = p->_wirelessNodeId; break; @@ -219,11 +218,11 @@ void Forwarder::eraseClient(Client* client) _mutex.lock(); ForwarderElement* p = _headClient; - while ( p ) + while (p) { - if ( p->_client == client ) + if (p->_client == client) { - if ( prev ) + if (prev) { prev->_next = p->_next; } @@ -251,10 +250,11 @@ SensorNetAddress* Forwarder::getSensorNetAddr(void) * Class ForwardedClient */ -ForwarderElement::ForwarderElement() - : _client{0} - , _wirelessNodeId{0} - , _next{0} +ForwarderElement::ForwarderElement() : + _client + { 0 }, _wirelessNodeId + { 0 }, _next + { 0 } { } @@ -273,7 +273,7 @@ void ForwarderElement::setClient(Client* client) void ForwarderElement::setWirelessNodeId(WirelessNodeId* id) { - if ( _wirelessNodeId == nullptr ) + if (_wirelessNodeId == nullptr) { _wirelessNodeId = new WirelessNodeId(); } diff --git a/MQTTSNGateway/src/MQTTSNGWForwarder.h b/MQTTSNGateway/src/MQTTSNGWForwarder.h index a7279d2..9730030 100644 --- a/MQTTSNGateway/src/MQTTSNGWForwarder.h +++ b/MQTTSNGateway/src/MQTTSNGWForwarder.h @@ -22,7 +22,6 @@ #include "MQTTSNGWEncapsulatedPacket.h" #include "SensorNetwork.h" - namespace MQTTSNGW { class Gateway; @@ -30,7 +29,7 @@ class Client; class WirelessNodeId; /*===================================== - Class ForwarderElement + Class ForwarderElement =====================================*/ class ForwarderElement { @@ -48,14 +47,14 @@ private: }; /*===================================== - Class Forwarder + Class Forwarder =====================================*/ class Forwarder { friend class ForwarderList; public: Forwarder(void); - Forwarder(SensorNetAddress* addr, MQTTSNString* forwarderId); + Forwarder(SensorNetAddress* addr, MQTTSNString* forwarderId); ~Forwarder(); void initialize(void); @@ -70,13 +69,13 @@ public: private: string _forwarderName; SensorNetAddress _sensorNetAddr; - ForwarderElement* _headClient{nullptr}; - Forwarder* _next {nullptr}; + ForwarderElement* _headClient { nullptr }; + Forwarder* _next { nullptr }; Mutex _mutex; }; /*===================================== - Class ForwarderList + Class ForwarderList =====================================*/ class ForwarderList { @@ -86,7 +85,7 @@ public: void initialize(Gateway* gw); Forwarder* getForwarder(SensorNetAddress* addr); - Forwarder* addForwarder(SensorNetAddress* addr, MQTTSNString* forwarderId); + Forwarder* addForwarder(SensorNetAddress* addr, MQTTSNString* forwarderId); private: Forwarder* _head; @@ -94,6 +93,4 @@ private: } - - #endif /* MQTTSNGATEWAY_SRC_MQTTSNGWFORWARDER_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWLogmonitor.cpp b/MQTTSNGateway/src/MQTTSNGWLogmonitor.cpp index 692e3fe..be4587f 100644 --- a/MQTTSNGateway/src/MQTTSNGWLogmonitor.cpp +++ b/MQTTSNGateway/src/MQTTSNGWLogmonitor.cpp @@ -22,7 +22,7 @@ using namespace MQTTSNGW; Logmonitor::Logmonitor() { - theProcess = this; + theProcess = this; } Logmonitor::~Logmonitor() @@ -32,17 +32,17 @@ Logmonitor::~Logmonitor() void Logmonitor::run() { - while (true) - { - const char* data = getLog(); - if ( *data == 0 ) - { - break; - } - else - { - printf("%s", data); - } - } + while (true) + { + const char* data = getLog(); + if (*data == 0) + { + break; + } + else + { + printf("%s", data); + } + } } diff --git a/MQTTSNGateway/src/MQTTSNGWLogmonitor.h b/MQTTSNGateway/src/MQTTSNGWLogmonitor.h index cb5838a..a0745bf 100644 --- a/MQTTSNGateway/src/MQTTSNGWLogmonitor.h +++ b/MQTTSNGateway/src/MQTTSNGWLogmonitor.h @@ -23,9 +23,9 @@ namespace MQTTSNGW class Logmonitor: public Process { public: - Logmonitor(); - ~Logmonitor(); - void run(); + Logmonitor(); + ~Logmonitor(); + void run(); }; } diff --git a/MQTTSNGateway/src/MQTTSNGWMessageIdTable.cpp b/MQTTSNGateway/src/MQTTSNGWMessageIdTable.cpp index b87e06c..63e32a2 100644 --- a/MQTTSNGateway/src/MQTTSNGWMessageIdTable.cpp +++ b/MQTTSNGateway/src/MQTTSNGWMessageIdTable.cpp @@ -29,187 +29,188 @@ 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(); + _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) +MessageIdElement* MessageIdTable::add(Aggregater* aggregater, Client* client, + uint16_t clientMsgId) { - if ( _cnt > _maxSize ) - { - return nullptr; - } + 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* 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* 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; + 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; + 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(); + _mutex.lock(); + MessageIdElement* p = find(msgId); + clear(p); + _mutex.unlock(); } void MessageIdTable::clear(MessageIdElement* elm) { - if ( elm == nullptr ) - { - return; - } + 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; - } + 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; + 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(void) : + _msgId + { 0 }, _clientMsgId + { 0 }, _client + { nullptr }, _next + { nullptr }, _prev + { nullptr } { } -MessageIdElement::MessageIdElement(uint16_t msgId, Client* client, uint16_t clientMsgId) - : MessageIdElement() +MessageIdElement::MessageIdElement(uint16_t msgId, Client* client, + uint16_t clientMsgId) : + MessageIdElement() { - _msgId = msgId; - _client = client; - _clientMsgId = clientMsgId; + _msgId = msgId; + _client = client; + _clientMsgId = clientMsgId; } MessageIdElement::~MessageIdElement(void) diff --git a/MQTTSNGateway/src/MQTTSNGWMessageIdTable.h b/MQTTSNGateway/src/MQTTSNGWMessageIdTable.h index 59f7be6..2f0b5e6 100644 --- a/MQTTSNGateway/src/MQTTSNGWMessageIdTable.h +++ b/MQTTSNGateway/src/MQTTSNGWMessageIdTable.h @@ -34,22 +34,23 @@ class Aggregater; class MessageIdTable { public: - MessageIdTable(); - ~MessageIdTable(); + 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); + 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; + 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; }; /*===================================== @@ -67,12 +68,11 @@ public: private: uint16_t _msgId; uint16_t _clientMsgId; - Client* _client; + Client* _client; MessageIdElement* _next; MessageIdElement* _prev; }; - } #endif /* MQTTSNGATEWAY_SRC_MQTTSNGWMESSAGEIDTABLE_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWPacket.cpp b/MQTTSNGateway/src/MQTTSNGWPacket.cpp index c2a017a..0e1f2ec 100644 --- a/MQTTSNGateway/src/MQTTSNGWPacket.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPacket.cpp @@ -29,286 +29,293 @@ void writeInt(unsigned char** pptr, int msgId); MQTTSNPacket::MQTTSNPacket(void) { - _buf = nullptr; - _bufLen = 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; - } + _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) - { - free(_buf); - } + if (_buf) + { + free(_buf); + } } int MQTTSNPacket::unicast(SensorNetwork* network, SensorNetAddress* sendTo) { - return network->unicast(_buf, _bufLen, sendTo); + return network->unicast(_buf, _bufLen, sendTo); } int MQTTSNPacket::broadcast(SensorNetwork* network) { - return network->broadcast(_buf, _bufLen); + return network->broadcast(_buf, _bufLen); } int MQTTSNPacket::serialize(uint8_t* buf) { - buf = _buf; - return _bufLen; + buf = _buf; + return _bufLen; } int MQTTSNPacket::desirialize(unsigned char* buf, unsigned short len) { - if ( _buf ) - { - free(_buf); - } + if (_buf) + { + free(_buf); + } - _buf = (unsigned char*)calloc(len, sizeof(unsigned char)); - if ( _buf ) - { - memcpy(_buf, buf, len); - _bufLen = len; - } - else - { - _bufLen = 0; - } - return _bufLen; + _buf = (unsigned char*) calloc(len, sizeof(unsigned char)); + if (_buf) + { + memcpy(_buf, buf, len); + _bufLen = len; + } + else + { + _bufLen = 0; + } + return _bufLen; } int MQTTSNPacket::recv(SensorNetwork* network) { - uint8_t buf[MQTTSNGW_MAX_PACKET_SIZE]; - int len = network->read((uint8_t*) buf, MQTTSNGW_MAX_PACKET_SIZE); - if (len > 1) - { - len = desirialize(buf, len); - } - else - { - len = 0; - } - return len; + uint8_t buf[MQTTSNGW_MAX_PACKET_SIZE]; + int len = network->read((uint8_t*) buf, MQTTSNGW_MAX_PACKET_SIZE); + if (len > 1) + { + len = desirialize(buf, len); + } + else + { + len = 0; + } + return len; } int MQTTSNPacket::getType(void) { - if ( _bufLen == 0 ) - { - return 0; - } - int value = 0; - int p = MQTTSNPacket_decode(_buf, _bufLen, &value); - return _buf[p]; + if (_bufLen == 0) + { + return 0; + } + int value = 0; + int p = MQTTSNPacket_decode(_buf, _bufLen, &value); + return _buf[p]; } bool MQTTSNPacket::isQoSMinusPUBLISH(void) { - if ( _bufLen == 0 ) + 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 )); + return ((_buf[p] == MQTTSN_PUBLISH) && ((_buf[p + 1] & 0x60) == 0x60)); } unsigned char* MQTTSNPacket::getPacketData(void) { - return _buf; + return _buf; } int MQTTSNPacket::getPacketLength(void) { - return _bufLen; + return _bufLen; } const char* MQTTSNPacket::getName() { - return MQTTSNPacket_name(getType()); + return MQTTSNPacket_name(getType()); } int MQTTSNPacket::setADVERTISE(uint8_t gatewayid, uint16_t duration) { - unsigned char buf[5]; - int buflen = sizeof(buf); - int len = MQTTSNSerialize_advertise(buf, buflen, (unsigned char) gatewayid, - (unsigned short) duration); - return desirialize(buf, len); + unsigned char buf[5]; + int buflen = sizeof(buf); + int len = MQTTSNSerialize_advertise(buf, buflen, (unsigned char) gatewayid, + (unsigned short) duration); + return desirialize(buf, len); } int MQTTSNPacket::setGWINFO(uint8_t gatewayId) { - unsigned char buf[3]; - int buflen = sizeof(buf); - int len = MQTTSNSerialize_gwinfo(buf, buflen, (unsigned char) gatewayId, 0, 0); - return desirialize(buf, len); + unsigned char buf[3]; + 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, buflen, &data); - return desirialize(buf, len); + unsigned char buf[40]; + int buflen = sizeof(buf); + MQTTSNPacket_connectData data; + data.clientID.cstring = (char*) "client01"; + int len = MQTTSNSerialize_connect(buf, buflen, &data); + return desirialize(buf, len); } bool MQTTSNPacket::isAccepted(void) { - return ( getType() == MQTTSN_CONNACK) && (_buf[2] == MQTTSN_RC_ACCEPTED); + return (getType() == MQTTSN_CONNACK) && (_buf[2] == MQTTSN_RC_ACCEPTED); } int MQTTSNPacket::setCONNACK(uint8_t returnCode) { - unsigned char buf[3]; - int buflen = sizeof(buf); - int len = MQTTSNSerialize_connack(buf, buflen, (int) returnCode); - return desirialize(buf, len); + unsigned char buf[3]; + 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 buflen = sizeof(buf); - int len = MQTTSNSerialize_willtopicreq(buf, buflen); - return desirialize(buf, len); + unsigned char 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 buflen = sizeof(buf); - int len = MQTTSNSerialize_willmsgreq(buf, buflen); - return desirialize(buf, len); + unsigned char 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) +int MQTTSNPacket::setREGISTER(uint16_t topicId, uint16_t msgId, + MQTTSNString* topicName) { - unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE]; - int buflen = sizeof(buf); - int len = MQTTSNSerialize_register(buf, buflen, (unsigned short) topicId, (unsigned short) msgId, - topicName); - return desirialize(buf, len); + unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE]; + int buflen = sizeof(buf); + int len = MQTTSNSerialize_register(buf, buflen, (unsigned short) topicId, + (unsigned short) msgId, topicName); + return desirialize(buf, len); } -int MQTTSNPacket::setREGACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode) +int MQTTSNPacket::setREGACK(uint16_t topicId, uint16_t msgId, + uint8_t returnCode) { - unsigned char buf[7]; - int buflen = sizeof(buf); - int len = MQTTSNSerialize_regack(buf, buflen, (unsigned short) topicId, (unsigned short) msgId, - (unsigned char) returnCode); - return desirialize(buf, len); + unsigned char buf[7]; + int buflen = sizeof(buf); + int len = MQTTSNSerialize_regack(buf, buflen, (unsigned short) topicId, + (unsigned short) msgId, (unsigned char) returnCode); + return desirialize(buf, len); } -int MQTTSNPacket::setPUBLISH(uint8_t dup, int qos, uint8_t retained, uint16_t msgId, MQTTSN_topicid topic, - uint8_t* payload, uint16_t payloadlen) +int MQTTSNPacket::setPUBLISH(uint8_t dup, int qos, uint8_t retained, + uint16_t msgId, MQTTSN_topicid topic, uint8_t* payload, + uint16_t payloadlen) { - unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE]; - int 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); + unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE]; + 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); } -int MQTTSNPacket::setPUBACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode) +int MQTTSNPacket::setPUBACK(uint16_t topicId, uint16_t msgId, + uint8_t returnCode) { - unsigned char buf[7]; - int buflen = sizeof(buf); - int len = MQTTSNSerialize_puback(buf, buflen, (unsigned short) topicId, (unsigned short) msgId, - (unsigned char) returnCode); - return desirialize(buf, len); + unsigned char buf[7]; + int buflen = sizeof(buf); + int len = MQTTSNSerialize_puback(buf, buflen, (unsigned short) topicId, + (unsigned short) msgId, (unsigned char) returnCode); + return desirialize(buf, len); } int MQTTSNPacket::setPUBREC(uint16_t msgId) { - unsigned char buf[4]; - int buflen = sizeof(buf); - int len = MQTTSNSerialize_pubrec(buf, buflen, (unsigned short) msgId); - return desirialize(buf, len); + unsigned char buf[4]; + 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 buflen = sizeof(buf); - int len = MQTTSNSerialize_pubrel(buf, buflen, (unsigned short) msgId); - return desirialize(buf, len); + unsigned char buf[4]; + 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 buflen = sizeof(buf); - int len = MQTTSNSerialize_pubcomp(buf, buflen, (unsigned short) msgId); - return desirialize(buf, len); + unsigned char buf[4]; + 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) +int MQTTSNPacket::setSUBACK(int qos, uint16_t topicId, uint16_t msgId, + uint8_t returnCode) { - unsigned char buf[8]; - int buflen = sizeof(buf); - int len = MQTTSNSerialize_suback(buf, buflen, qos, (unsigned short) topicId, - (unsigned short) msgId, (unsigned char) returnCode); - return desirialize(buf, len); + unsigned char buf[8]; + int buflen = sizeof(buf); + int len = MQTTSNSerialize_suback(buf, buflen, qos, (unsigned short) topicId, + (unsigned short) msgId, (unsigned char) returnCode); + return desirialize(buf, len); } int MQTTSNPacket::setUNSUBACK(uint16_t msgId) { - unsigned char buf[4]; - int buflen = sizeof(buf); - int len = MQTTSNSerialize_unsuback(buf, buflen, (unsigned short) msgId); - return desirialize(buf, len); + unsigned char buf[4]; + 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 buflen = sizeof(buf); - int len = MQTTSNSerialize_pingresp(buf, buflen); - return desirialize(buf, len); + unsigned char 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 buflen = sizeof(buf); - int len = MQTTSNSerialize_disconnect(buf, buflen, (int) duration); - return desirialize(buf, len); + unsigned char buf[4]; + 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 buflen = sizeof(buf); - int len = MQTTSNSerialize_willtopicresp(buf, buflen, (int) returnCode); - return desirialize(buf, len); + unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE]; + 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 buflen = sizeof(buf); - int len = MQTTSNSerialize_willmsgresp(buf, buflen, (int) returnCode); - return desirialize(buf, len); + unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE]; + int buflen = sizeof(buf); + int len = MQTTSNSerialize_willmsgresp(buf, buflen, (int) returnCode); + return desirialize(buf, len); } int MQTTSNPacket::setCONNECT(MQTTSNPacket_connectData* options) @@ -323,262 +330,276 @@ int MQTTSNPacket::setPINGREQ(MQTTSNString* clientId) { unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE]; int buflen = sizeof(buf); - int len = MQTTSNSerialize_pingreq( buf, buflen, *clientId); + 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); + return MQTTSNDeserialize_searchgw((unsigned char*) radius, + (unsigned char*) _buf, _bufLen); } int MQTTSNPacket::getCONNECT(MQTTSNPacket_connectData* data) { - return MQTTSNDeserialize_connect(data, _buf, _bufLen); + return MQTTSNDeserialize_connect(data, _buf, _bufLen); } int MQTTSNPacket::getCONNACK(uint8_t* returnCode) { - return MQTTSNSerialize_connack(_buf, _bufLen, (int) *returnCode); + return MQTTSNSerialize_connack(_buf, _bufLen, (int) *returnCode); } -int MQTTSNPacket::getWILLTOPIC(int* willQoS, uint8_t* willRetain, MQTTSNString* willTopic) +int MQTTSNPacket::getWILLTOPIC(int* willQoS, uint8_t* willRetain, + MQTTSNString* willTopic) { - return MQTTSNDeserialize_willtopic((int*) willQoS, (unsigned char*) willRetain, willTopic, _buf, _bufLen); + return MQTTSNDeserialize_willtopic((int*) willQoS, + (unsigned char*) willRetain, willTopic, _buf, _bufLen); } int MQTTSNPacket::getWILLMSG(MQTTSNString* willmsg) { - return MQTTSNDeserialize_willmsg(willmsg, _buf, _bufLen); + return MQTTSNDeserialize_willmsg(willmsg, _buf, _bufLen); } -int MQTTSNPacket::getREGISTER(uint16_t* topicId, uint16_t* msgId, MQTTSNString* topicName) +int MQTTSNPacket::getREGISTER(uint16_t* topicId, uint16_t* msgId, + MQTTSNString* topicName) { - return MQTTSNDeserialize_register((unsigned short*) topicId, (unsigned short*) msgId, topicName, - _buf, _bufLen); + return MQTTSNDeserialize_register((unsigned short*) topicId, + (unsigned short*) msgId, topicName, _buf, _bufLen); } -int MQTTSNPacket::getREGACK(uint16_t* topicId, uint16_t* msgId, uint8_t* returnCode) +int MQTTSNPacket::getREGACK(uint16_t* topicId, uint16_t* msgId, + uint8_t* returnCode) { - return MQTTSNDeserialize_regack((unsigned short*) topicId, (unsigned short*) msgId, (unsigned char*) returnCode, _buf, _bufLen); + return MQTTSNDeserialize_regack((unsigned short*) topicId, + (unsigned short*) msgId, (unsigned char*) returnCode, _buf, _bufLen); } -int MQTTSNPacket::getPUBLISH(uint8_t* dup, int* qos, uint8_t* retained, uint16_t* msgId, MQTTSN_topicid* topic, - uint8_t** payload, int* payloadlen) +int MQTTSNPacket::getPUBLISH(uint8_t* dup, int* qos, uint8_t* retained, + uint16_t* msgId, MQTTSN_topicid* topic, uint8_t** payload, + int* payloadlen) { - return MQTTSNDeserialize_publish((unsigned char*) dup, qos, (unsigned char*) retained, (unsigned short*) msgId, - topic, (unsigned char**) payload, (int*) payloadlen, _buf, _bufLen); + return MQTTSNDeserialize_publish((unsigned char*) dup, qos, + (unsigned char*) retained, (unsigned short*) msgId, topic, + (unsigned char**) payload, (int*) payloadlen, _buf, _bufLen); } -int MQTTSNPacket::getPUBACK(uint16_t* topicId, uint16_t* msgId, uint8_t* returnCode) +int MQTTSNPacket::getPUBACK(uint16_t* topicId, uint16_t* msgId, + uint8_t* returnCode) { - return MQTTSNDeserialize_puback((unsigned short*) topicId, (unsigned short*) msgId, (unsigned char*) returnCode, - _buf, _bufLen); + return MQTTSNDeserialize_puback((unsigned short*) topicId, + (unsigned short*) msgId, (unsigned char*) returnCode, _buf, _bufLen); } int MQTTSNPacket::getACK(uint16_t* msgId) { - unsigned char type; - return MQTTSNDeserialize_ack(&type, (unsigned short*) msgId, _buf, _bufLen); + unsigned char type; + return MQTTSNDeserialize_ack(&type, (unsigned short*) msgId, _buf, _bufLen); } -int MQTTSNPacket::getSUBSCRIBE(uint8_t* dup, int* qos, uint16_t* msgId, MQTTSN_topicid* topicFilter) +int MQTTSNPacket::getSUBSCRIBE(uint8_t* dup, int* qos, uint16_t* msgId, + MQTTSN_topicid* topicFilter) { - return MQTTSNDeserialize_subscribe((unsigned char*) dup, qos, (unsigned short*) msgId, topicFilter, _buf, _bufLen); + return MQTTSNDeserialize_subscribe((unsigned char*) dup, qos, + (unsigned short*) msgId, topicFilter, _buf, _bufLen); } int MQTTSNPacket::getUNSUBSCRIBE(uint16_t* msgId, MQTTSN_topicid* topicFilter) { - return MQTTSNDeserialize_unsubscribe((unsigned short*) msgId, topicFilter, _buf, _bufLen); + return MQTTSNDeserialize_unsubscribe((unsigned short*) msgId, topicFilter, + _buf, _bufLen); } int MQTTSNPacket::getPINGREQ(void) { - if (getType() == MQTTSN_PINGRESP && _bufLen > 2 ) - { - return _bufLen - 2; - } - return 0; + if (getType() == MQTTSN_PINGRESP && _bufLen > 2) + { + return _bufLen - 2; + } + return 0; } int MQTTSNPacket::getDISCONNECT(uint16_t* duration) { - int dur = 0; - int rc = MQTTSNDeserialize_disconnect(&dur, _buf, _bufLen); - *duration = (uint16_t)dur; - return rc; + int dur = 0; + int rc = MQTTSNDeserialize_disconnect(&dur, _buf, _bufLen); + *duration = (uint16_t) dur; + return rc; } -int MQTTSNPacket::getWILLTOPICUPD(uint8_t* willQoS, uint8_t* willRetain, MQTTSNString* willTopic) +int MQTTSNPacket::getWILLTOPICUPD(uint8_t* willQoS, uint8_t* willRetain, + MQTTSNString* willTopic) { - return MQTTSNDeserialize_willtopicupd((int*) willQoS, (unsigned char*) willRetain, willTopic, _buf, _bufLen); + return MQTTSNDeserialize_willtopicupd((int*) willQoS, + (unsigned char*) willRetain, willTopic, _buf, _bufLen); } int MQTTSNPacket::getWILLMSGUPD(MQTTSNString* willMsg) { - return MQTTSNDeserialize_willmsgupd(willMsg, _buf, _bufLen); + return MQTTSNDeserialize_willmsgupd(willMsg, _buf, _bufLen); } char* MQTTSNPacket::print(char* pbuf) { - char* ptr = pbuf; - char** pptr = &pbuf; - int size = _bufLen > SIZE_OF_LOG_PACKET ? SIZE_OF_LOG_PACKET : _bufLen; + char* ptr = pbuf; + char** pptr = &pbuf; + int size = _bufLen > SIZE_OF_LOG_PACKET ? SIZE_OF_LOG_PACKET : _bufLen; - for (int i = 0; i < size; i++) - { - sprintf(*pptr, " %02X", *(_buf + i)); - *pptr += 3; - } - **pptr = 0; - return ptr; + for (int i = 0; i < size; i++) + { + sprintf(*pptr, " %02X", *(_buf + i)); + *pptr += 3; + } + **pptr = 0; + return ptr; } char* MQTTSNPacket::getMsgId(char* pbuf) { - int value = 0; - int p = 0; + int value = 0; + int p = 0; - switch ( getType() ) - { - case MQTTSN_PUBLISH: - p = MQTTSNPacket_decode(_buf, _bufLen, &value); - if ( _buf[p + 1] & 0x80 ) - { - sprintf(pbuf, "+%02X%02X", _buf[p + 4], _buf[p + 5]); - } - else - { - sprintf(pbuf, " %02X%02X", _buf[p + 4], _buf[p + 5]); - } - break; - case MQTTSN_PUBACK: - case MQTTSN_REGISTER: - case MQTTSN_REGACK: - sprintf(pbuf, " %02X%02X", _buf[4], _buf[5]); - break; - case MQTTSN_PUBREC: - case MQTTSN_PUBREL: - case MQTTSN_PUBCOMP: - case MQTTSN_UNSUBACK: - sprintf(pbuf, " %02X%02X", _buf[2], _buf[3]); - break; - case MQTTSN_SUBSCRIBE: - case MQTTSN_UNSUBSCRIBE: - p = MQTTSNPacket_decode(_buf, _bufLen, &value); - sprintf(pbuf, " %02X%02X", _buf[p + 2], _buf[p + 3]); - break; - case MQTTSN_SUBACK: - sprintf(pbuf, " %02X%02X", _buf[5], _buf[6]); - break; - default: - sprintf(pbuf, " "); - break; - } - if ( strcmp(pbuf, " 0000") == 0 ) - { - sprintf(pbuf, " "); - } - return pbuf; + switch (getType()) + { + case MQTTSN_PUBLISH: + p = MQTTSNPacket_decode(_buf, _bufLen, &value); + if (_buf[p + 1] & 0x80) + { + sprintf(pbuf, "+%02X%02X", _buf[p + 4], _buf[p + 5]); + } + else + { + sprintf(pbuf, " %02X%02X", _buf[p + 4], _buf[p + 5]); + } + break; + case MQTTSN_PUBACK: + case MQTTSN_REGISTER: + case MQTTSN_REGACK: + sprintf(pbuf, " %02X%02X", _buf[4], _buf[5]); + break; + case MQTTSN_PUBREC: + case MQTTSN_PUBREL: + case MQTTSN_PUBCOMP: + case MQTTSN_UNSUBACK: + sprintf(pbuf, " %02X%02X", _buf[2], _buf[3]); + break; + case MQTTSN_SUBSCRIBE: + case MQTTSN_UNSUBSCRIBE: + p = MQTTSNPacket_decode(_buf, _bufLen, &value); + sprintf(pbuf, " %02X%02X", _buf[p + 2], _buf[p + 3]); + break; + case MQTTSN_SUBACK: + sprintf(pbuf, " %02X%02X", _buf[5], _buf[6]); + break; + default: + 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; + 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; + 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; + 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; - } + 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 ); + 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 7a624a3..c6fd4fc 100644 --- a/MQTTSNGateway/src/MQTTSNGWPacket.h +++ b/MQTTSNGateway/src/MQTTSNGWPacket.h @@ -26,72 +26,77 @@ namespace MQTTSNGW class MQTTSNPacket { public: - MQTTSNPacket(void); - MQTTSNPacket(MQTTSNPacket &packet); - ~MQTTSNPacket(void); - int unicast(SensorNetwork* network, SensorNetAddress* sendTo); - int broadcast(SensorNetwork* network); - int recv(SensorNetwork* network); - int serialize(uint8_t* buf); - int desirialize(unsigned char* buf, unsigned short len); - int getType(void); - unsigned char* getPacketData(void); - int getPacketLength(void); - const char* getName(); + MQTTSNPacket(void); + MQTTSNPacket(MQTTSNPacket &packet); + ~MQTTSNPacket(void); + int unicast(SensorNetwork* network, SensorNetAddress* sendTo); + int broadcast(SensorNetwork* network); + int recv(SensorNetwork* network); + int serialize(uint8_t* buf); + int desirialize(unsigned char* buf, unsigned short len); + int getType(void); + unsigned char* getPacketData(void); + int getPacketLength(void); + const char* getName(); - int setConnect(void); // Debug - int setADVERTISE(uint8_t gatewayid, uint16_t duration); - int setGWINFO(uint8_t gatewayId); - int setCONNACK(uint8_t returnCode); - int setWILLTOPICREQ(void); - int setWILLMSGREQ(void); - int setREGISTER(uint16_t topicId, uint16_t msgId, MQTTSNString* TopicName); - int setREGACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode); - int setPUBLISH(uint8_t dup, int qos, uint8_t retained, uint16_t msgId, - MQTTSN_topicid topic, uint8_t* payload, uint16_t payloadlen); - int setPUBACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode); - int setPUBREC(uint16_t msgId); - int setPUBREL(uint16_t msgId); - int setPUBCOMP(uint16_t msgId); - int setSUBACK(int qos, uint16_t topicId, uint16_t msgId, uint8_t returnCode); - int setUNSUBACK(uint16_t msgId); - int setPINGRESP(void); - int setDISCONNECT(uint16_t duration); - int setWILLTOPICRESP(uint8_t returnCode); - int setWILLMSGRESP(uint8_t returnCode); + int setConnect(void); // Debug + int setADVERTISE(uint8_t gatewayid, uint16_t duration); + int setGWINFO(uint8_t gatewayId); + int setCONNACK(uint8_t returnCode); + int setWILLTOPICREQ(void); + int setWILLMSGREQ(void); + int setREGISTER(uint16_t topicId, uint16_t msgId, MQTTSNString* TopicName); + int setREGACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode); + int setPUBLISH(uint8_t dup, int qos, uint8_t retained, uint16_t msgId, + MQTTSN_topicid topic, uint8_t* payload, uint16_t payloadlen); + int setPUBACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode); + int setPUBREC(uint16_t msgId); + int setPUBREL(uint16_t msgId); + int setPUBCOMP(uint16_t msgId); + int setSUBACK(int qos, uint16_t topicId, uint16_t msgId, + uint8_t returnCode); + int setUNSUBACK(uint16_t msgId); + int setPINGRESP(void); + int setDISCONNECT(uint16_t duration); + int setWILLTOPICRESP(uint8_t returnCode); + int setWILLMSGRESP(uint8_t returnCode); - int setCONNECT(MQTTSNPacket_connectData* options); - int setPINGREQ(MQTTSNString* clientId); + int setCONNECT(MQTTSNPacket_connectData* options); + int setPINGREQ(MQTTSNString* clientId); - int getSERCHGW(uint8_t* radius); - int getCONNECT(MQTTSNPacket_connectData* option); - int getCONNACK(uint8_t* returnCode); - int getWILLTOPIC(int* willQoS, uint8_t* willRetain, MQTTSNString* willTopic); - int getWILLMSG(MQTTSNString* willmsg); - int getREGISTER(uint16_t* topicId, uint16_t* msgId, MQTTSNString* topicName); - int getREGACK(uint16_t* topicId, uint16_t* msgId, uint8_t* returnCode); - int getPUBLISH(uint8_t* dup, int* qos, uint8_t* retained, uint16_t* msgId, - MQTTSN_topicid* topic, unsigned char** payload, int* payloadlen); - int getPUBACK(uint16_t* topicId, uint16_t* msgId, uint8_t* returnCode); - int getACK(uint16_t* msgId); - int getSUBSCRIBE(uint8_t* dup, int* qos, uint16_t* msgId, MQTTSN_topicid* topicFilter); - int getUNSUBSCRIBE(uint16_t* msgId, MQTTSN_topicid* topicFilter); - int getPINGREQ(void); - int getDISCONNECT(uint16_t* duration); - int getWILLTOPICUPD(uint8_t* willQoS, uint8_t* willRetain, MQTTSNString* willTopic); - int getWILLMSGUPD(MQTTSNString* willMsg); + int getSERCHGW(uint8_t* radius); + int getCONNECT(MQTTSNPacket_connectData* option); + int getCONNACK(uint8_t* returnCode); + int getWILLTOPIC(int* willQoS, uint8_t* willRetain, + MQTTSNString* willTopic); + int getWILLMSG(MQTTSNString* willmsg); + int getREGISTER(uint16_t* topicId, uint16_t* msgId, + MQTTSNString* topicName); + int getREGACK(uint16_t* topicId, uint16_t* msgId, uint8_t* returnCode); + int getPUBLISH(uint8_t* dup, int* qos, uint8_t* retained, uint16_t* msgId, + MQTTSN_topicid* topic, unsigned char** payload, int* payloadlen); + int getPUBACK(uint16_t* topicId, uint16_t* msgId, uint8_t* returnCode); + int getACK(uint16_t* msgId); + int getSUBSCRIBE(uint8_t* dup, int* qos, uint16_t* msgId, + MQTTSN_topicid* topicFilter); + int getUNSUBSCRIBE(uint16_t* msgId, MQTTSN_topicid* topicFilter); + int getPINGREQ(void); + int getDISCONNECT(uint16_t* duration); + int getWILLTOPICUPD(uint8_t* willQoS, uint8_t* willRetain, + MQTTSNString* willTopic); + int getWILLMSGUPD(MQTTSNString* willMsg); - 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); + 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: - unsigned char* _buf; // Ptr to a packet data - int _bufLen; // length of the packet data + unsigned char* _buf; // Ptr to a packet data + int _bufLen; // length of the packet data }; } diff --git a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp index f195d76..c94ccb5 100644 --- a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp @@ -44,16 +44,16 @@ char* currentDateTime(void); PacketHandleTask::PacketHandleTask(Gateway* gateway) { - _gateway = gateway; - _gateway->attach((Thread*)this); - _mqttConnection = new MQTTGWConnectionHandler(_gateway); - _mqttPublish = new MQTTGWPublishHandler(_gateway); - _mqttSubscribe = new MQTTGWSubscribeHandler(_gateway); - _mqttsnConnection = new MQTTSNConnectionHandler(_gateway); - _mqttsnPublish = new MQTTSNPublishHandler(_gateway); - _mqttsnSubscribe = new MQTTSNSubscribeHandler(_gateway); + _gateway = gateway; + _gateway->attach((Thread*) this); + _mqttConnection = new MQTTGWConnectionHandler(_gateway); + _mqttPublish = new MQTTGWPublishHandler(_gateway); + _mqttSubscribe = new MQTTGWSubscribeHandler(_gateway); + _mqttsnConnection = new MQTTSNConnectionHandler(_gateway); + _mqttsnPublish = new MQTTSNPublishHandler(_gateway); + _mqttsnSubscribe = new MQTTSNSubscribeHandler(_gateway); - _mqttsnAggrConnection = new MQTTSNAggregateConnectionHandler(_gateway); + _mqttsnAggrConnection = new MQTTSNAggregateConnectionHandler(_gateway); } /** @@ -61,315 +61,314 @@ PacketHandleTask::PacketHandleTask(Gateway* gateway) */ PacketHandleTask::~PacketHandleTask() { - if ( _mqttConnection ) - { - delete _mqttConnection; - } - if ( _mqttPublish ) - { - delete _mqttPublish; - } - if ( _mqttSubscribe ) - { - delete _mqttSubscribe; - } - if ( _mqttsnConnection ) - { - delete _mqttsnConnection; - } - if ( _mqttsnPublish ) - { - delete _mqttsnPublish; - } - if ( _mqttsnSubscribe ) - { - delete _mqttsnSubscribe; - } + if (_mqttConnection) + { + delete _mqttConnection; + } + if (_mqttPublish) + { + delete _mqttPublish; + } + if (_mqttSubscribe) + { + delete _mqttSubscribe; + } + if (_mqttsnConnection) + { + delete _mqttsnConnection; + } + if (_mqttsnPublish) + { + delete _mqttsnPublish; + } + if (_mqttsnSubscribe) + { + delete _mqttsnSubscribe; + } - if ( _mqttsnAggrConnection ) - { - delete _mqttsnAggrConnection; - } + if (_mqttsnAggrConnection) + { + delete _mqttsnAggrConnection; + } } void PacketHandleTask::run() { - Event* ev = nullptr; - EventQue* eventQue = _gateway->getPacketEventQue(); + Event* ev = nullptr; + EventQue* eventQue = _gateway->getPacketEventQue(); AdapterManager* adpMgr = _gateway->getAdapterManager(); - Client* client = nullptr; - MQTTSNPacket* snPacket = nullptr; - MQTTGWPacket* brPacket = nullptr; - char msgId[6]; - memset(msgId, 0, 6); + Client* client = nullptr; + MQTTSNPacket* snPacket = nullptr; + MQTTGWPacket* brPacket = nullptr; + char msgId[6]; + memset(msgId, 0, 6); - _advertiseTimer.start(_gateway->getGWParams()->keepAlive * 1000UL); + _advertiseTimer.start(_gateway->getGWParams()->keepAlive * 1000UL); - while (true) - { - /* wait Event */ - ev = eventQue->timedwait(EVENT_QUE_TIME_OUT); + while (true) + { + /* wait Event */ + ev = eventQue->timedwait(EVENT_QUE_TIME_OUT); - if (ev->getEventType() == EtStop) - { - WRITELOG("\n%s PacketHandleTask stopped.", currentDateTime()); - delete ev; - return; - } + if (ev->getEventType() == EtStop) + { + WRITELOG("\n%s PacketHandleTask stopped.", currentDateTime()); + delete ev; + return; + } - if (ev->getEventType() == EtTimeout) - { - /*------ Check Keep Alive Timer & send Advertise ------*/ - if (_advertiseTimer.isTimeup()) - { - _mqttsnConnection->sendADVERTISE(); - _advertiseTimer.start(_gateway->getGWParams()->keepAlive * 1000UL); - } + if (ev->getEventType() == EtTimeout) + { + /*------ Check Keep Alive Timer & send Advertise ------*/ + if (_advertiseTimer.isTimeup()) + { + _mqttsnConnection->sendADVERTISE(); + _advertiseTimer.start( + _gateway->getGWParams()->keepAlive * 1000UL); + } - /*------ Check Adapters Connect or PINGREQ ------*/ - adpMgr->checkConnection(); - } + /*------ Check Adapters Connect or PINGREQ ------*/ + adpMgr->checkConnection(); + } - /*------ Handle SEARCHGW Message ---------*/ - else if (ev->getEventType() == EtBroadcast) - { - snPacket = ev->getMQTTSNPacket(); - _mqttsnConnection->handleSearchgw(snPacket); - } + /*------ Handle SEARCHGW Message ---------*/ + else if (ev->getEventType() == EtBroadcast) + { + snPacket = ev->getMQTTSNPacket(); + _mqttsnConnection->handleSearchgw(snPacket); + } - /*------ Handle Messages form Clients ---------*/ - else if (ev->getEventType() == EtClientRecv) - { - client = ev->getClient(); - snPacket = ev->getMQTTSNPacket(); + /*------ Handle Messages form Clients ---------*/ + else if (ev->getEventType() == EtClientRecv) + { + client = ev->getClient(); + snPacket = ev->getMQTTSNPacket(); - DEBUGLOG(" PacketHandleTask gets %s %s from the client.\n", snPacket->getName(), snPacket->getMsgId(msgId)); + DEBUGLOG(" PacketHandleTask gets %s %s from the client.\n", snPacket->getName(), snPacket->getMsgId(msgId)); - if ( adpMgr->isAggregatedClient(client) ) - { - aggregatePacketHandler(client, snPacket); // client is converted to Aggregater by BrokerSendTask - } - else - { - transparentPacketHandler(client, snPacket); - } + if (adpMgr->isAggregatedClient(client)) + { + aggregatePacketHandler(client, snPacket); // client is converted to Aggregater by BrokerSendTask + } + else + { + transparentPacketHandler(client, snPacket); + } + /* Reset the Timer for PINGREQ. */ + client->updateStatus(snPacket); + } + /*------ Handle Messages form Broker ---------*/ + else if (ev->getEventType() == EtBrokerRecv) + { + client = ev->getClient(); + brPacket = ev->getMQTTGWPacket(); + DEBUGLOG(" PacketHandleTask gets %s %s from the broker.\n", brPacket->getName(), brPacket->getMsgId(msgId)); - /* Reset the Timer for PINGREQ. */ - client->updateStatus(snPacket); - } - /*------ Handle Messages form Broker ---------*/ - else if ( ev->getEventType() == EtBrokerRecv ) - { - client = ev->getClient(); - brPacket = ev->getMQTTGWPacket(); - DEBUGLOG(" PacketHandleTask gets %s %s from the broker.\n", brPacket->getName(), brPacket->getMsgId(msgId)); - - - if ( client->isAggregater() ) - { - aggregatePacketHandler(client, brPacket); - } - else - { - transparentPacketHandler(client, brPacket); - } - } - delete ev; - } + if (client->isAggregater()) + { + aggregatePacketHandler(client, brPacket); + } + else + { + transparentPacketHandler(client, brPacket); + } + } + delete ev; + } } - - -void PacketHandleTask::aggregatePacketHandler(Client*client, MQTTSNPacket* packet) +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_WILLTOPICUPD: - _mqttsnConnection->handleWilltopicupd(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; - } + 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_WILLTOPICUPD: + _mqttsnConnection->handleWilltopicupd(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) +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; - } + 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) +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_WILLTOPICUPD: - _mqttsnConnection->handleWilltopicupd(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; - } + 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_WILLTOPICUPD: + _mqttsnConnection->handleWilltopicupd(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) +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; - case DISCONNECT: - client->disconnected(); // Just change Client's status to "Disconnected" - break; - default: - break; - } + 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; + case DISCONNECT: + client->disconnected(); // Just change Client's status to "Disconnected" + break; + default: + break; + } } diff --git a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.h b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.h index a77eb65..43cc57e 100644 --- a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.h +++ b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.h @@ -40,40 +40,39 @@ class MQTTSNAggregateConnectionHandler; class Thread; class Timer; /*===================================== - Class PacketHandleTask + Class PacketHandleTask =====================================*/ -class PacketHandleTask : public Thread +class PacketHandleTask: public Thread { - MAGIC_WORD_FOR_THREAD; - friend class MQTTGWAggregatePublishHandler; - friend class MQTTGWAggregateSubscribeHandler; - friend class MQTTSNAggregateConnectionHandler; - friend class MQTTSNAggregatePublishHandler; - friend class MQTTSNAggregateSubscribeHandler; +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(); + PacketHandleTask(Gateway* gateway); + ~PacketHandleTask(); + void run(); private: - void aggregatePacketHandler(Client*client, MQTTSNPacket* packet); - void aggregatePacketHandler(Client*client, MQTTGWPacket* packet); - void transparentPacketHandler(Client*client, MQTTSNPacket* packet); - void transparentPacketHandler(Client*client, MQTTGWPacket* packet); + 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 {nullptr}; - MQTTGWPublishHandler* _mqttPublish {nullptr}; - MQTTGWSubscribeHandler* _mqttSubscribe {nullptr}; - MQTTSNConnectionHandler* _mqttsnConnection {nullptr}; - MQTTSNPublishHandler* _mqttsnPublish {nullptr}; - MQTTSNSubscribeHandler* _mqttsnSubscribe {nullptr}; - - MQTTSNAggregateConnectionHandler* _mqttsnAggrConnection {nullptr}; + Gateway* _gateway + { nullptr }; + Timer _advertiseTimer; + Timer _sendUnixTimer; + MQTTGWConnectionHandler* _mqttConnection { nullptr }; + MQTTGWPublishHandler* _mqttPublish { nullptr }; + MQTTGWSubscribeHandler* _mqttSubscribe { nullptr }; + MQTTSNConnectionHandler* _mqttsnConnection { nullptr }; + MQTTSNPublishHandler* _mqttsnPublish { nullptr }; + MQTTSNSubscribeHandler* _mqttsnSubscribe { nullptr }; + MQTTSNAggregateConnectionHandler* _mqttsnAggrConnection { nullptr }; }; - } #endif /* MQTTSNGWPACKETHANDLETASK_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWProcess.cpp b/MQTTSNGateway/src/MQTTSNGWProcess.cpp index 90accea..897aa29 100644 --- a/MQTTSNGateway/src/MQTTSNGWProcess.cpp +++ b/MQTTSNGateway/src/MQTTSNGWProcess.cpp @@ -44,7 +44,7 @@ volatile int theSignaled = 0; static void signalHandler(int sig) { - theSignaled = sig; + theSignaled = sig; } /*===================================== @@ -52,23 +52,23 @@ static void signalHandler(int sig) ====================================*/ Process::Process() { - _argc = 0; - _argv = 0; - _configDir = CONFIG_DIRECTORY; - _configFile = CONFIG_FILE; - _log = 0; + _argc = 0; + _argv = 0; + _configDir = CONFIG_DIRECTORY; + _configFile = CONFIG_FILE; + _log = 0; } Process::~Process() { - if (_rb ) - { - delete _rb; - } - if ( _rbsem ) - { - delete _rbsem; - } + if (_rb) + { + delete _rb; + } + if (_rbsem) + { + delete _rbsem; + } } void Process::run() @@ -78,168 +78,169 @@ void Process::run() void Process::initialize(int argc, char** argv) { - char param[MQTTSNGW_PARAM_MAX]; - _argc = argc; - _argv = argv; - signal(SIGINT, signalHandler); - signal(SIGTERM, signalHandler); - signal(SIGHUP, signalHandler); + char param[MQTTSNGW_PARAM_MAX]; + _argc = argc; + _argv = argv; + signal(SIGINT, signalHandler); + signal(SIGTERM, signalHandler); + signal(SIGHUP, signalHandler); - int opt; - while ((opt = getopt(_argc, _argv, "f:")) != -1) - { - if ( opt == 'f' ) - { - string config = string(optarg); - size_t pos = 0; - if ( (pos = config.find_last_of("/")) == string::npos ) - { - _configFile = optarg; - } - else - { - _configFile = config.substr(pos + 1, config.size() - pos - 1);; - _configDir = config.substr(0, pos + 1); - } - } - } - _rbsem = new NamedSemaphore(MQTTSNGW_RB_SEMAPHOR_NAME, 0); - _rb = new RingBuffer(_configDir.c_str()); + int opt; + while ((opt = getopt(_argc, _argv, "f:")) != -1) + { + if (opt == 'f') + { + string config = string(optarg); + size_t pos = 0; + if ((pos = config.find_last_of("/")) == string::npos) + { + _configFile = optarg; + } + else + { + _configFile = config.substr(pos + 1, config.size() - pos - 1); + ; + _configDir = config.substr(0, pos + 1); + } + } + } + _rbsem = new NamedSemaphore(MQTTSNGW_RB_SEMAPHOR_NAME, 0); + _rb = new RingBuffer(_configDir.c_str()); - if (getParam("ShearedMemory", param) == 0) - { - if (!strcasecmp(param, "YES")) - { - _log = 1; - } - else - { - _log = 0; - } - } + if (getParam("ShearedMemory", param) == 0) + { + if (!strcasecmp(param, "YES")) + { + _log = 1; + } + else + { + _log = 0; + } + } } void Process::putLog(const char* format, ...) { - _mt.lock(); - va_list arg; - va_start(arg, format); - vsprintf(_rbdata, format, arg); - va_end(arg); - if (strlen(_rbdata)) - { - if ( _log > 0 ) - { - _rb->put(_rbdata); - _rbsem->post(); - } - else - { - printf("%s", _rbdata); - } - } - _mt.unlock(); + _mt.lock(); + va_list arg; + va_start(arg, format); + vsprintf(_rbdata, format, arg); + va_end(arg); + if (strlen(_rbdata)) + { + if (_log > 0) + { + _rb->put(_rbdata); + _rbsem->post(); + } + else + { + printf("%s", _rbdata); + } + } + _mt.unlock(); } int Process::getArgc() { - return _argc; + return _argc; } char** Process::getArgv() { - return _argv; + return _argv; } int Process::getParam(const char* parameter, char* value) { - char str[MQTTSNGW_PARAM_MAX]; - char param[MQTTSNGW_PARAM_MAX]; - FILE *fp; + char str[MQTTSNGW_PARAM_MAX]; + char param[MQTTSNGW_PARAM_MAX]; + FILE *fp; - int i = 0, j = 0; - string configPath = _configDir + _configFile; + int i = 0, j = 0; + string configPath = _configDir + _configFile; - if ((fp = fopen(configPath.c_str(), "r")) == NULL) - { - throw Exception("No config file:[" + configPath + "]\n"); - } + if ((fp = fopen(configPath.c_str(), "r")) == NULL) + { + throw Exception("No config file:[" + configPath + "]\n"); + } - while (true) - { - if (fgets(str, MQTTSNGW_PARAM_MAX - 1, fp) == NULL) - { - fclose(fp); - return -3; - } - if (!strncmp(str, parameter, strlen(parameter))) - { - while (str[i++] != '=') - { - ; - } - while (str[i] != '\n') - { - param[j++] = str[i++]; - } - param[j] = '\0'; + while (true) + { + if (fgets(str, MQTTSNGW_PARAM_MAX - 1, fp) == NULL) + { + fclose(fp); + return -3; + } + if (!strncmp(str, parameter, strlen(parameter))) + { + while (str[i++] != '=') + { + ; + } + while (str[i] != '\n') + { + param[j++] = str[i++]; + } + param[j] = '\0'; - for (i = strlen(param) - 1; i >= 0 && isspace(param[i]); i--) - ; - param[i + 1] = '\0'; - for (i = 0; isspace(param[i]); i++) - ; - if (i > 0) - { - j = 0; - while (param[i]) - param[j++] = param[i++]; - param[j] = '\0'; - } - strcpy(value, param); - fclose(fp); - return 0; - } - } - fclose(fp); - return -2; + for (i = strlen(param) - 1; i >= 0 && isspace(param[i]); i--) + ; + param[i + 1] = '\0'; + for (i = 0; isspace(param[i]); i++) + ; + if (i > 0) + { + j = 0; + while (param[i]) + param[j++] = param[i++]; + param[j] = '\0'; + } + strcpy(value, param); + fclose(fp); + return 0; + } + } + fclose(fp); + return -2; } const char* Process::getLog() { - int len = 0; - _mt.lock(); - while ((len = _rb->get(_rbdata, PROCESS_LOG_BUFFER_SIZE)) == 0) - { - _rbsem->timedwait(1000); - if ( checkSignal() == SIGINT) - { - break; - } - } - *(_rbdata + len) = 0; - _mt.unlock(); - return _rbdata; + int len = 0; + _mt.lock(); + while ((len = _rb->get(_rbdata, PROCESS_LOG_BUFFER_SIZE)) == 0) + { + _rbsem->timedwait(1000); + if (checkSignal() == SIGINT) + { + break; + } + } + *(_rbdata + len) = 0; + _mt.unlock(); + return _rbdata; } void Process::resetRingBuffer() { - _rb->reset(); + _rb->reset(); } int Process::checkSignal(void) { - return theSignaled; + return theSignaled; } const string* Process::getConfigDirName(void) { - return &_configDir; + return &_configDir; } const string* Process::getConfigFileName(void) { - return &_configFile; + return &_configFile; } /*===================================== @@ -247,99 +248,97 @@ const string* Process::getConfigFileName(void) ====================================*/ MultiTaskProcess::MultiTaskProcess() { - theMultiTaskProcess = this; - _threadCount = 0; - _stopCount = 0; + theMultiTaskProcess = this; + _threadCount = 0; + _stopCount = 0; } MultiTaskProcess::~MultiTaskProcess() { - for (int i = 0; i < _threadCount; i++) - { - _threadList[i]->stop(); - } + for (int i = 0; i < _threadCount; i++) + { + _threadList[i]->stop(); + } } void MultiTaskProcess::initialize(int argc, char** argv) { - Process::initialize(argc, argv); - for (int i = 0; i < _threadCount; i++) - { - _threadList[i]->initialize(argc, argv); - } + Process::initialize(argc, argv); + for (int i = 0; i < _threadCount; i++) + { + _threadList[i]->initialize(argc, argv); + } } void MultiTaskProcess::run(void) { - for (int i = 0; i < _threadCount; i++) - { - _threadList[i]->start(); - } + for (int i = 0; i < _threadCount; i++) + { + _threadList[i]->start(); + } - try - { - while(true) - { - if (theProcess->checkSignal() == SIGINT) - { - return; - } - sleep(1); - } - } - catch(Exception* ex) - { - ex->writeMessage(); - } - catch(...) - { - throw; - } + try + { + while (true) + { + if (theProcess->checkSignal() == SIGINT) + { + return; + } + sleep(1); + } + } catch (Exception* ex) + { + ex->writeMessage(); + } catch (...) + { + throw; + } } void MultiTaskProcess::waitStop(void) { - while (_stopCount < _threadCount) - { - sleep(1); - } + while (_stopCount < _threadCount) + { + sleep(1); + } } void MultiTaskProcess::threadStopped(void) { - _mutex.lock(); - _stopCount++; - _mutex.unlock(); + _mutex.lock(); + _stopCount++; + _mutex.unlock(); } void MultiTaskProcess::attach(Thread* thread) { - _mutex.lock(); - if (_threadCount < MQTTSNGW_MAX_TASK) - { - _threadList[_threadCount] = thread; - _threadCount++; - } - else - { - _mutex.unlock(); - throw Exception("Full of Threads"); - } - _mutex.unlock(); + _mutex.lock(); + if (_threadCount < MQTTSNGW_MAX_TASK) + { + _threadList[_threadCount] = thread; + _threadCount++; + } + else + { + _mutex.unlock(); + throw Exception("Full of Threads"); + } + _mutex.unlock(); } int MultiTaskProcess::getParam(const char* parameter, char* value) { - _mutex.lock(); - int rc = Process::getParam(parameter, value); - _mutex.unlock(); - if (rc == -1) - { - throw Exception("No config file."); - } - return rc; + _mutex.lock(); + int rc = Process::getParam(parameter, value); + _mutex.unlock(); + if (rc == -1) + { + throw Exception("No config file."); + } + return rc; } /*===================================== @@ -347,30 +346,30 @@ int MultiTaskProcess::getParam(const char* parameter, char* value) ======================================*/ Exception::Exception(const string& message) { - _message = message; - _exNo = 0; - _fileName = 0; - _functionName = 0; - _line = 0; + _message = message; + _exNo = 0; + _fileName = 0; + _functionName = 0; + _line = 0; } Exception::Exception(const int exNo, const string& message) { - _message = message; - _exNo = exNo; - _fileName = nullptr; - _functionName = nullptr; - _line = 0; + _message = message; + _exNo = exNo; + _fileName = nullptr; + _functionName = nullptr; + _line = 0; } Exception::Exception(const int exNo, const string& message, const char* file, - const char* function, const int line) + const char* function, const int line) { - _message = message; - _exNo = exNo; - _fileName = file; - _functionName = function; - _line = line; + _message = message; + _exNo = exNo; + _fileName = file; + _functionName = function; + _line = line; } Exception::~Exception() throw () @@ -380,38 +379,39 @@ Exception::~Exception() throw () const char* Exception::what() const throw () { - return _message.c_str(); + return _message.c_str(); } const char* Exception::getFileName() { - return _fileName; + return _fileName; } const char* Exception::getFunctionName() { - return _functionName; + return _functionName; } const int Exception::getLineNo() { - return _line; + return _line; } const int Exception::getExceptionNo() { - return _exNo; + return _exNo; } void Exception::writeMessage() { - if (getExceptionNo() == 0 ) - { - WRITELOG("%s %s\n", currentDateTime(), what()); - } - else - { - WRITELOG("%s:%-6d %s line %-4d %s() : %s\n", currentDateTime(), getExceptionNo(), - getFileName(), getLineNo(), getFunctionName(), what()); - } + if (getExceptionNo() == 0) + { + WRITELOG("%s %s\n", currentDateTime(), what()); + } + else + { + WRITELOG("%s:%-6d %s line %-4d %s() : %s\n", currentDateTime(), + getExceptionNo(), getFileName(), getLineNo(), getFunctionName(), + what()); + } } diff --git a/MQTTSNGateway/src/MQTTSNGWProcess.h b/MQTTSNGateway/src/MQTTSNGWProcess.h index 42ff2a2..723bb72 100644 --- a/MQTTSNGateway/src/MQTTSNGWProcess.h +++ b/MQTTSNGateway/src/MQTTSNGWProcess.h @@ -47,29 +47,29 @@ namespace MQTTSNGW class Process { public: - Process(); - virtual ~Process(); - virtual void initialize(int argc, char** argv); - virtual void run(void); - void putLog(const char* format, ...); - void resetRingBuffer(void); - int getArgc(void); - char** getArgv(void); - int getParam(const char* parameter, char* value); - const char* getLog(void); - int checkSignal(void); - const string* getConfigDirName(void); - const string* getConfigFileName(void); + Process(); + virtual ~Process(); + virtual void initialize(int argc, char** argv); + virtual void run(void); + void putLog(const char* format, ...); + void resetRingBuffer(void); + int getArgc(void); + char** getArgv(void); + int getParam(const char* parameter, char* value); + const char* getLog(void); + int checkSignal(void); + const string* getConfigDirName(void); + const string* getConfigFileName(void); private: - int _argc; - char** _argv; - string _configDir; - string _configFile; - RingBuffer* _rb; - NamedSemaphore* _rbsem; - Mutex _mt; - int _log; - char _rbdata[PROCESS_LOG_BUFFER_SIZE + 1]; + int _argc; + char** _argv; + string _configDir; + string _configFile; + RingBuffer* _rb; + NamedSemaphore* _rbsem; + Mutex _mt; + int _log; + char _rbdata[PROCESS_LOG_BUFFER_SIZE + 1]; }; /*===================================== @@ -78,20 +78,20 @@ private: class MultiTaskProcess: public Process { public: - MultiTaskProcess(void); - ~MultiTaskProcess(); - void initialize(int argc, char** argv); - int getParam(const char* parameter, char* value); - void run(void); - void waitStop(void); - void threadStopped(void); - void attach(Thread* thread); + MultiTaskProcess(void); + ~MultiTaskProcess(); + void initialize(int argc, char** argv); + int getParam(const char* parameter, char* value); + void run(void); + void waitStop(void); + void threadStopped(void); + void attach(Thread* thread); private: - Thread* _threadList[MQTTSNGW_MAX_TASK]; - Mutex _mutex; - int _threadCount; - int _stopCount; + Thread* _threadList[MQTTSNGW_MAX_TASK]; + Mutex _mutex; + int _threadCount; + int _stopCount; }; /*===================================== @@ -100,50 +100,49 @@ private: class Exception: public exception { public: - Exception(const string& message); - Exception(const int exNo, const string& message); - Exception(const int exNo, const string& message, - const char* file, const char* func, const int line); - virtual ~Exception() throw (); - const char* getFileName(); - const char* getFunctionName(); - const int getLineNo(); - const int getExceptionNo(); - virtual const char* what() const throw (); - void writeMessage(); + Exception(const string& message); + Exception(const int exNo, const string& message); + Exception(const int exNo, const string& message, const char* file, + const char* func, const int line); + virtual ~Exception() throw (); + const char* getFileName(); + const char* getFunctionName(); + const int getLineNo(); + const int getExceptionNo(); + virtual const char* what() const throw (); + void writeMessage(); private: - int _exNo; - string _message; - const char* _fileName; - const char* _functionName; - int _line; + int _exNo; + string _message; + const char* _fileName; + const char* _functionName; + int _line; }; - /*===================================== Class QueElement ====================================*/ template class QueElement { - template friend class Que; + template friend class Que; public: - QueElement(T* t) - { - _element = t; - _next = nullptr; - _prev = nullptr; - } + QueElement(T* t) + { + _element = t; + _next = nullptr; + _prev = nullptr; + } - ~QueElement() - { - } + ~QueElement() + { + } private: - T* _element; - QueElement* _next; - QueElement* _prev; + T* _element; + QueElement* _next; + QueElement* _prev; }; /*===================================== @@ -153,105 +152,105 @@ template class Que { public: - Que() - { - _head = nullptr; - _tail = nullptr; - _cnt = 0; - _maxSize = 0; - } + Que() + { + _head = nullptr; + _tail = nullptr; + _cnt = 0; + _maxSize = 0; + } - ~Que() - { - QueElement* elm = _head; - while (elm) - { - QueElement* next = elm->_next; - delete elm->_element; - delete elm; - elm = next; - } - } + ~Que() + { + QueElement* elm = _head; + while (elm) + { + QueElement* next = elm->_next; + delete elm->_element; + delete elm; + elm = next; + } + } - void pop(void) - { - if ( _head ) - { - QueElement* head = _head; - if ( _head == _tail ) - { - _head = _tail = nullptr; - } - else - { - _head = head->_next; - head->_prev = nullptr; - } - delete head; - _cnt--; - } - } + void pop(void) + { + if (_head) + { + QueElement* head = _head; + if (_head == _tail) + { + _head = _tail = nullptr; + } + else + { + _head = head->_next; + head->_prev = nullptr; + } + delete head; + _cnt--; + } + } - T* front(void) - { - { - if ( _head ) - { - return _head->_element; - } - else - { - return 0; - } - } - } + T* front(void) + { + { + if (_head) + { + return _head->_element; + } + else + { + return 0; + } + } + } - int post(T* t) - { - if ( t && ( _maxSize == 0 || _cnt < _maxSize )) - { - QueElement* elm = new QueElement(t); - if ( _head ) - { - if ( _tail == _head ) - { - elm->_prev = _tail; - _tail = elm; - _head->_next = elm; - } - else - { - _tail->_next = elm; - elm->_prev = _tail; - _tail = elm; - } - } - else - { - _head = elm; - _tail = elm; - } - _cnt++; - return _cnt; - } - return 0; - } + int post(T* t) + { + if (t && (_maxSize == 0 || _cnt < _maxSize)) + { + QueElement* elm = new QueElement(t); + if (_head) + { + if (_tail == _head) + { + elm->_prev = _tail; + _tail = elm; + _head->_next = elm; + } + else + { + _tail->_next = elm; + elm->_prev = _tail; + _tail = elm; + } + } + else + { + _head = elm; + _tail = elm; + } + _cnt++; + return _cnt; + } + return 0; + } - int size(void) - { - return _cnt; - } + int size(void) + { + return _cnt; + } - void setMaxSize(int maxSize) - { - _maxSize = maxSize; - } + void setMaxSize(int maxSize) + { + _maxSize = maxSize; + } private: - int _cnt; - int _maxSize; - QueElement* _head; - QueElement* _tail; + int _cnt; + int _maxSize; + QueElement* _head; + QueElement* _tail; }; /*===================================== @@ -262,722 +261,760 @@ private: #define TREE23_BI_NODE (2) #define TREE23_TRI_NODE (3) -template -class Tree23Elm{ - template friend class Tree23; +template +class Tree23Elm +{ + template friend class Tree23; public: - Tree23Elm() - { - _key = 0; - _val = 0; - } + Tree23Elm() + { + _key = 0; + _val = 0; + } - Tree23Elm(K* key, V* val) - { - _key = key; - _val = val; - } + Tree23Elm(K* key, V* val) + { + _key = key; + _val = val; + } - ~Tree23Elm() - { + ~Tree23Elm() + { - } + } - int compare(Tree23Elm* elm) - { - return _key->compare(elm->_key); - } + int compare(Tree23Elm* elm) + { + return _key->compare(elm->_key); + } private: - K* _key; - V* _val; + K* _key; + V* _val; }; - -template -class Tree23Node{ - template friend class Tree23; +template +class Tree23Node +{ + template friend class Tree23; public: - Tree23Node(const int type) - { - _type = type; - _telm0 = _telm1 = NULL; - _left = _midle = _right = NULL; - } + Tree23Node(const int type) + { + _type = type; + _telm0 = _telm1 = NULL; + _left = _midle = _right = NULL; + } - Tree23Node(const int type, Tree23Node* midle) - { - _type = type; - _telm0 = _telm1 = NULL; - _left = _right = NULL; - _midle = midle; - } + Tree23Node(const int type, Tree23Node* midle) + { + _type = type; + _telm0 = _telm1 = NULL; + _left = _right = NULL; + _midle = midle; + } - Tree23Node(const int type, Tree23Elm* telm) - { - _type = type; - _telm0 = telm; - _telm1 = NULL; - _left = _midle = _right = NULL; - } + Tree23Node(const int type, Tree23Elm* telm) + { + _type = type; + _telm0 = telm; + _telm1 = NULL; + _left = _midle = _right = NULL; + } - Tree23Node(const int type, Tree23Elm* telm, Tree23Node* left, Tree23Node* right) - { - _type = type; - _telm0 = telm; - _telm1 = NULL; - _left = left; - _midle = NULL; - _right = right; - } + Tree23Node(const int type, Tree23Elm* telm, Tree23Node* left, + Tree23Node* right) + { + _type = type; + _telm0 = telm; + _telm1 = NULL; + _left = left; + _midle = NULL; + _right = right; + } - Tree23Node(const int type, Tree23Elm* telm0, Tree23Elm* telm1, Tree23Node* left, Tree23Node* midle, Tree23Node* right) - { - _type = type; - _telm0 = telm0; - _telm1 = telm1; - _left = left; - _midle = midle; - _right = right; - } + Tree23Node(const int type, Tree23Elm* telm0, Tree23Elm* telm1, + Tree23Node* left, Tree23Node* midle, + Tree23Node* right) + { + _type = type; + _telm0 = telm0; + _telm1 = telm1; + _left = left; + _midle = midle; + _right = right; + } - ~Tree23Node() - { + ~Tree23Node() + { - } + } private: - int _type; - Tree23Elm* _telm0; - Tree23Elm* _telm1; - Tree23Node* _left; - Tree23Node* _midle; - Tree23Node* _right; + int _type; + Tree23Elm* _telm0; + Tree23Elm* _telm1; + Tree23Node* _left; + Tree23Node* _midle; + Tree23Node* _right; }; -template -class Tree23{ +template +class Tree23 +{ public: - Tree23() - { - _root = NULL; - } + Tree23() + { + _root = NULL; + } - ~Tree23() - { - if ( _root ) - { - delete _root; - } - } + ~Tree23() + { + if (_root) + { + delete _root; + } + } - void add(K* key, V* val) - { - _root = add( _root, new Tree23Elm(key, val)); - _root->_type = abs(_root->_type); - } + void add(K* key, V* val) + { + _root = add(_root, new Tree23Elm(key, val)); + _root->_type = abs(_root->_type); + } - Tree23Node* add(Tree23Node* n, Tree23Elm* elm) - { - if ( n == 0 ) - { - return new Tree23Node(TREE23_INSERT_ACTIVE, elm); - } + Tree23Node* add(Tree23Node* n, Tree23Elm* elm) + { + if (n == 0) + { + return new Tree23Node(TREE23_INSERT_ACTIVE, elm); + } - int cmp0 = elm->compare(n->_telm0); - int cmp1 = 0; - switch ( n->_type ) - { - case 2: - if ( cmp0 < 0 ) - { - n->_left = add(n->_left, elm); - return addLeft2(n); - } - else if ( cmp0 == 0 ) - { - n->_telm0 = elm; - return n; - } - else - { - n->_right = add(n->_right, elm); - return addRight2(n); - } - break; - case 3: - cmp1 = elm->compare(n->_telm1); - if ( cmp0 < 0 ) - { - n->_left = add(n->_left, elm); - return addLeft3(n); - } - else if ( cmp0 == 0 ) - { - n->_telm0 = elm; - return n; - } - else if ( cmp1 < 0 ) - { - n->_midle = add(n->_midle, elm); - return addMidle3(n); - } - else if ( cmp1 == 0 ) - { - n->_telm1 = elm; - return n; - } - else - { - n->_right = add(n->_right, elm); - return addRight3(n); - } - break; - default: - break; - } - return 0; - } + int cmp0 = elm->compare(n->_telm0); + int cmp1 = 0; + switch (n->_type) + { + case 2: + if (cmp0 < 0) + { + n->_left = add(n->_left, elm); + return addLeft2(n); + } + else if (cmp0 == 0) + { + n->_telm0 = elm; + return n; + } + else + { + n->_right = add(n->_right, elm); + return addRight2(n); + } + break; + case 3: + cmp1 = elm->compare(n->_telm1); + if (cmp0 < 0) + { + n->_left = add(n->_left, elm); + return addLeft3(n); + } + else if (cmp0 == 0) + { + n->_telm0 = elm; + return n; + } + else if (cmp1 < 0) + { + n->_midle = add(n->_midle, elm); + return addMidle3(n); + } + else if (cmp1 == 0) + { + n->_telm1 = elm; + return n; + } + else + { + n->_right = add(n->_right, elm); + return addRight3(n); + } + break; + default: + break; + } + return 0; + } - void remove(K* k) - { - _root = remove(_root, k); - if ( _root != NULL && _root->_type == TREE23_DELETE_ACTIVE ) - { - _root = _root->_midle; - } - } + void remove(K* k) + { + _root = remove(_root, k); + if (_root != NULL && _root->_type == TREE23_DELETE_ACTIVE) + { + _root = _root->_midle; + } + } - Tree23Node* remove(Tree23Node* node, K* k) - { - if ( node == NULL ) - { - return NULL; - } - int cmp0 = k->compare(node->_telm0->_key); - int cmp1 = 0; - switch ( node->_type ) - { - case 2: - if ( cmp0 < 0 ) - { - node->_left = remove( node->_left, k); - return removeLeft2(node); - } - else if ( cmp0 == 0 ) - { - if ( node->_left == NULL) - { - return new Tree23Node(TREE23_DELETE_ACTIVE); - } - Tree23Elm* maxLeft = new Tree23Elm(); - node->_left = removeMax(node->_left, maxLeft); - node->_telm0 = maxLeft; - return removeLeft2(node); - } - else - { - node->_right = remove(node->_right, k); - return removeRight2(node); - } - case 3: - cmp1 = k->compare(node->_telm1->_key); - if ( cmp0 < 0 ) - { - node->_left = remove(node->_left, k); - return removeLeft3(node); - } - else if ( cmp0 == 0 ) - { - if ( node->_left == NULL ) - { - return new Tree23Node(TREE23_BI_NODE, node->_telm1); - } - Tree23Elm* maxLeft = new Tree23Elm(); - node->_left = removeMax(node->_left, maxLeft); - node->_telm0 = maxLeft; - return removeLeft3(node); - } - else if ( cmp1 < 0 ) - { - node->_midle = remove(node->_midle, k); - return removeMidle3(node); - } - else if ( cmp1 == 0 ) - { - if ( node->_midle == NULL ) - { - return new Tree23Node(TREE23_BI_NODE, node->_telm0); - } - Tree23Elm* maxMidle = new Tree23Elm(); - node->_midle = removeMax(node->_midle, maxMidle); - node->_telm1 = maxMidle; - return removeMidle3(node); - } - else - { - node->_right = remove(node->_right, k); - return removeRight3(node); - } - default: - break; - } - return NULL; - } + Tree23Node* remove(Tree23Node* node, K* k) + { + if (node == NULL) + { + return NULL; + } + int cmp0 = k->compare(node->_telm0->_key); + int cmp1 = 0; + switch (node->_type) + { + case 2: + if (cmp0 < 0) + { + node->_left = remove(node->_left, k); + return removeLeft2(node); + } + else if (cmp0 == 0) + { + if (node->_left == NULL) + { + return new Tree23Node(TREE23_DELETE_ACTIVE); + } + Tree23Elm* maxLeft = new Tree23Elm(); + node->_left = removeMax(node->_left, maxLeft); + node->_telm0 = maxLeft; + return removeLeft2(node); + } + else + { + node->_right = remove(node->_right, k); + return removeRight2(node); + } + case 3: + cmp1 = k->compare(node->_telm1->_key); + if (cmp0 < 0) + { + node->_left = remove(node->_left, k); + return removeLeft3(node); + } + else if (cmp0 == 0) + { + if (node->_left == NULL) + { + return new Tree23Node(TREE23_BI_NODE, node->_telm1); + } + Tree23Elm* maxLeft = new Tree23Elm(); + node->_left = removeMax(node->_left, maxLeft); + node->_telm0 = maxLeft; + return removeLeft3(node); + } + else if (cmp1 < 0) + { + node->_midle = remove(node->_midle, k); + return removeMidle3(node); + } + else if (cmp1 == 0) + { + if (node->_midle == NULL) + { + return new Tree23Node(TREE23_BI_NODE, node->_telm0); + } + Tree23Elm* maxMidle = new Tree23Elm(); + node->_midle = removeMax(node->_midle, maxMidle); + node->_telm1 = maxMidle; + return removeMidle3(node); + } + else + { + node->_right = remove(node->_right, k); + return removeRight3(node); + } + default: + break; + } + return NULL; + } - bool find(K* key) - { - Tree23Node* node = _root; - while (node != NULL) - { - int cmp0 = key->compare(node->_telm0->_key); - int cmp1 = 0; - switch (node->_type) - { - case 2: - if ( cmp0 < 0 ) node = node->_left; - else if ( cmp0 == 0 ) - { - return true; - } - else - { - node = node->_right; - } - break; - case 3: - cmp1 = key->compare(node->_telm1->_key); - if ( cmp0 < 0 ) - { - node = node->_left; - } - else if ( cmp0 == 0 ) - { - return true; - } - else if ( cmp1 < 0 ) - { - node = node->_midle; - } - else if ( cmp1 == 0 ) - { - return true; - } - else - { - node = node->_right; - } - break; - default: - break; - } - } - return false; - } + bool find(K* key) + { + Tree23Node* node = _root; + while (node != NULL) + { + int cmp0 = key->compare(node->_telm0->_key); + int cmp1 = 0; + switch (node->_type) + { + case 2: + if (cmp0 < 0) + node = node->_left; + else if (cmp0 == 0) + { + return true; + } + else + { + node = node->_right; + } + break; + case 3: + cmp1 = key->compare(node->_telm1->_key); + if (cmp0 < 0) + { + node = node->_left; + } + else if (cmp0 == 0) + { + return true; + } + else if (cmp1 < 0) + { + node = node->_midle; + } + else if (cmp1 == 0) + { + return true; + } + else + { + node = node->_right; + } + break; + default: + break; + } + } + return false; + } - - V* getVal(K* key) - { - Tree23Node* node = _root; - while (node != NULL) - { - int cmp0 = key->compare(node->_telm0->_key); - int cmp1 = 0; - switch (node->_type) - { - case 2: - if ( cmp0 < 0 ) - { - node = node->_left; - } - else if ( cmp0 == 0 ) - { - return node->_telm0->_val; - } - else - { - node = node->_right; - } - break; - case 3: - cmp1 = key->compare(node->_telm1->_key); - if ( cmp0 < 0 ) - { - node = node->_left; - } - else if ( cmp0 == 0 ) - { - return node->_telm0->_val; - } - else if ( cmp1 < 0 ) - { - node = node->_midle; - } - else if ( cmp1 == 0 ) - { - return node->_telm1->_val; - } - else - { - node = node->_right; - } - break; - default: - break; - } - } - return NULL; - } + V* getVal(K* key) + { + Tree23Node* node = _root; + while (node != NULL) + { + int cmp0 = key->compare(node->_telm0->_key); + int cmp1 = 0; + switch (node->_type) + { + case 2: + if (cmp0 < 0) + { + node = node->_left; + } + else if (cmp0 == 0) + { + return node->_telm0->_val; + } + else + { + node = node->_right; + } + break; + case 3: + cmp1 = key->compare(node->_telm1->_key); + if (cmp0 < 0) + { + node = node->_left; + } + else if (cmp0 == 0) + { + return node->_telm0->_val; + } + else if (cmp1 < 0) + { + node = node->_midle; + } + else if (cmp1 == 0) + { + return node->_telm1->_val; + } + else + { + node = node->_right; + } + break; + default: + break; + } + } + return NULL; + } private: - Tree23Node* addLeft2(Tree23Node* node) - { - Tree23Node* n = node->_left; - if ( n != NULL && n->_type == TREE23_INSERT_ACTIVE ) - { - return new Tree23Node(TREE23_TRI_NODE, n->_telm0, node->_telm0, n->_left, n->_right, node->_right); - } - return node; - } + Tree23Node* addLeft2(Tree23Node* node) + { + Tree23Node* n = node->_left; + if (n != NULL && n->_type == TREE23_INSERT_ACTIVE) + { + return new Tree23Node(TREE23_TRI_NODE, n->_telm0, + node->_telm0, n->_left, n->_right, node->_right); + } + return node; + } - Tree23Node* addLeft3(Tree23Node* node) - { - Tree23Node* n = node->_left; - if ( n != NULL && n->_type == TREE23_INSERT_ACTIVE) - { - n->_type = TREE23_BI_NODE; - Tree23Node* nn = new Tree23Node(TREE23_BI_NODE, node->_telm1, node->_midle, node->_right); - return new Tree23Node(TREE23_INSERT_ACTIVE, node->_telm0, n, nn); - } - return node; - } + Tree23Node* addLeft3(Tree23Node* node) + { + Tree23Node* n = node->_left; + if (n != NULL && n->_type == TREE23_INSERT_ACTIVE) + { + n->_type = TREE23_BI_NODE; + Tree23Node* nn = new Tree23Node(TREE23_BI_NODE, + node->_telm1, node->_midle, node->_right); + return new Tree23Node(TREE23_INSERT_ACTIVE, node->_telm0, n, + nn); + } + return node; + } - Tree23Node* addRight2(Tree23Node* node) - { - Tree23Node* n = node->_right; - if (n != NULL && n->_type == TREE23_INSERT_ACTIVE) - { - return new Tree23Node(TREE23_TRI_NODE, node->_telm0, n->_telm0, node->_left, n->_left, n->_right); - } - return node; - } + Tree23Node* addRight2(Tree23Node* node) + { + Tree23Node* n = node->_right; + if (n != NULL && n->_type == TREE23_INSERT_ACTIVE) + { + return new Tree23Node(TREE23_TRI_NODE, node->_telm0, + n->_telm0, node->_left, n->_left, n->_right); + } + return node; + } - Tree23Node* addRight3(Tree23Node* node) - { - Tree23Node* n = node->_right; - if (n != NULL && n->_type == TREE23_INSERT_ACTIVE) { - n->_type = TREE23_BI_NODE; - Tree23Node* nn = new Tree23Node(TREE23_BI_NODE, node->_telm0, node->_left, node->_midle); - return new Tree23Node(TREE23_INSERT_ACTIVE, node->_telm1, nn, n); - } - return node; - } + Tree23Node* addRight3(Tree23Node* node) + { + Tree23Node* n = node->_right; + if (n != NULL && n->_type == TREE23_INSERT_ACTIVE) + { + n->_type = TREE23_BI_NODE; + Tree23Node* nn = new Tree23Node(TREE23_BI_NODE, + node->_telm0, node->_left, node->_midle); + return new Tree23Node(TREE23_INSERT_ACTIVE, node->_telm1, nn, + n); + } + return node; + } - Tree23Node* addMidle3(Tree23Node* node) - { - Tree23Node* n = node->_midle; - if ( n != NULL && n->_type == TREE23_INSERT_ACTIVE ) - { - n->_left = new Tree23Node(TREE23_BI_NODE, node->_telm0, node->_left, n->_left); - n->_right = new Tree23Node(TREE23_BI_NODE, node->_telm1, n->_right, node->_right); - return n; - } - return node; - } + Tree23Node* addMidle3(Tree23Node* node) + { + Tree23Node* n = node->_midle; + if (n != NULL && n->_type == TREE23_INSERT_ACTIVE) + { + n->_left = new Tree23Node(TREE23_BI_NODE, node->_telm0, + node->_left, n->_left); + n->_right = new Tree23Node(TREE23_BI_NODE, node->_telm1, + n->_right, node->_right); + return n; + } + return node; + } + Tree23Node* removeMax(Tree23Node* node, Tree23Elm* elm) + { + if (node->_right == NULL) + { + switch (node->_type) + { + case 2: + elm->_key = node->_telm0->_key; + elm->_val = node->_telm0->_val; + return new Tree23Node(TREE23_DELETE_ACTIVE); + case 3: + elm->_key = node->_telm1->_key; + elm->_val = node->_telm1->_val; + return new Tree23Node(TREE23_BI_NODE, node->_telm0); + default: + break; + } + } + else + { + node->_right = removeMax(node->_right, elm); + switch (node->_type) + { + case 2: + return removeRight2(node); + case 3: + return removeRight3(node); + default: + break; + } + } + return NULL; + } - Tree23Node* removeMax(Tree23Node* node, Tree23Elm* elm) - { - if (node->_right == NULL) - { - switch (node->_type) - { - case 2: - elm->_key = node->_telm0->_key; - elm->_val = node->_telm0->_val; - return new Tree23Node(TREE23_DELETE_ACTIVE); - case 3: - elm->_key = node->_telm1->_key; - elm->_val = node->_telm1->_val; - return new Tree23Node(TREE23_BI_NODE, node->_telm0); - default: - break; - } - } - else - { - node->_right = removeMax(node->_right, elm); - switch (node->_type) - { - case 2: - return removeRight2(node); - case 3: - return removeRight3(node); - default: - break; - } - } - return NULL; - } + Tree23Node* removeLeft2(Tree23Node* node) + { + Tree23Node* n = node->_left; + if (n != NULL && n->_type == TREE23_DELETE_ACTIVE) + { + Tree23Node* r = node->_right; + Tree23Node* midle; + Tree23Node* left; + Tree23Node* right; + switch (r->_type) + { + case 2: + midle = new Tree23Node(TREE23_TRI_NODE, node->_telm0, + r->_telm0, n->_midle, r->_left, r->_right); + return new Tree23Node(TREE23_DELETE_ACTIVE, midle); + case 3: + left = new Tree23Node(TREE23_BI_NODE, node->_telm0, + n->_midle, r->_left); + right = new Tree23Node(TREE23_BI_NODE, r->_telm1, + r->_midle, r->_right); + return new Tree23Node(TREE23_BI_NODE, r->_telm0, left, + right); + default: + break; + } + } + return node; + } - Tree23Node* removeLeft2(Tree23Node* node) - { - Tree23Node* n = node->_left; - if ( n != NULL && n->_type == TREE23_DELETE_ACTIVE ) - { - Tree23Node* r = node->_right; - Tree23Node* midle; - Tree23Node* left; - Tree23Node* right; + Tree23Node* removeRight2(Tree23Node* node) + { + Tree23Node* n = node->_right; + if (n != NULL && n->_type == TREE23_DELETE_ACTIVE) + { + Tree23Node* l = node->_left; + Tree23Node* midle; + Tree23Node* left; + Tree23Node* right; - switch ( r->_type ) - { - case 2: - midle = new Tree23Node(TREE23_TRI_NODE, node->_telm0, r->_telm0, n->_midle, r->_left, r->_right); - return new Tree23Node(TREE23_DELETE_ACTIVE, midle); - case 3: - left = new Tree23Node(TREE23_BI_NODE, node->_telm0, n->_midle, r->_left); - right = new Tree23Node(TREE23_BI_NODE, r->_telm1, r->_midle, r->_right); - return new Tree23Node(TREE23_BI_NODE, r->_telm0, left, right); - default: - break; - } - } - return node; - } + switch (l->_type) + { + case 2: + midle = new Tree23Node(TREE23_TRI_NODE, l->_telm0, + node->_telm0, l->_left, l->_right, n->_midle); + return new Tree23Node(-1, midle); + case 3: + right = new Tree23Node(TREE23_BI_NODE, node->_telm0, + l->_right, n->_midle); + left = new Tree23Node(TREE23_BI_NODE, l->_telm0, l->_left, + l->_midle); + return new Tree23Node(TREE23_BI_NODE, l->_telm1, left, + right); + default: + break; + } + } + return node; + } - Tree23Node* removeRight2(Tree23Node* node) - { - Tree23Node* n = node->_right; - if ( n != NULL && n->_type == TREE23_DELETE_ACTIVE ) - { - Tree23Node* l = node->_left; - Tree23Node* midle; - Tree23Node* left; - Tree23Node* right; + Tree23Node* removeLeft3(Tree23Node* node) + { + Tree23Node* n = node->_left; + if (n != NULL && n->_type == TREE23_DELETE_ACTIVE) + { + Tree23Node* m = node->_midle; + Tree23Node* r = node->_right; + Tree23Node* left; + Tree23Node* midle; - switch (l->_type) - { - case 2: - midle = new Tree23Node(TREE23_TRI_NODE, l->_telm0, node->_telm0, l->_left, l->_right, n->_midle); - return new Tree23Node(-1, midle); - case 3: - right = new Tree23Node(TREE23_BI_NODE, node->_telm0, l->_right, n->_midle); - left = new Tree23Node(TREE23_BI_NODE, l->_telm0, l->_left, l->_midle); - return new Tree23Node(TREE23_BI_NODE, l->_telm1, left, right); - default: - break; - } - } - return node; - } + switch (m->_type) + { + case 2: + left = new Tree23Node(TREE23_TRI_NODE, node->_telm0, + m->_telm0, n->_midle, m->_left, m->_right); + return new Tree23Node(TREE23_BI_NODE, node->_telm1, left, + r); + case 3: + left = new Tree23Node(TREE23_BI_NODE, node->_telm0, + n->_midle, m->_left); + midle = new Tree23Node(TREE23_BI_NODE, m->_telm1, + m->_midle, m->_right); + return new Tree23Node(TREE23_TRI_NODE, m->_telm0, + node->_telm1, left, midle, r); + default: + break; + } + } + return node; + } - Tree23Node* removeLeft3(Tree23Node* node) - { - Tree23Node* n = node->_left; - if ( n != NULL && n->_type == TREE23_DELETE_ACTIVE ) - { - Tree23Node* m = node->_midle; - Tree23Node* r = node->_right; - Tree23Node* left; - Tree23Node* midle; + Tree23Node* removeMidle3(Tree23Node* node) + { + Tree23Node* n = node->_midle; + if (n != NULL && n->_type == TREE23_DELETE_ACTIVE) + { + Tree23Node* l = node->_left; + Tree23Node* r = node->_right; + Tree23Node* midle; + Tree23Node* right; + switch (r->_type) + { + case 2: + right = new Tree23Node(TREE23_TRI_NODE, node->_telm1, + r->_telm0, n->_midle, r->_left, r->_right); + return new Tree23Node(TREE23_BI_NODE, node->_telm0, l, + right); + case 3: + midle = new Tree23Node(TREE23_BI_NODE, node->_telm1, + n->_midle, r->_left); + right = new Tree23Node(TREE23_BI_NODE, r->_telm1, + r->_midle, r->_right); + return new Tree23Node(TREE23_TRI_NODE, node->_telm0, + r->_telm0, l, midle, right); + default: + break; + } + } + return node; + } - switch (m->_type) { - case 2: - left = new Tree23Node(TREE23_TRI_NODE, node->_telm0, m->_telm0, n->_midle, m->_left, m->_right); - return new Tree23Node(TREE23_BI_NODE, node->_telm1, left, r); - case 3: - left = new Tree23Node(TREE23_BI_NODE, node->_telm0, n->_midle, m->_left); - midle = new Tree23Node(TREE23_BI_NODE, m->_telm1, m->_midle, m->_right); - return new Tree23Node(TREE23_TRI_NODE, m->_telm0, node->_telm1, left, midle, r); - default: - break; - } - } - return node; - } + Tree23Node* removeRight3(Tree23Node* node) + { + Tree23Node* n = node->_right; + if (n != NULL && n->_type == TREE23_DELETE_ACTIVE) + { + Tree23Node* l = node->_left; + Tree23Node* m = node->_midle; + Tree23Node* midle; + Tree23Node* right; + switch (m->_type) + { + case 2: + right = new Tree23Node(TREE23_TRI_NODE, m->_telm0, + node->_telm1, m->_left, m->_right, n->_midle); + return new Tree23Node(TREE23_BI_NODE, node->_telm0, l, + right); + case 3: + right = new Tree23Node(TREE23_BI_NODE, node->_telm1, + m->_right, n->_midle); + midle = new Tree23Node(TREE23_BI_NODE, m->_telm0, + m->_left, m->_midle); + return new Tree23Node(TREE23_TRI_NODE, node->_telm0, + m->_telm1, l, midle, right); + default: + break; + } + } + return node; + } - Tree23Node* removeMidle3(Tree23Node* node) - { - Tree23Node* n = node->_midle; - if ( n != NULL && n->_type == TREE23_DELETE_ACTIVE ) - { - Tree23Node* l = node->_left; - Tree23Node* r = node->_right; - Tree23Node* midle; - Tree23Node* right; - switch (r->_type) - { - case 2: - right = new Tree23Node(TREE23_TRI_NODE, node->_telm1, r->_telm0, n->_midle, r->_left, r->_right); - return new Tree23Node(TREE23_BI_NODE, node->_telm0, l, right); - case 3: - midle = new Tree23Node(TREE23_BI_NODE, node->_telm1, n->_midle, r->_left); - right = new Tree23Node(TREE23_BI_NODE, r->_telm1, r->_midle, r->_right); - return new Tree23Node(TREE23_TRI_NODE, node->_telm0, r->_telm0, l, midle, right); - default: - break; - } - } - return node; - } - - Tree23Node* removeRight3(Tree23Node* node) - { - Tree23Node* n = node->_right; - if ( n != NULL && n->_type == TREE23_DELETE_ACTIVE ) - { - Tree23Node* l = node->_left; - Tree23Node* m = node->_midle; - Tree23Node* midle; - Tree23Node* right; - switch (m->_type) - { - case 2: - right = new Tree23Node(TREE23_TRI_NODE, m->_telm0, node->_telm1, m->_left, m->_right, n->_midle); - return new Tree23Node(TREE23_BI_NODE, node->_telm0, l, right); - case 3: - right = new Tree23Node(TREE23_BI_NODE, node->_telm1, m->_right, n->_midle); - midle = new Tree23Node(TREE23_BI_NODE, m->_telm0, m->_left, m->_midle); - return new Tree23Node(TREE23_TRI_NODE, node->_telm0, m->_telm1, l, midle, right); - default: - break; - } - } - return node; - } - - - Tree23Node* _root; + Tree23Node* _root; }; /*===================================== Class List =====================================*/ -template +template class ListElm { - template friend class List; + template friend class List; public: - ListElm() - { - _elm = nullptr; - _prev = _next = nullptr; - } - ListElm(T* elm) - { - _elm = elm; - _prev = _next = nullptr; - } - T* getContent(void) - { - return _elm; - } - ~ListElm(){} + ListElm() + { + _elm = nullptr; + _prev = _next = nullptr; + } + ListElm(T* elm) + { + _elm = elm; + _prev = _next = nullptr; + } + T* getContent(void) + { + return _elm; + } + ~ListElm() + { + } private: - ListElm* getNext(void){return _next;} - T* _elm; - ListElm* _prev; - ListElm* _next; + ListElm* getNext(void) + { + return _next; + } + T* _elm; + ListElm* _prev; + ListElm* _next; }; - -template -class List{ +template +class List +{ public: - List() - { - _head = _tail = nullptr; - _size = 0; - } - ~List() - { - clear(); - } + List() + { + _head = _tail = nullptr; + _size = 0; + } + ~List() + { + clear(); + } - int add(T* t) - { - ListElm* elm = new ListElm(t); - if ( elm == nullptr ) - { - return 0; - } - if ( _head == nullptr ) - { - _head = elm; - _tail = elm; - } - else - { - elm->_prev = _tail; - _tail->_next = elm; - _tail = elm; - } - _size++; - return 1; - } + int add(T* t) + { + ListElm* elm = new ListElm(t); + if (elm == nullptr) + { + return 0; + } + if (_head == nullptr) + { + _head = elm; + _tail = elm; + } + else + { + elm->_prev = _tail; + _tail->_next = elm; + _tail = elm; + } + _size++; + return 1; + } - void erase(ListElm* elm) - { - if ( _head == elm ) - { - _head = elm->_next; - _size--; - delete elm; - } - else if ( _tail == elm ) - { - _tail = elm->_prev; - elm->_prev->_next = nullptr; - _size--; - delete elm; - } - else - { - elm->_prev->_next = elm->_next; - elm->_next->_prev = elm->_prev; - _size--; - delete elm; - } - } - void clear(void) - { - ListElm* p = _head; - while ( p ) - { - ListElm* q = p->_next; - delete p; - p = q; - } - _head = nullptr; - _tail = nullptr; - _size = 0; - } + void erase(ListElm* elm) + { + if (_head == elm) + { + _head = elm->_next; + _size--; + delete elm; + } + else if (_tail == elm) + { + _tail = elm->_prev; + elm->_prev->_next = nullptr; + _size--; + delete elm; + } + else + { + elm->_prev->_next = elm->_next; + elm->_next->_prev = elm->_prev; + _size--; + delete elm; + } + } + void clear(void) + { + ListElm* p = _head; + while (p) + { + ListElm* q = p->_next; + delete p; + p = q; + } + _head = nullptr; + _tail = nullptr; + _size = 0; + } - ListElm* getElm(void) - { - return _head; - } + ListElm* getElm(void) + { + return _head; + } - ListElm* getNext(ListElm* elm) - { - return elm->getNext(); - } - - int getSize(void) - { - return _size; - } + ListElm* getNext(ListElm* elm) + { + return elm->getNext(); + } + int getSize(void) + { + return _size; + } private: - ListElm* _head; - ListElm* _tail; - int _size; + ListElm* _head; + ListElm* _tail; + int _size; }; - extern Process* theProcess; extern MultiTaskProcess* theMultiTaskProcess; diff --git a/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp b/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp index 5ef8d5b..8b79935 100644 --- a/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp @@ -27,7 +27,7 @@ using namespace MQTTSNGW; MQTTSNPublishHandler::MQTTSNPublishHandler(Gateway* gateway) { - _gateway = gateway; + _gateway = gateway; } MQTTSNPublishHandler::~MQTTSNPublishHandler() @@ -35,265 +35,280 @@ MQTTSNPublishHandler::~MQTTSNPublishHandler() } -MQTTGWPacket* MQTTSNPublishHandler::handlePublish(Client* client, MQTTSNPacket* packet) +MQTTGWPacket* MQTTSNPublishHandler::handlePublish(Client* client, + MQTTSNPacket* packet) { - uint8_t dup; - int qos; - uint8_t retained; - uint16_t msgId; - uint8_t* payload; + uint8_t dup; + int qos; + uint8_t retained; + uint16_t msgId; + uint8_t* payload; MQTTSN_topicid topicid; - int payloadlen; - Publish pub = MQTTPacket_Publish_Initializer; + int payloadlen; + Publish pub = MQTTPacket_Publish_Initializer; - char shortTopic[2]; + char shortTopic[2]; - if ( !_gateway->getAdapterManager()->getQoSm1Proxy()->isActive() ) - { - if ( client->isQoSm1() ) - { - _gateway->getAdapterManager()->getQoSm1Proxy()->savePacket(client, packet); + if (!_gateway->getAdapterManager()->getQoSm1Proxy()->isActive()) + { + if (client->isQoSm1()) + { + _gateway->getAdapterManager()->getQoSm1Proxy()->savePacket(client, + packet); - return nullptr; - } - } + return nullptr; + } + } - if ( packet->getPUBLISH(&dup, &qos, &retained, &msgId, &topicid, &payload, &payloadlen) ==0 ) - { - return nullptr; - } - pub.msgId = msgId; - pub.header.bits.dup = dup; - pub.header.bits.qos = ( qos == 3 ? 0 : qos ); - pub.header.bits.retain = retained; + if (packet->getPUBLISH(&dup, &qos, &retained, &msgId, &topicid, &payload, + &payloadlen) == 0) + { + return nullptr; + } + pub.msgId = msgId; + pub.header.bits.dup = dup; + pub.header.bits.qos = (qos == 3 ? 0 : qos); + pub.header.bits.retain = retained; - Topic* topic = nullptr; + Topic* topic = nullptr; - if( topicid.type == MQTTSN_TOPIC_TYPE_SHORT ) - { - shortTopic[0] = topicid.data.short_name[0]; - shortTopic[1] = topicid.data.short_name[1]; - pub.topic = shortTopic; - pub.topiclen = 2; - } - else - { - topic = client->getTopics()->getTopicById(&topicid); - if ( !topic ) - { - topic = _gateway->getTopics()->getTopicById(&topicid); - if ( topic ) - { - topic = client->getTopics()->add(topic->getTopicName()->c_str(), topic->getTopicId()); - } - } + if (topicid.type == MQTTSN_TOPIC_TYPE_SHORT) + { + shortTopic[0] = topicid.data.short_name[0]; + shortTopic[1] = topicid.data.short_name[1]; + pub.topic = shortTopic; + pub.topiclen = 2; + } + else + { + topic = client->getTopics()->getTopicById(&topicid); + if (!topic) + { + topic = _gateway->getTopics()->getTopicById(&topicid); + if (topic) + { + topic = client->getTopics()->add(topic->getTopicName()->c_str(), + topic->getTopicId()); + } + } - if( !topic && qos == 3 ) - { - WRITELOG("%s Invalid TopicId.%s %s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); - return nullptr; - } + if (!topic && qos == 3) + { + WRITELOG("%s Invalid TopicId.%s %s\n", ERRMSG_HEADER, + client->getClientId(), ERRMSG_FOOTER); + return nullptr; + } - if ( ( qos == 0 || qos == 3 ) && msgId > 0 ) - { - WRITELOG("%s Invalid MsgId.%s %s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); - return nullptr; - } + if ((qos == 0 || qos == 3) && msgId > 0) + { + WRITELOG("%s Invalid MsgId.%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(); - pubAck->setPUBACK( topicid.data.id, msgId, MQTTSN_RC_REJECTED_INVALID_TOPIC_ID); - Event* ev1 = new Event(); - ev1->setClientSendEvent(client, pubAck); - _gateway->getClientSendQue()->post(ev1); - return nullptr; - } - if ( topic ) - { - pub.topic = (char*)topic->getTopicName()->data(); - pub.topiclen = topic->getTopicName()->length(); - } - } - /* Save a msgId & a TopicId pare for PUBACK */ - if( msgId && qos > 0 && qos < 3) - { - client->setWaitedPubTopicId(msgId, topicid.data.id, topicid.type); - } + if (!topic && msgId && qos > 0 && qos < 3) + { + /* Reply PubAck with INVALID_TOPIC_ID to the client */ + MQTTSNPacket* pubAck = new MQTTSNPacket(); + pubAck->setPUBACK(topicid.data.id, msgId, + MQTTSN_RC_REJECTED_INVALID_TOPIC_ID); + Event* ev1 = new Event(); + ev1->setClientSendEvent(client, pubAck); + _gateway->getClientSendQue()->post(ev1); + return nullptr; + } + if (topic) + { + pub.topic = (char*) topic->getTopicName()->data(); + pub.topiclen = topic->getTopicName()->length(); + } + } + /* Save a msgId & a TopicId pare for PUBACK */ + if (msgId && qos > 0 && qos < 3) + { + client->setWaitedPubTopicId(msgId, topicid.data.id, topicid.type); + } - pub.payload = (char*)payload; - pub.payloadlen = payloadlen; + pub.payload = (char*) payload; + pub.payloadlen = payloadlen; - MQTTGWPacket* publish = new MQTTGWPacket(); - publish->setPUBLISH(&pub); + MQTTGWPacket* publish = new MQTTGWPacket(); + publish->setPUBLISH(&pub); - if ( _gateway->getAdapterManager()->isAggregaterActive() && client->isAggregated() ) - { - return publish; - } - else - { - Event* ev1 = new Event(); - ev1->setBrokerSendEvent(client, publish); - _gateway->getBrokerSendQue()->post(ev1); - return nullptr; - } + 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) { - uint16_t topicId; - uint16_t msgId; - uint8_t rc; - - if ( client->isActive() ) - { - if ( packet->getPUBACK(&topicId, &msgId, &rc) == 0 ) - { - return; - } - - if ( rc == MQTTSN_RC_ACCEPTED) - { - 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) - { - WRITELOG(" PUBACK %d : Invalid Topic ID\n", msgId); - } - } -} - -void MQTTSNPublishHandler::handleAck(Client* client, MQTTSNPacket* packet, uint8_t packetType) -{ - uint16_t msgId; - - if ( client->isActive() ) - { - if ( packet->getACK(&msgId) == 0 ) - { - return; - } - MQTTGWPacket* ackPacket = new MQTTGWPacket(); - ackPacket->setAck(packetType, msgId); - Event* ev1 = new Event(); - ev1->setBrokerSendEvent(client, ackPacket); - _gateway->getBrokerSendQue()->post(ev1); - } -} - -void MQTTSNPublishHandler::handleRegister(Client* client, MQTTSNPacket* packet) -{ - uint16_t id; - uint16_t msgId; - MQTTSNString topicName = MQTTSNString_initializer;; - MQTTSN_topicid topicid; - - if ( client->isActive() || client->isAwake()) - { - if ( packet->getREGISTER(&id, &msgId, &topicName) == 0 ) - { - return; - } - - topicid.type = MQTTSN_TOPIC_TYPE_NORMAL; - topicid.data.long_.len = topicName.lenstring.len; - topicid.data.long_.name = topicName.lenstring.data; - - id = client->getTopics()->add(&topicid)->getTopicId(); - - MQTTSNPacket* regAck = new MQTTSNPacket(); - regAck->setREGACK(id, msgId, MQTTSN_RC_ACCEPTED); - Event* ev = new Event(); - ev->setClientSendEvent(client, regAck); - _gateway->getClientSendQue()->post(ev); - } -} - -void MQTTSNPublishHandler::handleRegAck( Client* client, MQTTSNPacket* packet) -{ - uint16_t id; + uint16_t topicId; uint16_t msgId; uint8_t rc; - if ( client->isActive() || client->isAwake()) + + if (client->isActive()) { - if ( packet->getREGACK(&id, &msgId, &rc) == 0 ) + if (packet->getPUBACK(&topicId, &msgId, &rc) == 0) { return; } - MQTTSNPacket* regAck = client->getWaitREGACKPacketList()->getPacket(msgId); + if (rc == MQTTSN_RC_ACCEPTED) + { + 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) + { + WRITELOG(" PUBACK %d : Invalid Topic ID\n", msgId); + } + } +} - if ( regAck != nullptr ) +void MQTTSNPublishHandler::handleAck(Client* client, MQTTSNPacket* packet, + uint8_t packetType) +{ + uint16_t msgId; + + if (client->isActive()) + { + if (packet->getACK(&msgId) == 0) + { + return; + } + MQTTGWPacket* ackPacket = new MQTTGWPacket(); + ackPacket->setAck(packetType, msgId); + Event* ev1 = new Event(); + ev1->setBrokerSendEvent(client, ackPacket); + _gateway->getBrokerSendQue()->post(ev1); + } +} + +void MQTTSNPublishHandler::handleRegister(Client* client, MQTTSNPacket* packet) +{ + uint16_t id; + uint16_t msgId; + MQTTSNString topicName = MQTTSNString_initializer; + ; + MQTTSN_topicid topicid; + + if (client->isActive() || client->isAwake()) + { + if (packet->getREGISTER(&id, &msgId, &topicName) == 0) + { + return; + } + + topicid.type = MQTTSN_TOPIC_TYPE_NORMAL; + topicid.data.long_.len = topicName.lenstring.len; + topicid.data.long_.name = topicName.lenstring.data; + + id = client->getTopics()->add(&topicid)->getTopicId(); + + MQTTSNPacket* regAck = new MQTTSNPacket(); + regAck->setREGACK(id, msgId, MQTTSN_RC_ACCEPTED); + Event* ev = new Event(); + ev->setClientSendEvent(client, regAck); + _gateway->getClientSendQue()->post(ev); + } +} + +void MQTTSNPublishHandler::handleRegAck(Client* client, MQTTSNPacket* packet) +{ + uint16_t id; + uint16_t msgId; + uint8_t rc; + if (client->isActive() || client->isAwake()) + { + if (packet->getREGACK(&id, &msgId, &rc) == 0) + { + return; + } + + MQTTSNPacket* regAck = client->getWaitREGACKPacketList()->getPacket( + msgId); + + if (regAck != nullptr) { client->getWaitREGACKPacketList()->erase(msgId); Event* ev = new Event(); ev->setClientSendEvent(client, regAck); _gateway->getClientSendQue()->post(ev); } - if (client->isHoldPingReqest() && client->getWaitREGACKPacketList()->getCount() == 0 ) + if (client->isHoldPingReqest() + && client->getWaitREGACKPacketList()->getCount() == 0) { /* send PINGREQ to the broker */ - client->resetPingRequest(); - MQTTGWPacket* pingreq = new MQTTGWPacket(); - pingreq->setHeader(PINGREQ); - Event* evt = new Event(); - evt->setBrokerSendEvent(client, pingreq); - _gateway->getBrokerSendQue()->post(evt); + client->resetPingRequest(); + MQTTGWPacket* pingreq = new MQTTGWPacket(); + pingreq->setHeader(PINGREQ); + Event* evt = new Event(); + evt->setBrokerSendEvent(client, pingreq); + _gateway->getBrokerSendQue()->post(evt); } } } - - - -void MQTTSNPublishHandler::handleAggregatePublish(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); - } + 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) +void MQTTSNPublishHandler::handleAggregateAck(Client* client, + MQTTSNPacket* packet, int type) { - if ( type == MQTTSN_PUBREC ) - { - uint16_t msgId; + 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); - } + 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 85efeb8..d34b333 100644 --- a/MQTTSNGateway/src/MQTTSNGWPublishHandler.h +++ b/MQTTSNGateway/src/MQTTSNGWPublishHandler.h @@ -25,19 +25,19 @@ namespace MQTTSNGW class MQTTSNPublishHandler { public: - MQTTSNPublishHandler(Gateway* gateway); - ~MQTTSNPublishHandler(); - 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); + MQTTSNPublishHandler(Gateway* gateway); + ~MQTTSNPublishHandler(); + 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); + void handleAggregatePublish(Client* client, MQTTSNPacket* packet); + void handleAggregateAck(Client* client, MQTTSNPacket* packet, int type); private: - Gateway* _gateway; + Gateway* _gateway; }; } diff --git a/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.cpp b/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.cpp index 349996f..91b05f9 100644 --- a/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.cpp +++ b/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.cpp @@ -21,13 +21,13 @@ #include #include - using namespace MQTTSNGW; /*===================================== - Class QoSm1Proxy + Class QoSm1Proxy =====================================*/ -QoSm1Proxy:: QoSm1Proxy(Gateway* gw) : Adapter(gw) +QoSm1Proxy::QoSm1Proxy(Gateway* gw) : + Adapter(gw) { _gateway = gw; } @@ -37,24 +37,22 @@ QoSm1Proxy::~QoSm1Proxy(void) } - void QoSm1Proxy::initialize(char* gwName) { - if ( _gateway->hasSecureConnection() ) + if (_gateway->hasSecureConnection()) { - _isSecure = true; + _isSecure = true; } - /* Create QoS-1 Clients from clients.conf */ - _gateway->getClientList()->setClientList(QOSM1PROXY_TYPE); + /* Create QoS-1 Clients from clients.conf */ + _gateway->getClientList()->setClientList(QOSM1PROXY_TYPE); - /* Create a client for QoS-1 proxy */ - string name = string(gwName) + string("_QoS-1"); - setup(name.c_str(), Atype_QoSm1Proxy); - _isActive = true; + /* Create a client for QoS-1 proxy */ + string name = string(gwName) + string("_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 index 82e5f2a..125b1b9 100644 --- a/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.h +++ b/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.h @@ -27,12 +27,12 @@ class SensorNetAddress; class MQTTSNPacket; /*===================================== - Class QoSm1Proxy + Class QoSm1Proxy =====================================*/ -class QoSm1Proxy : public Adapter +class QoSm1Proxy: public Adapter { public: - QoSm1Proxy(Gateway* gw); + QoSm1Proxy(Gateway* gw); ~QoSm1Proxy(void); void initialize(char* GWnAME); @@ -41,13 +41,10 @@ public: private: Gateway* _gateway; - bool _isActive {false}; - bool _isSecure {false}; + bool _isActive { false }; + bool _isSecure { false }; }; - } - - #endif /* MQTTSNGATEWAY_SRC_MQTTSNGWQOSM1PROXY_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp index a08bf49..3f0d5f0 100644 --- a/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp @@ -26,7 +26,7 @@ using namespace MQTTSNGW; MQTTSNSubscribeHandler::MQTTSNSubscribeHandler(Gateway* gateway) { - _gateway = gateway; + _gateway = gateway; } MQTTSNSubscribeHandler::~MQTTSNSubscribeHandler() @@ -34,65 +34,70 @@ MQTTSNSubscribeHandler::~MQTTSNSubscribeHandler() } -MQTTGWPacket* 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 = nullptr; + uint8_t dup; + int qos; + uint16_t msgId; + MQTTSN_topicid topicFilter; + Topic* topic = nullptr; uint16_t topicId = 0; MQTTGWPacket* subscribe; Event* ev1; Event* evsuback; - if ( packet->getSUBSCRIBE(&dup, &qos, &msgId, &topicFilter) == 0 ) - { - return nullptr; - } + if (packet->getSUBSCRIBE(&dup, &qos, &msgId, &topicFilter) == 0) + { + return nullptr; + } - if ( msgId == 0 ) - { - return nullptr; - } + if (msgId == 0) + { + return nullptr; + } - if ( topicFilter.type == MQTTSN_TOPIC_TYPE_PREDEFINED ) + if (topicFilter.type == MQTTSN_TOPIC_TYPE_PREDEFINED) { topic = client->getTopics()->getTopicById(&topicFilter); - if ( !topic ) + if (!topic) { - topic = _gateway->getTopics()->getTopicById(&topicFilter); - if ( topic ) - { - topic = client->getTopics()->add(topic->getTopicName()->c_str(), topic->getTopicId()); - } - else - { - goto RespExit; - } + topic = _gateway->getTopics()->getTopicById(&topicFilter); + if (topic) + { + topic = client->getTopics()->add(topic->getTopicName()->c_str(), + topic->getTopicId()); + } + else + { + goto RespExit; + } } topicId = topic->getTopicId(); subscribe = new MQTTGWPacket(); - subscribe->setSUBSCRIBE((char*)topic->getTopicName()->c_str(), (uint8_t)qos, (uint16_t)msgId); + subscribe->setSUBSCRIBE((char*) topic->getTopicName()->c_str(), + (uint8_t) qos, (uint16_t) msgId); } else if (topicFilter.type == MQTTSN_TOPIC_TYPE_NORMAL) { topic = client->getTopics()->getTopicByName(&topicFilter); - if ( topic == nullptr ) + if (topic == nullptr) { topic = client->getTopics()->add(&topicFilter); - if ( topic == nullptr ) + if (topic == nullptr) { - WRITELOG("%s Client(%s) can't add the Topic.%s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); + WRITELOG("%s Client(%s) can't add the Topic.%s\n", + ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); return nullptr; } } topicId = topic->getTopicId(); subscribe = new MQTTGWPacket(); - subscribe->setSUBSCRIBE((char*)topic->getTopicName()->c_str(), (uint8_t)qos, (uint16_t)msgId); + subscribe->setSUBSCRIBE((char*) topic->getTopicName()->c_str(), + (uint8_t) qos, (uint16_t) msgId); } else //MQTTSN_TOPIC_TYPE_SHORT { @@ -103,73 +108,72 @@ MQTTGWPacket* MQTTSNSubscribeHandler::handleSubscribe(Client* client, MQTTSNPack topicId = topicFilter.data.short_name[0] << 8; topicId |= topicFilter.data.short_name[1]; subscribe = new MQTTGWPacket(); - subscribe->setSUBSCRIBE(topicstr, (uint8_t)qos, (uint16_t)msgId); + subscribe->setSUBSCRIBE(topicstr, (uint8_t) qos, (uint16_t) msgId); } client->setWaitedSubTopicId(msgId, topicId, topicFilter.type); - if ( !client->isAggregated() ) + if (!client->isAggregated()) { - ev1 = new Event(); - ev1->setBrokerSendEvent(client, subscribe); - _gateway->getBrokerSendQue()->post(ev1); - return nullptr; + ev1 = new Event(); + ev1->setBrokerSendEvent(client, subscribe); + _gateway->getBrokerSendQue()->post(ev1); + return nullptr; } else { - return subscribe; + return subscribe; } - -RespExit: - MQTTSNPacket* sSuback = new MQTTSNPacket(); - sSuback->setSUBACK(qos, topicFilter.data.id, msgId, MQTTSN_RC_NOT_SUPPORTED); - evsuback = new Event(); - evsuback->setClientSendEvent(client, sSuback); - _gateway->getClientSendQue()->post(evsuback); - return nullptr; + RespExit: MQTTSNPacket* sSuback = new MQTTSNPacket(); + sSuback->setSUBACK(qos, topicFilter.data.id, msgId, + MQTTSN_RC_NOT_SUPPORTED); + evsuback = new Event(); + evsuback->setClientSendEvent(client, sSuback); + _gateway->getClientSendQue()->post(evsuback); + return nullptr; } -MQTTGWPacket* MQTTSNSubscribeHandler::handleUnsubscribe(Client* client, MQTTSNPacket* packet) +MQTTGWPacket* MQTTSNSubscribeHandler::handleUnsubscribe(Client* client, + MQTTSNPacket* packet) { - uint16_t msgId; - MQTTSN_topicid topicFilter; + uint16_t msgId; + MQTTSN_topicid topicFilter; MQTTGWPacket* unsubscribe = nullptr; - if ( packet->getUNSUBSCRIBE(&msgId, &topicFilter) == 0 ) - { - return nullptr; - } - - if ( msgId == 0 ) + if (packet->getUNSUBSCRIBE(&msgId, &topicFilter) == 0) { - return nullptr; + return nullptr; } + if (msgId == 0) + { + return nullptr; + } - if (topicFilter.type == MQTTSN_TOPIC_TYPE_SHORT) - { - char shortTopic[3]; + if (topicFilter.type == MQTTSN_TOPIC_TYPE_SHORT) + { + char shortTopic[3]; shortTopic[0] = topicFilter.data.short_name[0]; shortTopic[1] = topicFilter.data.short_name[1]; shortTopic[2] = 0; unsubscribe = new MQTTGWPacket(); unsubscribe->setUNSUBSCRIBE(shortTopic, msgId); - } - else - { - Topic* topic = nullptr; + } + else + { + Topic* topic = nullptr; - if (topicFilter.type == MQTTSN_TOPIC_TYPE_PREDEFINED) - { - topic = client->getTopics()->getTopicById(&topicFilter); - } - else - { - topic = client->getTopics()->getTopicByName(&topicFilter); - } + if (topicFilter.type == MQTTSN_TOPIC_TYPE_PREDEFINED) + { + topic = client->getTopics()->getTopicById(&topicFilter); + } + else + { + topic = client->getTopics()->getTopicByName(&topicFilter); + } - if ( topic == nullptr ) + if (topic == nullptr) { MQTTSNPacket* sUnsuback = new MQTTSNPacket(); sUnsuback->setUNSUBACK(msgId); @@ -183,85 +187,99 @@ MQTTGWPacket* MQTTSNSubscribeHandler::handleUnsubscribe(Client* client, MQTTSNPa unsubscribe = new MQTTGWPacket(); unsubscribe->setUNSUBSCRIBE(topic->getTopicName()->c_str(), msgId); } - } + } - if ( !client->isAggregated() ) + if (!client->isAggregated()) { - Event* ev1 = new Event(); - ev1->setBrokerSendEvent(client, unsubscribe); - _gateway->getBrokerSendQue()->post(ev1); - return nullptr; + Event* ev1 = new Event(); + ev1->setBrokerSendEvent(client, unsubscribe); + _gateway->getBrokerSendQue()->post(ev1); + return nullptr; } else { - return unsubscribe; + return unsubscribe; } } -void MQTTSNSubscribeHandler::handleAggregateSubscribe(Client* client, MQTTSNPacket* packet) +void MQTTSNSubscribeHandler::handleAggregateSubscribe(Client* client, + MQTTSNPacket* packet) { - MQTTGWPacket* subscribe = handleSubscribe(client, packet); + MQTTGWPacket* subscribe = handleSubscribe(client, packet); - if ( subscribe != nullptr ) - { - int msgId = 0; - if ( packet->isDuplicate() ) - { - msgId = _gateway->getAdapterManager()->getAggregater()->getMsgId(client, packet->getMsgId()); - } - else - { - msgId = _gateway->getAdapterManager()->getAggregater()->addMessageIdTable(client, packet->getMsgId()); - } + if (subscribe != nullptr) + { + 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; - } + if (msgId == 0) + { + WRITELOG( + "%s MQTTSNSubscribeHandler can't create MessageIdTableElement %s%s\n", + ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); + return; + } - UTF8String str = subscribe->getTopic(); - string* topicName = new string(str.data, str.len); // topicName is delete by topic - Topic topic = Topic(topicName, MQTTSN_TOPIC_TYPE_NORMAL); + UTF8String str = subscribe->getTopic(); + string* topicName = new string(str.data, str.len); // topicName is delete by topic + Topic topic = Topic(topicName, MQTTSN_TOPIC_TYPE_NORMAL); - _gateway->getAdapterManager()->getAggregater()->addAggregateTopic(&topic, client); + _gateway->getAdapterManager()->getAggregater()->addAggregateTopic( + &topic, client); - subscribe->setMsgId(msgId); - Event* ev = new Event(); - ev->setBrokerSendEvent(client, subscribe); - _gateway->getBrokerSendQue()->post(ev); - } + subscribe->setMsgId(msgId); + Event* ev = new Event(); + ev->setBrokerSendEvent(client, subscribe); + _gateway->getBrokerSendQue()->post(ev); + } } -void MQTTSNSubscribeHandler::handleAggregateUnsubscribe(Client* client, MQTTSNPacket* packet) +void MQTTSNSubscribeHandler::handleAggregateUnsubscribe(Client* client, + MQTTSNPacket* packet) { - MQTTGWPacket* unsubscribe = handleUnsubscribe(client, packet); - if ( unsubscribe != nullptr ) - { - int msgId = 0; - if ( packet->isDuplicate() ) - { - msgId = _gateway->getAdapterManager()->getAggregater()->getMsgId(client, packet->getMsgId()); - } - else - { - msgId = _gateway->getAdapterManager()->getAggregater()->addMessageIdTable(client, packet->getMsgId()); - } + MQTTGWPacket* unsubscribe = handleUnsubscribe(client, packet); + if (unsubscribe != nullptr) + { + 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; - } + if (msgId == 0) + { + WRITELOG( + "%s MQTTSNUnsubscribeHandler can't create MessageIdTableElement %s%s\n", + ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); + return; + } - UTF8String str = unsubscribe->getTopic(); - string* topicName = new string(str.data, str.len); // topicName is delete by topic - Topic topic = Topic(topicName, MQTTSN_TOPIC_TYPE_NORMAL); - _gateway->getAdapterManager()->getAggregater()->removeAggregateTopic(&topic, client); + UTF8String str = unsubscribe->getTopic(); + string* topicName = new string(str.data, str.len); // topicName is delete by topic + Topic topic = Topic(topicName, MQTTSN_TOPIC_TYPE_NORMAL); + _gateway->getAdapterManager()->getAggregater()->removeAggregateTopic( + &topic, client); - unsubscribe->setMsgId(msgId); - Event* ev = new Event(); - ev->setBrokerSendEvent(client, unsubscribe); - _gateway->getBrokerSendQue()->post(ev); - } + 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 5b2202a..dd21e3e 100644 --- a/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.h +++ b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.h @@ -24,23 +24,22 @@ namespace MQTTSNGW { /*===================================== - Class MQTTSNSubscribeHandler + Class MQTTSNSubscribeHandler =====================================*/ class MQTTSNSubscribeHandler { public: - MQTTSNSubscribeHandler(Gateway* gateway); - ~MQTTSNSubscribeHandler(); - MQTTGWPacket* handleSubscribe(Client* client, MQTTSNPacket* packet); - MQTTGWPacket* handleUnsubscribe(Client* client, MQTTSNPacket* packet); - void handleAggregateSubscribe(Client* client, MQTTSNPacket* packet); - void handleAggregateUnsubscribe(Client* client, MQTTSNPacket* packet); + MQTTSNSubscribeHandler(Gateway* gateway); + ~MQTTSNSubscribeHandler(); + 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; + Gateway* _gateway; }; } - #endif /* MQTTSNGWSUBSCRIBEHANDLER_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWTopic.cpp b/MQTTSNGateway/src/MQTTSNGWTopic.cpp index 8f56a4c..43bf82e 100644 --- a/MQTTSNGateway/src/MQTTSNGWTopic.cpp +++ b/MQTTSNGateway/src/MQTTSNGWTopic.cpp @@ -27,35 +27,35 @@ using namespace MQTTSNGW; Topic::Topic() { _type = MQTTSN_TOPIC_TYPE_NORMAL; - _topicName = nullptr; - _topicId = 0; - _next = nullptr; + _topicName = nullptr; + _topicId = 0; + _next = nullptr; } Topic::Topic(string* topic, MQTTSN_topicTypes type) { _type = type; - _topicName = topic; - _topicId = 0; - _next = nullptr; + _topicName = topic; + _topicId = 0; + _next = nullptr; } Topic::~Topic() { - if ( _topicName ) - { - delete _topicName; - } + if (_topicName) + { + delete _topicName; + } } string* Topic::getTopicName(void) { - return _topicName; + return _topicName; } uint16_t Topic::getTopicId(void) { - return _topicId; + return _topicId; } MQTTSN_topicTypes Topic::getType(void) @@ -65,108 +65,109 @@ MQTTSN_topicTypes Topic::getType(void) Topic* Topic::duplicate(void) { - Topic* newTopic = new Topic(); - newTopic->_type = _type; - newTopic->_topicId = _topicId; - newTopic->_topicName = new string(_topicName->c_str()); - return newTopic; + Topic* newTopic = new Topic(); + newTopic->_type = _type; + newTopic->_topicId = _topicId; + newTopic->_topicName = new string(_topicName->c_str()); + return newTopic; } bool Topic::isMatch(string* topicName) { - string::size_type tlen = _topicName->size(); + 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 = "+"; + 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); + 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; - } + 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; - } + 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; + tpos = tloc + 1; - return _topicName->substr(tpos) == wildcard; - } - else if ( loc != string::npos && tloc == string::npos ) - { - return _topicName->substr(tpos) == wildcard; - } - } + 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); + WRITELOG("TopicName=%s ID=%d Type=%d\n", _topicName->c_str(), _topicId, + _type); } /*===================================== @@ -198,11 +199,11 @@ Topic* Topics::getTopicByName(const MQTTSN_topicid* topicid) string sname = string(ch, ch + topicid->data.long_.len); while (p) { - if ( p->_topicName->compare(sname) == 0 ) - { - return p; - } - p = p->_next; + if (p->_topicName->compare(sname) == 0) + { + return p; + } + p = p->_next; } return 0; } @@ -213,7 +214,7 @@ Topic* Topics::getTopicById(const MQTTSN_topicid* topicid) while (p) { - if ( p->_type == topicid->type && p->_topicId == topicid->data.id ) + if (p->_type == topicid->type && p->_topicId == topicid->data.id) { return p; } @@ -225,14 +226,14 @@ Topic* Topics::getTopicById(const MQTTSN_topicid* topicid) // For MQTTSN_TOPIC_TYPE_NORMAL */ Topic* Topics::add(const MQTTSN_topicid* topicid) { - if (topicid->type != MQTTSN_TOPIC_TYPE_NORMAL ) + if (topicid->type != MQTTSN_TOPIC_TYPE_NORMAL) { return 0; } Topic* topic = getTopicByName(topicid); - if ( topic ) + if (topic) { return topic; } @@ -244,18 +245,17 @@ Topic* Topics::add(const char* topicName, uint16_t id) { MQTTSN_topicid topicId; - if ( _cnt >= MAX_TOPIC_PAR_CLIENT ) + if (_cnt >= MAX_TOPIC_PAR_CLIENT) { return 0; } - topicId.data.long_.name = (char*)const_cast(topicName); + topicId.data.long_.name = (char*) const_cast(topicName); topicId.data.long_.len = strlen(topicName); - Topic* topic = getTopicByName(&topicId); - if ( topic ) + if (topic) { return topic; } @@ -270,7 +270,7 @@ Topic* Topics::add(const char* topicName, uint16_t id) string* name = new string(topicName); topic->_topicName = name; - if ( id == 0 ) + if (id == 0) { topic->_type = MQTTSN_TOPIC_TYPE_NORMAL; topic->_topicId = getNextTopicId(); @@ -278,12 +278,12 @@ Topic* Topics::add(const char* topicName, uint16_t id) else { topic->_type = MQTTSN_TOPIC_TYPE_PREDEFINED; - topic->_topicId = id; + topic->_topicId = id; } _cnt++; - if ( _first == nullptr) + if (_first == nullptr) { _first = topic; } @@ -331,7 +331,6 @@ Topic* Topics::match(const MQTTSN_topicid* topicid) return 0; } - void Topics::eraseNormal(void) { Topic* topic = _first; @@ -340,14 +339,14 @@ void Topics::eraseNormal(void) while (topic) { - if ( topic->_type == MQTTSN_TOPIC_TYPE_NORMAL ) + if (topic->_type == MQTTSN_TOPIC_TYPE_NORMAL) { next = topic->_next; - if ( _first == topic ) + if (_first == topic) { _first = next; } - if ( prev ) + if (prev) { prev->_next = next; } @@ -365,18 +364,18 @@ void Topics::eraseNormal(void) Topic* Topics::getFirstTopic(void) { - return _first; + return _first; } Topic* Topics::getNextTopic(Topic* topic) { - return topic->_next; + return topic->_next; } void Topics::print(void) { Topic* topic = _first; - if (topic == nullptr ) + if (topic == nullptr) { WRITELOG("No Topic.\n"); } @@ -398,7 +397,8 @@ uint8_t Topics::getCount(void) /*===================================== Class TopicIdMap =====================================*/ -TopicIdMapElement::TopicIdMapElement(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type) +TopicIdMapElement::TopicIdMapElement(uint16_t msgId, uint16_t topicId, + MQTTSN_topicTypes type) { _msgId = msgId; _topicId = topicId; @@ -419,7 +419,7 @@ MQTTSN_topicTypes TopicIdMapElement::getTopicType(void) uint16_t TopicIdMapElement::getTopicId(void) { - return _topicId; + return _topicId; } TopicIdMap::TopicIdMap() @@ -434,7 +434,7 @@ TopicIdMap::TopicIdMap() TopicIdMap::~TopicIdMap() { TopicIdMapElement* p = _first; - while ( p ) + while (p) { TopicIdMapElement* q = p->_next; delete p; @@ -445,9 +445,9 @@ TopicIdMap::~TopicIdMap() TopicIdMapElement* TopicIdMap::getElement(uint16_t msgId) { TopicIdMapElement* p = _first; - while ( p ) + while (p) { - if ( p->_msgId == msgId ) + if (p->_msgId == msgId) { return p; } @@ -456,23 +456,25 @@ TopicIdMapElement* TopicIdMap::getElement(uint16_t msgId) return 0; } -TopicIdMapElement* TopicIdMap::add(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type) +TopicIdMapElement* TopicIdMap::add(uint16_t msgId, uint16_t topicId, + MQTTSN_topicTypes type) { - if ( _cnt > _maxInflight * 2 || ( topicId == 0 && type != MQTTSN_TOPIC_TYPE_SHORT ) ) + if (_cnt > _maxInflight * 2 + || (topicId == 0 && type != MQTTSN_TOPIC_TYPE_SHORT)) { return 0; } - if ( getElement(msgId) ) + if (getElement(msgId)) { erase(msgId); } TopicIdMapElement* elm = new TopicIdMapElement(msgId, topicId, type); - if ( elm == 0 ) + if (elm == 0) { return 0; } - if ( _first == nullptr ) + if (_first == nullptr) { _first = elm; _end = elm; @@ -490,11 +492,11 @@ TopicIdMapElement* TopicIdMap::add(uint16_t msgId, uint16_t topicId, MQTTSN_topi void TopicIdMap::erase(uint16_t msgId) { TopicIdMapElement* p = _first; - while ( p ) + while (p) { - if ( p->_msgId == msgId ) + if (p->_msgId == msgId) { - if ( p->_prev == nullptr ) + if (p->_prev == nullptr) { _first = p->_next; } @@ -503,7 +505,7 @@ void TopicIdMap::erase(uint16_t msgId) p->_prev->_next = p->_next; } - if ( p->_next == nullptr ) + if (p->_next == nullptr) { _end = p->_prev; } @@ -523,7 +525,7 @@ void TopicIdMap::erase(uint16_t msgId) void TopicIdMap::clear(void) { TopicIdMapElement* p = _first; - while ( p ) + while (p) { TopicIdMapElement* q = p->_next; delete p; @@ -534,5 +536,3 @@ void TopicIdMap::clear(void) _cnt = 0; } - - diff --git a/MQTTSNGateway/src/MQTTSNGWTopic.h b/MQTTSNGateway/src/MQTTSNGWTopic.h index 4d7b0c3..6946b1c 100644 --- a/MQTTSNGateway/src/MQTTSNGWTopic.h +++ b/MQTTSNGateway/src/MQTTSNGWTopic.h @@ -24,7 +24,6 @@ namespace MQTTSNGW { - /*===================================== Class Topic ======================================*/ @@ -46,7 +45,7 @@ public: private: MQTTSN_topicTypes _type; uint16_t _topicId; - string* _topicName; + string* _topicName; Topic* _next; }; @@ -72,7 +71,7 @@ public: private: uint16_t _nextTopicId; Topic* _first; - uint8_t _cnt; + uint8_t _cnt; }; /*===================================== @@ -101,7 +100,8 @@ public: TopicIdMap(); ~TopicIdMap(); TopicIdMapElement* getElement(uint16_t msgId); - TopicIdMapElement* add(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type); + TopicIdMapElement* add(uint16_t msgId, uint16_t topicId, + MQTTSN_topicTypes type); void erase(uint16_t msgId); void clear(void); private: @@ -112,9 +112,6 @@ private: int _maxInflight; }; - } - - #endif /* MQTTSNGATEWAY_SRC_MQTTSNGWTOPIC_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWVersion.h b/MQTTSNGateway/src/MQTTSNGWVersion.h index 251e5af..e0e6186 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.4.0" +#define PAHO_GATEWAY_VERSION "1.5.0" #endif /* MQTTSNGWVERSION_H_IN_ */ diff --git a/MQTTSNGateway/src/MQTTSNGateway.cpp b/MQTTSNGateway/src/MQTTSNGateway.cpp index 6ed0c04..83821e2 100644 --- a/MQTTSNGateway/src/MQTTSNGateway.cpp +++ b/MQTTSNGateway/src/MQTTSNGateway.cpp @@ -43,77 +43,77 @@ Gateway::Gateway(void) Gateway::~Gateway() { - if ( _params.loginId ) - { - free(_params.loginId); - } - if ( _params.password ) - { - free(_params.password); - } - if ( _params.gatewayName ) - { - free(_params.gatewayName); - } - if ( _params.brokerName ) - { - free(_params.brokerName); - } - if ( _params.port ) - { - free(_params.port); - } - if ( _params.portSecure ) - { - free(_params.portSecure); - } - if ( _params.certKey ) - { - free(_params.certKey); - } - if ( _params.privateKey ) - { - free(_params.privateKey); - } - if ( _params.rootCApath ) - { - free(_params.rootCApath); - } - if ( _params.rootCAfile ) - { - free(_params.rootCAfile); - } - if ( _params.clientListName ) - { - free(_params.clientListName); - } - if ( _params.predefinedTopicFileName ) - { - free( _params.predefinedTopicFileName); - } - if ( _params.configName ) - { - free(_params.configName); - } + if (_params.loginId) + { + free(_params.loginId); + } + if (_params.password) + { + free(_params.password); + } + if (_params.gatewayName) + { + free(_params.gatewayName); + } + if (_params.brokerName) + { + free(_params.brokerName); + } + if (_params.port) + { + free(_params.port); + } + if (_params.portSecure) + { + free(_params.portSecure); + } + if (_params.certKey) + { + free(_params.certKey); + } + if (_params.privateKey) + { + free(_params.privateKey); + } + if (_params.rootCApath) + { + free(_params.rootCApath); + } + if (_params.rootCAfile) + { + free(_params.rootCAfile); + } + if (_params.clientListName) + { + free(_params.clientListName); + } + if (_params.predefinedTopicFileName) + { + free(_params.predefinedTopicFileName); + } + if (_params.configName) + { + free(_params.configName); + } - if ( _params.qosMinusClientListName ) + if (_params.qosMinusClientListName) { free(_params.qosMinusClientListName); } - if ( _adapterManager ) + if (_adapterManager) { delete _adapterManager; } - if ( _clientList ) + if (_clientList) { delete _clientList; } - if ( _topics ) - { - delete _topics; - } + if (_topics) + { + delete _topics; + } // WRITELOG("Gateway is deleted normally.\r\n"); } @@ -124,256 +124,258 @@ int Gateway::getParam(const char* parameter, char* value) char* Gateway::getClientListFileName(void) { - return _params.clientListName; + return _params.clientListName; } char* Gateway::getPredefinedTopicFileName(void) { - return _params.predefinedTopicFileName; + return _params.predefinedTopicFileName; } void Gateway::initialize(int argc, char** argv) { - char param[MQTTSNGW_PARAM_MAX]; - string fileName; + char param[MQTTSNGW_PARAM_MAX]; + string fileName; theGateway = this; - MultiTaskProcess::initialize(argc, argv); - resetRingBuffer(); + MultiTaskProcess::initialize(argc, argv); + resetRingBuffer(); - _params.configDir = *getConfigDirName(); + _params.configDir = *getConfigDirName(); fileName = _params.configDir + *getConfigFileName(); _params.configName = strdup(fileName.c_str()); - if (getParam("BrokerName", param) == 0) - { - _params.brokerName = strdup(param); - } - if (getParam("BrokerPortNo", param) == 0) - { - _params.port = strdup(param); - } - if (getParam("BrokerSecurePortNo", param) == 0) - { - _params.portSecure = strdup(param); - } + if (getParam("BrokerName", param) == 0) + { + _params.brokerName = strdup(param); + } + if (getParam("BrokerPortNo", param) == 0) + { + _params.port = strdup(param); + } + if (getParam("BrokerSecurePortNo", param) == 0) + { + _params.portSecure = strdup(param); + } - if (getParam("CertKey", param) == 0) - { - _params.certKey = strdup(param); - } - if (getParam("PrivateKey", param) == 0) - { - _params.privateKey = strdup(param); - } - if (getParam("RootCApath", param) == 0) - { - _params.rootCApath = strdup(param); - } - if (getParam("RootCAfile", param) == 0) - { - _params.rootCAfile = strdup(param); - } + if (getParam("CertKey", param) == 0) + { + _params.certKey = strdup(param); + } + if (getParam("PrivateKey", param) == 0) + { + _params.privateKey = strdup(param); + } + if (getParam("RootCApath", param) == 0) + { + _params.rootCApath = strdup(param); + } + if (getParam("RootCAfile", param) == 0) + { + _params.rootCAfile = strdup(param); + } - if (getParam("GatewayID", param) == 0) - { - _params.gatewayId = atoi(param); - } + if (getParam("GatewayID", param) == 0) + { + _params.gatewayId = atoi(param); + } - if (_params.gatewayId == 0 || _params.gatewayId > 255) - { - throw Exception( "Gateway::initialize: invalid Gateway Id"); - } + if (_params.gatewayId == 0 || _params.gatewayId > 255) + { + throw Exception("Gateway::initialize: invalid Gateway Id"); + } - if (getParam("GatewayName", param) == 0) - { - _params.gatewayName = strdup(param); - } + if (getParam("GatewayName", param) == 0) + { + _params.gatewayName = strdup(param); + } - if (_params.gatewayName == 0 ) - { - throw Exception( "Gateway::initialize: Gateway Name is missing."); - } + if (_params.gatewayName == 0) + { + throw Exception("Gateway::initialize: Gateway Name is missing."); + } - _params.mqttVersion = DEFAULT_MQTT_VERSION; - if (getParam("MQTTVersion", param) == 0) - { - _params.mqttVersion = atoi(param); - } + _params.mqttVersion = DEFAULT_MQTT_VERSION; + if (getParam("MQTTVersion", param) == 0) + { + _params.mqttVersion = atoi(param); + } - _params.maxInflightMsgs = DEFAULT_MQTT_VERSION; - if (getParam("MaxInflightMsgs", param) == 0) - { - _params.maxInflightMsgs = atoi(param); - } + _params.maxInflightMsgs = DEFAULT_MQTT_VERSION; + if (getParam("MaxInflightMsgs", param) == 0) + { + _params.maxInflightMsgs = atoi(param); + } - _params.keepAlive = DEFAULT_KEEP_ALIVE_TIME; - if (getParam("KeepAlive", param) == 0) - { - _params.keepAlive = atoi(param); - } + _params.keepAlive = DEFAULT_KEEP_ALIVE_TIME; + if (getParam("KeepAlive", param) == 0) + { + _params.keepAlive = atoi(param); + } - if (getParam("LoginID", param) == 0) - { - _params.loginId = strdup(param); - } + if (getParam("LoginID", param) == 0) + { + _params.loginId = strdup(param); + } - if (getParam("Password", param) == 0) - { - _params.password = strdup(param); - } + if (getParam("Password", param) == 0) + { + _params.password = strdup(param); + } - if (getParam("ClientAuthentication", param) == 0) - { - if (!strcasecmp(param, "YES")) - { - _params.clientAuthentication = true; - } - } + if (getParam("ClientAuthentication", param) == 0) + { + if (!strcasecmp(param, "YES")) + { + _params.clientAuthentication = true; + } + } - if (getParam("ClientsList", param) == 0) - { - _params.clientListName = strdup(param); - } + if (getParam("ClientsList", param) == 0) + { + _params.clientListName = strdup(param); + } - if (getParam("PredefinedTopic", param) == 0) - { - if ( !strcasecmp(param, "YES") ) - { - _params.predefinedTopic = true; - if (getParam("PredefinedTopicList", param) == 0) - { - _params.predefinedTopicFileName = strdup(param); - } - } - } + if (getParam("PredefinedTopic", param) == 0) + { + if (!strcasecmp(param, "YES")) + { + _params.predefinedTopic = true; + if (getParam("PredefinedTopicList", param) == 0) + { + _params.predefinedTopicFileName = strdup(param); + } + } + } - if (getParam("AggregatingGateway", param) == 0) - { - if ( !strcasecmp(param, "YES") ) - { - _params.aggregatingGw = true; - } - } + if (getParam("AggregatingGateway", param) == 0) + { + if (!strcasecmp(param, "YES")) + { + _params.aggregatingGw = true; + } + } - if (getParam("Forwarder", param) == 0) - { - if ( !strcasecmp(param, "YES") ) - { - _params.forwarder = true; - } - } + if (getParam("Forwarder", param) == 0) + { + if (!strcasecmp(param, "YES")) + { + _params.forwarder = true; + } + } - if (getParam("QoS-1", param) == 0) - { - if ( !strcasecmp(param, "YES") ) - { - _params.qosMinus1 = true; - } - } + if (getParam("QoS-1", param) == 0) + { + if (!strcasecmp(param, "YES")) + { + _params.qosMinus1 = true; + } + } + /* Initialize adapters */ + _adapterManager->initialize(_params.gatewayName, _params.aggregatingGw, + _params.forwarder, _params.qosMinus1); - /* Initialize adapters */ - _adapterManager->initialize( _params.gatewayName, _params.aggregatingGw, _params.forwarder, _params.qosMinus1); - - /* Setup ClientList and Predefined topics */ - _clientList->initialize(_params.aggregatingGw); + /* Setup ClientList and Predefined topics */ + _clientList->initialize(_params.aggregatingGw); } void Gateway::run(void) { /* write prompts */ - _lightIndicator.redLight(true); - WRITELOG("\n%s", PAHO_COPYRIGHT4); - WRITELOG("\n%s\n", PAHO_COPYRIGHT0); - WRITELOG("%s\n", PAHO_COPYRIGHT1); - WRITELOG("%s\n", PAHO_COPYRIGHT2); - WRITELOG(" *\n%s\n", PAHO_COPYRIGHT3); - WRITELOG(" * Version: %s\n", PAHO_GATEWAY_VERSION); - WRITELOG("%s\n", PAHO_COPYRIGHT4); - WRITELOG("\n%s %s has been started.\n\n", currentDateTime(), _params.gatewayName); - WRITELOG(" ConfigFile: %s\n", _params.configName); + _lightIndicator.redLight(true); + WRITELOG("\n%s", PAHO_COPYRIGHT4); + WRITELOG("\n%s\n", PAHO_COPYRIGHT0); + WRITELOG("%s\n", PAHO_COPYRIGHT1); + WRITELOG("%s\n", PAHO_COPYRIGHT2); + WRITELOG(" *\n%s\n", PAHO_COPYRIGHT3); + WRITELOG(" * Version: %s\n", PAHO_GATEWAY_VERSION); + WRITELOG("%s\n", PAHO_COPYRIGHT4); + WRITELOG("\n%s %s has been started.\n\n", currentDateTime(), + _params.gatewayName); + WRITELOG(" ConfigFile: %s\n", _params.configName); - if ( _params.clientListName ) - { - WRITELOG(" ClientList: %s\n", _params.clientListName); - } + if (_params.clientListName) + { + WRITELOG(" ClientList: %s\n", _params.clientListName); + } - if ( _params.predefinedTopicFileName ) + if (_params.predefinedTopicFileName) { WRITELOG(" PreDefFile: %s\n", _params.predefinedTopicFileName); } - WRITELOG(" SensorN/W: %s\n", _sensorNetwork.getDescription()); - WRITELOG(" Broker: %s : %s, %s\n", _params.brokerName, _params.port, _params.portSecure); - WRITELOG(" RootCApath: %s\n", _params.rootCApath); - WRITELOG(" RootCAfile: %s\n", _params.rootCAfile); - WRITELOG(" CertKey: %s\n", _params.certKey); - WRITELOG(" PrivateKey: %s\n\n\n", _params.privateKey); + WRITELOG(" SensorN/W: %s\n", _sensorNetwork.getDescription()); + WRITELOG(" Broker: %s : %s, %s\n", _params.brokerName, _params.port, + _params.portSecure); + WRITELOG(" RootCApath: %s\n", _params.rootCApath); + WRITELOG(" RootCAfile: %s\n", _params.rootCAfile); + WRITELOG(" CertKey: %s\n", _params.certKey); + WRITELOG(" PrivateKey: %s\n\n\n", _params.privateKey); - _stopFlg = false; + _stopFlg = false; - /* Run Tasks until CTRL+C entred */ - MultiTaskProcess::run(); + /* Run Tasks until CTRL+C entred */ + MultiTaskProcess::run(); - _stopFlg = true; + _stopFlg = true; - /* stop Tasks */ - Event* ev = new Event(); - ev->setStop(); - _packetEventQue.post(ev); - ev = new Event(); - ev->setStop(); - _brokerSendQue.post(ev); - ev = new Event(); - ev->setStop(); - _clientSendQue.post(ev); + /* stop Tasks */ + Event* ev = new Event(); + ev->setStop(); + _packetEventQue.post(ev); + ev = new Event(); + ev->setStop(); + _brokerSendQue.post(ev); + ev = new Event(); + ev->setStop(); + _clientSendQue.post(ev); - /* wait until all Task stop */ - MultiTaskProcess::waitStop(); + /* wait until all Task stop */ + MultiTaskProcess::waitStop(); - WRITELOG("\n\n%s MQTT-SN Gateway stopped.\n\n", currentDateTime()); - _lightIndicator.allLightOff(); + WRITELOG("\n\n%s MQTT-SN Gateway stopped.\n\n", currentDateTime()); + _lightIndicator.allLightOff(); } bool Gateway::IsStopping(void) { - return _stopFlg; + return _stopFlg; } EventQue* Gateway::getPacketEventQue() { - return &_packetEventQue; + return &_packetEventQue; } EventQue* Gateway::getClientSendQue() { - return &_clientSendQue; + return &_clientSendQue; } EventQue* Gateway::getBrokerSendQue() { - return &_brokerSendQue; + return &_brokerSendQue; } ClientList* Gateway::getClientList() { - return _clientList; + return _clientList; } SensorNetwork* Gateway::getSensorNetwork() { - return &_sensorNetwork; + return &_sensorNetwork; } LightIndicator* Gateway::getLightIndicator() { - return &_lightIndicator; + return &_lightIndicator; } GatewayParams* Gateway::getGWParams(void) { - return &_params; + return &_params; } AdapterManager* Gateway::getAdapterManager(void) @@ -388,10 +390,8 @@ Topics* Gateway::getTopics(void) bool Gateway::hasSecureConnection(void) { - return ( _params.certKey - && _params.privateKey - && _params.rootCApath - && _params.rootCAfile ); + return (_params.certKey && _params.privateKey && _params.rootCApath + && _params.rootCAfile); } /*===================================== Class EventQue @@ -403,87 +403,86 @@ EventQue::EventQue() EventQue::~EventQue() { - _mutex.lock(); - while (_que.size() > 0) - { - delete _que.front(); - _que.pop(); - } - _mutex.unlock(); + _mutex.lock(); + while (_que.size() > 0) + { + delete _que.front(); + _que.pop(); + } + _mutex.unlock(); } -void EventQue::setMaxSize(uint16_t maxSize) +void EventQue::setMaxSize(uint16_t maxSize) { - _que.setMaxSize((int)maxSize); + _que.setMaxSize((int) maxSize); } Event* EventQue::wait(void) { - Event* ev = nullptr; + Event* ev = nullptr; - while(ev == nullptr) - { - if ( _que.size() == 0 ) - { - _sem.wait(); - } - _mutex.lock(); - ev = _que.front(); - _que.pop(); - _mutex.unlock(); - } - return ev; + while (ev == nullptr) + { + if (_que.size() == 0) + { + _sem.wait(); + } + _mutex.lock(); + ev = _que.front(); + _que.pop(); + _mutex.unlock(); + } + return ev; } Event* EventQue::timedwait(uint16_t millsec) { - Event* ev; - if ( _que.size() == 0 ) - { - _sem.timedwait(millsec); - } - _mutex.lock(); + Event* ev; + if (_que.size() == 0) + { + _sem.timedwait(millsec); + } + _mutex.lock(); - if (_que.size() == 0) - { - ev = new Event(); - ev->setTimeout(); - } - else - { - ev = _que.front(); - _que.pop(); - } - _mutex.unlock(); - return ev; + if (_que.size() == 0) + { + ev = new Event(); + ev->setTimeout(); + } + else + { + ev = _que.front(); + _que.pop(); + } + _mutex.unlock(); + return ev; } void EventQue::post(Event* ev) { - if ( ev ) - { - _mutex.lock(); - if ( _que.post(ev) ) - { - _sem.post(); - } - else - { - delete ev; - } - _mutex.unlock(); - } + if (ev) + { + _mutex.lock(); + if (_que.post(ev)) + { + _sem.post(); + } + else + { + delete ev; + } + _mutex.unlock(); + } } int EventQue::size() { - _mutex.lock(); - int sz = _que.size(); - _mutex.unlock(); - return sz; + _mutex.lock(); + int sz = _que.size(); + _mutex.unlock(); + return sz; } - /*===================================== Class Event =====================================*/ @@ -494,96 +493,95 @@ Event::Event() Event::~Event() { - if (_sensorNetAddr) - { - delete _sensorNetAddr; - } + if (_sensorNetAddr) + { + delete _sensorNetAddr; + } - if (_mqttSNPacket) - { - delete _mqttSNPacket; - } + if (_mqttSNPacket) + { + delete _mqttSNPacket; + } - if (_mqttGWPacket) - { - delete _mqttGWPacket; - } + if (_mqttGWPacket) + { + delete _mqttGWPacket; + } } EventType Event::getEventType() { - return _eventType; + return _eventType; } void Event::setClientSendEvent(Client* client, MQTTSNPacket* packet) { - _client = client; - _eventType = EtClientSend; - _mqttSNPacket = packet; + _client = client; + _eventType = EtClientSend; + _mqttSNPacket = packet; } void Event::setBrokerSendEvent(Client* client, MQTTGWPacket* packet) { - _client = client; - _eventType = EtBrokerSend; - _mqttGWPacket = packet; + _client = client; + _eventType = EtBrokerSend; + _mqttGWPacket = packet; } void Event::setClientRecvEvent(Client* client, MQTTSNPacket* packet) { - _client = client; - _eventType = EtClientRecv; - _mqttSNPacket = packet; + _client = client; + _eventType = EtClientRecv; + _mqttSNPacket = packet; } void Event::setBrokerRecvEvent(Client* client, MQTTGWPacket* packet) { - _client = client; - _eventType = EtBrokerRecv; - _mqttGWPacket = packet; + _client = client; + _eventType = EtBrokerRecv; + _mqttGWPacket = packet; } void Event::setTimeout(void) { - _eventType = EtTimeout; + _eventType = EtTimeout; } void Event::setStop(void) { - _eventType = EtStop; + _eventType = EtStop; } void Event::setBrodcastEvent(MQTTSNPacket* msg) { - _mqttSNPacket = msg; - _eventType = EtBroadcast; + _mqttSNPacket = msg; + _eventType = EtBroadcast; } void Event::setClientSendEvent(SensorNetAddress* addr, MQTTSNPacket* msg) { - _eventType = EtSensornetSend; - _sensorNetAddr = addr; - _mqttSNPacket = msg; + _eventType = EtSensornetSend; + _sensorNetAddr = addr; + _mqttSNPacket = msg; } Client* Event::getClient(void) { - return _client; + return _client; } SensorNetAddress* Event::getSensorNetAddress(void) { - return _sensorNetAddr; + return _sensorNetAddr; } MQTTSNPacket* Event::getMQTTSNPacket() { - return _mqttSNPacket; + return _mqttSNPacket; } MQTTGWPacket* Event::getMQTTGWPacket(void) { - return _mqttGWPacket; + return _mqttGWPacket; } - diff --git a/MQTTSNGateway/src/MQTTSNGateway.h b/MQTTSNGateway/src/MQTTSNGateway.h index 86c7952..10c6c2a 100644 --- a/MQTTSNGateway/src/MQTTSNGateway.h +++ b/MQTTSNGateway/src/MQTTSNGateway.h @@ -46,8 +46,8 @@ namespace MQTTSNGW #define LEFTARROW "<---" #define RIGHTARROW "--->" -#define LEFTARROWB "<===" -#define RIGHTARROWB "===>" +#define LEFTARROWB "<===" +#define RIGHTARROWB "===>" #define FORMAT_Y_G_G_NL "\n%s \033[0m\033[0;33m%-18s\033[0m\033[0;32m%-6s%-34.32s \033[0m\033[0;34m%s\033[0m\033[0;37m\n" #define FORMAT_Y_G_G "%s \033[0m\033[0;33m%-18s\033[0m\033[0;32m%-6s%-34.32s \033[0m\033[0;34m%s\033[0m\033[0;37m\n" @@ -68,150 +68,147 @@ namespace MQTTSNGW #define FORMAT_BL_NL "\n%s \033[0m\033[0;34m%-18s%-6s%-34.32s %s\033[0m\033[0;37m\n" #define FORMAT_W_NL "\n%s %-18s%-6s%-34.32s %s\n" -#define ERRMSG_HEADER "\033[0m\033[0;31mError:" -#define ERRMSG_FOOTER "\033[0m\033[0;37m" +#define ERRMSG_HEADER "\033[0m\033[0;31mError:" +#define ERRMSG_FOOTER "\033[0m\033[0;37m" /*===================================== - Class Event - ====================================*/ + Class Event + ====================================*/ class Client; -enum EventType{ - Et_NA = 0, - EtStop, - EtTimeout, - EtBrokerRecv, - EtBrokerSend, - EtClientRecv, - EtClientSend, - EtBroadcast, - EtSensornetSend +enum EventType +{ + Et_NA = 0, + EtStop, + EtTimeout, + EtBrokerRecv, + EtBrokerSend, + EtClientRecv, + EtClientSend, + EtBroadcast, + EtSensornetSend }; - -class Event{ +class Event +{ public: - Event(); - ~Event(); - EventType getEventType(void); - void setClientRecvEvent(Client*, MQTTSNPacket*); - void setClientSendEvent(Client*, MQTTSNPacket*); - void setBrokerRecvEvent(Client*, MQTTGWPacket*); - void setBrokerSendEvent(Client*, MQTTGWPacket*); - void setBrodcastEvent(MQTTSNPacket*); // ADVERTISE and GWINFO - void setTimeout(void); // Required by EventQue.timedwait() - void setStop(void); - void setClientSendEvent(SensorNetAddress*, MQTTSNPacket*); - Client* getClient(void); - SensorNetAddress* getSensorNetAddress(void); - MQTTSNPacket* getMQTTSNPacket(void); - MQTTGWPacket* getMQTTGWPacket(void); + Event(); + ~Event(); + EventType getEventType(void); + void setClientRecvEvent(Client*, MQTTSNPacket*); + void setClientSendEvent(Client*, MQTTSNPacket*); + void setBrokerRecvEvent(Client*, MQTTGWPacket*); + void setBrokerSendEvent(Client*, MQTTGWPacket*); + void setBrodcastEvent(MQTTSNPacket*); // ADVERTISE and GWINFO + void setTimeout(void); // Required by EventQue.timedwait() + void setStop(void); + void setClientSendEvent(SensorNetAddress*, MQTTSNPacket*); + Client* getClient(void); + SensorNetAddress* getSensorNetAddress(void); + MQTTSNPacket* getMQTTSNPacket(void); + MQTTGWPacket* getMQTTGWPacket(void); private: - EventType _eventType {Et_NA}; - Client* _client {nullptr}; - SensorNetAddress* _sensorNetAddr {nullptr}; - MQTTSNPacket* _mqttSNPacket {nullptr}; - MQTTGWPacket* _mqttGWPacket {nullptr}; + EventType _eventType { Et_NA }; + Client* _client { nullptr }; + SensorNetAddress* _sensorNetAddr { nullptr }; + MQTTSNPacket* _mqttSNPacket { nullptr }; + MQTTGWPacket* _mqttGWPacket { nullptr }; }; - /*===================================== Class EventQue ====================================*/ class EventQue { public: - EventQue(); - ~EventQue(); - Event* wait(void); - Event* timedwait(uint16_t millsec); - void setMaxSize(uint16_t maxSize); - void post(Event*); - int size(); + EventQue(); + ~EventQue(); + Event* wait(void); + Event* timedwait(uint16_t millsec); + void setMaxSize(uint16_t maxSize); + void post(Event*); + int size(); private: - Que _que; - Mutex _mutex; - Semaphore _sem; + Que _que; + Mutex _mutex; + Semaphore _sem; }; - - /*===================================== Class GatewayParams ====================================*/ class 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* predefinedTopicFileName {nullptr}; - char* privateKey {nullptr}; - char* qosMinusClientListName {nullptr}; - bool clientAuthentication {false}; - bool predefinedTopic {false}; - bool aggregatingGw {false}; - bool qosMinus1 {false}; - bool forwarder {false}; + 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* predefinedTopicFileName { nullptr }; + char* privateKey { nullptr }; + char* qosMinusClientListName { nullptr }; + bool clientAuthentication { false }; + bool predefinedTopic { false }; + bool aggregatingGw { false }; + bool qosMinus1 { false }; + bool forwarder { false }; }; - - /*===================================== - Class Gateway + Class Gateway =====================================*/ class AdapterManager; class ClientList; -class Gateway: public MultiTaskProcess{ +class Gateway: public MultiTaskProcess +{ public: Gateway(void); - ~Gateway(); - virtual void initialize(int argc, char** argv); - void run(void); + ~Gateway(); + virtual void initialize(int argc, char** argv); + void run(void); - EventQue* getPacketEventQue(void); - EventQue* getClientSendQue(void); - EventQue* getBrokerSendQue(void); - ClientList* getClientList(void); - SensorNetwork* getSensorNetwork(void); - LightIndicator* getLightIndicator(void); - GatewayParams* getGWParams(void); - AdapterManager* getAdapterManager(void); - int getParam(const char* parameter, char* value); - char* getClientListFileName(void); - char* getPredefinedTopicFileName(void); + EventQue* getPacketEventQue(void); + EventQue* getClientSendQue(void); + EventQue* getBrokerSendQue(void); + ClientList* getClientList(void); + SensorNetwork* getSensorNetwork(void); + LightIndicator* getLightIndicator(void); + GatewayParams* getGWParams(void); + AdapterManager* getAdapterManager(void); + int getParam(const char* parameter, char* value); + char* getClientListFileName(void); + char* getPredefinedTopicFileName(void); - bool hasSecureConnection(void); - Topics* getTopics(void); - bool IsStopping(void); + bool hasSecureConnection(void); + Topics* getTopics(void); + bool IsStopping(void); private: - GatewayParams _params; - ClientList* _clientList {nullptr}; - EventQue _packetEventQue; - EventQue _brokerSendQue; - EventQue _clientSendQue; - LightIndicator _lightIndicator; - SensorNetwork _sensorNetwork; - AdapterManager* _adapterManager {nullptr}; - Topics* _topics; - bool _stopFlg; + GatewayParams _params; + ClientList* _clientList { nullptr }; + EventQue _packetEventQue; + EventQue _brokerSendQue; + EventQue _clientSendQue; + LightIndicator _lightIndicator; + SensorNetwork _sensorNetwork; + AdapterManager* _adapterManager { nullptr }; + Topics* _topics; + bool _stopFlg; }; } diff --git a/MQTTSNGateway/src/mainGateway.cpp b/MQTTSNGateway/src/mainGateway.cpp index 4c6657c..d657deb 100644 --- a/MQTTSNGateway/src/mainGateway.cpp +++ b/MQTTSNGateway/src/mainGateway.cpp @@ -26,11 +26,11 @@ using namespace MQTTSNGW; * Gateway Application */ Gateway gateway; -PacketHandleTask task1(&gateway); -ClientRecvTask task2(&gateway); -ClientSendTask task3(&gateway); -BrokerRecvTask task4(&gateway); -BrokerSendTask task5(&gateway); +PacketHandleTask task1(&gateway); +ClientRecvTask task2(&gateway); +ClientSendTask task3(&gateway); +BrokerRecvTask task4(&gateway); +BrokerSendTask task5(&gateway); int main(int argc, char** argv) { @@ -38,13 +38,12 @@ int main(int argc, char** argv) gateway.run(); try { - gateway.initialize(argc, argv); - gateway.run(); - } - catch (const std::exception &ex) + gateway.initialize(argc, argv); + gateway.run(); + } catch (const std::exception &ex) { - WRITELOG("\nEclipse Paho MQTT-SN Gateway exception: %s\n", ex.what()); - WRITELOG("MQTT-SNGateway [-f Config file name]\n"); - } - return 0; + WRITELOG("\nEclipse Paho MQTT-SN Gateway exception: %s\n", ex.what()); + WRITELOG("MQTT-SNGateway [-f Config file name]\n"); + } + return 0; } diff --git a/MQTTSNGateway/src/mainLogmonitor.cpp b/MQTTSNGateway/src/mainLogmonitor.cpp index f73a2a9..da66757 100644 --- a/MQTTSNGateway/src/mainLogmonitor.cpp +++ b/MQTTSNGateway/src/mainLogmonitor.cpp @@ -19,15 +19,14 @@ using namespace MQTTSNGW; - /* * Logmonitor process */ int main(int argc, char** argv) { - Logmonitor monitor = Logmonitor(); - monitor.initialize(argc, argv); - monitor.run(); - return 0; + Logmonitor monitor = Logmonitor(); + monitor.initialize(argc, argv); + monitor.run(); + return 0; } From 60fcab2504cf60242b829080b4480d5c25f41d90 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 27 Apr 2021 21:31:22 +0900 Subject: [PATCH 02/67] Change Client Type Signed-off-by: tomoaki --- MQTTSNGateway/src/MQTTSNGWClient.cpp | 2 +- MQTTSNGateway/src/MQTTSNGWClient.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MQTTSNGateway/src/MQTTSNGWClient.cpp b/MQTTSNGateway/src/MQTTSNGWClient.cpp index a971bc2..03244bc 100644 --- a/MQTTSNGateway/src/MQTTSNGWClient.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClient.cpp @@ -59,7 +59,7 @@ Client::Client(bool secure) _hasPredefTopic = false; _holdPingRequest = false; _forwarder = nullptr; - _clientType = Ctype_Regular; + _clientType = Ctype_Normal; } Client::~Client() diff --git a/MQTTSNGateway/src/MQTTSNGWClient.h b/MQTTSNGateway/src/MQTTSNGWClient.h index 1774ad9..55685f0 100644 --- a/MQTTSNGateway/src/MQTTSNGWClient.h +++ b/MQTTSNGateway/src/MQTTSNGWClient.h @@ -163,7 +163,7 @@ typedef enum typedef enum { - Ctype_Regular = 0, + Ctype_Normal = 0, Ctype_Forwarded, Ctype_QoS_1, Ctype_Aggregated, From aaad3a0122213d233fe68f48025492cc50704f9c Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 27 Apr 2021 21:34:08 +0900 Subject: [PATCH 03/67] Bugfix of Handling Exception #236 Signed-off-by: tomoaki --- MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp | 4 +-- MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp | 4 +-- MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp | 3 +- MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp | 4 +-- .../src/MQTTSNGWPacketHandleTask.cpp | 3 +- MQTTSNGateway/src/MQTTSNGWProcess.cpp | 32 +++++++------------ MQTTSNGateway/src/MQTTSNGWVersion.h | 2 +- MQTTSNGateway/src/MQTTSNGateway.cpp | 2 +- MQTTSNGateway/src/linux/Threading.cpp | 23 ++++++------- MQTTSNGateway/src/linux/Threading.h | 27 +++++++++------- MQTTSNGateway/src/mainGateway.cpp | 12 +++---- 11 files changed, 56 insertions(+), 60 deletions(-) diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp index 9a570b6..4138db4 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp @@ -32,11 +32,11 @@ BrokerRecvTask::BrokerRecvTask(Gateway* gateway) _gateway = gateway; _gateway->attach((Thread*) this); _light = nullptr; + setTaskName("BrokerRecvTask"); } BrokerRecvTask::~BrokerRecvTask() { - } /** @@ -64,7 +64,7 @@ void BrokerRecvTask::run(void) _light->blueLight(false); if (CHK_SIGINT) { - WRITELOG("\n%s BrokerRecvTask stopped.", currentDateTime()); + WRITELOG("\n%s %s stopped.", currentDateTime(), getTaskName()); return; } timeout.tv_sec = 0; diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp index ebe8a3c..4f27645 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp @@ -37,11 +37,11 @@ BrokerSendTask::BrokerSendTask(Gateway* gateway) _gateway->attach((Thread*) this); _gwparams = nullptr; _light = nullptr; + setTaskName("BrokerSendTask"); } BrokerSendTask::~BrokerSendTask() { -// WRITELOG("BrokerSendTask is deleted normally.\r\n"); } /** @@ -70,7 +70,7 @@ void BrokerSendTask::run() if (ev->getEventType() == EtStop) { - WRITELOG("\n%s BrokerSendTask stopped.", currentDateTime()); + WRITELOG("\n%s %s stopped.", currentDateTime(), getTaskName()); delete ev; return; } diff --git a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp index 49568b5..e9720dd 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp @@ -32,6 +32,7 @@ ClientRecvTask::ClientRecvTask(Gateway* gateway) _gateway = gateway; _gateway->attach((Thread*) this); _sensorNetwork = _gateway->getSensorNetwork(); + setTaskName("ClientRecvTask"); } ClientRecvTask::~ClientRecvTask() @@ -78,7 +79,7 @@ void ClientRecvTask::run() if (CHK_SIGINT) { - WRITELOG("\n%s ClientRecvTask stopped.", currentDateTime()); + WRITELOG("\n%s %s stopped.", currentDateTime(), getTaskName()); delete packet; return; } diff --git a/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp index 0734a5e..2d2fa97 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp @@ -31,11 +31,11 @@ ClientSendTask::ClientSendTask(Gateway* gateway) _gateway = gateway; _gateway->attach((Thread*) this); _sensorNetwork = _gateway->getSensorNetwork(); + setTaskName("ClientSendTask"); } ClientSendTask::~ClientSendTask() { -// WRITELOG("ClientSendTask is deleted normally.\r\n"); } void ClientSendTask::run() @@ -51,7 +51,7 @@ void ClientSendTask::run() if (ev->getEventType() == EtStop || _gateway->IsStopping()) { - WRITELOG("\n%s ClientSendTask stopped.", currentDateTime()); + WRITELOG("\n%s %s stopped.", currentDateTime(), getTaskName()); delete ev; break; } diff --git a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp index c94ccb5..6540a87 100644 --- a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp @@ -54,6 +54,7 @@ PacketHandleTask::PacketHandleTask(Gateway* gateway) _mqttsnSubscribe = new MQTTSNSubscribeHandler(_gateway); _mqttsnAggrConnection = new MQTTSNAggregateConnectionHandler(_gateway); + setTaskName("PacketHandleTask"); } /** @@ -113,7 +114,7 @@ void PacketHandleTask::run() if (ev->getEventType() == EtStop) { - WRITELOG("\n%s PacketHandleTask stopped.", currentDateTime()); + WRITELOG("\n%s %s stopped.", currentDateTime(), getTaskName()); delete ev; return; } diff --git a/MQTTSNGateway/src/MQTTSNGWProcess.cpp b/MQTTSNGateway/src/MQTTSNGWProcess.cpp index 897aa29..6db7588 100644 --- a/MQTTSNGateway/src/MQTTSNGWProcess.cpp +++ b/MQTTSNGateway/src/MQTTSNGWProcess.cpp @@ -57,6 +57,8 @@ Process::Process() _configDir = CONFIG_DIRECTORY; _configFile = CONFIG_FILE; _log = 0; + _rbsem = NULL; + _rb = NULL; } Process::~Process() @@ -99,7 +101,6 @@ void Process::initialize(int argc, char** argv) else { _configFile = config.substr(pos + 1, config.size() - pos - 1); - ; _configDir = config.substr(0, pos + 1); } } @@ -278,22 +279,17 @@ void MultiTaskProcess::run(void) _threadList[i]->start(); } - try + while (true) { - while (true) + if (theProcess->checkSignal() == SIGINT ) { - if (theProcess->checkSignal() == SIGINT) - { - return; - } - sleep(1); + return; } - } catch (Exception* ex) - { - ex->writeMessage(); - } catch (...) - { - throw; + else if (_stopCount > 0) + { + throw Exception(0,"Abort",__FILE__, __func__, __LINE__); + } + sleep(1); } } @@ -334,10 +330,6 @@ int MultiTaskProcess::getParam(const char* parameter, char* value) _mutex.lock(); int rc = Process::getParam(parameter, value); _mutex.unlock(); - if (rc == -1) - { - throw Exception("No config file."); - } return rc; } @@ -348,8 +340,8 @@ Exception::Exception(const string& message) { _message = message; _exNo = 0; - _fileName = 0; - _functionName = 0; + _fileName = nullptr; + _functionName = nullptr; _line = 0; } diff --git a/MQTTSNGateway/src/MQTTSNGWVersion.h b/MQTTSNGateway/src/MQTTSNGWVersion.h index e0e6186..275be35 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.5.0" +#define PAHO_GATEWAY_VERSION "1.6.0" #endif /* MQTTSNGWVERSION_H_IN_ */ diff --git a/MQTTSNGateway/src/MQTTSNGateway.cpp b/MQTTSNGateway/src/MQTTSNGateway.cpp index 83821e2..b722a56 100644 --- a/MQTTSNGateway/src/MQTTSNGateway.cpp +++ b/MQTTSNGateway/src/MQTTSNGateway.cpp @@ -315,7 +315,7 @@ void Gateway::run(void) _stopFlg = false; - /* Run Tasks until CTRL+C entred */ + /* Run Tasks until CTRL+C entered or Exception occurred */ MultiTaskProcess::run(); _stopFlg = true; diff --git a/MQTTSNGateway/src/linux/Threading.cpp b/MQTTSNGateway/src/linux/Threading.cpp index 7c452e7..d1cb5c8 100644 --- a/MQTTSNGateway/src/linux/Threading.cpp +++ b/MQTTSNGateway/src/linux/Threading.cpp @@ -135,7 +135,7 @@ void Mutex::lock(void) } } catch (char* errmsg) { - throw Exception( -1, "The same thread can't aquire a mutex twice."); + throw Exception( -1, "The same thread can't acquire a mutex twice."); } } } @@ -263,11 +263,6 @@ void NamedSemaphore::timedwait(uint16_t millsec) /*========================================= Class RingBuffer =========================================*/ -RingBuffer::RingBuffer() -{ - RingBuffer(MQTTSNGW_KEY_DIRECTORY); -} - RingBuffer::RingBuffer(const char* keyDirectory) { int fp = 0; @@ -506,6 +501,7 @@ void RingBuffer::reset() Thread::Thread() { _threadID = 0; + _taskName = nullptr; } Thread::~Thread() @@ -539,11 +535,6 @@ int Thread::start(void) return pthread_create(&_threadID, 0, _run, runnable); } -void Thread::stopProcess(void) -{ - theMultiTaskProcess->threadStopped(); -} - void Thread::stop(void) { if ( _threadID ) @@ -552,3 +543,13 @@ void Thread::stop(void) _threadID = 0; } } + +void Thread::setTaskName(const char* name) +{ + _taskName = name; +} + +const char* Thread::getTaskName(void) +{ + return _taskName; +} diff --git a/MQTTSNGateway/src/linux/Threading.h b/MQTTSNGateway/src/linux/Threading.h index 795ee5a..4dbd085 100644 --- a/MQTTSNGateway/src/linux/Threading.h +++ b/MQTTSNGateway/src/linux/Threading.h @@ -92,8 +92,7 @@ private: class RingBuffer { public: - RingBuffer(); - RingBuffer(const char* keyDirctory); + RingBuffer(const char* keyDirctory = MQTTSNGW_KEY_DIRECTORY); ~RingBuffer(); void put(char* buffer); int get(char* buffer, int bufferLength); @@ -124,15 +123,17 @@ public: #define MAGIC_WORD_FOR_THREAD \ public: void EXECRUN() \ { \ - try \ - { \ - run(); \ - stopProcess(); \ - } \ - catch(...) \ - { \ - throw; \ - } \ + try \ + { \ + run(); \ + theMultiTaskProcess->threadStopped(); \ + } \ + catch ( Exception &ex ) \ + { \ + theMultiTaskProcess->threadStopped(); \ + WRITELOG("%s catch exception\n", getTaskName()); \ + ex.writeMessage(); \ + } \ } /*===================================== @@ -146,12 +147,14 @@ public: static pthread_t getID(); static bool equals(pthread_t*, pthread_t*); virtual void initialize(int argc, char** argv); - void stopProcess(void); void waitStop(void); void stop(void); + const char* getTaskName(void); + void setTaskName(const char* name); private: static void* _run(void*); pthread_t _threadID; + const char* _taskName; }; } diff --git a/MQTTSNGateway/src/mainGateway.cpp b/MQTTSNGateway/src/mainGateway.cpp index d657deb..c0b351c 100644 --- a/MQTTSNGateway/src/mainGateway.cpp +++ b/MQTTSNGateway/src/mainGateway.cpp @@ -34,16 +34,14 @@ BrokerSendTask task5(&gateway); int main(int argc, char** argv) { - gateway.initialize(argc, argv); - gateway.run(); try { gateway.initialize(argc, argv); gateway.run(); - } catch (const std::exception &ex) - { - WRITELOG("\nEclipse Paho MQTT-SN Gateway exception: %s\n", ex.what()); - WRITELOG("MQTT-SNGateway [-f Config file name]\n"); } - return 0; + catch (Exception &ex) + { + ex.writeMessage(); + abort(); + } } From 48772fce3b2f0632db27e07789409b51b3f824bd Mon Sep 17 00:00:00 2001 From: tomoaki Date: Thu, 29 Apr 2021 10:47:00 +0900 Subject: [PATCH 04/67] Stop compiler warning message #206 Signed-off-by: tomoaki --- MQTTSNPacket/src/MQTTSNSerializePublish.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MQTTSNPacket/src/MQTTSNSerializePublish.c b/MQTTSNPacket/src/MQTTSNSerializePublish.c index 256a8d3..2531ba7 100644 --- a/MQTTSNPacket/src/MQTTSNSerializePublish.c +++ b/MQTTSNPacket/src/MQTTSNSerializePublish.c @@ -232,7 +232,7 @@ int MQTTSNSerialize_register(unsigned char* buf, int buflen, unsigned short topi int topicnamelen = 0; FUNC_ENTRY; - topicnamelen = (topicname->cstring) ? strlen(topicname->cstring) : topicname->lenstring.len; + topicnamelen = (topicname->cstring) ? (int)strlen(topicname->cstring) : topicname->lenstring.len; if ((len = MQTTSNPacket_len(MQTTSNSerialize_registerLength(topicnamelen))) > buflen) { rc = MQTTSNPACKET_BUFFER_TOO_SHORT; From c12e93122f9488052bf516ea76ade660518e7bca Mon Sep 17 00:00:00 2001 From: tomoaki Date: Thu, 29 Apr 2021 21:32:25 +0900 Subject: [PATCH 05/67] Add CMakelists.txt for MQTTSNGateway #235 Signed-off-by: tomoaki --- CMakeLists.txt | 3 +- MQTTSNGateway/CMakeLists.txt | 16 ++++ MQTTSNGateway/{Makefile => Makefile.org} | 0 MQTTSNGateway/src/CMakeLists.txt | 113 +++++++++++++++++++++++ MQTTSNGateway/src/tests/TestProcess.cpp | 2 - MQTTSNPacket/src/CMakeLists.txt | 3 + 6 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 MQTTSNGateway/CMakeLists.txt rename MQTTSNGateway/{Makefile => Makefile.org} (100%) create mode 100644 MQTTSNGateway/src/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index bdb6b98..66cfb53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ # Ian Craggs - initial version #*******************************************************************************/ -CMAKE_MINIMUM_REQUIRED(VERSION 2.8) +CMAKE_MINIMUM_REQUIRED(VERSION 3.1) PROJECT("paho-mqttsn" CXX) MESSAGE(STATUS "CMake version: " ${CMAKE_VERSION}) MESSAGE(STATUS "CMake system name: " ${CMAKE_SYSTEM_NAME}) @@ -39,3 +39,4 @@ INCLUDE(CPack) ENABLE_TESTING() ADD_SUBDIRECTORY(MQTTSNPacket) +ADD_SUBDIRECTORY(MQTTSNGateway) \ No newline at end of file diff --git a/MQTTSNGateway/CMakeLists.txt b/MQTTSNGateway/CMakeLists.txt new file mode 100644 index 0000000..51a8eec --- /dev/null +++ b/MQTTSNGateway/CMakeLists.txt @@ -0,0 +1,16 @@ +#******************************************************************************* +# Copyright (c) 2022 a1lu +# +# 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: +# a1lu - initial version +#*******************************************************************************/ +ADD_SUBDIRECTORY(src) \ No newline at end of file diff --git a/MQTTSNGateway/Makefile b/MQTTSNGateway/Makefile.org similarity index 100% rename from MQTTSNGateway/Makefile rename to MQTTSNGateway/Makefile.org diff --git a/MQTTSNGateway/src/CMakeLists.txt b/MQTTSNGateway/src/CMakeLists.txt new file mode 100644 index 0000000..74d8473 --- /dev/null +++ b/MQTTSNGateway/src/CMakeLists.txt @@ -0,0 +1,113 @@ +#******************************************************************************* +# Copyright (c) 2022 a1lu +# +# 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: +# a1lu - initial version +#*******************************************************************************/ +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ../Build) +set(CMAKE_CXX_STANDARD 11) + +SET(OS linux) +SET(SENSORNET udp) + +ADD_LIBRARY(mqtt-sngateway_common + MQTTGWConnectionHandler.cpp + MQTTGWPacket.cpp + MQTTGWPublishHandler.cpp + MQTTGWSubscribeHandler.cpp + MQTTSNGateway.cpp + MQTTSNGWBrokerRecvTask.cpp + MQTTSNGWBrokerSendTask.cpp + MQTTSNGWClient.cpp + MQTTSNGWClientRecvTask.cpp + MQTTSNGWClientSendTask.cpp + MQTTSNGWConnectionHandler.cpp + MQTTSNGWLogmonitor.cpp + MQTTSNGWPacket.cpp + MQTTSNGWPacketHandleTask.cpp + MQTTSNGWProcess.cpp + MQTTSNGWPublishHandler.cpp + MQTTSNGWSubscribeHandler.cpp + MQTTSNGWEncapsulatedPacket.cpp + MQTTSNGWForwarder.cpp + MQTTSNGWQoSm1Proxy.cpp + MQTTSNGWAdapter.cpp + MQTTSNGWAggregater.cpp + MQTTSNGWClientList.cpp + MQTTSNGWTopic.cpp + MQTTSNGWAdapterManager.cpp + MQTTSNAggregateConnectionHandler.cpp + MQTTSNGWMessageIdTable.cpp + MQTTSNGWAggregateTopicTable.cpp + ${OS}/${SENSORNET}/SensorNetwork.cpp + ${OS}/${SENSORNET}/SensorNetwork.h + ${OS}/Timer.cpp + ${OS}/Timer.h + ${OS}/Network.cpp + ${OS}/Network.h + ${OS}/Threading.cpp + ${OS}/Threading.h + ) + +include_directories(../../MQTTSNPacket/src) +link_directories("/usr/local/lib") +link_directories("/usr/local/opt/openssl/lib") + + +TARGET_INCLUDE_DIRECTORIES(mqtt-sngateway_common + PUBLIC + . + ${OS} + ${OS}/${SENSORNET} + ) + +TARGET_LINK_LIBRARIES(mqtt-sngateway_common + PRIVATE + MQTTSNPacketClient + MQTTSNPacketServer + pthread + ssl + crypto) + +ADD_EXECUTABLE(MQTT-SNGateway + mainGateway.cpp + ) + +TARGET_LINK_LIBRARIES(MQTT-SNGateway + mqtt-sngateway_common + ) + +ADD_EXECUTABLE(MQTT-SNLogmonitor + mainLogmonitor.cpp + ) + +TARGET_LINK_LIBRARIES(MQTT-SNLogmonitor + mqtt-sngateway_common + ) + +ADD_EXECUTABLE(testPFW + tests/mainTestProcess.cpp + tests/TestProcess.cpp + tests/TestQue.cpp + tests/TestTree23.cpp + tests/TestTopics.cpp + tests/TestTopicIdMap.cpp + tests/TestTask.cpp + ) +TARGET_LINK_LIBRARIES(testPFW + mqtt-sngateway_common + ) + + +ADD_TEST(NAME testPFW + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/.. + COMMAND testPFW -f ./gateway.conf) diff --git a/MQTTSNGateway/src/tests/TestProcess.cpp b/MQTTSNGateway/src/tests/TestProcess.cpp index 56ba0b1..282d2c3 100644 --- a/MQTTSNGateway/src/tests/TestProcess.cpp +++ b/MQTTSNGateway/src/tests/TestProcess.cpp @@ -29,7 +29,6 @@ using namespace std; using namespace MQTTSNGW; -#define ARGV "./Build/testPFW" #define CONFDIR "./" #define CONF "gateway.conf" @@ -63,7 +62,6 @@ void TestProcess::run(void) /* Test command line parameter */ assert(1 == getArgc() || 3 == getArgc() ); - assert(0 == strcmp(ARGV, *getArgv())); getParam("BrokerName", value); assert(0 == strcmp("mqtt.eclipse.org", value)); diff --git a/MQTTSNPacket/src/CMakeLists.txt b/MQTTSNPacket/src/CMakeLists.txt index 3e53996..1992656 100644 --- a/MQTTSNPacket/src/CMakeLists.txt +++ b/MQTTSNPacket/src/CMakeLists.txt @@ -22,3 +22,6 @@ ADD_LIBRARY(MQTTSNPacketClient SHARED MQTTSNConnectClient.c MQTTSNPacket.c MQTTS ADD_LIBRARY(MQTTSNPacketServer SHARED MQTTSNConnectServer.c MQTTSNPacket.c MQTTSNSearchServer.c MQTTSNSubscribeServer.c MQTTSNUnsubscribeServer.c MQTTSNSerializePublish.c MQTTSNDeserializePublish.c) + +TARGET_INCLUDE_DIRECTORIES(MQTTSNPacketClient PUBLIC .) +TARGET_INCLUDE_DIRECTORIES(MQTTSNPacketServer PUBLIC .) \ No newline at end of file From 2bf7985e2b1a1eb3ae3d0e3609d7bc96e0544646 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Fri, 30 Apr 2021 14:55:22 +0900 Subject: [PATCH 06/67] Bugfix cmake related files Signed-off-by: tomoaki --- MQTTSNGateway/src/CMakeLists.txt | 15 ++++++++++----- MQTTSNPacket/samples/CMakeLists.txt | 14 ++++++++------ MQTTSNPacket/samples/build | 7 ------- MQTTSNPacket/src/CMakeLists.txt | 10 +++------- MQTTSNPacket/test/CMakeLists.txt | 6 ++++-- 5 files changed, 25 insertions(+), 27 deletions(-) delete mode 100755 MQTTSNPacket/samples/build diff --git a/MQTTSNGateway/src/CMakeLists.txt b/MQTTSNGateway/src/CMakeLists.txt index 74d8473..788d661 100644 --- a/MQTTSNGateway/src/CMakeLists.txt +++ b/MQTTSNGateway/src/CMakeLists.txt @@ -13,11 +13,17 @@ # Contributors: # a1lu - initial version #*******************************************************************************/ -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ../Build) +PROJECT(mqtt-sn-gateway CXX) + +set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Build) set(CMAKE_CXX_STANDARD 11) SET(OS linux) -SET(SENSORNET udp) + +if(NOT DEFINED SENSORNET) + set(SENSORNET udp) +endif() +message(STATUS "SENSORNET: " ${SENSORNET}) ADD_LIBRARY(mqtt-sngateway_common MQTTGWConnectionHandler.cpp @@ -58,7 +64,6 @@ ADD_LIBRARY(mqtt-sngateway_common ${OS}/Threading.h ) -include_directories(../../MQTTSNPacket/src) link_directories("/usr/local/lib") link_directories("/usr/local/opt/openssl/lib") @@ -68,12 +73,12 @@ TARGET_INCLUDE_DIRECTORIES(mqtt-sngateway_common . ${OS} ${OS}/${SENSORNET} + ../../MQTTSNPacket/src ) TARGET_LINK_LIBRARIES(mqtt-sngateway_common PRIVATE - MQTTSNPacketClient - MQTTSNPacketServer + MQTTSNPacket pthread ssl crypto) diff --git a/MQTTSNPacket/samples/CMakeLists.txt b/MQTTSNPacket/samples/CMakeLists.txt index 99300f9..7be7351 100644 --- a/MQTTSNPacket/samples/CMakeLists.txt +++ b/MQTTSNPacket/samples/CMakeLists.txt @@ -16,6 +16,8 @@ PROJECT(mqtt-sn-samples) +set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Build) + INCLUDE_DIRECTORIES(../src) ADD_EXECUTABLE( @@ -23,39 +25,39 @@ ADD_EXECUTABLE( qos0pub.c transport.c ) -TARGET_LINK_LIBRARIES(qos0pub MQTTSNPacketClient) +TARGET_LINK_LIBRARIES(qos0pub MQTTSNPacket) ADD_EXECUTABLE( qos0pub_register qos0pub_register.c transport.c ) -TARGET_LINK_LIBRARIES(qos0pub_register MQTTSNPacketClient) +TARGET_LINK_LIBRARIES(qos0pub_register MQTTSNPacket) ADD_EXECUTABLE( qos-1pub qos-1pub.c transport.c ) -TARGET_LINK_LIBRARIES(qos-1pub MQTTSNPacketClient) +TARGET_LINK_LIBRARIES(qos-1pub MQTTSNPacket) ADD_EXECUTABLE( qos-1pub_extended qos-1pub_extended.c transport.c ) -TARGET_LINK_LIBRARIES(qos-1pub_extended MQTTSNPacketClient) +TARGET_LINK_LIBRARIES(qos-1pub_extended MQTTSNPacket) ADD_EXECUTABLE( qos1pub qos1pub.c transport.c ) -TARGET_LINK_LIBRARIES(qos1pub MQTTSNPacketClient) +TARGET_LINK_LIBRARIES(qos1pub MQTTSNPacket) ADD_EXECUTABLE( pub0sub1 pub0sub1.c transport.c ) -TARGET_LINK_LIBRARIES(pub0sub1 MQTTSNPacketClient) +TARGET_LINK_LIBRARIES(pub0sub1 MQTTSNPacket) \ No newline at end of file diff --git a/MQTTSNPacket/samples/build b/MQTTSNPacket/samples/build deleted file mode 100755 index a6e4937..0000000 --- a/MQTTSNPacket/samples/build +++ /dev/null @@ -1,7 +0,0 @@ -gcc -Wall -c transport.c -Os -s -gcc -Wall qos0pub.c transport.o -I ../src ../src/MQTTSNSerializePublish.c ../src/MQTTSNPacket.c ../src/MQTTSNConnectClient.c -o qos0pub -Os -s -gcc -Wall qos0pub_register.c transport.o -I ../src ../src/MQTTSNSerializePublish.c ../src/MQTTSNDeserializePublish.c ../src/MQTTSNPacket.c ../src/MQTTSNConnectClient.c -o qos0pub_register -Os -s -gcc -Wall qos-1pub.c transport.o -I ../src ../src/MQTTSNSerializePublish.c ../src/MQTTSNPacket.c -o qos-1pub -Os -s -gcc -Wall qos-1pub_extended.c transport.o -I ../src ../src/MQTTSNSerializePublish.c ../src/MQTTSNPacket.c -o qos-1pub_extended -Os -s -gcc -Wall qos1pub.c transport.o -I ../src ../src/MQTTSNSerializePublish.c ../src/MQTTSNDeserializePublish.c ../src/MQTTSNPacket.c ../src/MQTTSNConnectClient.c -o qos1pub -Os -s -gcc -Wall pub0sub1.c transport.o -I ../src ../src/MQTTSNSerializePublish.c ../src/MQTTSNDeserializePublish.c ../src/MQTTSNPacket.c ../src/MQTTSNConnectClient.c ../src/MQTTSNSubscribeClient.c -o pub0sub1 -Os -s diff --git a/MQTTSNPacket/src/CMakeLists.txt b/MQTTSNPacket/src/CMakeLists.txt index 1992656..cab550f 100644 --- a/MQTTSNPacket/src/CMakeLists.txt +++ b/MQTTSNPacket/src/CMakeLists.txt @@ -17,11 +17,7 @@ PROJECT(mqtt-sn-packet C) -ADD_LIBRARY(MQTTSNPacketClient SHARED MQTTSNConnectClient.c MQTTSNPacket.c MQTTSNSearchClient.c MQTTSNSubscribeClient.c - MQTTSNUnsubscribeClient.c MQTTSNSerializePublish.c MQTTSNDeserializePublish.c) +ADD_LIBRARY(MQTTSNPacket SHARED MQTTSNConnectClient.c MQTTSNPacket.c MQTTSNSearchClient.c MQTTSNSubscribeClient.c + MQTTSNUnsubscribeClient.c MQTTSNSerializePublish.c MQTTSNDeserializePublish.c MQTTSNConnectServer.c MQTTSNPacket.c + MQTTSNSearchServer.c MQTTSNSubscribeServer.c MQTTSNUnsubscribeServer.c MQTTSNSerializePublish.c MQTTSNDeserializePublish.c) -ADD_LIBRARY(MQTTSNPacketServer SHARED MQTTSNConnectServer.c MQTTSNPacket.c MQTTSNSearchServer.c MQTTSNSubscribeServer.c - MQTTSNUnsubscribeServer.c MQTTSNSerializePublish.c MQTTSNDeserializePublish.c) - -TARGET_INCLUDE_DIRECTORIES(MQTTSNPacketClient PUBLIC .) -TARGET_INCLUDE_DIRECTORIES(MQTTSNPacketServer PUBLIC .) \ No newline at end of file diff --git a/MQTTSNPacket/test/CMakeLists.txt b/MQTTSNPacket/test/CMakeLists.txt index f6c98b2..f586b11 100644 --- a/MQTTSNPacket/test/CMakeLists.txt +++ b/MQTTSNPacket/test/CMakeLists.txt @@ -16,6 +16,8 @@ PROJECT(mqtt-sn-tests) +set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Build) + INCLUDE_DIRECTORIES(../src) ADD_EXECUTABLE( @@ -23,7 +25,7 @@ ADD_EXECUTABLE( test1.c ) -TARGET_LINK_LIBRARIES(test1 MQTTSNPacketClient MQTTSNPacketServer) +TARGET_LINK_LIBRARIES(test1 MQTTSNPacket) ADD_TEST(NAME test1 COMMAND test1) @@ -32,4 +34,4 @@ ADD_EXECUTABLE( test2.c ) -TARGET_LINK_LIBRARIES(test2 MQTTSNPacketClient MQTTSNPacketServer) +TARGET_LINK_LIBRARIES(test2 MQTTSNPacket) \ No newline at end of file From 9a84cc9a6a0cea2bccc8fcf58f099438296e0ef5 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Fri, 30 Apr 2021 16:18:14 +0900 Subject: [PATCH 07/67] Bugfix #276 failed Signed-off-by: tomoaki --- .travis.yml | 10 ---------- travis-build.sh | 10 ++++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index ed564b5..029d9d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,16 +16,6 @@ addons: script: - ./travis-build.sh - - - cd MQTTSNGateway - - make SENSORNET="xbee" - - make SENSORNET="udp" - - make SENSORNET="udp6" - - - make test - - - cd GatewayTester - - make notifications: emails: diff --git a/travis-build.sh b/travis-build.sh index 696aa53..4828211 100755 --- a/travis-build.sh +++ b/travis-build.sh @@ -9,3 +9,13 @@ echo "travis build dir $TRAVIS_BUILD_DIR pwd $PWD" cmake .. make ctest -VV --timeout 600 +cmake .. -DSENSORNET=xbee +make MQTT-SNGateway +cmake .. -DSENSORNET=udp6 +make MQTT-SNGateway +cmake .. -DSENSORNET=loralink +make MQTT-SNGateway +make test +cd MQTTSMGateway/GatewayTester +make + From c15d3ac2523ecc6837c4e90df03941215bfe97ac Mon Sep 17 00:00:00 2001 From: tomoaki Date: Fri, 30 Apr 2021 16:28:09 +0900 Subject: [PATCH 08/67] Bugfix of Travis CI Build failed Signed-off-by: tomoaki --- travis-build.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/travis-build.sh b/travis-build.sh index 4828211..fc0f03b 100755 --- a/travis-build.sh +++ b/travis-build.sh @@ -15,7 +15,6 @@ cmake .. -DSENSORNET=udp6 make MQTT-SNGateway cmake .. -DSENSORNET=loralink make MQTT-SNGateway -make test -cd MQTTSMGateway/GatewayTester +cd ../MQTTSMGateway/GatewayTester make From e4ccfe9487346ad452b75b5289ef2b37b79cd69f Mon Sep 17 00:00:00 2001 From: tomoaki Date: Fri, 30 Apr 2021 16:38:53 +0900 Subject: [PATCH 09/67] Bugfix of Travis CI build Signed-off-by: tomoaki --- travis-build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis-build.sh b/travis-build.sh index fc0f03b..6e4bc02 100755 --- a/travis-build.sh +++ b/travis-build.sh @@ -15,6 +15,6 @@ cmake .. -DSENSORNET=udp6 make MQTT-SNGateway cmake .. -DSENSORNET=loralink make MQTT-SNGateway -cd ../MQTTSMGateway/GatewayTester +cd ../MQTTSNGateway/GatewayTester make From 5c7cefdf4859e3fa3496fa420cd5ffd025e986cc Mon Sep 17 00:00:00 2001 From: tomoaki Date: Fri, 30 Apr 2021 19:20:39 +0900 Subject: [PATCH 10/67] Update README Signed-off-by: tomoaki --- .gitignore | 5 +++++ MQTTSNGateway/README.md | 29 +++++++++++------------------ README.md | 2 +- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index ee251ce..d497d0f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,8 @@ /Release/ /Debug/ /core +Build +*.a +CMakeFiles/ +*.cmake +CMakeCache.txt diff --git a/MQTTSNGateway/README.md b/MQTTSNGateway/README.md index c7a791c..3480b95 100644 --- a/MQTTSNGateway/README.md +++ b/MQTTSNGateway/README.md @@ -5,27 +5,21 @@ This Gateway can run as a transparent or aggregating Gateway by specifying the g ### **step1. Build the gateway** ```` -$ git clone -b develop https://github.com/eclipse/paho.mqtt-sn.embedded-c -$ cd paho.mqtt-sn.embedded-c/MQTTSNGateway -$ make [SENSORNET={udp6|xbee|loralink}] -$ make install -$ make clean +$ git clone -b develop https://github.com/eclipse/paho.mqtt-sn.embedded-c +$ cmake .. [-DSENSORNET={udp|udp6|xbee|loralink}] +$ make + ```` By default, a gateway for UDP is built. -In order to create a gateway for UDP6, XBee or LoRaLink, SENSORNET argument is required. +In order to create a gateway for UDP6, XBee or LoRaLink, -DSENSORNET argument is required. -MQTT-SNGateway, MQTT-SNLogmonitor and *.conf files are copied into ../ directory. -If you want to install the gateway into specific directories, enter a command line as follows: -```` -$ make install INSTALL_DIR=/path/to/your_directory CONFIG_DIR=/path/to/your_directory -```` - +MQTT-SNGateway and MQTT-SNLogmonitor (executable programs) are built in the Build directory. ### **step2. Execute the Gateway.** ```` -$ cd ../../ -$ ./MQTT-SNGateway [-f Config file name] + +$ ./Build/MQTT-SNGateway -f ./MQTTSNGateway/gateway.conf ```` If you get the error message as follows: ```` @@ -34,13 +28,12 @@ Aborted (core dumped) ```` You have to start using sudo command only once for the first time. ```` -$ sudo ./MQTT-SNGateway [-f Config file name] +$ sudo ./Build/MQTT-SNGateway -f ./MQTTSNGateway/gateway.conf ```` ### **How to Change the configuration of the gateway** -**../gateway.conf** Contents are follows: +**gateway.conf** Contents are follows: -
    
 
 # config file of MQTT-SN Gateway
 #
@@ -102,7 +95,7 @@ DeviceTxLoRaLink=/dev/ttyLoRaLinkTx
 # 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(). diff --git a/README.md b/README.md index 5a46018..db89200 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ MQTT project, but it's not yet complete. ## Build requirements / compilation -CMake builds for MQTTSNPacket with a Makefile for MQTTSNGateway have been introduced, along with Travis-CI configuration for automated build & testing. +CMake builds have been introduced, along with Travis-CI configuration for automated build & testing. The travis-build.sh file has the full build and test sequence for Linux. From 18af949c7a1aea856e2b70f754ed35b236ede521 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Fri, 30 Apr 2021 19:21:49 +0900 Subject: [PATCH 11/67] Change Execption messages Signed-off-by: tomoaki --- MQTTSNGateway/src/MQTTSNGWProcess.cpp | 4 ++-- MQTTSNGateway/src/mainGateway.cpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/MQTTSNGateway/src/MQTTSNGWProcess.cpp b/MQTTSNGateway/src/MQTTSNGWProcess.cpp index 6db7588..5d16ae4 100644 --- a/MQTTSNGateway/src/MQTTSNGWProcess.cpp +++ b/MQTTSNGateway/src/MQTTSNGWProcess.cpp @@ -164,7 +164,7 @@ int Process::getParam(const char* parameter, char* value) if ((fp = fopen(configPath.c_str(), "r")) == NULL) { - throw Exception("No config file:[" + configPath + "]\n"); + throw Exception("No config file:[" + configPath + "]\n\nUsage: Command -f path/config_file_name\n"); } while (true) @@ -287,7 +287,7 @@ void MultiTaskProcess::run(void) } else if (_stopCount > 0) { - throw Exception(0,"Abort",__FILE__, __func__, __LINE__); + throw Exception("Task stopped !!\n\n"); } sleep(1); } diff --git a/MQTTSNGateway/src/mainGateway.cpp b/MQTTSNGateway/src/mainGateway.cpp index c0b351c..b3c59cb 100644 --- a/MQTTSNGateway/src/mainGateway.cpp +++ b/MQTTSNGateway/src/mainGateway.cpp @@ -42,6 +42,7 @@ int main(int argc, char** argv) catch (Exception &ex) { ex.writeMessage(); + WRITELOG("ABORT Gateway!!!\n\n\n"); abort(); } } From 53433c2b64e82acc686f290a2b3a8d6cdf1a03ab Mon Sep 17 00:00:00 2001 From: tomoaki Date: Fri, 30 Apr 2021 20:36:55 +0900 Subject: [PATCH 12/67] Bugfix of README Signed-off-by: tomoaki --- MQTTSNGateway/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MQTTSNGateway/README.md b/MQTTSNGateway/README.md index 3480b95..138f6ea 100644 --- a/MQTTSNGateway/README.md +++ b/MQTTSNGateway/README.md @@ -34,7 +34,7 @@ $ sudo ./Build/MQTT-SNGateway -f ./MQTTSNGateway/gateway.conf ### **How to Change the configuration of the gateway** **gateway.conf** Contents are follows: - +

 # config file of MQTT-SN Gateway
 #
 
@@ -95,7 +95,7 @@ DeviceTxLoRaLink=/dev/ttyLoRaLinkTx
 # 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(). From 0ad10f9759ccf3fdff36cb98fae99337012d9f26 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Fri, 30 Apr 2021 20:38:23 +0900 Subject: [PATCH 13/67] Update UDP6 Address comment Signed-off-by: tomoaki --- MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp b/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp index 915aef8..a0593f6 100644 --- a/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp +++ b/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp @@ -66,7 +66,7 @@ void SensorNetAddress::setAddress(struct sockaddr_in6 *IpAddr, uint16_t port) /** * convert Text data to SensorNetAddress - * @param data is a IP_Address:PortNo format string + * @param data is a IPV6_Address:PortNo format string * @return success = 0, Invalid format = -1 */ int SensorNetAddress::setAddress(string* data) From 12fc05b19688dbb6ea37461097a3592ec83eb1e8 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Fri, 30 Apr 2021 23:11:37 +0900 Subject: [PATCH 14/67] Bugfix of #231 Signed-off-by: tomoaki --- MQTTSNGateway/gateway.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MQTTSNGateway/gateway.conf b/MQTTSNGateway/gateway.conf index 73f110e..a321b56 100644 --- a/MQTTSNGateway/gateway.conf +++ b/MQTTSNGateway/gateway.conf @@ -35,7 +35,7 @@ PredefinedTopic=NO #RootCAfile=/etc/ssl/certs/ca-certificates.crt #RootCApath=/etc/ssl/certs/ -#CertsFile=/path/to/certKey.pem +#CertsKey=/path/to/certKey.pem #PrivateKey=/path/to/privateKey.pem GatewayID=1 From c4efb6d31c4ce50f755d2b2f086853ba2824ed55 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Fri, 30 Apr 2021 23:29:49 +0900 Subject: [PATCH 15/67] Add MQTT-SN Gateway Overview Signed-off-by: tomoaki --- MQTTSNGateway/Gateway Model Overview.pdf | Bin 0 -> 86964 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 MQTTSNGateway/Gateway Model Overview.pdf diff --git a/MQTTSNGateway/Gateway Model Overview.pdf b/MQTTSNGateway/Gateway Model Overview.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c3aabed38db08de380bb35e60aea1b6f2d15e1d7 GIT binary patch literal 86964 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

%u?_vX&{yJOT_2ZYZFc;^dijly&wv7 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 h&Dq%xIV4YX^k~LbeQ4npn03EdmMo` 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 literal 0 HcmV?d00001 From 8a2d28a5e4b84b4cbd3c0834bfb8a696d8ff84a0 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Sat, 1 May 2021 16:36:01 +0900 Subject: [PATCH 16/67] Add Gateway build script. Signed-off-by: tomoaki --- .gitignore | 4 +++- MQTTSNGateway/README.md | 12 ++++++------ MQTTSNGateway/build.sh | 17 +++++++++++++++++ MQTTSNGateway/src/CMakeLists.txt | 15 ++++++++------- MQTTSNPacket/samples/CMakeLists.txt | 2 -- MQTTSNPacket/test/CMakeLists.txt | 2 -- travis-build.sh | 6 ++++-- 7 files changed, 38 insertions(+), 20 deletions(-) create mode 100755 MQTTSNGateway/build.sh diff --git a/.gitignore b/.gitignore index d497d0f..e0543c1 100644 --- a/.gitignore +++ b/.gitignore @@ -10,8 +10,10 @@ /Release/ /Debug/ /core -Build +Build/ *.a CMakeFiles/ *.cmake CMakeCache.txt +bin/ +/build.gateway/ \ No newline at end of file diff --git a/MQTTSNGateway/README.md b/MQTTSNGateway/README.md index 138f6ea..e592b4c 100644 --- a/MQTTSNGateway/README.md +++ b/MQTTSNGateway/README.md @@ -5,9 +5,9 @@ This Gateway can run as a transparent or aggregating Gateway by specifying the g ### **step1. Build the gateway** ```` -$ git clone -b develop https://github.com/eclipse/paho.mqtt-sn.embedded-c -$ cmake .. [-DSENSORNET={udp|udp6|xbee|loralink}] -$ make +$ git clone -b develop https://github.com/eclipse/paho.mqtt-sn.embedded-c +$ cd paho.mqtt-sn.embedded-c/MQTTSNGateway +$ ./build.sh {udp|udp6|xbee|loralink}] ```` By default, a gateway for UDP is built. @@ -19,7 +19,7 @@ MQTT-SNGateway and MQTT-SNLogmonitor (executable programs) are built in the Buil ```` -$ ./Build/MQTT-SNGateway -f ./MQTTSNGateway/gateway.conf +$ ./bin/MQTT-SNGateway -f gateway.conf ```` If you get the error message as follows: ```` @@ -28,7 +28,7 @@ Aborted (core dumped) ```` You have to start using sudo command only once for the first time. ```` -$ sudo ./Build/MQTT-SNGateway -f ./MQTTSNGateway/gateway.conf +$ sudo ./bin/MQTT-SNGateway -f gateway.conf ```` ### **How to Change the configuration of the gateway** @@ -119,7 +119,7 @@ Restart the gateway with sudo only once to create shared memories. open ssh terminal and execute LogMonitor. -`$ ./MQTT-SNLogmonitor` +`$ ./bin/MQTT-SNLogmonitor` Now you can get the Log on your terminal. diff --git a/MQTTSNGateway/build.sh b/MQTTSNGateway/build.sh new file mode 100755 index 0000000..2895de5 --- /dev/null +++ b/MQTTSNGateway/build.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +if [ $# -eq 0 ]; then + echo "Usage: build.sh { udp | udp6 | xbee | loralink }" +else + echo "Start building MQTT-SN Gateway" + + SCRIPT_DIR=$(cd $(dirname $0); pwd) + cd $SCRIPT_DIR/.. + rm -rf build.gateway + mkdir build.gateway + cd build.gateway + cmake .. -DSENSORNET=$1 + make MQTTSNPacke + make MQTT-SNGateway + make MQTT-SNLogmonitor +fi \ No newline at end of file diff --git a/MQTTSNGateway/src/CMakeLists.txt b/MQTTSNGateway/src/CMakeLists.txt index 788d661..b0540c7 100644 --- a/MQTTSNGateway/src/CMakeLists.txt +++ b/MQTTSNGateway/src/CMakeLists.txt @@ -11,19 +11,20 @@ # http://www.eclipse.org/org/documents/edl-v10.php. # # Contributors: -# a1lu - initial version +# a1lu - initial version +# ty4tw - modify #*******************************************************************************/ PROJECT(mqtt-sn-gateway CXX) -set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Build) -set(CMAKE_CXX_STANDARD 11) +SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../bin) +SET(CMAKE_CXX_STANDARD 11) SET(OS linux) -if(NOT DEFINED SENSORNET) - set(SENSORNET udp) -endif() -message(STATUS "SENSORNET: " ${SENSORNET}) +IF(NOT DEFINED SENSORNET) + SET(SENSORNET udp) +ENDIF() +MESSAGE(STATUS "SENSORNET: " ${SENSORNET}) ADD_LIBRARY(mqtt-sngateway_common MQTTGWConnectionHandler.cpp diff --git a/MQTTSNPacket/samples/CMakeLists.txt b/MQTTSNPacket/samples/CMakeLists.txt index 7be7351..c7fc47b 100644 --- a/MQTTSNPacket/samples/CMakeLists.txt +++ b/MQTTSNPacket/samples/CMakeLists.txt @@ -16,8 +16,6 @@ PROJECT(mqtt-sn-samples) -set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Build) - INCLUDE_DIRECTORIES(../src) ADD_EXECUTABLE( diff --git a/MQTTSNPacket/test/CMakeLists.txt b/MQTTSNPacket/test/CMakeLists.txt index f586b11..4d563b3 100644 --- a/MQTTSNPacket/test/CMakeLists.txt +++ b/MQTTSNPacket/test/CMakeLists.txt @@ -16,8 +16,6 @@ PROJECT(mqtt-sn-tests) -set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Build) - INCLUDE_DIRECTORIES(../src) ADD_EXECUTABLE( diff --git a/travis-build.sh b/travis-build.sh index 6e4bc02..d8907ff 100755 --- a/travis-build.sh +++ b/travis-build.sh @@ -6,15 +6,17 @@ rm -rf build.paho mkdir build.paho cd build.paho echo "travis build dir $TRAVIS_BUILD_DIR pwd $PWD" -cmake .. +cmake .. -DSENSORNET=loralink make ctest -VV --timeout 600 cmake .. -DSENSORNET=xbee make MQTT-SNGateway cmake .. -DSENSORNET=udp6 make MQTT-SNGateway -cmake .. -DSENSORNET=loralink +cmake .. -DSENSORNET=udp make MQTT-SNGateway cd ../MQTTSNGateway/GatewayTester make + + From 4478eafc8d1976ac1a3c1c2bdd8e36205f5d0874 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Mon, 3 May 2021 19:20:52 +0900 Subject: [PATCH 17/67] Bugfix of Exception Handling Signed-off-by: tomoaki --- MQTTSNGateway/README.md | 22 ++++++-------- MQTTSNGateway/build.sh | 2 +- MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp | 2 +- MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp | 2 +- MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp | 2 +- MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp | 2 +- .../src/MQTTSNGWPacketHandleTask.cpp | 2 +- MQTTSNGateway/src/MQTTSNGWProcess.cpp | 30 ++++++++++++++----- MQTTSNGateway/src/MQTTSNGWProcess.h | 4 ++- MQTTSNGateway/src/linux/Threading.h | 4 ++- MQTTSNGateway/src/mainGateway.cpp | 1 - 11 files changed, 43 insertions(+), 30 deletions(-) diff --git a/MQTTSNGateway/README.md b/MQTTSNGateway/README.md index e592b4c..81f249a 100644 --- a/MQTTSNGateway/README.md +++ b/MQTTSNGateway/README.md @@ -1,4 +1,4 @@ -# MQTT-SN Transparent / Aggregating Gateway + MQTT-SN Transparent / Aggregating Gateway **MQTT-SN** requires a MQTT-SN Gateway which acts as a protocol converter to convert **MQTT-SN messages to MQTT messages**. MQTT-SN client over SensorNetwork can not communicate directly with MQTT broker(TCP/IP). This Gateway can run as a transparent or aggregating Gateway by specifying the gateway.conf. @@ -7,11 +7,10 @@ This Gateway can run as a transparent or aggregating Gateway by specifying the g ```` $ git clone -b develop https://github.com/eclipse/paho.mqtt-sn.embedded-c $ cd paho.mqtt-sn.embedded-c/MQTTSNGateway -$ ./build.sh {udp|udp6|xbee|loralink}] +$ ./build.sh {udp|udp6|xbee|loralink} -```` -By default, a gateway for UDP is built. -In order to create a gateway for UDP6, XBee or LoRaLink, -DSENSORNET argument is required. +```` +In order to build a gateway, an argument is required. MQTT-SNGateway and MQTT-SNLogmonitor (executable programs) are built in the Build directory. @@ -19,16 +18,16 @@ MQTT-SNGateway and MQTT-SNLogmonitor (executable programs) are built in the Buil ```` -$ ./bin/MQTT-SNGateway -f gateway.conf +$ ./bin/MQTT-SNGateway ```` If you get the error message as follows: ```` -what(): RingBuffer can't create a shared memory. -Aborted (core dumped) +RingBuffer can't create a shared memory. +ABORT Gateway!!! ```` You have to start using sudo command only once for the first time. ```` -$ sudo ./bin/MQTT-SNGateway -f gateway.conf +$ sudo ./bin/MQTT-SNGateway ```` ### **How to Change the configuration of the gateway** @@ -132,7 +131,4 @@ Uncomment the line 62, 63 in MQTTSNDefines.h then you can get more precise logs. ==================================*/ //#define DEBUG // print out log for debug //#define DEBUG_NWSTACK // print out SensorNetwork log -``` - - - +``` \ No newline at end of file diff --git a/MQTTSNGateway/build.sh b/MQTTSNGateway/build.sh index 2895de5..f56afc1 100755 --- a/MQTTSNGateway/build.sh +++ b/MQTTSNGateway/build.sh @@ -11,7 +11,7 @@ else mkdir build.gateway cd build.gateway cmake .. -DSENSORNET=$1 - make MQTTSNPacke + make MQTTSNPacket make MQTT-SNGateway make MQTT-SNLogmonitor fi \ No newline at end of file diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp index 4138db4..b4a6e59 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp @@ -30,7 +30,7 @@ char* currentDateTime(void); BrokerRecvTask::BrokerRecvTask(Gateway* gateway) { _gateway = gateway; - _gateway->attach((Thread*) this); + Runnable::threadNo =_gateway->attach((Thread*) this); _light = nullptr; setTaskName("BrokerRecvTask"); } diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp index 4f27645..c3b33d4 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp @@ -34,7 +34,7 @@ char* currentDateTime(); BrokerSendTask::BrokerSendTask(Gateway* gateway) { _gateway = gateway; - _gateway->attach((Thread*) this); + Runnable::threadNo =_gateway->attach((Thread*) this); _gwparams = nullptr; _light = nullptr; setTaskName("BrokerSendTask"); diff --git a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp index e9720dd..1fdf3f3 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp @@ -30,7 +30,7 @@ char* currentDateTime(void); ClientRecvTask::ClientRecvTask(Gateway* gateway) { _gateway = gateway; - _gateway->attach((Thread*) this); + Runnable::threadNo =_gateway->attach((Thread*) this); _sensorNetwork = _gateway->getSensorNetwork(); setTaskName("ClientRecvTask"); } diff --git a/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp index 2d2fa97..a247e59 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp @@ -29,7 +29,7 @@ char* currentDateTime(void); ClientSendTask::ClientSendTask(Gateway* gateway) { _gateway = gateway; - _gateway->attach((Thread*) this); + Runnable::threadNo =_gateway->attach((Thread*) this); _sensorNetwork = _gateway->getSensorNetwork(); setTaskName("ClientSendTask"); } diff --git a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp index 6540a87..8ff3687 100644 --- a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp @@ -45,7 +45,7 @@ char* currentDateTime(void); PacketHandleTask::PacketHandleTask(Gateway* gateway) { _gateway = gateway; - _gateway->attach((Thread*) this); + Runnable::threadNo =_gateway->attach((Thread*) this); _mqttConnection = new MQTTGWConnectionHandler(_gateway); _mqttPublish = new MQTTGWPublishHandler(_gateway); _mqttSubscribe = new MQTTGWSubscribeHandler(_gateway); diff --git a/MQTTSNGateway/src/MQTTSNGWProcess.cpp b/MQTTSNGateway/src/MQTTSNGWProcess.cpp index 5d16ae4..96af29c 100644 --- a/MQTTSNGateway/src/MQTTSNGWProcess.cpp +++ b/MQTTSNGateway/src/MQTTSNGWProcess.cpp @@ -13,12 +13,13 @@ * Contributors: * Tomoaki Yamaguchi - initial API and implementation and/or initial documentation **************************************************************************************/ - #include #include #include #include #include +#include +#include #include #include #include @@ -252,13 +253,17 @@ MultiTaskProcess::MultiTaskProcess() theMultiTaskProcess = this; _threadCount = 0; _stopCount = 0; + _abortThreadNo = -1; } MultiTaskProcess::~MultiTaskProcess() { for (int i = 0; i < _threadCount; i++) { - _threadList[i]->stop(); + if ( i != _abortThreadNo) + { + _threadList[i]->stop(); + } } } @@ -281,20 +286,20 @@ void MultiTaskProcess::run(void) while (true) { - if (theProcess->checkSignal() == SIGINT ) + if (theProcess->checkSignal() == SIGINT || _abortThreadNo > -1) { return; } - else if (_stopCount > 0) - { - throw Exception("Task stopped !!\n\n"); - } sleep(1); } } void MultiTaskProcess::waitStop(void) { + /* Let threads exit from Select() */ + pid_t pid = getpid(); + kill(pid, SIGINT); + while (_stopCount < _threadCount) { sleep(1); @@ -309,11 +314,19 @@ void MultiTaskProcess::threadStopped(void) } -void MultiTaskProcess::attach(Thread* thread) +void MultiTaskProcess::abort(int threadNo) { + _abortThreadNo = threadNo; + threadStopped(); +} + +int MultiTaskProcess::attach(Thread* thread) +{ + int indexNo = 0; _mutex.lock(); if (_threadCount < MQTTSNGW_MAX_TASK) { + indexNo = _threadCount; _threadList[_threadCount] = thread; _threadCount++; } @@ -323,6 +336,7 @@ void MultiTaskProcess::attach(Thread* thread) throw Exception("Full of Threads"); } _mutex.unlock(); + return indexNo; } int MultiTaskProcess::getParam(const char* parameter, char* value) diff --git a/MQTTSNGateway/src/MQTTSNGWProcess.h b/MQTTSNGateway/src/MQTTSNGWProcess.h index 723bb72..cad637f 100644 --- a/MQTTSNGateway/src/MQTTSNGWProcess.h +++ b/MQTTSNGateway/src/MQTTSNGWProcess.h @@ -85,13 +85,15 @@ public: void run(void); void waitStop(void); void threadStopped(void); - void attach(Thread* thread); + int attach(Thread* thread); + void abort(int threadNo); private: Thread* _threadList[MQTTSNGW_MAX_TASK]; Mutex _mutex; int _threadCount; int _stopCount; + int _abortThreadNo; }; /*===================================== diff --git a/MQTTSNGateway/src/linux/Threading.h b/MQTTSNGateway/src/linux/Threading.h index 4dbd085..980d025 100644 --- a/MQTTSNGateway/src/linux/Threading.h +++ b/MQTTSNGateway/src/linux/Threading.h @@ -118,6 +118,7 @@ public: Runnable(){} virtual ~Runnable(){} virtual void EXECRUN(){} + int threadNo {0}; }; #define MAGIC_WORD_FOR_THREAD \ @@ -130,9 +131,9 @@ public: void EXECRUN() \ } \ catch ( Exception &ex ) \ { \ - theMultiTaskProcess->threadStopped(); \ WRITELOG("%s catch exception\n", getTaskName()); \ ex.writeMessage(); \ + theMultiTaskProcess->abort(threadNo); \ } \ } @@ -151,6 +152,7 @@ public: void stop(void); const char* getTaskName(void); void setTaskName(const char* name); + void abort(int threadNo); private: static void* _run(void*); pthread_t _threadID; diff --git a/MQTTSNGateway/src/mainGateway.cpp b/MQTTSNGateway/src/mainGateway.cpp index b3c59cb..a995fa7 100644 --- a/MQTTSNGateway/src/mainGateway.cpp +++ b/MQTTSNGateway/src/mainGateway.cpp @@ -43,6 +43,5 @@ int main(int argc, char** argv) { ex.writeMessage(); WRITELOG("ABORT Gateway!!!\n\n\n"); - abort(); } } From 2adc167207a3dbec70313d9b520e62f3a8aac5f2 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 4 May 2021 16:14:39 +0900 Subject: [PATCH 18/67] Refactor Exception handle scheme Signed-off-by: tomoaki --- MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp | 2 +- MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp | 2 +- MQTTSNGateway/src/MQTTSNGWClient.cpp | 2 +- MQTTSNGateway/src/MQTTSNGWClientList.cpp | 8 +- MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp | 4 +- MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp | 2 +- .../src/MQTTSNGWPacketHandleTask.cpp | 2 +- MQTTSNGateway/src/MQTTSNGWProcess.cpp | 88 ++++++++++--------- MQTTSNGateway/src/MQTTSNGWProcess.h | 16 ++-- MQTTSNGateway/src/MQTTSNGateway.cpp | 4 +- MQTTSNGateway/src/MQTTSNGateway.h | 1 + MQTTSNGateway/src/linux/Threading.cpp | 24 ++--- MQTTSNGateway/src/linux/Threading.h | 8 +- MQTTSNGateway/src/linux/udp/SensorNetwork.cpp | 1 + 14 files changed, 85 insertions(+), 79 deletions(-) diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp index b4a6e59..4138db4 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp @@ -30,7 +30,7 @@ char* currentDateTime(void); BrokerRecvTask::BrokerRecvTask(Gateway* gateway) { _gateway = gateway; - Runnable::threadNo =_gateway->attach((Thread*) this); + _gateway->attach((Thread*) this); _light = nullptr; setTaskName("BrokerRecvTask"); } diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp index c3b33d4..4f27645 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp @@ -34,7 +34,7 @@ char* currentDateTime(); BrokerSendTask::BrokerSendTask(Gateway* gateway) { _gateway = gateway; - Runnable::threadNo =_gateway->attach((Thread*) this); + _gateway->attach((Thread*) this); _gwparams = nullptr; _light = nullptr; setTaskName("BrokerSendTask"); diff --git a/MQTTSNGateway/src/MQTTSNGWClient.cpp b/MQTTSNGateway/src/MQTTSNGWClient.cpp index 03244bc..bafb99b 100644 --- a/MQTTSNGateway/src/MQTTSNGWClient.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClient.cpp @@ -544,7 +544,7 @@ void Client::setAdapterType(AdapterType type) _clientType = Ctype_Aggregater; break; default: - throw Exception("Client::setAdapterType(): Invalid Type."); + throw EXCEPTION("Client::setAdapterType(): Invalid Type.", 0); break; } } diff --git a/MQTTSNGateway/src/MQTTSNGWClientList.cpp b/MQTTSNGateway/src/MQTTSNGWClientList.cpp index a1e0dfb..d40c0fc 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientList.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientList.cpp @@ -72,8 +72,8 @@ void ClientList::setClientList(int type) { if (!createList(theGateway->getGWParams()->clientListName, type)) { - throw Exception( - "ClientList::setClientList No client list defined by config file."); + throw EXCEPTION( + "ClientList::setClientList No client list defined by config file.", 0); } } @@ -82,8 +82,8 @@ void ClientList::setPredefinedTopics(bool aggrecate) if (!readPredefinedList(theGateway->getGWParams()->predefinedTopicFileName, aggrecate)) { - throw Exception( - "ClientList::setPredefinedTopics No predefindTopi list defined by config file."); + throw EXCEPTION( + "ClientList::setPredefinedTopics No predefindTopi list defined by config file.",0); } } diff --git a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp index 1fdf3f3..ccf6192 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp @@ -30,7 +30,7 @@ char* currentDateTime(void); ClientRecvTask::ClientRecvTask(Gateway* gateway) { _gateway = gateway; - Runnable::threadNo =_gateway->attach((Thread*) this); + _gateway->attach((Thread*) this); _sensorNetwork = _gateway->getSensorNetwork(); setTaskName("ClientRecvTask"); } @@ -47,7 +47,7 @@ void ClientRecvTask::initialize(int argc, char** argv) { if (_sensorNetwork->initialize() < 0) { - throw Exception(" Can't open the sensor network.\n"); + throw EXCEPTION(" Can't open the sensor network.\n", 0); } } diff --git a/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp index a247e59..2d2fa97 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp @@ -29,7 +29,7 @@ char* currentDateTime(void); ClientSendTask::ClientSendTask(Gateway* gateway) { _gateway = gateway; - Runnable::threadNo =_gateway->attach((Thread*) this); + _gateway->attach((Thread*) this); _sensorNetwork = _gateway->getSensorNetwork(); setTaskName("ClientSendTask"); } diff --git a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp index 8ff3687..6540a87 100644 --- a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp @@ -45,7 +45,7 @@ char* currentDateTime(void); PacketHandleTask::PacketHandleTask(Gateway* gateway) { _gateway = gateway; - Runnable::threadNo =_gateway->attach((Thread*) this); + _gateway->attach((Thread*) this); _mqttConnection = new MQTTGWConnectionHandler(_gateway); _mqttPublish = new MQTTGWPublishHandler(_gateway); _mqttSubscribe = new MQTTGWSubscribeHandler(_gateway); diff --git a/MQTTSNGateway/src/MQTTSNGWProcess.cpp b/MQTTSNGateway/src/MQTTSNGWProcess.cpp index 96af29c..7cded4b 100644 --- a/MQTTSNGateway/src/MQTTSNGWProcess.cpp +++ b/MQTTSNGateway/src/MQTTSNGWProcess.cpp @@ -18,8 +18,6 @@ #include #include #include -#include -#include #include #include #include @@ -165,7 +163,7 @@ int Process::getParam(const char* parameter, char* value) if ((fp = fopen(configPath.c_str(), "r")) == NULL) { - throw Exception("No config file:[" + configPath + "]\n\nUsage: Command -f path/config_file_name\n"); + throw Exception("No config file:\n\nUsage: Command -f path/config_file_name\n", 0); } while (true) @@ -253,17 +251,13 @@ MultiTaskProcess::MultiTaskProcess() theMultiTaskProcess = this; _threadCount = 0; _stopCount = 0; - _abortThreadNo = -1; } MultiTaskProcess::~MultiTaskProcess() { for (int i = 0; i < _threadCount; i++) { - if ( i != _abortThreadNo) - { - _threadList[i]->stop(); - } + _threadList[i]->stop(); } } @@ -286,7 +280,7 @@ void MultiTaskProcess::run(void) while (true) { - if (theProcess->checkSignal() == SIGINT || _abortThreadNo > -1) + if (theProcess->checkSignal() == SIGINT) { return; } @@ -296,10 +290,6 @@ void MultiTaskProcess::run(void) void MultiTaskProcess::waitStop(void) { - /* Let threads exit from Select() */ - pid_t pid = getpid(); - kill(pid, SIGINT); - while (_stopCount < _threadCount) { sleep(1); @@ -314,29 +304,25 @@ void MultiTaskProcess::threadStopped(void) } -void MultiTaskProcess::abort(int threadNo) +void MultiTaskProcess::abort(void) { - _abortThreadNo = threadNo; - threadStopped(); + signalHandler(SIGINT); } -int MultiTaskProcess::attach(Thread* thread) +void MultiTaskProcess::attach(Thread* thread) { - int indexNo = 0; _mutex.lock(); if (_threadCount < MQTTSNGW_MAX_TASK) { - indexNo = _threadCount; _threadList[_threadCount] = thread; _threadCount++; } else { _mutex.unlock(); - throw Exception("Full of Threads"); + throw Exception("The maximum number of threads has been exceeded.", -1); } _mutex.unlock(); - return indexNo; } int MultiTaskProcess::getParam(const char* parameter, char* value) @@ -350,30 +336,20 @@ int MultiTaskProcess::getParam(const char* parameter, char* value) /*===================================== Class Exception ======================================*/ -Exception::Exception(const string& message) +Exception::Exception(const char* message, const int exNo) { - _message = message; - _exNo = 0; - _fileName = nullptr; - _functionName = nullptr; - _line = 0; -} - -Exception::Exception(const int exNo, const string& message) -{ - _message = message; + _message = message; _exNo = exNo; _fileName = nullptr; _functionName = nullptr; _line = 0; } - -Exception::Exception(const int exNo, const string& message, const char* file, +Exception::Exception(const char* message, const int exNo, const char* file, const char* function, const int line) { - _message = message; + _message = message; _exNo = exNo; - _fileName = file; + _fileName = getFileName(file);; _functionName = function; _line = line; } @@ -385,7 +361,7 @@ Exception::~Exception() throw () const char* Exception::what() const throw () { - return _message.c_str(); + return _message; } const char* Exception::getFileName() @@ -410,14 +386,42 @@ const int Exception::getExceptionNo() void Exception::writeMessage() { - if (getExceptionNo() == 0) + if (_fileName == nullptr) { - WRITELOG("%s %s\n", currentDateTime(), what()); + if (_exNo == 0) + { + WRITELOG("%s %s\n", currentDateTime(), _message); + } + else + { + + WRITELOG("%s %s ExNo: %d\n", currentDateTime(), _message, _exNo); + } } else { - WRITELOG("%s:%-6d %s line %-4d %s() : %s\n", currentDateTime(), - getExceptionNo(), getFileName(), getLineNo(), getFunctionName(), - what()); + if (_exNo == 0) + { + WRITELOG("%s %s line %-4d %s() : %s\n", + currentDateTime(), _fileName, _line, _functionName, _message); + } + else + { + WRITELOG("%s %s line %-4d %s() : %s ExNo: %d\n", + currentDateTime(), _fileName, _line, _functionName, _message, _exNo); + } } } + +const char* Exception::getFileName(const char* file) +{ + for ( int len = strlen(file); len > 0; len-- ) + { + if (*(file + len) == '/') + { + return file + len + 1; + } + } + return file; +} + diff --git a/MQTTSNGateway/src/MQTTSNGWProcess.h b/MQTTSNGateway/src/MQTTSNGWProcess.h index cad637f..be69da8 100644 --- a/MQTTSNGateway/src/MQTTSNGWProcess.h +++ b/MQTTSNGateway/src/MQTTSNGWProcess.h @@ -41,6 +41,8 @@ namespace MQTTSNGW #define WRITELOG theProcess->putLog #define CHK_SIGINT (theProcess->checkSignal() == SIGINT) #define UNUSED(x) ((void)(x)) +#define EXCEPTION(...) Exception(__VA_ARGS__, __FILE__, __func__, __LINE__) + /*================================= Class Process ==================================*/ @@ -85,15 +87,14 @@ public: void run(void); void waitStop(void); void threadStopped(void); - int attach(Thread* thread); - void abort(int threadNo); + void attach(Thread* thread); + void abort(void); private: Thread* _threadList[MQTTSNGW_MAX_TASK]; Mutex _mutex; int _threadCount; int _stopCount; - int _abortThreadNo; }; /*===================================== @@ -102,10 +103,8 @@ private: class Exception: public exception { public: - Exception(const string& message); - Exception(const int exNo, const string& message); - Exception(const int exNo, const string& message, const char* file, - const char* func, const int line); + Exception(const char* message, const int exNo); + Exception(const char* message, const int exNo, const char* file, const char* func, int line); virtual ~Exception() throw (); const char* getFileName(); const char* getFunctionName(); @@ -115,8 +114,9 @@ public: void writeMessage(); private: + const char* getFileName(const char* file); int _exNo; - string _message; + const char* _message; const char* _fileName; const char* _functionName; int _line; diff --git a/MQTTSNGateway/src/MQTTSNGateway.cpp b/MQTTSNGateway/src/MQTTSNGateway.cpp index b722a56..81ad403 100644 --- a/MQTTSNGateway/src/MQTTSNGateway.cpp +++ b/MQTTSNGateway/src/MQTTSNGateway.cpp @@ -182,7 +182,7 @@ void Gateway::initialize(int argc, char** argv) if (_params.gatewayId == 0 || _params.gatewayId > 255) { - throw Exception("Gateway::initialize: invalid Gateway Id"); + throw Exception("Gateway::initialize: invalid Gateway Id", 0); } if (getParam("GatewayName", param) == 0) @@ -192,7 +192,7 @@ void Gateway::initialize(int argc, char** argv) if (_params.gatewayName == 0) { - throw Exception("Gateway::initialize: Gateway Name is missing."); + throw Exception("Gateway::initialize: Gateway Name is missing.", 0); } _params.mqttVersion = DEFAULT_MQTT_VERSION; diff --git a/MQTTSNGateway/src/MQTTSNGateway.h b/MQTTSNGateway/src/MQTTSNGateway.h index 10c6c2a..1f6d6de 100644 --- a/MQTTSNGateway/src/MQTTSNGateway.h +++ b/MQTTSNGateway/src/MQTTSNGateway.h @@ -20,6 +20,7 @@ #include "MQTTSNGWProcess.h" #include "MQTTSNPacket.h" #include "MQTTSNGWClient.h" +#include "MQTTSNGWProcess.h" namespace MQTTSNGW { diff --git a/MQTTSNGateway/src/linux/Threading.cpp b/MQTTSNGateway/src/linux/Threading.cpp index d1cb5c8..9fe834e 100644 --- a/MQTTSNGateway/src/linux/Threading.cpp +++ b/MQTTSNGateway/src/linux/Threading.cpp @@ -79,23 +79,23 @@ Mutex::Mutex(const char* fileName) if ((_shmid = shmget(key, sizeof(pthread_mutex_t), IPC_CREAT | 0666)) < 0) { - throw Exception( -1, "Mutex can't create a shared memory."); + throw Exception("Mutex can't create a shared memory.", -1); } _pmutex = (pthread_mutex_t*) shmat(_shmid, NULL, 0); if (_pmutex == (void*) -1) { - throw Exception( -1, "Mutex can't attach shared memory."); + throw Exception("Mutex can't attach shared memory.", -1); } pthread_mutexattr_init(&attr); if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED) != 0) { - throw Exception( -1, "Mutex can't set the process-shared flag"); + throw Exception("Mutex can't set the process-shared flag", -1); } if (pthread_mutex_init(_pmutex, &attr) != 0) { - throw Exception( -1, "Mutex can't initialize."); + throw Exception("Mutex can't initialize.", -1); } } @@ -135,7 +135,7 @@ void Mutex::lock(void) } } catch (char* errmsg) { - throw Exception( -1, "The same thread can't acquire a mutex twice."); + throw Exception("The same thread can't acquire a mutex twice.", -1); } } } @@ -157,7 +157,7 @@ void Mutex::unlock(void) } } catch (char* errmsg) { - throw Exception( -1, "Mutex can't unlock."); + throw Exception("Mutex can't unlock.", -1); } } } @@ -225,12 +225,12 @@ NamedSemaphore::NamedSemaphore(const char* name, unsigned int val) _psem = sem_open(name, O_CREAT, 0666, val); if (_psem == SEM_FAILED) { - throw Exception( -1, "Semaphore can't be created."); + throw Exception("Semaphore can't be created.", -1); } _name = strdup(name); if (_name == NULL) { - throw Exception( -1, "Semaphore can't allocate memories."); + throw Exception("Semaphore can't allocate memories.", -1); } } @@ -298,7 +298,7 @@ RingBuffer::RingBuffer(const char* keyDirectory) } else { - throw Exception(-1, "RingBuffer can't attach shared memory."); + throw Exception("RingBuffer can't attach shared memory.", -1); } } else if ((_shmid = shmget(key, PROCESS_LOG_BUFFER_SIZE, IPC_CREAT | 0666)) != -1) @@ -313,12 +313,12 @@ RingBuffer::RingBuffer(const char* keyDirectory) } else { - throw Exception(-1, "RingBuffer can't create a shared memory."); + throw Exception("RingBuffer can't create a shared memory.", -1); } } else { - throw Exception(-1, "RingBuffer can't create a shared memory."); + throw Exception( "RingBuffer can't create a shared memory.", -1); } _pmx = new Mutex(MQTTSNGW_RB_MUTEX_KEY); @@ -490,7 +490,7 @@ void RingBuffer::reset() } else { - throw Exception(-1, "RingBuffer can't reset. need to clear shared memory."); + throw Exception("RingBuffer can't reset. need to clear shared memory.", -1); } _pmx->unlock(); } diff --git a/MQTTSNGateway/src/linux/Threading.h b/MQTTSNGateway/src/linux/Threading.h index 980d025..7969fdd 100644 --- a/MQTTSNGateway/src/linux/Threading.h +++ b/MQTTSNGateway/src/linux/Threading.h @@ -118,7 +118,6 @@ public: Runnable(){} virtual ~Runnable(){} virtual void EXECRUN(){} - int threadNo {0}; }; #define MAGIC_WORD_FOR_THREAD \ @@ -127,14 +126,15 @@ public: void EXECRUN() \ try \ { \ run(); \ - theMultiTaskProcess->threadStopped(); \ } \ catch ( Exception &ex ) \ { \ - WRITELOG("%s catch exception\n", getTaskName()); \ + WRITELOG("\033[0m\033[0;31m"); \ ex.writeMessage(); \ - theMultiTaskProcess->abort(threadNo); \ + WRITELOG("\033[0m\033[0;37m%s caught an exception and stopped.\n", getTaskName()); \ + theMultiTaskProcess->abort(); \ } \ + theMultiTaskProcess->threadStopped(); \ } /*===================================== diff --git a/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp b/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp index 1b57ff5..e96dca6 100644 --- a/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp +++ b/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp @@ -246,6 +246,7 @@ UDPPort::UDPPort() _disconReq = false; _sockfdUnicast = -1; _sockfdMulticast = -1; + _ttl = 0; } UDPPort::~UDPPort() From 29486503d103e0afcd08eada056f294dddf8bc10 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Wed, 5 May 2021 11:00:32 +0900 Subject: [PATCH 19/67] Set Gateway version by CMakeFile.txt Signed-off-by: tomoaki --- MQTTSNGateway/src/CMakeLists.txt | 9 +++++++++ MQTTSNGateway/src/MQTTSNGWVersion.h.in | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/MQTTSNGateway/src/CMakeLists.txt b/MQTTSNGateway/src/CMakeLists.txt index b0540c7..236c1eb 100644 --- a/MQTTSNGateway/src/CMakeLists.txt +++ b/MQTTSNGateway/src/CMakeLists.txt @@ -16,6 +16,15 @@ #*******************************************************************************/ PROJECT(mqtt-sn-gateway CXX) +SET(GW_VERSION_MAJOR 1) +SET(GW_VERSION_MINOR 5) +SET(GW_VERSION_PATCH 1) + +SET(GATEWAY_VERSION ${GW_VERSION_MAJOR}.${GW_VERSION_MINOR}.${GW_VERSION_PATCH}) +MESSAGE(STATUS "VERSION : ${GATEWAY_VERSION}") + +configure_file( MQTTSNGWVersion.h.in ${CMAKE_CURRENT_SOURCE_DIR}/MQTTSNGWVersion.h ) + SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../bin) SET(CMAKE_CXX_STANDARD 11) diff --git a/MQTTSNGateway/src/MQTTSNGWVersion.h.in b/MQTTSNGateway/src/MQTTSNGWVersion.h.in index 8dab1a0..f012fe7 100644 --- a/MQTTSNGateway/src/MQTTSNGWVersion.h.in +++ b/MQTTSNGateway/src/MQTTSNGWVersion.h.in @@ -17,6 +17,6 @@ #ifndef MQTTSNGWVERSION_H_IN_ #define MQTTSNGWVERSION_H_IN_ -#define PAHO_GATEWAY_VERSION "@GATEWAY_VERSION@" +#define PAHO_GATEWAY_VERSION "@GATEWAY_VERSION@" #endif /* MQTTSNGWVERSION_H_IN_ */ \ No newline at end of file From f631f27c250a8b69fc4b590ad7742e800e97ff5e Mon Sep 17 00:00:00 2001 From: tomoaki Date: Wed, 5 May 2021 15:29:59 +0900 Subject: [PATCH 20/67] Add errno to a Exception property Signed-off-by: tomoaki --- MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp | 5 +--- MQTTSNGateway/src/MQTTSNGWProcess.cpp | 29 +++++++++---------- MQTTSNGateway/src/MQTTSNGWProcess.h | 8 ++--- MQTTSNGateway/src/linux/Threading.h | 6 ++-- .../src/linux/loralink/SensorNetwork.cpp | 13 +++++++-- .../src/linux/loralink/SensorNetwork.h | 2 +- MQTTSNGateway/src/linux/udp/SensorNetwork.cpp | 9 ++++-- MQTTSNGateway/src/linux/udp/SensorNetwork.h | 2 +- .../src/linux/udp6/SensorNetwork.cpp | 9 ++++-- MQTTSNGateway/src/linux/udp6/SensorNetwork.h | 2 +- .../src/linux/xbee/SensorNetwork.cpp | 9 ++++-- MQTTSNGateway/src/linux/xbee/SensorNetwork.h | 2 +- 12 files changed, 57 insertions(+), 39 deletions(-) diff --git a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp index ccf6192..46100fa 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp @@ -45,10 +45,7 @@ ClientRecvTask::~ClientRecvTask() */ void ClientRecvTask::initialize(int argc, char** argv) { - if (_sensorNetwork->initialize() < 0) - { - throw EXCEPTION(" Can't open the sensor network.\n", 0); - } + _sensorNetwork->initialize(); } /* diff --git a/MQTTSNGateway/src/MQTTSNGWProcess.cpp b/MQTTSNGateway/src/MQTTSNGWProcess.cpp index 7cded4b..55bc475 100644 --- a/MQTTSNGateway/src/MQTTSNGWProcess.cpp +++ b/MQTTSNGateway/src/MQTTSNGWProcess.cpp @@ -336,19 +336,19 @@ int MultiTaskProcess::getParam(const char* parameter, char* value) /*===================================== Class Exception ======================================*/ -Exception::Exception(const char* message, const int exNo) +Exception::Exception(const char* message, const int errNo) { _message = message; - _exNo = exNo; + _errNo = errNo; _fileName = nullptr; _functionName = nullptr; _line = 0; } -Exception::Exception(const char* message, const int exNo, const char* file, +Exception::Exception(const char* message, const int errNo, const char* file, const char* function, const int line) { _message = message; - _exNo = exNo; + _errNo = errNo; _fileName = getFileName(file);; _functionName = function; _line = line; @@ -379,36 +379,35 @@ const int Exception::getLineNo() return _line; } -const int Exception::getExceptionNo() +const int Exception::getErrNo() { - return _exNo; + return _errNo; } void Exception::writeMessage() { if (_fileName == nullptr) { - if (_exNo == 0) + if (_errNo == 0) { - WRITELOG("%s %s\n", currentDateTime(), _message); + WRITELOG("%s%s %s%s\n", currentDateTime(), RED_HDR, _message, CLR_HDR); } else { - - WRITELOG("%s %s ExNo: %d\n", currentDateTime(), _message, _exNo); + WRITELOG("%s%s %s.\n errno=%d : %s%s\n", currentDateTime(), RED_HDR,_message, _errNo, strerror(_errNo), CLR_HDR); } } else { - if (_exNo == 0) + if (_errNo == 0) { - WRITELOG("%s %s line %-4d %s() : %s\n", - currentDateTime(), _fileName, _line, _functionName, _message); + WRITELOG("%s%s %s. %s line %-4d %s()%s\n", + currentDateTime(), RED_HDR, _message, _fileName, _line, _functionName, CLR_HDR); } else { - WRITELOG("%s %s line %-4d %s() : %s ExNo: %d\n", - currentDateTime(), _fileName, _line, _functionName, _message, _exNo); + WRITELOG("%s%s %s. %s line %-4d %s()\n errno=%d : %s%s\n", + currentDateTime(), RED_HDR, _message, _fileName, _line, _functionName, _errNo, strerror(_errNo), CLR_HDR); } } } diff --git a/MQTTSNGateway/src/MQTTSNGWProcess.h b/MQTTSNGateway/src/MQTTSNGWProcess.h index be69da8..7827d59 100644 --- a/MQTTSNGateway/src/MQTTSNGWProcess.h +++ b/MQTTSNGateway/src/MQTTSNGWProcess.h @@ -103,19 +103,19 @@ private: class Exception: public exception { public: - Exception(const char* message, const int exNo); - Exception(const char* message, const int exNo, const char* file, const char* func, int line); + Exception(const char* message, const int errNo); + Exception(const char* message, const int errNo, const char* file, const char* func, int line); virtual ~Exception() throw (); const char* getFileName(); const char* getFunctionName(); const int getLineNo(); - const int getExceptionNo(); + const int getErrNo(); virtual const char* what() const throw (); void writeMessage(); private: const char* getFileName(const char* file); - int _exNo; + int _errNo; const char* _message; const char* _fileName; const char* _functionName; diff --git a/MQTTSNGateway/src/linux/Threading.h b/MQTTSNGateway/src/linux/Threading.h index 7969fdd..7a8f985 100644 --- a/MQTTSNGateway/src/linux/Threading.h +++ b/MQTTSNGateway/src/linux/Threading.h @@ -31,6 +31,9 @@ namespace MQTTSNGW #define MQTTSNGW_RB_MUTEX_KEY "rbmutex.key" #define MQTTSNGW_RB_SEMAPHOR_NAME "/rbsemaphor" +#define RED_HDR "\033[0m\033[0;31m" +#define CLR_HDR "\033[0m\033[0;37m" + /*===================================== Class Mutex ====================================*/ @@ -129,9 +132,8 @@ public: void EXECRUN() \ } \ catch ( Exception &ex ) \ { \ - WRITELOG("\033[0m\033[0;31m"); \ ex.writeMessage(); \ - WRITELOG("\033[0m\033[0;37m%s caught an exception and stopped.\n", getTaskName()); \ + WRITELOG("%s%s caught an exception and stopped.%s\n", RED_HDR, getTaskName(), CLR_HDR); \ theMultiTaskProcess->abort(); \ } \ theMultiTaskProcess->threadStopped(); \ diff --git a/MQTTSNGateway/src/linux/loralink/SensorNetwork.cpp b/MQTTSNGateway/src/linux/loralink/SensorNetwork.cpp index 854854c..fc7f8e0 100644 --- a/MQTTSNGateway/src/linux/loralink/SensorNetwork.cpp +++ b/MQTTSNGateway/src/linux/loralink/SensorNetwork.cpp @@ -119,7 +119,7 @@ int SensorNetwork::read(uint8_t* buf, uint16_t bufLen) return LoRaLink::recv(buf, bufLen, &_clientAddr); } -int SensorNetwork::initialize(void) +void SensorNetwork::initialize(void) { char param[MQTTSNGW_PARAM_MAX]; uint32_t baudrate = 115200; @@ -135,15 +135,22 @@ int SensorNetwork::initialize(void) theProcess->getParam("DeviceRxLoRaLink", param); _description += ", SerialRx "; _description += param; + errno = 0; + if ( LoRaLink::open(LORALINK_MODEM_RX, param, baudrate) < 0 ) { - return -1; + throw EXCEPTION("Can't open a LoRaLink", errno); } theProcess->getParam("DeviceTxLoRaLink", param); _description += ", SerialTx "; _description += param; - return LoRaLink::open(LORALINK_MODEM_TX, param, baudrate); + errno = 0; + + if ( LoRaLink::open(LORALINK_MODEM_TX, param, baudrate) < 0 ) + { + throw EXCEPTION("Can't open a LoRaLink", errno); + } } const char* SensorNetwork::getDescription(void) diff --git a/MQTTSNGateway/src/linux/loralink/SensorNetwork.h b/MQTTSNGateway/src/linux/loralink/SensorNetwork.h index 0565ff1..febfeda 100644 --- a/MQTTSNGateway/src/linux/loralink/SensorNetwork.h +++ b/MQTTSNGateway/src/linux/loralink/SensorNetwork.h @@ -173,7 +173,7 @@ public: int unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendto); int broadcast(const uint8_t* payload, uint16_t payloadLength); int read(uint8_t* buf, uint16_t bufLen); - int initialize(void); + void initialize(void); const char* getDescription(void); SensorNetAddress* getSenderAddress(void); diff --git a/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp b/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp index e96dca6..8a27510 100644 --- a/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp +++ b/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp @@ -177,9 +177,8 @@ int SensorNetwork::read(uint8_t* buf, uint16_t bufLen) * Prepare UDP sockets and description of SensorNetwork like * "UDP Multicast 225.1.1.1:1883 Gateway Port 10000". * The description is for a start up prompt. - * @return success = 0, error = -1 */ -int SensorNetwork::initialize(void) +void SensorNetwork::initialize(void) { char param[MQTTSNGW_PARAM_MAX]; uint16_t multicastPortNo = 0; @@ -224,7 +223,11 @@ int SensorNetwork::initialize(void) } /* Prepare UDP sockets */ - return UDPPort::open(ip.c_str(), multicastPortNo, unicastPortNo, ttl); + errno = 0; + if ( UDPPort::open(ip.c_str(), multicastPortNo, unicastPortNo, ttl) < 0 ) + { + throw EXCEPTION("Can't open a UDP", errno); + } } const char* SensorNetwork::getDescription(void) diff --git a/MQTTSNGateway/src/linux/udp/SensorNetwork.h b/MQTTSNGateway/src/linux/udp/SensorNetwork.h index 735a3c5..9fc9ce3 100644 --- a/MQTTSNGateway/src/linux/udp/SensorNetwork.h +++ b/MQTTSNGateway/src/linux/udp/SensorNetwork.h @@ -91,7 +91,7 @@ public: int unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendto); int broadcast(const uint8_t* payload, uint16_t payloadLength); int read(uint8_t* buf, uint16_t bufLen); - int initialize(void); + void initialize(void); const char* getDescription(void); SensorNetAddress* getSenderAddress(void); diff --git a/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp b/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp index a0593f6..85acc2e 100644 --- a/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp +++ b/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp @@ -169,7 +169,7 @@ int SensorNetwork::read(uint8_t* buf, uint16_t bufLen) return UDPPort6::recv(buf, bufLen, &_clientAddr); } -int SensorNetwork::initialize(void) +void SensorNetwork::initialize(void) { char param[MQTTSNGW_PARAM_MAX]; uint16_t unicastPortNo = 0; @@ -209,7 +209,12 @@ int SensorNetwork::initialize(void) _description += param; } - return UDPPort6::open(ip.c_str(), unicastPortNo, broadcast.c_str(), interface.c_str(), hops); + errno = 0; + + if ( UDPPort6::open(ip.c_str(), unicastPortNo, broadcast.c_str(), interface.c_str(), hops) < 0 ) + { + throw EXCEPTION("Can't open a UDP6", errno); + } } const char* SensorNetwork::getDescription(void) diff --git a/MQTTSNGateway/src/linux/udp6/SensorNetwork.h b/MQTTSNGateway/src/linux/udp6/SensorNetwork.h index 0e3ab7e..59be5fa 100644 --- a/MQTTSNGateway/src/linux/udp6/SensorNetwork.h +++ b/MQTTSNGateway/src/linux/udp6/SensorNetwork.h @@ -99,7 +99,7 @@ public: int unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendto); int broadcast(const uint8_t* payload, uint16_t payloadLength); int read(uint8_t* buf, uint16_t bufLen); - int initialize(void); + void initialize(void); const char* getDescription(void); SensorNetAddress* getSenderAddress(void); diff --git a/MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp b/MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp index 502a17d..06bd7f7 100644 --- a/MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp +++ b/MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp @@ -118,7 +118,7 @@ int SensorNetwork::read(uint8_t* buf, uint16_t bufLen) return XBee::recv(buf, bufLen, &_clientAddr); } -int SensorNetwork::initialize(void) +void SensorNetwork::initialize(void) { char param[MQTTSNGW_PARAM_MAX]; uint32_t baudrate = 9600; @@ -145,7 +145,12 @@ int SensorNetwork::initialize(void) _description += ", SerialDevice "; _description += param; - return XBee::open(param, baudrate); + errno =0; + + if ( XBee::open(param, baudrate) < 0 ) + { + throw EXCEPTION("Can't open a XBee", errno); + } } const char* SensorNetwork::getDescription(void) diff --git a/MQTTSNGateway/src/linux/xbee/SensorNetwork.h b/MQTTSNGateway/src/linux/xbee/SensorNetwork.h index 24b8752..52ad29e 100644 --- a/MQTTSNGateway/src/linux/xbee/SensorNetwork.h +++ b/MQTTSNGateway/src/linux/xbee/SensorNetwork.h @@ -126,7 +126,7 @@ public: int unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendto); int broadcast(const uint8_t* payload, uint16_t payloadLength); int read(uint8_t* buf, uint16_t bufLen); - int initialize(void); + void initialize(void); const char* getDescription(void); SensorNetAddress* getSenderAddress(void); From 17cbed659018fc24cdda40365287a4646c84df8a Mon Sep 17 00:00:00 2001 From: tomoaki Date: Fri, 7 May 2021 18:43:12 +0900 Subject: [PATCH 21/67] Disabled build log Signed-off-by: tomoaki --- .cproject | 10 +++------- .settings/language.settings.xml | 4 ++-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/.cproject b/.cproject index bf962d5..f6208d0 100644 --- a/.cproject +++ b/.cproject @@ -37,7 +37,7 @@ - + @@ -301,13 +301,9 @@ - - - - - + - + diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index e5b4485..f8d47a4 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -11,7 +11,7 @@ - + @@ -33,7 +33,7 @@ - + From f933946043288ebf6aa9d73950db824b0aa6c447 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Sat, 8 May 2021 16:45:54 +0900 Subject: [PATCH 22/67] Add mutex keys to a gitignore Signed-off-by: tomoaki --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index e0543c1..9e7e964 100644 --- a/.gitignore +++ b/.gitignore @@ -5,8 +5,8 @@ *.pyc /doc/MQTTSNClient/ /doc/MQTTSNPacket/ -/rbmutex.key -/ringbuffer.key +rbmutex.key +ringbuffer.key /Release/ /Debug/ /core From 4d77386026941a6ddc4a1f261caf7e1286f219bc Mon Sep 17 00:00:00 2001 From: tomoaki Date: Sat, 8 May 2021 17:11:29 +0900 Subject: [PATCH 23/67] Bugfix of #229 Signed-off-by: tomoaki --- .cproject | 2 +- .../src/linux/udp6/SensorNetwork.cpp | 25 +++++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/.cproject b/.cproject index f6208d0..6c81531 100644 --- a/.cproject +++ b/.cproject @@ -133,7 +133,7 @@ - + diff --git a/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp b/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp index 85acc2e..0d78c06 100644 --- a/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp +++ b/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp @@ -376,6 +376,7 @@ int UDPPort6::unicast(const uint8_t* buf, uint32_t length, SensorNetAddress* add hints.ai_family = AF_INET6; // use IPv6 hints.ai_socktype = SOCK_DGRAM; + int err = 0; int port = 0; string portStr; if(addr->getPortNo() != 0) @@ -387,6 +388,8 @@ int UDPPort6::unicast(const uint8_t* buf, uint32_t length, SensorNetAddress* add portStr = to_string(port); } + errno = 0; + if(strlen(_interfaceName) != 0) { strcpy(destStr, addr->getAddress()); @@ -394,22 +397,28 @@ int UDPPort6::unicast(const uint8_t* buf, uint32_t length, SensorNetAddress* add strcat(destStr,_interfaceName); if(IN6_IS_ADDR_LINKLOCAL(&addr->getIpAddress()->sin6_addr)) { - getaddrinfo(destStr, portStr.c_str(), &hints, &res); + err = getaddrinfo(destStr, portStr.c_str(), &hints, &res); } else { - getaddrinfo(addr->getAddress(), portStr.c_str(), &hints, &res); + err = getaddrinfo(addr->getAddress(), portStr.c_str(), &hints, &res); } } else { strcpy(destStr, addr->getAddress()); - getaddrinfo(addr->getAddress(), portStr.c_str(), &hints, &res); + err = getaddrinfo(addr->getAddress(), portStr.c_str(), &hints, &res); + } + + if ( err != 0) + { + WRITELOG("UDP6::broadcast - getaddrinfo: %s",strerror(errno)); + return err; } int status = ::sendto(_sockfdUnicast, buf, length, 0, res->ai_addr, res->ai_addrlen); if (status < 0) { - WRITELOG("errno in UDPPort::unicast(sendto): %d, %s\n",status,strerror(status)); + WRITELOG("errno in UDPPort::unicast(sendto): %d, %s\n",status,strerror(errno)); } return status; @@ -425,7 +434,7 @@ int UDPPort6::broadcast(const uint8_t* buf, uint32_t length) hint.ai_socktype = SOCK_DGRAM; hint.ai_protocol = 0; - + errno = 0; if(strlen(_interfaceName) != 0) { @@ -447,15 +456,15 @@ int UDPPort6::broadcast(const uint8_t* buf, uint32_t length) } if( err != 0 ) { - WRITELOG("UDP6::broadcast - getaddrinfo: %s",strerror(err)); + WRITELOG("UDP6::broadcast - getaddrinfo: %s",strerror(errno)); return err; } err = sendto(_sockfdMulticast, buf, length, 0, info->ai_addr, info->ai_addrlen ); if(err < 0 ) { - WRITELOG("UDP6::broadcast - sendto: %s",strerror(err)); - return errno; + WRITELOG("UDP6::broadcast - sendto: %s",strerror(errno)); + return err; } return 0; From 63b546e2542cd68318630f3da7138a1737973bec Mon Sep 17 00:00:00 2001 From: tomoaki Date: Sat, 8 May 2021 20:53:02 +0900 Subject: [PATCH 24/67] Flush message immediately Signed-off-by: tomoaki --- MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp | 2 +- MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp | 2 +- MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp | 2 +- MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp | 2 +- MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp | 2 +- MQTTSNGateway/src/MQTTSNGateway.cpp | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp index 4138db4..467cd8a 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp @@ -64,7 +64,7 @@ void BrokerRecvTask::run(void) _light->blueLight(false); if (CHK_SIGINT) { - WRITELOG("\n%s %s stopped.", currentDateTime(), getTaskName()); + WRITELOG("%s %s stopped.\n", currentDateTime(), getTaskName()); return; } timeout.tv_sec = 0; diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp index 4f27645..42d5fd0 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp @@ -70,7 +70,7 @@ void BrokerSendTask::run() if (ev->getEventType() == EtStop) { - WRITELOG("\n%s %s stopped.", currentDateTime(), getTaskName()); + WRITELOG("%s %s stopped.\n", currentDateTime(), getTaskName()); delete ev; return; } diff --git a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp index 46100fa..779def3 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp @@ -76,7 +76,7 @@ void ClientRecvTask::run() if (CHK_SIGINT) { - WRITELOG("\n%s %s stopped.", currentDateTime(), getTaskName()); + WRITELOG("%s %s stopped.\n", currentDateTime(), getTaskName()); delete packet; return; } diff --git a/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp index 2d2fa97..4211d5e 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp @@ -51,7 +51,7 @@ void ClientSendTask::run() if (ev->getEventType() == EtStop || _gateway->IsStopping()) { - WRITELOG("\n%s %s stopped.", currentDateTime(), getTaskName()); + WRITELOG("%s %s stopped.\n", currentDateTime(), getTaskName()); delete ev; break; } diff --git a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp index 6540a87..b9726d9 100644 --- a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp @@ -114,7 +114,7 @@ void PacketHandleTask::run() if (ev->getEventType() == EtStop) { - WRITELOG("\n%s %s stopped.", currentDateTime(), getTaskName()); + WRITELOG("%s %s stopped.\n", currentDateTime(), getTaskName()); delete ev; return; } diff --git a/MQTTSNGateway/src/MQTTSNGateway.cpp b/MQTTSNGateway/src/MQTTSNGateway.cpp index 81ad403..2e7b386 100644 --- a/MQTTSNGateway/src/MQTTSNGateway.cpp +++ b/MQTTSNGateway/src/MQTTSNGateway.cpp @@ -317,7 +317,7 @@ void Gateway::run(void) /* Run Tasks until CTRL+C entered or Exception occurred */ MultiTaskProcess::run(); - + WRITELOG("\n"); _stopFlg = true; /* stop Tasks */ @@ -334,7 +334,7 @@ void Gateway::run(void) /* wait until all Task stop */ MultiTaskProcess::waitStop(); - WRITELOG("\n\n%s MQTT-SN Gateway stopped.\n\n", currentDateTime()); + WRITELOG("\n%s MQTT-SN Gateway stopped.\n\n", currentDateTime()); _lightIndicator.allLightOff(); } From 2cf6df41f4c624ee2c709f5253cfac08ed8ce0bc Mon Sep 17 00:00:00 2001 From: tomoaki Date: Mon, 10 May 2021 10:43:17 +0900 Subject: [PATCH 25/67] Add Include path of OpenSSL Signed-off-by: tomoaki --- MQTTSNGateway/src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/MQTTSNGateway/src/CMakeLists.txt b/MQTTSNGateway/src/CMakeLists.txt index 236c1eb..1af71b5 100644 --- a/MQTTSNGateway/src/CMakeLists.txt +++ b/MQTTSNGateway/src/CMakeLists.txt @@ -84,6 +84,7 @@ TARGET_INCLUDE_DIRECTORIES(mqtt-sngateway_common ${OS} ${OS}/${SENSORNET} ../../MQTTSNPacket/src + /usr/local/opt/ssl/include ) TARGET_LINK_LIBRARIES(mqtt-sngateway_common From 9a22c1bd7ee4a0346ff86125e9ffc8d5ed79071e Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 11 May 2021 12:28:04 +0900 Subject: [PATCH 26/67] Change a brokers host name Signed-off-by: tomoaki --- MQTTSNGateway/gateway.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MQTTSNGateway/gateway.conf b/MQTTSNGateway/gateway.conf index a321b56..e13c853 100644 --- a/MQTTSNGateway/gateway.conf +++ b/MQTTSNGateway/gateway.conf @@ -14,7 +14,7 @@ # config file of MQTT-SN Gateway # -BrokerName=mqtt.eclipse.org +BrokerName=mqtt.eclipseprojects.io BrokerPortNo=1883 BrokerSecurePortNo=8883 From dd13618845d0a226a1f294675b6466493f91026e Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 11 May 2021 13:57:22 +0900 Subject: [PATCH 27/67] Add Exception message to Mutex Signed-off-by: tomoaki --- MQTTSNGateway/src/linux/Threading.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MQTTSNGateway/src/linux/Threading.cpp b/MQTTSNGateway/src/linux/Threading.cpp index 9fe834e..4341034 100644 --- a/MQTTSNGateway/src/linux/Threading.cpp +++ b/MQTTSNGateway/src/linux/Threading.cpp @@ -131,11 +131,11 @@ void Mutex::lock(void) { if (pthread_mutex_lock(&_mutex)) { - throw; + throw Exception("Mutex lock error", errno); } } catch (char* errmsg) { - throw Exception("The same thread can't acquire a mutex twice.", -1); + throw Exception("The same thread can't acquire a mutex twice", errno); } } } @@ -153,7 +153,7 @@ void Mutex::unlock(void) { if (pthread_mutex_unlock(&_mutex)) { - throw; + throw Exception("Mutex unlock error", errno); } } catch (char* errmsg) { From 4777252df00601f6019420abf0882ef8ade001f2 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 11 May 2021 13:58:21 +0900 Subject: [PATCH 28/67] Refacter UDP SensorNetwork Signed-off-by: tomoaki --- MQTTSNGateway/src/linux/udp/SensorNetwork.cpp | 16 ++++++++-------- MQTTSNGateway/src/linux/udp/SensorNetwork.h | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp b/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp index 8a27510..eb0d038 100644 --- a/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp +++ b/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp @@ -170,7 +170,7 @@ int SensorNetwork::broadcast(const uint8_t* payload, uint16_t payloadLength) int SensorNetwork::read(uint8_t* buf, uint16_t bufLen) { - return UDPPort::recv(buf, bufLen, &_clientAddr); + return UDPPort::recv(buf, bufLen, &_senderAddr); } /** @@ -237,7 +237,7 @@ const char* SensorNetwork::getDescription(void) SensorNetAddress* SensorNetwork::getSenderAddress(void) { - return &_clientAddr; + return &_senderAddr; } /*========================================= @@ -283,8 +283,8 @@ int UDPPort::open(const char* ipAddress, uint16_t multiPortNo, uint16_t uniPortN } uint32_t ip = inet_addr(ipAddress); - _grpAddr.setAddress(ip, htons(multiPortNo)); - _clientAddr.setAddress(ip, htons(uniPortNo)); + _multicastAddr.setAddress(ip, htons(multiPortNo)); + _unicastAddr.setAddress(ip, htons(uniPortNo)); _ttl = ttl; /*------ Create unicast socket --------*/ @@ -327,7 +327,7 @@ int UDPPort::open(const char* ipAddress, uint16_t multiPortNo, uint16_t uniPortN sockaddr_in addrm; addrm.sin_family = AF_INET; - addrm.sin_port = _grpAddr.getPortNo(); + addrm.sin_port = _multicastAddr.getPortNo(); addrm.sin_addr.s_addr = INADDR_ANY; if (::bind(_sockfdMulticast, (sockaddr*) &addrm, sizeof(addrm)) < 0) @@ -344,7 +344,7 @@ int UDPPort::open(const char* ipAddress, uint16_t multiPortNo, uint16_t uniPortN ip_mreq mreq; mreq.imr_interface.s_addr = INADDR_ANY; - mreq.imr_multiaddr.s_addr = _grpAddr.getIpAddress(); + mreq.imr_multiaddr.s_addr = _multicastAddr.getIpAddress(); if (setsockopt(_sockfdMulticast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { @@ -387,7 +387,7 @@ int UDPPort::unicast(const uint8_t* buf, uint32_t length, SensorNetAddress* addr int UDPPort::broadcast(const uint8_t* buf, uint32_t length) { - return unicast(buf, length, &_grpAddr); + return unicast(buf, length, &_multicastAddr); } int UDPPort::recv(uint8_t* buf, uint16_t len, SensorNetAddress* addr) @@ -420,7 +420,7 @@ int UDPPort::recv(uint8_t* buf, uint16_t len, SensorNetAddress* addr) } else if (FD_ISSET(_sockfdMulticast, &recvfds)) { - rc = recvfrom(_sockfdMulticast, buf, len, 0, &_grpAddr); + rc = recvfrom(_sockfdMulticast, buf, len, 0, &_multicastAddr); } } return rc; diff --git a/MQTTSNGateway/src/linux/udp/SensorNetwork.h b/MQTTSNGateway/src/linux/udp/SensorNetwork.h index 9fc9ce3..9d1aef8 100644 --- a/MQTTSNGateway/src/linux/udp/SensorNetwork.h +++ b/MQTTSNGateway/src/linux/udp/SensorNetwork.h @@ -73,8 +73,8 @@ private: int _sockfdUnicast; int _sockfdMulticast; - SensorNetAddress _grpAddr; - SensorNetAddress _clientAddr; + SensorNetAddress _multicastAddr; + SensorNetAddress _unicastAddr; bool _disconReq; unsigned int _ttl; }; @@ -96,7 +96,7 @@ public: SensorNetAddress* getSenderAddress(void); private: - SensorNetAddress _clientAddr; // Sender's address. not gateway's one. + SensorNetAddress _senderAddr; string _description; }; From fb4958c271f836d62669b90eda0cd8e341278b39 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 11 May 2021 14:40:57 +0900 Subject: [PATCH 29/67] Bugfix of CMakeFile Signed-off-by: tomoaki --- MQTTSNGateway/src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MQTTSNGateway/src/CMakeLists.txt b/MQTTSNGateway/src/CMakeLists.txt index 1af71b5..1a1f4ac 100644 --- a/MQTTSNGateway/src/CMakeLists.txt +++ b/MQTTSNGateway/src/CMakeLists.txt @@ -84,7 +84,7 @@ TARGET_INCLUDE_DIRECTORIES(mqtt-sngateway_common ${OS} ${OS}/${SENSORNET} ../../MQTTSNPacket/src - /usr/local/opt/ssl/include + /usr/local/opt/openssl/include ) TARGET_LINK_LIBRARIES(mqtt-sngateway_common From 5876ab8f3ce99f25b1752eb268284f790506b795 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 11 May 2021 14:41:25 +0900 Subject: [PATCH 30/67] BugFix of #220 Signed-off-by: tomoaki --- MQTTSNGateway/src/linux/Network.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/MQTTSNGateway/src/linux/Network.cpp b/MQTTSNGateway/src/linux/Network.cpp index 842e121..4951f8d 100644 --- a/MQTTSNGateway/src/linux/Network.cpp +++ b/MQTTSNGateway/src/linux/Network.cpp @@ -279,6 +279,7 @@ bool Network::connect(const char* host, const char* port, const char* caPath, co char errmsg[256]; char peer_CN[256]; bool rc; + X509* peer = nullptr; _mutex.lock(); try @@ -385,7 +386,7 @@ bool Network::connect(const char* host, const char* port, const char* caPath, co throw false; } - X509* peer = SSL_get_peer_certificate(_ssl); + peer = SSL_get_peer_certificate(_ssl); X509_NAME_get_text_by_NID(X509_get_subject_name(peer), NID_commonName, peer_CN, 256); char* pos = peer_CN; if ( *pos == '*') @@ -413,7 +414,12 @@ bool Network::connect(const char* host, const char* port, const char* caPath, co { rc = x; } + _mutex.unlock(); + if (peer != nullptr) + { + X509_free(peer); + } return rc; } From e1b000b6f472ecf7af5219f574e5e1f019a0c3f9 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 11 May 2021 15:11:12 +0900 Subject: [PATCH 31/67] Fix of Test error Signed-off-by: tomoaki --- MQTTSNGateway/src/tests/TestProcess.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MQTTSNGateway/src/tests/TestProcess.cpp b/MQTTSNGateway/src/tests/TestProcess.cpp index 282d2c3..9f1a4ea 100644 --- a/MQTTSNGateway/src/tests/TestProcess.cpp +++ b/MQTTSNGateway/src/tests/TestProcess.cpp @@ -63,7 +63,7 @@ void TestProcess::run(void) assert(1 == getArgc() || 3 == getArgc() ); getParam("BrokerName", value); - assert(0 == strcmp("mqtt.eclipse.org", value)); + assert(0 == strcmp("mqtt.eclipseprojects.io", value)); /* Test RingBuffer */ for ( i = 0; i < 1000; i++) From 390f940b4af73bc5688f544f5ec3656003842eba Mon Sep 17 00:00:00 2001 From: tomoaki Date: Thu, 13 May 2021 10:37:56 +0900 Subject: [PATCH 32/67] Update BrokerName Signed-off-by: tomoaki --- MQTTSNGateway/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MQTTSNGateway/README.md b/MQTTSNGateway/README.md index 81f249a..9d40bf6 100644 --- a/MQTTSNGateway/README.md +++ b/MQTTSNGateway/README.md @@ -37,7 +37,7 @@ $ sudo ./bin/MQTT-SNGateway # config file of MQTT-SN Gateway # -BrokerName=mqtt.eclipse.org +BrokerName=mqtt.eclipseprojects.io BrokerPortNo=1883 BrokerSecurePortNo=8883 From ceaa3ab592884f5865028e866c9f04032fd7d164 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Thu, 13 May 2021 12:56:06 +0900 Subject: [PATCH 33/67] Add Exception Handling scheme explanation. #173 Signed-off-by: tomoaki --- MQTTSNGateway/Gateway Model Overview.pdf | Bin 86964 -> 0 bytes MQTTSNGateway/Gateway Overview.pdf | Bin 0 -> 117278 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 MQTTSNGateway/Gateway Model Overview.pdf create mode 100644 MQTTSNGateway/Gateway Overview.pdf diff --git a/MQTTSNGateway/Gateway Model Overview.pdf b/MQTTSNGateway/Gateway Model Overview.pdf deleted file mode 100644 index c3aabed38db08de380bb35e60aea1b6f2d15e1d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 86964 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

%u?_vX&{yJOT_2ZYZFc;^dijly&wv7 zSjV1%>0OdqnkR+-nQS$iwl>#cA?UDwcgcUtRHZfI-qG4!V9K!bbi~M@uRj?k!5iLs z;47i2VbUQhxkM`XjwBOxHHs4l<-)u_ZEl9tQHV#-)}#}2o9voF1B>AU7L&Sh8y)fv z*cVK`9D0CNS6J?1X(oB427LwhBefDq^01hKH&?_|n#ER_xb4%$s8>zQN~=a!SN%TZ z8AS2L^}+z#7#KLTy<059$Mw>qow^8%oM#wbRa=1tRDJxW>M#LT@&m#D3Ae88I~YzC zkh?7fA34|%V*MB*>!n#f-IFR5{v=S7S`X5I=D%;wh797mwC-CxPXYrbNfV8Y63;Uxgl4df%_D=!eAHg zRv_sc%;n`YWDUIGGut{YXAf_AVxLAst~qLgZ-}+%SI0PR}AFs?Cmvj zz`r`rHPX|c!$i0n;VlmWi9ve<$OrE5Kv6xmE8`yUyhm{|J#OiD=M9S#W z^-hQQpJV-DhG5l4%FVpMsjFsqYG7rnlfivT%(DSaHzteYBbAZEd-zto-+<&}H4v2x zquFHe9~P#QVE1cpbq-J4B7oN0p++Z7kdw$yI!<30S z?Q-3!89?mBEE&n4uT0Wr=|5n8yXN;4p#etFvKHn-wi%K%MP>zrBA=3GxZZ8EJ*)}Gq}C9PQ!9IkIuQw%+wAkxc1f2DAruM`gyEx z2_!Dix)4-vV{pHwy~0vvb-&2`bSZ`6%f&JEha&d>1Y)c5C$iLsZ@~rRKm_`{g#TTE z!eIm>yu(~k+@37>dm@Ym2oC<=ZwUIt_e1@UgZN}_k|3U-zH2S`hpN?vt1(lP|8ZZ? zmqQ$(FSzS+*@t%P@5yh`F*w<6=uPD0^D6Px7zx$&)xRB?&fOdu4C@G}d2 z!Od!kPd<9Q5!45jhaD{j!R`x^|0>rA0BL;hKe(6OUK;_|3|(c2y=$V#qTmCEBHi59 zi?Dv0dtr^v!qm9#pFoQ`8{O=CEEU+dtQ3ni&7>6bBb@yh6TF_X;kefnf!5+VJe3Lo zZ#fiiGXpu*M*q&o~`%x5yJJosE68fjNp)xMzi?8y_)z3nq0Y~2OS$E_{s z5@b{Ln~JomXAQZ^N%O_}%J2#0H#P|1@^(eG@=PVrX4*8xM!`hy<;6t}PfRe+{oC2z zEiEuBkA%UJ-bm8X_m+amfn{5kasL=cbF16V$0{YtBXB*AYmx}-LVwcIqDFhQok)O3 zy6Xg2dg-5A#29BcE$FSqzE6jlOqfKFUM0HkVEJl~jZl&{M(gQ0aN~1_^HVK^+a7OJ z5Q#&Hp-W|Y39);h(B$}>7ix65E~B=^)W6Oj&BK!&5E}38+`Q_+MCj~2P){ce4wMED z>b0Fq&?NU}K5}_bV&c}?{(F51wG3=Y;}58ch&{Nv0SwbAua@pHj3&7+`R^6qI)u3J zw0z22jz(;8${dw*%3suYwwq|usMELpBj>;Fi~In}wXfGGOtk2QZm3G{{s@u3>{bf| z7_C)K%A-qL)@=-b+g~}#4=8>@WK~K^|FD7h%xxf`yXx~i40)lGu{;^I>A7w3sn;v$V+H45r z3iSxE|NZKP%y%v`*D=x8GctupXwrdj(yaPfW9OgoNY9zu6_xR4odJYEUOwv#7lOg1 zrh^0bfjhEjDy4svj4lUYT(pkmBsY5o-*Mw|0*6RZ;R7p{6GRhsah97q1I?t2sAu^- z)ll>D^Zt(T$~nZ&rW60717)yfIWKdxgC*O^$fuuEw|Jpr!d9LoX8k}dHeS9^x5ntl z9uvo7oue;WtK!WjAN>xi6!=Pj|JRX$JcN25uDH?onvNOck#dM}}k! z^g7q5hwMEH8Othc?^But$V<3iUgKT51!wh$H>PvlZjTeso@OUT$lh&1Ut4*wHS4{8 zZxyC_u(n>6aojn|UZ|{|E?C9lJvZF#CF3#AL0|pba=ntf;MR>DaN;)$VwUi1c9` zjc6S60F4xwpXuw3U(Ps!pBI?(Y3jmU&j zXr})u9ItPZl}+}gd%#yjiZ2}%H@azCm%*46S!eovq#m&1{~t&HaVZzQl9S(2sBhQ6 z?>lw#e+}8+t$;1}`qTM+TRy)WO^hrohJQlV4%<35(UOwdT-R4@&zuc)Me$jIwd%XOtUQVsc`VGU^qq4 zJv;CCn8S@?fqoo-vO2du-j_!a6xs2mchn<(x}aG73O_u@@73J0YY_|=WpZtr*TYanjYntMFrS->8PqpACd4*tIw`wFN!nkH?W5Zv9}-8~T8AxLnC;O_43 z?jGFTEs)^u5ZvAE@?Y}FySv}JXa94cXYR~&cXf~Sd8(eO(v`kqB8V=vv^=PWXLBa_ z`A>F1WuzCqJCv-QyF>qdpk-@{!i&ZFI)t){S?{{{6UbV{x8Gh>Htp5OX+K7Z-5jbm zOU316zCTb4k9*Ice9}!>dJ|E6c9IV_Cb2SJO`=0s)NHgVD`)3Q!x50iqnODzjXCU)V%yHv&-%zXM86&gj>ZFl+iL`)fu%ei3p z@sxa&bEwEAPuH>UnEUG|Q*?9q2aj1gn}?X$Ln*FkgRWMnJ2G2)NI|wZ9-|bkApi#E44^Gst@@aA{||( zcH1Qb9}q>SvV02qtW@Lv#dS#DA*yEwTA>cO#C|_j;_lMT_@Zzgt}CnvV>{_Xkzs1$ zO#%kx2Q`bH2(yT}U-zFLBf#CS%%9brP$sTgat1M>z07685{^c2`|0l|S~*~wVCfLM zE-cP^JLx_`UM)8^oix@;%0$O>Uf&NeWpA>msb<<3ff*BA`|gC^jva&wx3pJj`o(Tr zIC+Jjs%=drm|7WSX4h1nhvd&&tUKnz`q8$%Al`+7XE)Qd6Rl?rsAw&iRf)$*u3KE$ zldd6ETzu{h369x+p>AeU(|S19sDDCh*|czE-WdOi72OCSMWY4_Rl(@FKeqv#!B`mvzgs zaWPBU@=O4rezRrZ5f}RX!TzmoyU(u8dlWPoEm1`^d1r-Nc;bSq;&TXwG{P^`J8SbP zVlFE#a|zM{+r~x z+Z_I|tfzP1B5T(1W%!c4FL_v!V6)>*R$Hmt;@fKwv|y7trE}?HF+*j*maq7Oc??@+ z2)+0HpU+)f_KVw4W7h+CdgRqPs{BjK^?Kk}Yl)Iue=7;5=s*UCAb;MgaK`!@NZfO8 zuF@^1yR_)Q1mM^=187_TKWB zre*h>a=w&sFOD(k>uchzrv|l$P!%40&!~1;Z#Yo?CkLW)qqg*;CD0*-B5W0{jgWPSHqDcnw=+TyN5_@Qbp113=(F&FPREQ z;465FE=5mnVVghE zO}|ej7&l4#|G0tQospcG3imRliz0f&oJE{FPek@vfjg4UnsvCn{QY3bi2$GVP1ons zj`1W3#8wc?(kM1FDb3t%j`9MI*dBIfJ!@Bo9+Eh z`4BE-a>$_JhI4qe{8rV$%NjAwPsb-KQ#|MG!M)P!yTD4ABHK?zn)l*Gm8RHglEgJ7 znT#;G@t9Vpmwjs@+Qxp5`gDMbTIF;z@oj~E20>bI<#Xio(<+&cp&!RHg+)T)R6PRyRc33xX}l(YgJv?a~Q+cu0#b z@%O5Dj=xK_C?fV&w{im_ABvxb>x@?}MZ zih`R82!$8C)+p%~G{HbXN}y*ZK(8dcC)F~nRu>}otEDC+F%-iPB18n=aT$Kk=!9Qa z+0N&gF5e{!VW2!;?0gpDgxnfJnOc$v5hTr%Mx^@uJsq>zjD=+t+9(31Ce-&kXGH5NJZ`Vf_@b z++H6ptxABmo{k0~Jb(ZUCNF-Y6+9Faqz7(~6gWb*4}+9+vm2+KtKX&nK_r(R zX}@_6k{SRqR`E#<-y4Cdm(L&QMqUK=Zb zcgsG1w0B?REcb43tImQB>W~Gh@<$m1Tx*TJvP{tm$=520LeOu!JDP)U@09Cm6bfho z_dfjcn;mv4>RUAmhbr0UGl_#^0!Y`d0TMCvglFA&a@r@1U)4un@J9RWUS>VOD?=s= zPP4@D^qPO)Y!5cmNKIJAT){?a6Pm0(!(4xA%BJele5~0z>fI5lv-5&PzSQh){H^jj z@^f6ey{?WU#I7V*by(}mdMPeCdeQzzRgZqNku*_6sU@@mi>LTU3zq5m4=}DMj3(0g zTHRm+-(Ezk59re_NesnNCO)pk>I2Z#WBE~CfDV~i0*a7()J?|J5B@d&7L8U}w+qeC z%t)FG+hInB^PNLBQLhWfK2`Oe*C<&gqDk~+c{n)1 zDC-m62gfD9J+`LtP%*+!W65#~#%e7lagN8FlZ};Wst@*ItEv#2bE7w2* zrzdZ#>x-S8k*24kvg0%ok$tedvT-L_K1SZy1P%3N?kNxE;DCP8lO3F~0x}GeUpDEP zmdj^B7xRJyrE(a*Yqmll!VrIm+YGYaEcdOc^D`@9^k>#9n=4{V=3xR3&wT)|-7gO3 zudt>gZGijZw=YRTqjBv`a4W|prOL;aW{PbYHqq46J`f$#s@*+GD7IMFhoWO zKZg6W(zA2MRRJFidVR$6VLNzqrdLz5ng1o`L1MFGnG!aUKuJaA@NFfNXlg%8RQkbL z{4fif(g=AFl79R4kabAs`@dW?<>vF>Stn3HEI-4yV#ueyiah{2^uPH_vRbm5(o`ed zWy9wP6#S~w1chy$?L6VZDC-WUp+3PXmt8pIKyl71H_u_@tg;j;z-~eBhhJQq^bzBwiu(%iBI#7^rF5%MeP3L_g+*6w z?%Q(LPV?k>ax4+ufYKY9e|t#rU?#&|m_V)yVBjx)eU6!!=D(Gf%r{#&@Oixq{z^zm ze{hB9vv9@{#iZbQ-w?H6y_eejg{bxoF!eAOTwklwYgnS=d0`PL8$ceBa!a|5++0KTdz5kMvGxg?KPoBzCs$nvPt505*d&6RjSN} z|8X&+L|n~66n*I)N|bIODJjGAe4<`{EeJxAecS38EEiJp!e%fL$Rr7*TLl;u?*3Mp zbAYnz@vyN;H>18FKh`~3F8}}b?R4s9|DwIBoRFcmOVA5eVFr`W2;0m z#wkYC3S%${@je^2w%piE8xN`pXX3hOfaAr6_2n1|q-wF)mJ&O4gTJIH!B(_&`3aLPfN{Xl=fOGlIkXSj&!4wG^GoS43XL;Tg z9CDUSTw%(MJWf0M&ZIK`av7Z9E230FjvKR)Cf@h5t-L&gBIf!kBNv-EPHeG^(nolF zM2mJpvQ~$9+V*d>yf{rBy$%ENNT*iVR;`M>t4=J5W@=*I4tBX>Yfm%s;6EhUg6p;> ze6pIkkUE>$UvEnQ;3U@u^17P$3*GaBIGVCmDtTlIGVJW=L~jA7hI5j9^>XE1P(=fh zw@!hZ$2Ow&^hBU)cxNnejpe7Xcpca=XDJ=S@Zfv0WL;swSE5RwWi66c|$Y}~b=dT8AW z0S@&5#i*ml6`a}M!1(EO6Cba2RD`Uo^CWT{@vILYp7)>a()xlkfQi(C=0d{LVoW_Dpag%)j-f`2X) z#K}1*>rm90;a*fy1R6=_T}i?%EIWF2G6>~mJRNaoMLJFq#=7)c-DD!d!GzDzqrQNP}V)gti8xxrJ9%s9~VknDCWnrVcM?IX*IEq z=gq?Kg(XuS6gj|1bjaKHk4%{nvW1i?-n@@iU+UVm;U9veV*m@0(QS|J`?3)NkQzFR zWnK+)9(OE?VymZNKl7?dCGW^?n}M(dlo;maa~Ig60l)wBl+8h_QtAHQ;Qvyw zqX&vU@j)x4-7CPz9iKOP4-=!^dW@zB(eNn_`jP|%sKBOKMA;olrTOHVoTI)IEjNQ| zrWH3DVcfB<`ch;1t+B~GWuW3^5d%8#2p8wTq6t1kXj@XmOLilu;8}9F%S06mV?lm5 zf;eg^wTqdW!&kNrU9inpqs@B%avQqtiw+wft-)~|YMSuqp(^|UMzx&mS|Zkwq(ftx z9H+UfM2i7VYmB)h44g;Bvh%}9+IIUqq&ivBj;?~BO1H8JM-bVqmKPtFz)F;eND6d? zAn_H;jTBNS<}V{w(}otLq@$;aQVaNc7`XBIw>TdXTxN7RJc}f=wWXQ??QH*2dBs;m z7x^yt4n@7@h{L`jakWZ4Z>$JGiz&>1yFuKk9k*%YCy1!2NV~>mD+4uTJK4@^tla9l z-nYN9C{D|xmE%sDd74B}_jMRN7I_4wV!3BzG35=Euq{7gXHHnR5fk86yEJEMjAbm` zePnTRQq$Ru$v~JLBmj5;`U&%mtefUpdvr8$y5?3x3%W0>VuK`Os@N(77M8Wscl4=M zLy79`@}FB0`MMLiAjgRj4!lf$E)-#&EM?bg?2dS@6m+4*-16R^{FMKQ*)gOUegY}K z%c9ZnxK72gmBO%Q%VD(UjOcQQN1HY52U*0);)&_R8AW>7`$u8$?N(CQS-0E81I|Y> zg|Gw}x`%Gm3njVG2Be3(_J2m7Awz;LF-n&2i@yfOy`h{3eksSK;xkt|moeoD_$@v2 z4!g4Gja$I%Y^5q5$>^vzfT3o9?ofY)n#pq*s`%Yc-+%k~X-f&?onER=#pH>S9R1!K z5Gv=2rQFtMs18qx5lqeHyCje1dmZrzNv`PMSVwcndA z--jkW#R>8|GZjb!`DYZ58#!HwHr=O6Os{6n3uIHI5SP9QQ1lSpVAHd24de(wKfXl) zn1`Z2b0Fi50H?YYuvwL#OI@O2e=&s+RdvA|z}123jbPTi<+B!(R=eL<%%x{JTz8b9 z2lQxy0?9;$16p|h5nzIB=Gm&qBZGbJP-mP7;XE)0yqF8l?YQZtX}AlvZsmtt!6LbLhku}=p{%%Hl|*$OirN7 z>ieL$Lb!T>ToM%4e;L^Fb+BKi+1!DZ@Q-BRgl=ndy( zAt08vAYAl74Nfdk*U9Jl-U&Z4sm`?(H=WPKbY6Bu;$%$#h1oZCQ4d-eA{Nf)^X}ta zNy@hAG`oBMy6NvW9z75sH3Y#I6oJ{InS3qxg3-*QK!Sp5X0di2+X-llXduOE7 z`u6~WWYgQ=7=iB}xU|-j{O171<{iA1r<;)c-d^=u#UU-~-m)tnDx4SL3BetspR)Vb zM2YaS#kTxom=M9({A9LH1q_9~x;{s=cskye7a>5SSM2FIi|5h1>Ad*E@%Tq<4pVyS zQTUhu4w|WUDc$pS>vkjEs2tleQ_xHdknxZrpmW}?tp!j+H(GNJqF+T%INd~Go4z|! z{L!K!spRNaKqPdEf?NBOBeA$mrb=Pf;(W13GyOD`-G}^+Sf}$x<{Q$D^UgQ2dryLu zn)E3KyP5}v?GkUQBWt;JC$h&&!6SffjigyY#_wNy)}^powB&8E2W5t5FGT0~PAF;S z9@Ms9LAZ#4^gJT(lg4$wUs=6cG)tU^S`n({R)RPOo?93BZl~Xv*^IM&AqM%UzAP3i zFk;9UGb?8wR4rwZXIIsz4&j}kg)D6tKO_RJsRY3ikwC@cMMytoBFCNh_NuGqv600~ zm_&>18qPKv$ocnCQA{f9%SPb2nps> ztevQb$1Kl2sZ%bK{KwTlWHTzpb@AxBMs7+$is$4tdXu)3buh6AMHBE*+^6*XyBD0b zNBm&n@Jb&S+s7lFB?p5mGHsu<|E2N&U;|S(7v)X`xjDiN|fUgA|Ah$Aq zIkjd|@srFmUD1?>jL$M{0xRf??_XelQ@DA_&hefh!Ba`x;HuePENdMQZYmR28_OA1 z$WRTe>$-rRwbW-`Bh(_cx(a>dY+PR7@BrQ77N#kWDsFajIraYV6CIt%5Cp&oqlcRYav@3G7rZUete8P)XwZN2mP%D zjGy;AjO=k8C#tDnZ~c|>b-8NGwM)4&b^sVpV(4pqm9=}%W>1cBo_R!#hM2H96d_Ru4$H zLndq+U$r4<2F1rwpL@k|lP4GpM(=9lnqc?{=sq4GsrR!Ly&VxYmqO zpuf$|fyzGOAbh*3Y229(`!=Rf8on3G1wn9r(v9;Tc~8BrMM(sK&r2tHE370?J`5bl z78H>M#*=S@<#x6CDc5?XbsuVoTYYi1awMK(Ji#{v3?@j2|9wjvp7G4)+E*Ww)vl-A z#;f9x2U(_MD6=(jOER9&W?{D2gQt!bb+58*k$wF+wnxtNkaj0j!WC zXPn@~iK7W0rIFQ-yN<|PmMS}iDIGgs_31VFAL%a7Af(11zh8R4eU=I1LlN%d@0fRQjt8n@NNgD!g`XesqU2U1sg_=SC4M++>c`Qbe|w zi}i%Qv|W7nFB_@c~a}@o|iS= zWkHssXi|iE_E?7%4{{_-kDg$NI&{~f?e99j@b<7v-Lz#XV#fm4-0?#nvp=q?+}3(Sunqp zHQ^JlF`{Gg?U7L23&_VHO$jEU;4g<}f$Z{qV*PZRO^$pNtJ_s_`66mva?MVyZHq(q z9SpaLKbK5@G*?U&*b!ffWnJ?Tzz6kQsXEr6yFpi6^ghM9IfvmmD1H`wnf1QvkSot5 zH6@fC0iIV|qON12Y|3YS{?tQ!3r@?xEh~hlA|xb39^DdvPSVmR@`VzWNH5lgU|zb_ zn|3^7XOOg})Zy|7LH{rqnKa+EMk!a{1h?jgXiQ9$uexGPa$cwR2B?Ll;2?BR}HMq$0+Kz z{Yu}d+7EAq=(!Wvea5t+wbeMDmcwzT=H&+^YYpa0r-k(o)POiV6&wu6B`70k1^LtvI|Le^hQRRw7aX#!HO8 zP-z@ncsDJig`P;Wvwkl@1EANZh1p(OQ!badUzeKiSmm)kE#&c>6C zV4p6c7sU9{ug-$5dG{`B3-GcK(^Bqd^^3b^Ezjv-iK)T__BB=&W*)rmC%q~lWNt0c z(SBv~RQgklkXJBHK8H8D_Q?$>5h;Q}pT$biAxP1I`ZGb4GsD0~aFK2o!X58Ba3wNX zeHa?783-J+&he){pS%bDioqo|y#AF@NH_aTo)pBu~b|c%> z*22XEe!Z(fewJ*M(6725+7!B}wN&4RN@hJ?+-@xEf;byee5?2_n?;*4j%%U0`K9q1 zb!akr`6c&SE!tjyy~%A7`i5f&yQLniBn0#X-fjnkfn1=sz-M89vwXV`*pKHpw>yXE zw{ME3NW}%~Z`Wy3#n~NM&nC4g;aG=p!0o*muUz2Zam4Arn z{|bn<(GdAElzdv}Q+L3eZJ8n)|I@%pA5MmgmHUIwR)!RF5)CpoGrGN@qifQkm|uA@ ztc7E_4FZ|A!vt0hCb$YSFNbRti$nD6lLVo+tX8;?keWE4VLdnio-oZ zdOO}%hdNB|pOgR;Kvd`A)zwl45NTz6##eXf29c(etopmR_g~4bxH#DUdV4wkb9H%NY5%Xcw^Ktp zW|af33;6Ef>6PSXV=yt*)W?9e7HQ{(%nGk^6LeY9!}u%hnHq5ljIj6v;j- zeRc4^)4Z0qSjKgzv-)+0wh{{--3?fJxvP3@_e%zJ0p_rtCcD@mr1-q8jYm5s0+4Wq z7beC^T<9_Z3Vpk!cG#EMdh$LEg8cbr8v4t>A&>%@eHK`460W|=7*Mou zgcCn*&w!z;eGDh|3|Jh!_*N!2e7Q3M1z%3aIWjc!d+s<7BVDU)JzyudJr*_wSoM)S z@=9!1c)b&zHgeW&zU}b@$j^_$rwgB)V#iDVCT;9xAZ$dn(&1J(tGRz1CvME19LGtQsd z@{k}xV0FI*CXdcEDt|3anOL%A^V?u%F4kRuf@?7_up#?>My0}6dazi1U&x4qN@cD% znW~uyGcM(>60pJY(aVBs_MrC}a|-Ujz1E+fSNhlbxdl{FHriMqu1h;$e!`;rjdGrQ za(BCnvV60}Frk)yn8GEo>0!((2aNJ-T~<-&FT{QE>rgxIN9f>zj4b0|%vp)I~UhKB7*C)>K6AKNq?O%my|fP1(fHu-QEnia!+ z{=F52HdM*4@MLg}*0is%#-BYRE;S})VB8zhAfJrro$I~}7#SFToHGs2jz(*mZIq|} zELVtEyObf*W&jzt3V9c0&)WEnRd}c;OkzrA%*w=*nX=5rl9|11B5^1XqOgY8^uJdz z2D2|f7sXI6=RoC$f*sLH3W^x>OgT^vJ+b$PD9YB%<7xBo_++R|@QlPe@sXu<--dFwMdZ1vOlK5N9 z`zTm-mLjAjQ_i|*^I#qqVKTTt`IkQ)hVF`E%O*}C8@_i5xxyD-tmuS<;s6Hargntf zD#OO=Qj(2Kdyc$tW?ZU~urIn&1Fe!l__q-Z_J)VS*+rthjYz~{*PUTTVYW^9!H@)O znOgX{Cbw<-We<9a=oWa*`3zHbpQzv<^J>fsE79?iy5H|;Vw5aZo#*eds#Tdv`Xz93 zXP(U%tL4d?{9ZdRq5W%}@$Hs9&2a17nfc@t?cyv;e7fkLyeUvKq|BdZOWY!=6E3Oy)LMGEM)M-Ikd zVj?`4%Ey%V+G`^|D^x`j-n+&?gtHCLlV7^$-lk4OhcNp~R&e@*4sEv+5**i%(dGG-JaP2aSc|fbkC9kURzL&Ue4yvD~h#~evw&GFj*IzpB zgn0R@83|ik#j45pUcz$wL5uK88b{-)Mr1E z_<@ulHW?{gu;!^Kd@bh-2l5l`SpkZxH8RVWQu6aBGYOi3SZO6{m0o-~npA76Fn0V*R;ERr(iiqa(x3&k}Dk|(6E+x~#GXCas0dT>nCZxsgxtFmVt z*32oVcPu9kYu32yNDBMAco*&nI&7$FSW;ccWdSpCJCe{ex$Mb^r`>7e83}*4&i@N3 zGjp>t{k70@|Hnel@{TP3&xKxlB$})lxnn}@Mx!VC!5bt1)VWZ*zpb*-7cp4AiClQG zmRS4d*@WUJjjD^9*w?R&5Rp9Xr0Tr}v4f_SZVf3L1m3NwBe>TG46RQ?j$!Og6WxI0 z&1zk305GEQ%|^AL0M^sy)ss-}XpW%vlj)v!de~$L;8-3}&~q?s#)m#AB?hsJ!;@%n z$VaEkdm|npB}R}B`}yT^Kg5NQP+;}EWMa7DB4uUXD(7SKhP)DpHToQo)#~0*Atx=Bb!q48Q(hF4l`wGeh_| zCY;Aj!zLcIS2&qTFKQG>ML?1pttw(9$|7M7{G$q9I~0}aOI1WQlJQH`KouSR4#PsB z|6cxQ1EcK1Vn%_#(}_rP5vpKN@)sbm{SpyUn!6`=L6nJ1TC{#Rrho$*JG1wt#@a?t z5BTJuU>5yxOfip}nk``jl!O$b6^|$v!M-(AF9jSziD&uw4s!tlnf050BsCJNg?}hE zyYLUP$oCR0^74=DRPVBXpUgx{Z>1OxjYQHyHG-J!Wf%T*0~8~6dh-geW(2fYXwKHIR7?C=1gMS~lpQz1&GW^z?#H4oYSeDd3`FAMCk>gz$Ilk$V}SL!YJ02g-u6jeZ3**-5fdY(D{J$oj_wl>|mS?W_potCiO@2bknC-1T5t!ummCsoRS{B zu_=SGDgCi2YBrA`6L~A#9@|z>8McqWx!OU)3filf)Iv*#oyTL5WqX`=m&CdYjy&{E zW?q{BNgy(Lz}BnT+cd@A{zr+P-kxJDb6*d<0_uIZ6CeeXnds>epB#GAOVqOZ%1KOI zzx*HzP18wYR=>U}3$^=G0%x=T{p>R-Tm{pBoTdEB&Ym_d8~>@iKvw?cV;H4DMq zKLHZJjwm>S74oO7o?LyUGi-amg0+Y2z3acE=Ii{1ri1?8AcgSgOx*c{jhHnL?Ey1wda0uM49;Q2Pkd5DdToJMIr*NNj z;CoH~zLw>Q6o}#ZW*s2UGK>Y%F3m*O?|r?xboaC5t~SPbEn(v3)#GV#w&DCx{Mz|N z{fUWd+GQhF53oE7)3BSC)S3+Qwi?{E%{kFpiGQ{(;BdD3dzK#FCKOO-T5P(@=<}`B zKBkJt=dp5dqmdVI9RUBxtmS!kiqS35(8eDikBQ*VS=k_PX}{^j<{QFhb_ww4^5aao z3YMA)TK)*Q?SzeQp{v|)`n4vuizo6t~>}h>)x74i4tiUs`e99$?Yb`09 z5H;Z~JT6xF$(|2+PN{MB!~OS7?yL2?hRDt^sH@mti#Q}EyKnYW)`!6rja8V}vuv$* zwtHLmU0w*5qspI*?v>6HKctaUe(sF_@a7#j&|2zqM>gUS`bRO!B&CmkqtXMP#L$d6c?^--go4iN$l37wT7V z_i3UP=Z)9F6edDA&G=QlCg=LE8|ec<-qTk=Ff}xFb*tCl$uWbFzcjD?8Q)dHu=ywR zbw>@xp|F?A(Z<)AY|yZ;H<%V|t$Vmu{O~%7tvZJc_CfTH$I*_aIIOV<*Yn*CArkq} zMtN_YnuKI(hhNg8oy=DZo#YYr&*_4Gw?c84;@OM~PyU3e{_QH(qM+&SWT=U-DA!ce zd2q%-9FM8gFrv)V$g+}S%AYRZwc6ISFy)C*Rl4dTvK4~){iEl-rYW&frCE`!{k2lN zn_?AsB1#z)bz3Ehg6gr!J~I5a>2^#G<+tq#lQ*7`jywBiFoj@vm!Ug%p`~m9?-;ie z#(=vm<-W;j_)gCluN9ym1R_a2#vObfnD=FJt0>9dVnOTKrpE!G<0+t8~_4 z^E*2{J?IcW>Ig4h2Bt|(!Z7B`jEo`7L36gzekVcxxl^p%9S+3Zu zSmU8<-X-|`(1oisLVx(s3qrpXArw`d`W0E&y&r+PX9s zZ58)^;t-@#k55Y5Atszvm0`;|IVhZh#Bo`7X5#Bwbg0vIE(cDcD&CJr2CvZ8hd33J z%0H6(I!k)Cclej%7BCBX4e;T;j)`|WZha9jBZ`_jPHF}U1(;IfHZv=SpE2tzBlepk zZV$!>ow2IBL;8+Pjhdv#AjAqBmI;FAq2c)Ur>1Xi$j*^(zq_?4;APO+GTKJGL_Z(q zy>TdOkUlk*ET>h69QatF2!_nBsLHAOM5J6htk5)R%6~q;5_qj~#Hl#d#%nc(&0C?| zxOsKw4DgUH*^yx7=-Meac`VjQ)HZON_u6X_e;rpw%+CQiaIpclpTUq;S}}DNKkmsd z+C4<>qjH=kJwBV$x?AdiCYe>7!8rh=Ytkum_ z^w8osD0O|{`CDlzhtqNF8fjvkA5M`d{Gj5HsgnI#zJrup$EA_d3kD2Yy%GxhP-uML zcKoXmdg5@sK?2G)@NnIV*d_(2;wK)3gIR>ai@^TEhG=0wG(rTlBT(XxHeXh#5cUV? zjkn+e@2d{T7ISUYj$s(jSUztupdzA$tnGf&UfumRt?;tNfYSub(J6r0sJKjo+BSmT zuJrW{IXTS2tE52z&pAcf37lO@3MX85_476QWGq`uYx~HcFZ^M?HZ>?}U;ORw+U}>s zRk2GA;mxXBx!T3}@uWFj2AY@MRlhopb<(XeVzNnLFFd9KI$0rvSXM7HZju-nb3fRG z@8DZQu~wqO=`LBhqpv;4LF-;A)O;5!)aH?rqEfq$r^uf<#r#poe+-dd*HTgatooep zf8vkuYqb(zkz=(oiF%2U>JS;z@C=rLbZdwwKe44Pf)_EgZ!I=TDImBmC7ctgw{)-? zRycDZC$~=N>!3d%zeG)g3j2BFy6j2JPDeyCqPwGfQ8zn9g)=;6QFlEh35D(s^OOhy zmi%rBL+2`W${dW33$}hQksc*ot6j-+qZfqA4ZPEyHHO+R#0Zz%Do!X5!>vHH`EwsD zJpon60W8(3%NkV}1u_x24bc%K79{zMkY!0BJqnc*t=G|1%OGqCf4Xb#@49M}>seZt z_L}~0JPI_MeV(`VH#I&f;c_VS6)_`ZJ zsEqAW_dlzMZbHsv#n<+m<^1}zImaO(8PV?<=zMA3`l+v(b9YdijcHJA*xN}>?xV|Y zn^L%POT@ydvy@^>`SP4LyBU?69j0tiA1_9v?kc)W-&sD)N{|7*vs#TEvr!FXJ1tjx z3vG+<8oFzfPl0Pe?!)Kg5KgX#x`zm7N+F*qzB#F%i@N%jDY%ITwcVd&BD&2up^M3y zA7~3hU(ufgiX?xkZdT(VBvxFgF_(9{eg;#TKB`tiPdrlfxxC|(paxa|hrhwha@C@) zQORfLU8QNWocb}S+kgqByt-^0!JsES4M+jzM5F~Ce+K_NWgOAPkQ^xt-0Gj!4dx!y z4YoKh8NlKE0$wZ$JZcU+T6j>09QtwM9bprwU=0j_`Y~3GTKhH$d4jTBhDq#3< z%iiY8`m}fBb(_K}dVYP`b>&1TOikLV>(gbZ0N7984I`dmLFq$ zBs}*+Ygdn#gYT_F4U&dV`;T7DsDlc!4TWe}EsaL@QT+D5|`QXs-ZXX1ifjkXn(O>a@v; zRjy836%wR-7FdDik@x2PYS+cgaxFskO#k3`*n1$E)N)$3b?#O9!bS+UfS5JQ-$Dm7 zqZ&!DETG#3aif_dw1cL*@cRz0U*F{jQ)&JD;xy@ee;0#(_pFJ^^1DZ{J5$5mSZ^Zn zaxcnNHaYL!y?77rw8=LwkLCCqRV@C_1@^^{1tkw{P~m+KB+K&Q+hm-SgLd)VB6ddW zb?w-61N7g%d9X?G4>edBW_Cxhth=s#WgRnQ%i`G5uVCNOeWaO@upq-6OPLrtl}&MQ zhGyKmEl!=b=06*?SwB{El)mG*hc8^KTX1n0hg%bKqApH5IwoF@FvqcsvSs#K@?2#s zzRt`-pV82v^yY^Z**z=Y(i%FnOCOleD_NPlYoCn~Ps|P!lqR}{v)edyqxUE4P!1jD zL&xXhU7(?g8ZPl49cc|0VAh`BCa~W4ECKCcwH46XwHpqw$%Z8dnBc9VbJXq$GeBfVY6;nHy_!OV&L%)4)t{M<1OjWw;TR+Vn7Km=Or{rWy&QxI2>WQ*DE}Z&^mN$j zPEa7+`GZr7&ZVj1mEnWQK465&*Y>%!WbQK-_m|lFa^*wfdV8k!x#oD8_V>jZmJ-o{u5sU`_#yD;{xI?pjb)FyAa^(txlrc)6aYa`cpvV_6+_dLzWtlfEKQEb)gEl$sE`^yW65*H86 zsq^>z8~8TU`PJ%gAh~k_p;RCA!9Q`4&GLMo6)7U1*=5ZKK?MR#CJJsy;22cR7(R}D z&TFM%Q>$3Q7H}pve4wk2r1o>6mWUyOkN}ya^^F9!5I3#^Y6PKjl&6H46#bFNKnyY# zIG*z?^*A0?j99Kg{NF-1g5O>H}WJqGV=_Q~LzEb?a z?xz(&fvN_OKdJ^0;N1Q<`Q21OkXdO!E}D0JO21q*!x8zAiVBDB+4$N@P(9)j@x9jv zBx7Rt1H^z&&52Fm|LFe=0EKmT&p%3t<;E*u=X_mv?0QvAhy5hL-#B%T>%#l8uHy_J zvf;APp4GIVQk4MWn0GJQodr>|amDfim|N<;cifL!A!K-iJo?7*@HaZCKdPp8%P|`V z2lKymQY`O0hWDdD)3J)1tudpzyumkPLq|qsCj-a#-;!4PrpAnF=0=WYL|lv##^$DG zj=-Hy=8g^u#`YpMR<<_Q#@3ER%#8n}gs`x@tF%7;ixeUvBB`Pxrtd0hY-nR-%=nLu zg1)_#1F%PFB6?=VPnP3 z;`aJ(AO9kkP~^V>K#0KpZnW=GypQWI76;3}jBkHg$ywfcF8`PMtx~NwdW8$F^O@F> z0ZEO__$L?~_$`@6ZgUf;JC*y&DFaj*WK#+N5TBUI)r4m{*$WbGq&Pc6`dC=Yo~k?N z^CLa0aw<@wkyF;P*4bav|V`5Cgf;`QUJvv^#J`m+Gzsorq;&o#1 zInn3(g0{3Cwsa_e4H&M<;(k4#yD8Z}vMm#!Kgnow8w0!OvX&K5Z*Kr|W3PUg?^Q<3 za$23t#$CMUJ+X{U_LspwojiB#yRWJztg7d@d!%hJ&;wsNzXHqhi|G8UpeyqBdc(Xa zeIW4GD^&X<)X4ktfi&Ssi#Uf4#|-jX8qx^c2`5VyN3o{SRucZ={FF*_-4%Jh+eo$Q z*+_TCB24eDsGwe>UMwb@Mx$hE&b`kSO=f2~&dz`;%ns3y`ljzGT62R_N`Gbv+^3s~ z?Hahk5kuaklYVD@qtIWrGmAd5)a(8obl=opyb&i>K8NuGkdQ9si$}si4nK?RDtX`t z_VwlpxtWOA_6op2mL>a)5N`(FfSP*sEL?#q_u>CB_7*^OHQCxQ9z3|a1$R5RySoO5 z;O-8=T>`<~-Q7L7JHg#u!+&^Z-kG`oov-RrRM(bXYj^kBr)xdEpVe!GnLFqUm%a>? z^5UsvBvlT`!=`(ARt7}|c&dyvsP`3I9`7Xy&U6ed3&3q_Kk29ScN8D6a`R~9yZ#;S5o`ctE^oV2IkA}d;moABm& zBJfldBq0z0O0`*UN*h^=_Rv0|f>bdJ+;$^2yHcDP{$N66Coz{nM^zJHQ1zK4uMP(r{VAPYYHvyGxY`+qvgv`HbVwj zz%ABjWb|_iM9f9*{7t9>N|U4S&GY%tXt~OElX(A?YG- zp090C&(UkKxb){Ld{!QE+S+`A?>&~00p9O^d`mavC3)K>ix4|$13OM$$T~_cEIciR zh7-RHyiyzxLv9&Ro64w38Fh4aF9Lh3_YZF(CiUEG$B7o&vum%&eEMumc%lVV+>_dHZvK$=b6%dK4E4Wao`7FTlEZugp4n~0`XzO&K?IvK z`}{q9y3?n{VHxiA0G>BP)OQ|M_Y_oD8SM>cl9o25%5c21HxG|0wX$*kH;H|t80?HE zsawy0XUC9TTXyyVKIDxB(5KwFWy(D$;Ffuqv~OL7um?Xdq6a1+%bwD6M+Y)@w47j^ z*)7+8f>oe4DY3YshgfMg$t&aGrI6TnzLO-dC?WU>Nq~i+ z`nCTo|4?j=L``wHj-bj}RbLNks5{+kyodKgtrRlW0T{5*5+YJksREZRU>9#gm96b3 z*1Jy$4Z!Nw%TuJeB0$I`7bRaT;NoMhO(QF-=-+_wr(WEROSE>|;R(*&Rwqk>QkD01jTx#g`I|W1dyFX^}U!!(|nQH6^Kf z1rJ6@yKGhF*yaokl9K_h0+EDM_Ik|)v4gl=l~Zj7Qg-X zj8BSn*F}yrfN5h#-_+tt4aM9&1(0CFRP6Z31%ffDlQI0lj zYrfkQKx@10A@IaPjvIFd?5IJMX|yGqXE=-~CNP*E`PHF0%1pj~-Qzu1bLg-sis{drwL)4D}>#LjTB|R~{D9 zgx)qL@*i2PeSwFM3HQRv}T;LuZc|28sU4DOEB&a3JALzz|7080jyU zt?s83x+lx%nDm7P6ocgw(gT!cB+rrZhbHd^21UH$E~FgPj3?P5gC9m)ZEOk?zab_D z4n)#e-ATJa0-q+-?hulx`|QAQRYOYZqiGYkMybq6$R8IA&ChkF66@ggLXOKzH)Djy z_u24!Uzbw`(DtlGt#$5y|hnn5LWxUxnH-k9M&}ymXg_CMB7yC*g6d+@!honG&!%RQHWa0p_tFRmR(Xpv%@S=Pfc+JDy>Po0nfKqouhW0I?K zDeoB}s_IlJKL@Uwl?3mVeJ>EdQI(%JP39v{tB&SgZ*E39U5GR#*k4 z9ti@_<(gof0PNwO-6YPQNbswHt}J!knezL{sKD$aHM+Owj$@0`WnOh({1)u_ZHJSS zT|-l)vQaFAW`Cq2(8^`QyC8J<&|5?`>m zHIHJ%&gh^tk55~dJ~hNvwmg{bvjRMh&D!stIy;#}f)7T`1QN8guFkPfaHk#>5EJo+ z3T=7{jQ1whaLvlPse1=SCp>Ng=MUXuMcw~!U01ITIXtcPUewfn)3#o-+?e@kE25Th z!Seu-15##-{RG>!VXyr7LzIyF>wVo^+%49=NveSTG3QjkccGfgQjOF1=tffFI#?>I zToG~Nh+EeTOeisWl0Bb=NYc7rn`~^iXrVhWrD({!ie&-4uA77R3@}nif5_{?FNB-e zPMU4SO++H+Bm>fR;iiPOL*C&tobWXmI=p1^tS4$i2R@@%Ot9M^fOc zZ(M*b!U+T}PdLD`nw^rL;4(rkl81(^BJ>4NFP^XFmSS z-Tj~CLa5?-L$IERK2C}*n}L|*PmlCj^cV&U zDmATHz%>JgF(S83u81-ov@q?Dk7T&qDel2N1}GYS7)eQA2z-Ytf9pGbGyd(NLjhll z2I*wi`|R7>;M=16m#&L<7b4vAnJ|Tgr{#v0Ox{T;;~AGO7rl*Qho_q0x01YH*Mj|W zS?h$TWr*juCLsKooz6qb4_k74_gAinZiFw#B)gsUsKZ51{X;$cQ3igD=dVb;ho5}? zcm_E)$)q9LN5QKC^_OBg4T_oD=OI@|i5q>pV~sg}Wy11Y`4t9#S|-961V!8_ntj=K zaD1F}J>|aFh+F$Sc#(2oi~lsnK_SvPSRhP|mm54$nd2vjJm3FrX&g^OhZ5QqS)7JH zt0Q=}WG-s7jO%JSPuC_-2b!x0dF6~VwfMc zqAiB%#vg6F74fGTS+BH#z z?78UAoykf$lr`Onq^fOkJx{ zlWBY~Ji})=ToRSG0NuJ~n?+LQ*ir71aS#wfLCDD;FDQ_yRmeXqMHmP{K^${ZZX6J3 zOj2TqpM%m(&_R~RAdr{5R{lM`ExsWe=D8VSOhck+fm3~fm4t&kKuxFGOjuPaI}~mP zdmLxzxtOh29VO=6tC;~M@(O1JYUYOUp1Cf|e0r1? zS~F^#w6pqBqRA)T<|s)m;@U$TZsRNX3Z+SxBB4FOEJKR)%rnQV_)&A=fHc~)#wqiu z240fpyin{4=0IOurfk&N;Ylt`n3)_94Ph-HF_-4C3!Jg=ZwPzrqZJQW^P{&3tzy zcUs(bu;#^yaB>x`F!#3O2i?T##rbd3(%%aeOpKiWUa4XE-!x&C{|ilc-~)e%!vpch z;Y|Ry#~f;Eu-iZ32XT`zDu(41?vQ%U4?tXH82?RI&wW@N zmC`o#e7g5`b1^=7vC@TOb@%WT1Lc(CZJtQA^3p%0kfDTv6O`~ z(R-12cB}oet|-!We_QhjPcAF9ujI*Y;DY--2?5P3S^IO1w8^Ito8>F%7by);4{|~EEU07R7&2Z3eE9BAr2TIddu`>%q!S@VLsZwZ z-Mk)Qb$Bpnk}V29_4PI+WH!IX&@H2S{*tK1oDkVrY)b{iWQLjIutgwN%^<1NnfNIR z&!8<4e?y7Xn}hZ!4(JZ| z*rjBI@HnMpd5zgQT5%Z$!t=&+80^*A)g+Q0+?;Eiwo;np4zFB{-LNoVP@wl#h2KE4 zGe^DWzeh0B{bEy3Cj*BXkFyYFO!54Y$_f~+B{^of{b3ekC0KnRJf7`+rq?{KRpUl^ zUwrMYN>DmVUcs=19AlbxCS2dhe%`DbGoTVKSZk~sOEQths$|}&m!njYU9;f&r`5~( zePZph)iK!Ho7g0mZE+v!E}rSda&7dN<|^oBKOUhU zN}Z7cqN=ZNoGtAVlBwYasGRf7Fsw~0o7^OPHm_f z@-@X9XKC}KxYr8=>)b{s$5uTZTsl*;1y6PtG{IhMfnFyHrKAedZhW>HMdj`{oa#jZ zUH&koHa6|aAZ=J~s8YUjit^kQMU;w^b84S;D&^PWzMSu2YBqTewDXB}G_HivNuus$ z-;A|XsK~@GD|=RvoQBsoE0(XY>;;XjtY8*ek74=e(Za1oP%{PA>_~-Si`C@k;h^s& zZ7~%8YKgDqHAB-(bi#h(Sb&mBnp9 z9b~qK;1q&jMOizu3_ZvXjEQ7^D)X#n)psp>@ARfGNpkN@l|Ed4zGt<3vvdW^ns>jR+{>JuVheLpY8Jba1q%R!n?pd?AB0#4yW=*FG{a42;$%%{q&&8r_ zHTaYzcq&l1Tr}7oM&l88!do5F)sT!Vq;iFU`p;+lxcrxe|7{}td&z}~3GnZD36}p& zqh$TR(kRKB5Y`{m*Bbm=7PLvGzUfnB!fa>kfYw6S{u+gDMdeI;^$}50EqK|EJF8(5 zkgvJOaZ=$L$kk|_KR=a!_k6zEmAhC2q*D(#0!)6rJ$Cu}KF_Kb`SL%ZzQ0`XXW{wU zd3YKs{McDcAc(j)S%4-yEaK;R+o3T}f4{@v^YRIwy9zVNdUtt#R<`BJ;CtU$eoCHv z_jrDMI%>o9;ycLN-5dpE)b3<$Bg=*H{&~eqeIK01)XUWMy5i&EzP{Sa@VzJF-x<~8 z^DUG0aec1w4B9A>zuV2=A8_&%^5H>0YED-g^VaB`IjXXi*L&Zhdz|HX2Y7Rk#)pK4 zBLRdUh(-KmXpFUpXQ5KqhwCT3Sdf?9LyMueNJWr@Ack3m3Xz%C(a>@N;QJL~gNVLk z!7?MEGgri#2g=|YbD`a0)ldx!sQ@q6B7H{!WsZt97m*Q9q((O%6H)oD5S0Qg6bhE2 zHe4@Mh`?+eTVgRL03VeCd~zuhsvtBn(JXX|Sih5UYzR=TupmYNk|E`=fXd(1j})ei z`U{ER6p?|Kh5pqZd_`)rd?r*yWFaH zQezzC*_>>MI(xVrSZ3t!NTon^|E^91&V*+CQ9a;4sv{S~|A_Jg4gwP^)QvNoA`wtK zunU5~F5u$?KDCDZedn+C55CB>+*d0_x6pd#iySOnl_#0iuTpZeB)raNd2?FOdjmz<*wdLTZ<`j?y@j&RK<0|;bQG(G5({hSIRiv zzc{9%g{8a#q7r0a7{}X-?HN+$3?ED;91g4ZXF5~iBjgy^L2Gvly`2qQy174#eR(z0 z@&F{fLF6P7OFc64LU5F#H3;z3qHnO69mLe%QFl`Zld}nOqP|9VD1htij-B zdTIL!9^?%qax5rH@$Ez6cxbTL=l>^hXJi=c^C59pmmk%fjeyEhZ(sy%6wEF&HWeJD z`Js9da>Cl5h0cy(rJ6B~-3s0ScxOc1D56Y*AB5D=z(|E3L>MdYxrV8f(C>c;sJ;FC znM3GD9I5z5Yu?B3t*;;6dI{LeoPRt8<3qEvzoYi13|x8$JMCB@0+p+aMO?@C~tuAQ$Z$Lk5v9jk4(84X9S zr)9(K7>Qx1s>pt=5ANd2HnVYaBU;l7L*(A5%izwY#wxGyao)Lg>shnWQ!@ns9B;k1 zp<$~KLoN7nfIHCuqVh0k*#GK`YR2I1NV!b${fRp0$j+MTIu{sbvb%V6>lsG-Cq4Ar z`54St5xpp%?HkllU^9;sWvNr@2*#x3bdzL+kX}KzA{CK9KNWKa zDg-5ur<8o^rly2ahkXhqM~M55E4Off^^e_b?Q;)^KV&9bF$|fc9x+{nUiKFNYVr8X zcmL6`w|Ds%V2*VKY#@&`0@{8JgE3rG5Yx-~p*6h-TAay#$u3xI@z_FCG zrWL(qSl{Y^i9K%3w@v;+)p@YpKC9IEd!l7&l!a(H{9!rOf2ip|VeeToT}P+&(*p@N z_3TeRgTCX-$v8*U_EcWQvY~dzP z3VBjV_xD(6`(l_DtCGnLB|@bQ9O~;j^TL}rUxslHjtfdQk#v?bfDq!A%u9!l1}V)Z zZv*BKuEm31v%S~ygv~&j@NrGw?_r}D{8vXrg16#>XvtF_6v8nPxsK(Z7jU_M=BneQ zm#W115aOzu>_rhRby^0lRNYLXPTXuvh@D=!GB(mcecA`NNGn4=CzG2s75OnhMdK|x zTFQWNFp3Li-6@`nT_A57$UNID9|d)8?176)_gWq1Cr`eh*N zlOSiCs$MkxY9(8AzhYj!#Jn})fi$6gm=!c;Rn-?Kg5(ZcMw9m(DHMM}qr?|>zO>O9 zluzArrfe&PV^7MgX?+z%@ts*$Z3Uxh^}2B(b=xU4-lCsc8LQS<*zgMN-1;WKk6xc= zmX~JBT$#q9db$AoOjhTsaOO(8$FbUEnO5s*xNinx(6CZTAeq@iBAMP=Ik!TL<>S%E3?Z`7APqb+$7^ zMdwG=6uYu!aq85W0WO6}yJ^W8N1rrnB~!jY9Z~yp^OYmG&MNMS8DRplQfM_BwJ`DR ztx4n<_t72a+ak5XZuwY#w!P$jQxC2P|H46WfwL$wF+Z3J`ux zC`c}cd-|zPR^Eig#y*tvu+!HEO}kALWg`ydc8hyw!>s*~r*N$a3vaVpTcdaKHj&O| zyTv@N)*@JwSM}rNH1X&wBZ+ttT6%r;2Jb!>dv`WCq^x9qqv6coSCxYp8tJ$4qwYIbGU7bFfk4UebT6fW-F zjchtgc8;XJ7=Lebw67bBZ1^;dVH}5TX((pMtCKux z>vHAn66XNr^ih%Xbh9wWa!DM~W=1_bTsMFWAtYkx8MZ?988$vgFqyGUrS}=OLFRco zh;t6pOg*Gis05Cl9C-Jd2dYH^r@3u6@($errRLj{L*4N*r2zs`%XEa6eGVqIL(Cd& zEwv>qEWHf94m-=SD{k=!uc5|9%-oQ}(V|4E&T)YBRQzvKQB7wM%<(La2(fFkmVU;z zejd7Mg4X)DlZYSH!l}WTn`912kw{03AP5aQjm)k5xKHVrBspMwetY zHJx0W4y>fQ+ELI_;G5J9t=oPMt5BvN!i>;?b+ig)uT`K#qfRsXTR;-yQ`%ldq^+M) zn(nR|v~Iw;wSu%w^RTGRdWf`+y?w$$0NLkZ(V5u30S4%qrsaVHNarU;IHei7T@qYX z#N_7fZ3<_1Nqql^A|60@%0v9_Ibwyr_Y($#&h7Oc2v`{`o?|o$S_qX!gOqipmObNl zQOf8n@%eCJdY2Lt2fu+Fm4nhB=g>m*J@IT zUuXsI;Pp$j>}ULRw{;q}=OEN7IMV>7YE(cGPP0^yrD}`ezPpR{}D*z&GomYF?Mt zv-dy6=bPj98!|C`=GHG$b1R20Sk9m8)uM%QwK;cL=qzk}c2Z8i-OS)v|EYe!axUsN zwpLaVZ?nb3$jtrig7;8#bTxb~Kf6=&RR;BfMyd@g!bjVh(zH(Hv#2zgu>VdSS=O14 z+?!Zh@U*{?(E3^6c$u%+7uNDrs9F$B+j=b|Xxv6l9ijzb9W8h8$8+ zZ^?(>R3}E%a%Ey_eY!B+twzOQsK$%rtTZXwh!MYw>o<4N%@*{zK4G+ZpB!#}d#BIV zlEq%5EMl$io$l_?@!qodWS9G^n-42ln_Fcn_0A~s^pcfgdZMBaAZ9wYCr{&L;I^dN za-sgRpa$;&zbf=(&S1;b-Fo)6F7xy0BgJ_P84W>x>wQ#Mk;1*z*! z!Qe#Q=K(suJb#s7f0Zh@>_AsKi!h4r+L|Dn5SJyqo&CdCHZocPJ81l;%&pOf46p>s z0815q_P?Cz>g<2Ivp|>JY7ERwYg6XuO(6p64%2}wE(L}DMA~0Ib{O^w<77;K5)q`d zHb02+HdruYp=qQ!T>9!iMCy(|>GSNDKZE}C1C;rI{N)N~u~~1XV;Fq6>2`7vjDO(- z1E9W-laFVl&w`CjK~0$VJWVgnoURobMgo;Uf3&QS?w_#2U_zLmebDHm1U3a&esoHO z-<5H*gAg+)-Mpdepn~J#&5hwV>K0p9#H(mj#G*aKlf|hUT(Qqxc63+mb#WyliRwxx z@q_Zllf4Q?J>~j}kcl9{eJsmH?skM;w@PG*J*e=9F=oNcdeZ~@KK}0%Il3YE8=bX( zhBGnI0~@6j{4*yishZs?(gOUWjkxT=|F8rouq!|a0t7oU16cD=-AF*VbLv=JQ@~zM z=vM*+9H2lb@h=;If7Fio06HJFKY!HrNvcQ2sQ*Aj|G+F^Igk_I0k$jEOn=$o1L#l> z{*6d(@GPw2Fvo#->2LY^4@8y1cmPB&J?SAnRv%+X{Q;o<36_G=7l6{VyY=j*-;9Wh zAhE{WX9tDkEP*dWyE*Ve1CuZ=9H1iV!@fC#Nmd8-KA_4>Vt3$--Ht@XUd{{lM@T=eBL_RTxY;8$bzd2<|v``S7FlrRdX&Hyp%ZTqkh z^qgt#9d9AA%MR5y{k82yTrHr-!^!zUwD|tFM$5|emb+0xvMoW%Dm(SXiW_ESqxCDH zSm?aee_4O|Ygy&v`xq+=C)>yUk7HQYzo~WqCc?0Od^7uRJi3390-1=|IGH~feU45J zCI;59Zs~jK)>hi{*glgTe=KGP<){>6rM<_jrI@*0RzPIirnth+$YfVI2~AyoY5iW} zsF60*zPFZYQ#DTT`$axgQ_)@A|GnOyJ^yQyl~hqQRFrutJH$&3Av|o{Ab)DZi5e@Y z^?l~f2`dbpgwc%8DMjald)C8E`vKmI4x6ihzbYdP$>a8pg9{z8-y$LCaO&fCse@H7 zv@2Ra1>Sgk{3=V22V0QsE|9Uo=^A0uuBRL6I}r4-FYzk7{e;n0-$Vcb*WQw3Tvde3 zd0u#X2qX4)2K+j#*{{^Ul4@jhTmo?o1_13TgL@%$rAN@SUH;6nqdUKB_67*EUx`y6 zj9J{-Kymj$7ucD-*^7*;5P6LR0pIURhLJb-c0&DrHoyA%U>9w=9I|eFRvW&4iI?_* zJlCImijclo^xWrvvQ;yn;>`@o>Mdi0yy)g|7DW<@4FDge?fe?TPdr+Q1m826Z5L5p z)y;Y=?ZV^+o7onm3!UlDa@j_%Da45QyI0Ex^deUF(o=^TyIF|#6917-tRrBpGA#&& z`ii}GYnbF-*X=7O6gQ+!kp`p%M3sIZ$0pfwM4T$#!CY^sHXr7#J!ilJs6;P>p%3=O z`zb@U;U7ZIQqpSFPPhuj#^D`2cR`)78xCj&eR;iu^rmuF*YKAhJ=orci@Zx-tbrIA zyVKspC0HLL^q%ztI1$pV9{)d`3K!?PyzAU;T-*VmzMk4;wnO(X+MS)&mN!W+=j(Ha zcdX4P=NlSrf~})R#hThCb!wHB8ZEts?AQpo0^Rtr0ZgUVk>^M>OEUj}hAxWg8wBF>>zXQl?rZK*m+s*okG;qA3WKaluBlj!&P)RiaqFwE+ zmWG4oDLFF^1;N=Q`R64fq3Sn9YLP;pn7-B+nzYSTmRs2g+nYf4!is2RB+|vVo_z<; zp|7r>^fO_TE(>b_1>^)hlYn-uA4Re^x7ACHOsY;z2wN1ojE@1o2+-h1Pv?3TUiQ}` z1RGVV!cYy`1p8X!dLOs~cBXSZm~o&O2qS?5qf8P~8( z__js8X_wy;A&sqRCezSZ)~%1Us!a(&jzilIdwu)5TPy1r{l2K|(?fyOEtV|Lc+&L4BS)C`5(iD7yE)10)FCT?v zLSJ*{eO*bcmDb*nOOc9(vS^b>-dd8Os%{wCd?aoS-C@HLs5-18)l##8s*$@P7 z*}_x>O0a=Fm=aOpyF8gCBZ#$~Wk%)9+-EV?EJA9%_3HBGbd#=bhYTDl(SO_r&Mg5susSh`#CYfVj=XRpYJJfe2yE= zdJ>d~Mw_0)UQHW`R+HSj89z(gfPsU2YKVqlEipv|R#E|Zk=n8lK#0qpUT0O(*f0fM zBfN|=I(2L=aCPD$^A%-oI7!*l43HWYhE>!tdmhOptsbZ?z&4MX7ZSwQP*;v(d6fnN z0PV92zpD+daL0*5qoO7+*@qKdTGH@zOTII`%sg>qYZlR(qqRciRMf@LU}?x6?QCw* z`jm{>KVfoQS(}PMtMnk?51D-H=l8?aygRA7s^!;&EC1@GlER>DBzNk?fzb4UktblJ z(OU3W3N7DX0B(#Mw!jkVcy+ng?)0Rs^NNO1uO}Oev zn$7h?3Ma{nisZ9quXrrqV>R$n{!v%Dpt*Mocl!)=eR`MA^g1&67R-_3bWNs8h^=Ss zW1iKpN6jf^mfci%?%^=v9stZHM<)1XYVx$5z|WTUCoO*;Y_I6$$$r5O%hnF%5K?!r z87L1XHnohly-K96IDtkes&=U46my{wsCd?V4YUhqu@U$RPlXYwN^b-g`wGLR|Fk{173PAWi=l@9OypFR5txcjo)IYZ zz&IDi7TScBf zo-bRwElsLU1X1wwbC(0;~kb zil^pyIZD8aK(aP%GNFQlJB8IXtIgG#qj1~Wqcm*KvAD9k>IiX))NHj`x3F++X}&6T z5vr42PmQZF8M-zvVznQp-JSfX5a3Tl#+PjlaJ#Lp#5cZ_&76u4r72sg27QU`S5 zOlLR&M&!60<20})TQ^v~B9i*%%Q~iADC)c^YsC-x$2o~jXbe9H?lz$Nau0#uz&PrK zp&mAghqqQIDLWC01#%F#6=EjGr$T+Tk?sP)V7y!cA~9@4bYsP6K9k%hF$PcKB46t$ zU6yP*2D~tj65Lt@f{0lL3HEnX<1V8$C12&`HbgeUc77QNB^06$v}M;z?E3T;;!aQ~ znd6Pq0G=+H!*GK)(A2?1P=oF`5GQ#<3#hl+boRE7WSHgeR`e09gE=wuzS(>_H0{*G zcq((wpLG_8qweR`WKhYZ8?S(}jjzFEiO%LfSwk4*jH$@g2~QVH zpKEI+#Ec{77Qb23fr-#q*$EKS9 z^9pSg-r|l2Cyw~&`<(m$e*B)d$|FxquC@6DFV8+_Wfeh(uzBaXW(XoJj!_9mla{66 zAKJ6@8gl!kvDz;;bn01)Cxlz>Qo5ttyn){8ZcV)D_{T!qgtPam0(nP}%_;dXQ%WPVz?TKuk; zb;DJDfOh~fl(NARla6e}fO;|-og6fEQ*#is^Cj#qe<%MT|1s}?C;EVEfjbjm-(+;( zzlRD2=L=M-+T+bn7Q^#4H!E~sGcpv-Pa((W@v68r*Z%}VOjzn_JVP(ux?>s5oodm$ zPr+n`a)3WJ%dex28F_XCxX+o+%n=(>5bxM&EMzkv#jq3*E;~eW4ec-#^OE9WNTqwr zxr^p|9Sf!pfv~K~TU?DGO}`simxHfoX>)WaT0$>(b#h_lF2|2Xv>npMCv?&|W;{C~ zV%YS(RJrt0xP?6F5Y)5lU}>(LC8)G%<+ZY`4Tc0Wn1L{;a^9fUsCX%l(GaCM1u>{i z#TsD+e8t1FYiTVSzj-XQg*lrZR;+OGTle-BPCY7y+REXLBO#U-Bg{w*Xyk5d7zYRD z)i$fwmL|GnVhrncF{{B@$$e@+HpH}VK_ckpZbl?(;Ls!KQB@11k-v5yJ_w6A;uL|p zrWa!genPrkOZ((vq=ngJNSRf&{9+4hLgxG5kjLL7JQhYy_J1RfzlkwGck1CM2*UEwnE=fAPw*^R8k$=g?<*|)OW~7D_t9(&(uJ*yyFDi z^~7hzPdlYRGNnUhiSYCHuHOm3ofm66LA*7so&THl|AXrEFFXG$B25JtCid4=Ap=K~ zkCFa=o7>#M(MkB5fy0LxWeom#47Ai=;cSlDEbMGV%xsKAy8p1)zuzPx*1s5^una1; zsy5~yfonvpe}#(u4@3UVPWZPWS^r-FA^*a`OzfNh=Kr+px+j8$%3{Oe*Ozn_7PDXj zQ+-aqz%lr~cMx!v*WoNYNGN#fcUVe9XiAZwEpb#MB{n8iCb1i{nH7}_Ya83tdS^xo z!`aoPEV2uBCW{32rbYIZIrbyj;(P{k&pdeBGnPPp$(5H**WV8v7oMLc0G1aW_bZlF z9SbX#XW&MpX)h8G%YvLF4_3$bMajEM(8N`!V2ZrjgH~;eIy!!rm8rhJLZH#54`ggmtxSl10G6YM$A|fUO1xG zpFGwkW;H5%ujSbh@0@<;oC|nB;?O?W9Cyz0%V%^OxsxVY2d<|*4{~@N@gxxviOil5 z;^2Fx8Bd@n@r|#%k$V5x8SIiluAP#Ae)v=l{%W8O5kRe0h{sSohoe{)F(r-@Sy=qd zF%k_IlYcUvk$>8v?h7DZS!s5Lg*iiW8BnQn{k}@xPTwwfj_eYTRjca0;c!LXFLO?0 zd@roldIewk+BF&^<}SpOA1goniG%Gmwq3GQ9BlV=d?^+R+v<)eT!(@%LH!SgYQ9-e z0jyhG`WJ?TgLfzb^4|g2*S1J89zH00Wu#vbfB@h^m>DrM1=8a{}lRPmVr6^e*!5rtUYgPqDvT1B(LW zz0zCxX45U5@eNG+`$6%7R~B{exdPqhWkO>`v{S8D32^k2!;X=xc~=%~Ib zsA$9{pZpq`kdl{{m2@FnuCO;vm_{mDG#8E1BEQ6gj8{FobXf)~(FNt3SJX}${}pXh ze%M)(OQYXMeNn*)s+}BQ+J>$yHs+kwlPLW2+F6Ei<(Gt}OH##(0bF{C!xBYKUJb(5 zn`*R+w!V~qG8JQ1DR9r<>eZT%3a-koUl@M$+Roi=1-|XAWw1xGhxI?AfALwnV5CeP zBh3+`Nw_|KA@U}s1d*+xPstX^GwXwDPCP!}5D+%fcK$J7V>>yag%awdLM5B8M2xMV z3N;5Sxe8*Gaat#9oI&8LKO?c=0wDFk?^rKe1=HcU$3G|?8gl(4Ga(S1M;&XwxW}39 zu17SgsETjLTlI8@TcL}@g z!tW@yNA0a@hUz8RGe=GY-?Ef!A_Y83<+co2uiyDH3x>qic{Ow@jd2Z0J0dQCRq*r#iC3NH-O&xj@=bLGc39wXzKu)xJBk$A zHD$Uz4aDlw9-pj0iO~lFI&9AUQhQq?aeoNyW(ikO!6C+4gx8{T$HM0+pB10OzS|td z2!l1AmJ3v{)ZfxsgSNnews5zL&7-!^pH8m_NwX>x(CT&XU49yi9#~vVs8QveS}Syd zafSOy1D;>@WsPRDw9=4twREVhREU;QD|)a|xu3<;oaDEu`-Jedq$j#?618HLQrXa| z$0B68ZqnEKdgn&=2wtM59k3?umFJa|+??;s^jmf=CjB54R_0}vE^}-y^>olIC>Hv= zkBP^VvG(y_9+zzw8n_I z%h1M4r7xwuZslHZivA_aCTDnT=rkl5zqBGc)(Ki`>nPb*d%=x9BcNKG>7XVDWP+Sf z#w(Woq}};BvATli9ql6CMMuO@U(>>LMX7`cCmiSQR-t7>wN6HhhFW8EqvH?5vgxd4 zgJF{`My1EF;8W;6qElzBvr}wIVAhXs5C8$tLm`q0+JmHsFnk-!#NV)CHLU+OkU8|l zIAz&^pJmm4D1O6U+)+CvAc|m@U{u$toKoqNGhIYo-Bb!)rd@aDAPn|Bt80Bm@A^z* zQNbA}q}Fmnvo{I$>WbX5U6q0bRhh|;a(yF6u@V?K9LV1eQWVA^GrwrirCQ8TLY0bA z%D`t>B!!&^Te!lVy^7`3j+cVU&=zBu#ol$TPfSi6T|M93)VXKvNpeIkF~K%9LTBu0 z(?LqZp}*mKM}Tt;8LH{^9McHhQL9ynjf23{)}7;UsB!a!jhePmkYjbte9b}Uuw@%b z0okVJuG~*3TtlVaQa2d_gcGG~YBY40#+0c>Tbc~{&wI+aD2J~bSLHV9GxH#yVrubw zH-_`~1;Ev&Ak_du>)`yt!20&e0~YO!ogYiVD5&D{rl@scqC5Jr1 z+<;7|lU__J4Y$r^J98B2h|Nk$I`R^adE7xX-_Ja4+}}SxIG8jKUAv({gT`jw0E4bJ zLT;UmDA7)qf`b}qj(%r@8TYfha1C9VK)r|x)+EqScnL5Mu<}|zJ7$$@QPh%a|DKPh z726f7CeV{Ep|qcGESFE%`(s~x8dxNm6W@6S&z zi zePAmD(Nod7hz@f~G!*&xpN?f{`wpb`%2wh4EBRE0)d2=8cL*9_d7juIf)Lk!6&tJjLEQe{Y@hY z777z|WpwoJL})f>^lxrU@UfpHGpiMp$K`?}4v$ z0;@x+gC|;oE?4*y$T70OrmBHr;g0;Fv|rwRn|F{&ORbyFrG8Y1)X4EX zJ&T~0F-46)ci=RcD0bB;Z7-;@|9WZOO7A+!^3L^Ycq#we+Qt(R{>ufwr&~8pdNj4= zZygS|`rl{RoX>^J=aFw$U6Wp^i(gYZkA{%!ce4au4E1~#&yxzvpOwV#q7QAA6qTKW!XZs9yknOGrVDbmC%NZrb=zU~)0z^`g% zzo_?3CPoP(RyvY>jz0Blem31Gu9_|Gv}6wQatD77v${nMBa52rLb}M{U>LA8{*{ol zU(ROQ%zVt^g)NLN&ivh2IZEF`N-n8fRx58#BJv7}uxg2~?lSz6B-;@Cx4}XT9HZHp z%-T&)C6=2(9MXvW*yR~Oz;+e5RhjM0pAl#7OhTIU7P?A1(I;!mF(NU#mB-I{6Ro*q zu=3_m_i-t}#(Be)t?V_-Sk(#JRl=BEn19Dn_uPlMk$Xa>p-C%1jSjID% zfQ)YC9~sk3uKv)qHdpyhm|FaE%(M;8sNx}J-pmQAmDq@WZSzS3*!6`VW>ieItJ7!P z-`HyDd8lJ?hj`O8TvIg6pHe*Pe9^9z589zuOCG`9PcqkHPqb@{GhwIHp?;%sGAjBD zlk;@CzvbAdUk3P6*10Q+J?9pV^(JkLq}HFU<)}H{#|sg6WV7-ujlYZEbc`I|zCtqL zsx|R=>{lvJ0<=C`wR-zT^tBudn&{r=R;~tRkR?}o5Dyi87o(M!VH(ahn3UL;HT&UU zY++#-9bP`++_fLoH zn(f$EM%cWSi;LK%CxUnGhkJ|^qE^jblos6Db=cY6O6WMNYqPWoMc5bMWdah2%jW{l zd>N0M=>VQ5AF?*Z%mHx`JR~ekGy%hoga?gm27ZO%8oKUn!#=FqM8Uc(k2UFsx05)C z^;@9|J`}zx%Q?{Nlz9jCi!(3YIJz~XG@HL9qR*}$Bllf{sz|dzPB}g(R!gN647Z78WEN&q?Nw zVH+rn!Cqq!y2@Mc$`BOQ`olcjpn^Aqy2m$>)9)uTkKvSNexNV{JPvqojNlH3VXw>8 z$<}=OSjxmlzm9-Nd6g{L;v}fZ`p4Z2vdsg=)V`REChf8RGbxle6gp!BibH*nU;q~>yB2jIws zTZRTdaNO&I=G*s|{tkt*ecBHyZ{Tm5Z=z}{)iV8k`Wt^x2dSiFo0TUZpCoj*6W1uc zTzrKq5K!F8g7Oo?vFif*xn=v!!-)^A>~u!^Kj5M}gNzO-BfO;92>fWAagg3mS=$S? z2+d&)qJc`maWr$w#iFj#9W-<3qAR3)RD7h4*dnRI3=t3hFMbl5II;Q(uW(Fx~QtMGZD) zy@*~`V>^km_RH`kbqp~SaIq44Y1pow@1e?DOwdsZ1$)C%$;REIxg zLhvK**7U{6HH0=mwEseW4hs=&eGt86Rm4E*rA!Y0O*G7$$VE~k?}-*xW+s{oK2X0W z8b_QjJAwL1R87_a{|x5@g^KZ(*ZS5M+&+;Jk(Kvg%7Jpp9i_bM`~7C7 zn>a#AHZh0EvfYXyGU@M)x?X9F%(>Nea)n%Q-t8tYJ)uv;gwBS3z?MRO*ceS$wzf#0 z62;5C@HCJWHT11Qj_%6r;lX^il(Njrq62F>eyw*ZRe|?QW>hb>WKr`@iRr$g7EIXe zQsKO=vU2q)z4!2bjwg&uUQ=r610!Hovsp9_e~q^r^HNV7FEIfbVggvBRJXdwAFTmv z#$S&3j}gZ{X$S;8QkLRyp@m3w(fp~dy8>Vfz;m-J5!`tQ^6Q|vmoL{KBD%WBiq==F zk`W>h{@7!X?%{+irXE0d$!uuU)wAE*T-w4xuRe>&U9#Gi(L?vMnZwnAT3UQpZv^tn zzq-e#0mKenulq@t1NS0zHPiuh2;U#^Q<@}P_>(7*OWn!k@V1j( zNJK@DOnRvC_)kTeu{b|to&tL3T~r_^S$#_$3!l6lr4;VUL=tE6GRirzROcdNQC0*_ z{uyx6%LMn9fN&IsFmCT)v!ffHu6BUf>_?|YarpS zuf1X_D#%6?h~R-&PZ%HCY9Nvbi-u_@ca&Xf>Mk60hI%Bg=k=j>Ri|XJdE^F^;ql?l zGClaS{?IL}1$*;;S9KrFZ~x&9If!B@D|LZ@()ga~A}J{}vtm$#o(BsK42UgY%cYj^0S_H@ZUz|cCz^q9i$_phZ=i=+m zNDuNznnmbNscus)C=h><&XX=QQZ4@ki&zw*P29m#$(7Ye;D*zp@E2vu-6$n8xR4<0iR?DBw);3Wx7L&qntN*!(QfQL z@^aJ+IG(VFoN?uV->z?i-M+H+vO~Xh&ozJ9`*;g}tG}~(SJJ0+wfUSKEWN~&VuA_2 zSO(U*ehS;fX?xpWA|6f{Z9WJ1xLKXF;w}Qr(SAS68_|94R)lx^G=c6Xlq955bV>a1 zZ4t9)tLo5Uy@E6QqRyeyugb*#;CL~1jag>WaaG7J3K3Yqf{nQkVVGpaDxF#}xMEU1 zd^u`(&3uhdD`$V7NK6GxK14+vQ6FhCyDZ=^>>SzHxtoPeg(g!`LM^|ElcVdiPCJ4!-6$^B(nFns{}H4EU7@#hk?o z{PakecWE{?RHMgKFW3@rRA6Ss+P<<M6k-aMMFB~A zj@$P7^wakoL?(fU(I$9gU?P4g&J;MrQ*)~6eSKc7vgsg^ z{7~IYJ1TBzqAtlL*eN&YP%9h`C6g?bx7~Wv zc$03yKMK@ZyKIkw&Z{FF%qOF(WL0xThv$1ajW&Xr1@kqC5x86nE^D>zGHO_>FjFgr zZBiEl{=I7LteI4CIQVn&X(Afj-5)$bod+db-=1^ZuhuU_r9NTxV8ruU6uo8TLx=SX zOTi7)&~WlJ5CF--4ur%6JNP*2yr2JevVu_?SE4e|2gets%r3vQ-)7l`pk<(tKf^>p z)$#iYNzR*)wocrLFX{}zYjcwtpT}Z6*e+7-oN#Mqe#e%s5qPE}tbK{UY3We!`(P+) z`Uq+QM?m_u>|GB_E+vB*Izt+1wRdjsVaM^f4z|u~)&?>uAPSPy0rDPfiG}Z>TKn4V za`$cV+&G-)^z6VxyXw(Gg3>XdR*t79ccS9U=do zS^)t>)V6ZUV=PikOvuA(4?@|M(K*ipAP+$GUNmhy*s83x${AKme!8ln++e9dfuM50 zd>eqPO*iDd1NCe+=`ME<%N4i;I~AG&=aJT#SSpfLgeJ8ZA@paet z=oN2H$M@e~IGNA8d|19bk);U-6oROE9+^0Gq6cC#5TAyN^N7EUdmt&hc>$*SRi zjuzx6r%mNHyI#obve{Dr4||>!7u@j(U(tn+dPv2hRBP~SF>9szZlD+Q&b#5bN0M8B zS_Ew8n_9qjoYB5S1%@#zo4uIxlJ;)t%ZCd|>br^4I5;Wyyd5hK>X!kE=l7p!$=k$& zo=R9B8moNkDj%6Q^xelDu=V^s9Iq1^Em0Q$8tHLKLKYS-e2-|^L%y7BV;~k~QAaQ` z<&gqcWyu_bJF6j3Nw)GwEjg9isQ(JQ)GR99UOwtznen3KSwnt9zQzOAaRcsCkk_=<&DZNltw8mz zwPON+mF--*Nc0AGSW(+o;90B5+#K3}@ghCi*~j0(a=*AkPZ(9z@9{XH+&7h0&k}=a zNdb;CbW6+t{)=05&y1dORds{Jw!p2#2rL5)A6i2TBSe(WeJ);f-MVM9=*l}dBa zQe~Ep)%>Y6zwdM+U7-et%SFA;Eu1f*$agn%1@iCdK3Y{L^p<)rqy=4mr6RG=`(nJw9*N|!e&ht)m~E}KbWS)?SNG0w|g@E+WNgZdr;-4tR(B=-@9 zI#Na)rD?Sbx9~OrVk8wDI8WX$Hn9Cn5np>b?Go1yduNaL@L@g7^wQkt?fZRt_3iHC z)nkACEq8H-AF|Id?54EZ`e-;IS)`rPOuM_V`lnN9&U-_f4#)hH?DzpW?^yoZ8ki{P zG?R?r>|*U$M_tW$JuPGb4>jEdFXeSik~HI#MzN-k9d3PANzBWTl;w_5zL-UEST5I&Hhs9idcv$l5S&&)$8sk5^-fRg9-g<6%`#v z-F*`T-NxWS{V=;pd3dNwaiMi&jZx|2?G16>M*d*hXkSr}c1(K>sHu0F-@ST!UsA<3 z|GDw{*x5^GeR~%xdv9SP(!)!TuFhWK2VK0>Nu$Ui+#H779HauR;9uGYf zOye1t@(N4qqFxqPj!e$r;B5{@pWvCAjI>2b56!MnET6DKZ3E-fDpM^0FXU=`D0^rU z$%)+=M=B}Opp@03{Cm<9BmGU2mAIAQD#D$Szrj{->oSpxEX4-ILT zY>)*a(fS5vs^|Z;Etw;MLP`7tK#DCu;-TqHZII5lCbfv|p`}f>s1wrm#x9kYzNrG? zkK2krae$0X3P9QzcNa)#P|H_ELa77lDYSOfcyTTv86G$|u3xk_>Won@pCMKC0!E7b*Sb}2UG*l=~TIDxuu+XBb z!9(~7a!mh1T4KbDNxmY9yd!^q>>8~O{Ft`?n2VlYpvrCst~i*5w~?nXy5#g$mBSSC z@->w5C!?Es^MiNnnR8%@UhHGT;YlY;xs>7SC!zAK?Xm5#d}Oga_9(myw8QRCTUDH| z8sc#rx+t%Ly8Dc)G`DL!7CxwQ$}~3)qNPIMnRFxKr(WY3d{2MT)D2K^Sxc%zC21?1 zUf40cwuDdmA8S#`EaOWig!&~&9OUX_iw>C-R$!DvNy7GM96wM^)eQPDVwH3QdjM2P zU_%m_NRIAPElGB#a`4cckrd(^!(80Fpw0;jJzpoZX5>y_-O!u4L1XtD@Y^4c*Hvtp z!?(mq-H(*LogW_b7JI40%Cf=o)RgP;yf8#k0qOG=zo~FTQJMiWMli)pghpTIWs39feEVjqc2iGph$>rG(x2FdDq=BrW?q0CMs! zkd0tJ<%d>3CE=$&nR_lmdJoI0jZKE9uunJmc@XmTFm&Xo>^`6e%)deiV!S2F7VbxF zy%Q5>jU0WyX;&+$$Y>uhkz#(smhG+n<&_7TyecXh_=TVLJUlS?(ax=J`3NcqJUGS9 zn+yGVHHsB2Pzwsh%=tyq`OQ9SD^a#-FNT^rc?eZkn&dF|n-6}>DHx_fRmXR-Z_-{w zUBWyOTxPk7*D*~IM|{9E^*CUO!_RI5njOSjefIf|(C>>?P0I?(0B6?e)p@p!p+L9Q zYoKe3YnGQRXS+@!b^|#N){j1s6Hz#ko@96E!ASinF#LV?Mvb?bmbItrf0hg03v$@V zjVFdlQp7th^!XBDHY9XF?nS@o7WoZu6I_2*w9su=o!5aG^&ka$+?r6p08-~8gAKD& zNBa#m1U%l%Fx28K9Eo7cM|BSt87c_PG*E&?ksvD#H9~kEbiV1!a8~ewA59>-kb{Xw zh0=TGH1!7NEY}c&{YV_|`xr>EYy~lnMugX z!@J@X)#6eTv=bA2fCC6keE!V)^dd|defFGaY(uEQ!K`Tk(gD9_bRlX$&|jWw+#=y ziG_f@4-b8i(k zS44(xY|sc^&k)ef4I#)S+cZ>94~@hSeg5|997*>vIeF^JuFcGgd#vIHV}ofCdH@4k zZnup!RO#FQcy=$4$072rONxvIs>^;zU^MElCK#Ad8R z&=LYeqz2CuH6i|5vCU^FOMJW847sM2(hqJ$@t`GJl(0dx6l}?^>6XG)xM{z|6TYw= zxFpWF;T2*t*hJ8Lb{W3LiOh>H% zD$X&Q*i+64Q!oryWZjPkdt(9oEq9R=P_-+KAFQfIB1ycd#wmK>m|aAdrD@|J|^S zp%tkgXPi^Fb&km1@Wcri%Z^-jYM=-A-O`A#tg>}t?Q zb;x$@xQDU$VzE1>{Ovr@p#ywuwo`=3Fx4}o8e82LEf44I_<(#>aQd^{`fY^eQ5R?# zbvr4KTD(f9gXrU{Zt|^t{BX&IzDUytP`cq>`>|Ykod~Gx&JG;dH&t6E!X>HW|1ney zYlmrP`@}*rc6tlBrSDL$<_PqaMPJ|bSPycZ!7ttDoW<|@_23rW`4d8iYdShNhZ~=N zJK`GoxY51Z5Q${<2mL3(B2{;4?Fe;uYT{8ANc)9r-i8#J;a%a9l-y5FOK!@X3$9as z%9`cggkw3m92Bx%vU6+1>({E|)7j%`-s(d3xao7E&fxv7eJ6kDTO4_+o2uaqV(=Tt z5x0)a?DXA6JOFMvhw}l39S7K5t;DEw*Z%iZ^tF9T7xO3X+XXY|k~x-AWpU5Xd;7PM zsSfm>8(Ib)*zFLFP%_g2D8{?1V5akB_+rhRfp=@yYYrHB*ZE3uJpLyR-UHeiEWAcO zDSXaUE3cP4m2*FErzLQFiAJm^?Pulfue{Io=jp5C!_V1Ty?$T<{#<5PSdU7N)0As= z4XYnZhKj~;1Pe@V|reM=)d?}7k_$NJOhu%4Si57G3JRn-xgG*`HygyBF2Grbp5<0dug^!8FUG@8mNIhK~Wm- z;ZU@%mAr3*bA?sL57(N{ug~|h{kbISx=;)}ZIE56&V+x08u3p58d&DXOr{)OzBng4HqJtqU}e*x_Oa@zj^ z*#9%}|3cXRs|n_R2DASX-T&Lu6`?o^ zlrT{rCrf++65uG6%#lD)JN;?T)6O|v-{{NRV`S^hDwm9`>*5Dqn9FQ(z=aq33zLrU z_)$;s7J0JFa`QaT-1pN)q$Jk!m0e2MG`9~<@;J#S@-m%rOIo`sJI)KASO*a;V=sY-1wK)udn<5>0PB z?`ZK6mSCE^Xx6&91o?i|&Dz|P++X`?B}CI$%Q8MDi<{P?#sSU`#eGw6pLapEtJLb) zhiV123wqRegjm5zZ911pzHr=Uy8UVL5c2I734$8>HOq_6zoHo zhW3RD+26eZ)xRy-738A|)!!ZKQFB8+>F1N@v72+Qc|*^N{}uGs)2%YS`qwjS=lVd- z;z=K}KL@SvhWu48{aXKcS6&O=XAb9uyV9>a0RZ_Ww*m35D`={J`&9G(bG#Y(17P~1 z9-lM)Rm8TkAvtGthvu!l(y)wR^nMmF+m#f3$@}f4yw5O3_xbsQlXSiIe|WT6|4%cU zf2jlh?PT-cbp!vukMjSh9bn=3FX90X4o(7ARyG1Ac6I_bMg{`*zmfTG1L=Qq|BU}# z`zQWW=lEOuC;q)3>Yw;e{$DjVHUj3qYyFdB`#b(8_s{%)*8OMv&zk?P{VOsuK>e%6 z!0@lyzxV%VjeqWC|7*hYe_sF0`zQCm_WalW|AX-1pU=Qw_n!X{KK$!#`Y#F=*8koB zfc5{`0Dy^|iH+qy3m+CcAYD<08yU2U+dRzN(PXE~beRig`3lm+3UnhEAS^Km(SVRF z1SNjbhKjcL&@=_YVt}yK$<{Eg#0GKZ*#u?0WtVM!1I$Ow?Hprp@9mj0ZqiO2ic%HR9S_#@J4e zh?cC%Al)s;2a5l>Qj352i6pPt?r;*F5>Hh@vL$Z+=hunuyt6skG-1OT!6<)A?PYXV zP`Eo-UNQ_)^K*mE#mGDU5ik-wQDOX>J9r3OUWH{~n+5iz7cj2ZYq__Q)Si6&(`R@g z&}#udEhLo%4l_-$LYZr$Sb4-8G+4ptuUfI;fuTWi60+5cXcKcOD=l|1v*hut%iHjJ zN6%KbSI{8QLDKrqqQ5WtT`OvmpPS&r_cH!7+A~^P!nz-gMTBSf=`b2G^IGK0!!V2U zCtu^<_oiA&UkvlfZzm|+Zc1zTwup_KR?179H$-ZngL}P+lP`zKAYq2vSVX!llQ!jpteUZYnY^YAzsI3sgziZ?!zQ1rO*sMwaNVfF>lmj;DQR znQ!E_C!}CzGC11ug4PSpZnTD$CU`Vn`cyl7`?5 z5=wh!nUO83fK|KTLddG5nU=!r!0U2*wiV%& zgBu~vi9e%=xM3VPg@K(+W;Q{*AeB#J3I_9QwPQZb|T02<}pg08rBdJv{sk!$~2YqH4(4vSxnl?g%qctIH4z#6oXL!!cv$; zof&Mnm-RW$@{yPP)VYh5bT;kvoi?Ukp_as^!>MDnwI0G?>J;;uh+`XXf-t9U;v<(8 zB`~cNOJ_yPXQf?wq=79ey_WdzC~;RD^j@9-DQyzbI4aL@3kHE;mtQnH4d6ps!)sG= zF;&iMpvNngmChB_@sSK=rQ}6Zaz1wYo)k6Rgd`1BL38-v8uk=?b#i~A@8^Z6oNIEEv^JmQ)K zgBugnR2yB^g>|qn(Ui`Heg-O8#4!p+i+G`V>x7e|7Gg#|5s?cD->Ps?YZHHGEDa%m zJpFQ^IDwM)vhk8ABLFI;WfD&+7Nw`0U6T4!(k_(U6}!BO&cr=lJxOk(X8K&`-YQY3 zF~Y+hsI@F271WW0+F<5!s9`PI0*R6Wko=?`VfVUqs^a|u#UB%eMMYWRN|{mBI@Iv; zFdtdM+Lq&}oY%v@hLD6c@yE`5#Dz_q8G$g>BU$7;z!G+~wefmnGJlL8dh3%A?!!dE z&Cqg##xnQv#DFDijipjGtscIW0R}>m@aGlyId!*sfT#4QY=krxC`FmFGrMSZYE_ zV40d5mvEvnq>$dc%*~w%JJt9UtD-FbE*2t=cQ|4&VvLtozLsIc4ughCc0jPojL4Om z=S%%H)C)VAu)mz&t6f)aR(EMkW&T*l7`}li7%DMdE)*JHqhb-7(wcKu&pacRnrh!L zF>PE-8g_T5HP&Q2RrbVqT=%xh#G)y96}c^S&XjLeQbjxMoG@7N(SZC!!%5qlZ5s7h z4IxsrrmX$V1IE+b*s<#bHCpa7C}$Fs8E#1>TZqUVr640MDMH#m+)YHtLUml{=#Qfh zK#R@%lP(F|a6|)F49RSnT3EZwA}LqE&m_%gJ&KX=*gm%4hbE^!<3ySVQzO*mah|Gh`oTh$0VN$tHBy;X zPK;H9Ob zX(z6>Tt+b@?C{lf@z2)VV1v2U(+K)llvhclQ{{9rOfDNKsSXcQH7G;34?2G@5y)PepQv{i z_dT)TQam>R_{>}1A>eDCOFtd>6<&j)m_(kWm^8&v+hD| z-PBaFv@ZqppR`j9F?d&zMb`H9r}7%YaPy*EljEV%zJ`UYiW6F#62fZ}(7p>?;m{%u z{Uz9x>_5uDEev&Jv18AB_1$+wTHp)tdg6P6$?bIVinJrDBn4m;?=LGqbW| zL5MLuq=}TXeoCbDkzgolHdMDx90M>tcXSs$DT`ZMTZ42yAJ_%F%PmOmer1oQj^eZs z?rR;D*$ccx;f%DJ(A;@=b!p~Pe^~!fukVk|(2v#6RS@$-%G@!Wo1d$kl{8@Fkd%&3 zJyH7e!xPMwb60{)s=EHP815>YD|hDfQ7YgE$zv(KVg1~%1?ETt#`4^2eh-55d^c8l=L*8cO#MsbQ@(C$L}dzA<7a2 zFX^*wgDu-FJF}&so;8sZiC|Qyk_^zO)0tFQY?*c0cUhUt(%Ha$CM@QfLEYmahu5fA zjU@Qw%r=~g381X0vB3f|$sDNC!Gf(n%D2aRwY+!_w@t1%cJz3(Lz=YCY|TOS=?k=A z2c0TM?JCZY>76Dmbc2xHr!nm&6jWokQ%L;*;RoD-!UoZOVDKnVw-kP$Go04|eyKlR@*ncHrMeM0=*y1U zc!DofJ3Do;J+3y3PvKXTa=Ln(9HfMtC*ymo>p}AjEO7}h{Uq&>)<_M>xx2p2xt}QK zQMrZvK=Y=bPQK~6ujToQ4C()nck7_XsoraMdzyTHiE;e^;OXrVCZL>^>-XXgDua1vOD|w8NX2E z=U4ggv|M9dYi7The$I^J6Jw^hk?!T~Fu@lnG4oI59H;5wS-IZa2{29F+lPlZ;JLpd z;z4(0rMzHeXC3Vl!5>rfsVSXsOefzOq-5lo{MEx_g>@*1JyOO{3rh`E;iwvsnwohz z2`N~T`@_`I;s6JxjME+ZHowxU1G=I2i~@ra@DCa`23nRip0MDnp_o4!HKak_z>eSo zrjYz@{t!w7@fCa{G4v z5ZPmS*8f@E?3QdnB$2*@%;EFVqSNH|X8eR72tGc8Uzjaiq@V~TpV)KdxxxvJH|3iE zH^Z@qOE-)Nz8>q!gm}%|!$*qK*JH#y#2t~xir+?CGx|d_DlM%<5h|^R#XQkYMbe+L zMCp)?D8nG(SLB=-lFZT$?jPPi;xaN}kdCEJckzXjtAO%G;*!e}by zenil9N-HJFYIw~URWW;sd*=0zQxELF8Ha2xA|EfUl)ALI*?R5j(Vrs z-nk>j!0_y7S37E1V{1)5qWu0!0@@hf8cRA3*OM!^8V59+cE8d&x!Hcx+V@rk3uAwp z=Sb69WG2LOv=?z;-3DG)VVnGy=Jo!|FDQGCcI$x8tn#^XMh8jabR8xquBqp%hv)6A;?UyPlSXU=zYchWpk&@abzTZ#m7x=H0Biu$0?al(dp*bh0Ea8=C0eLH@1|7-Z0~5L`(s_~w z`+Tvv9fwI#*d+^&d>LZI9g;Qg6NIdf&%J+iEmsSZu6rEW>Y4Dmfj+?511sT-fn7)WB)*RZ$A?Nx|(z z$EKI(w_CJJJ=!764!V+~J&ucT!ZQ361IeD!Qc0lE{%5pk6g&zOsN?ALom+m$L24;SYw3BE>Qd_urz8rox9Rsyewk%)|;aE19glc+rWrim^Nu8S) z#6SO}-Dq`ByHIk;7+0AwMNWQBewI4%+`&xo==)9Y)pHQ{2i7y4Lw)a0Wx2V09FTX_ zwP=P>MO`U>M0k9CJ$sOyqa~H1EL#!>&xrk$5BPohV^fN8vTYh8Zl z{e05Pc9m44L&4lf2tmW83h$o&6RwRJ}E^mYa@T8Smu7nN4XlREV-hj zS#vW;O{bZ%4$j^(nvqHW2AUThXz$ENLo~iP(2zOP+m*dwIrfD%!fjmp zeGPWcyZuD#&H zE4gP|c44U&3qk@>KKuS^^BV7QSa8z;U|Wmgnb`9x`~3sVmHwR8-Hg*Ih z%XhfeG$@x!?BnT$^-s(}$m=PmXiUfJ!d0L-T(Tg4jm;P2wIKM-m)!S2>;yiiaom#J z)>m84$_#k~7}x3zQHvrQ2|`uIAo2~nmhIm@duHN?hLz3%7??}+hepGPd8=r6an9_> z*TK|xJD-_wi*nC`&zS7mM`TQEv@Nw#lB8~6al?mFBdS7mNQsbXk$Tq?Gg$tsfqxE) zQG3oz@@eV>CD9b#a;0V?#oQ7WTgqP3vtOqxN58PWftP*Q*D{)SIww&``Rg=L-#W@| z!Cg?_B4-C!9^K!;Vfgf4ax_Y5KdWx^nLmqtKHRQ>m&@H?tdBs7YY&XSIWUOaADEp6?Z zxNS;p9QhQ*ab^LRrKgsZY@`0))=X?wJdCT7Mu7br(6%XnGIeUX32g1IOJRHnhATwB zArKs4i@d8$&vV`|!dCiUjM0K}4 zV97`h;V2nSQ?D&H%L;)(fCe_juiQFJSf*UT-5){3lX2G&99*~=IPJLd9D0r)E4O+3 z%pp&*?!$0x$uix~iZ`&}Gcq0bM?~R1T6()R@fE(toTK@eyC#$UIUGCrz}_b>LBKf< zJr3X-m##B@AviNV}sc!uY)FE5z(qsD23`{fb}H^DUl z=Q-;z=(la(ao(d3uP(ra4-^1_AR<8Ef70X`iGv~-6;SCA$u)$F47YSnU{$!&BgHg7 zl5H|$ZQbHZh0=cj_g8FtSdPgsK|#yTysdtFJh|$)APT&7?kTQO8Cs(i$=+w=m`}Yo zn`;Q3)Ma_Eg#gOgNzSb>4evq9F%xy9=y-3m(_wgE`GwaPoh62|n_K3YmNQdgCv}OSa z4V(g30UJKq)gnB2#o~meM~hbBI0|zjt>9^5Rwi@7Nye6ba+{UUR+Ge(X3e5^s z3D!~U`j1`)X2@h@RtRcEg@R9(%b&xEg~e+g_QyfMqyBl!>(s(F`I3_8+Y0}4&krS{ z0Z+Lla3FTczn>#}3;{Jv=K^5}^z-BM+XDAoB=_pNB7sd=sCT~TRUIWVU zl=vS6*~9LF_K@o!6HrGtQCRleVUW+kH&war`o8B5bb3G3ekAo6Xrj*SkVV$l3}M(M z+AR)|?epy;?oUTuW2?@Kx%R(QA>y<5$?Xdg+p-D;)h>lziWx+i5qsb7{r-_Iz)YEI zL?*zDddq^mRh(-dXyi{84&HYPzpZBd(u>fdectZs;bB&0+HU*nN08EIJy!qeu2m81 zZa69^JDZ@QSzvYP{U5f?^f2ql9oC;rP+}De#=P(%OK)R+G8>N6!c}dIU1ws!onifU zM=yTZfuy7PI^6qhMP|PN8aP~;>~-eD)qmLJKV&VLuu-5AR`cI3aN>;P8!Pf7F)R;F z)js-bK087vUOhs+?SzYzf(;O9SBxAiZ2TbIlSKuH+Cr-c`&HafNA-%_qrq-!<89mTmcv_LhIyv5oe-;BH#Vvp#7=Wr6VWLWw zYNC;ri8WRATv2rK3qj!T-8bfWxGmsm8tv+&b_A2}g&i&J9jvp9ov%l0h;)jrKs6OW z2|q6S0Pv32>YfOv!} zAuoUwV$tHv%URbhafW9iPu)*N$T{~xx|2t8^-`|)|2Z)bk})7cQ>Z|o9@2~KL>ezO z+E=I;@{eTABv|k7sv9{$GA;HYFv5+)1m|jzOm&wrL!&+8VO02Leo6S*cv)oaLM!7r zORxl9SXCCuY|aqix2jmfK;Bkk>~mR&&ad9uGS$WdsSK5j&m4vD%C14I*-px zU%OcHqmyoNb`yES8nYIshT*(2HXUBmM05%iPMcwgWRQF}@o!5;P)Q#VWIT3U_8^(a zQVSL3qGY24f2&6B7LHm{#PzVr1uYiEK=FuNiR{LQ3Ik0<2vGw^KpLxa;?I3bbtQYL zaNW?dT`g8GES@r;sNj0N`#*vBA{szR@}CQ)ocp*fW-Lf~poY~Q7h?r5OyHapLD{ep&!XZH&RZTy_3=XQHCXX#E;_&s)0Ah-7h!?~uH z2$%a{0Xk8?7lYvJX;(T1k|=)D*Hmf{6;30XCz-Cw1Xqkr1%bzGG)`x#9xO~(JEIqo zL#1mJH+S&K&<{kLd5gW!;KE8vH$l{pVl5T+VS!x$Wyqp($bDX>4Y;%UjcOvB*T<~D zuh6e(w)4u>l)tGIl--v_41}vemZ@=a2_l6KNmW{Eld%-k00+S(3KVUV23*V8`M^j< zhIVIMSi)n*E3xf4#J8fz+$ufyE#bbUysYYiuZv}0PfDgKZ?h_FIQgU$dXQS>dKjjl z#3W?IJf&1^=4Q2fsm|Vo{O#|mLWjPeyGH1p}&3efQ7Ju3p7Jb@q)w)9DzR-d9L|JSQMIsJY zT5@V92qiSjT-k3-rvNRU$QHgeXR_+6M&BjbRTuoHVD>jpuV9;NxxG1Z_lx%T{rXW) z&Xv1c%gy7%87yj2X9UwGbh|Y5JDTZkVJZBdFQwY=6!031mG6j8mn@B}?AD`!ruMFS zE@H1o4qcqaejCdD4!U9gK7`;8?zJ6ZnxqCubtuhf{`hxKrj1{Bl^C zlOLxbStacy?fLsEZ5pCcvJ9ucolGYouhBeFueohaUNh9R+Xxs$XIp=pGEIk|>zoNk zQR}wR&A7VQaCzI_wsGFB{&t~D>xj`z*5OrGalFb$s&^68%l9}0zD(F+$hsnOdQ;CY zFU+S^IwSFcYYB1L)n z2%M`f+&^_XiFnW!f0yO5WYuht;GdUN7ioG7!E__IikEke_9tXgUBH%kU64#&#w64M zM)A?*4@=bMnpfs=eO%S{;M(&0rWGofFs<`mkBxCZK8xp$cQBr6!=X7huM^HPH(sT^ z&`VaOs2r0W+mu>DiLILf+BYR;JBnI6UPZ}08ONUPZ{kUv3JB|naN}4q62Y>Ik`gF2 zWSY$T78!{xePGkSHy3LnNY606#$iK{Y7~2SU+4FIZ_XO& z{o(kX(+d+o{>_}%(CD}|RMyb&dJcS88GqT@7-bNQk-6QXb$MrYdvi%Id)m87rhx|2TjfFs#>U}Z9vm44=0&+^J6xj*nvqzOd41q=AL6REb!sQD zX#s5%yuiH(z9cZ3`zwD4m|LFq)T zEC7oX8AAGwTEx4aO*aj0UOU28YxwNkv^Om<7*R0&0ioQV zAgsve!pS8&`+kVUcpGj6HX7`QS)Lkr^&&zt^{qL1t`D-3 z{Ux$iIqp^Ii>0Livn(m>$a!c4(g7%h9Rx7qCQ^6gQXL#go>*5J#Zq}1;$G#jV!;fjfH@)PNu0?n~57zEAP<` z&&F`K*X&AC+(o(|Bl><#X7l3aO=P`q6uG*uq#gV&|GGc)UAc20mv^rSND_2}TIo~B zuG8Z+hTqg*Id7ctoi|(}7?71v`sF8b{IOVNpR!+%-b+W| z$!fRi{CtP}$HOE(13t=4L+~+j$}Dp%Iybu4eNA_$mF=F*b;fO57X#ed$qV^uWQq0Q(+TYOP!y|Pu=1qP4yqNJFhxit1!u=N zr_ie+a#H)w*euumK*-FTW!oE^?)?*w&2zitZmRTrbU%W3bsAl0Gdf~!Fcgb4c$p!D{&>$^ z3^TLtwf9;jt##TD>sg$18FgaerWB9f&O0%bu-@H(eqk!8vQQ^l z&qGv}F(zgpVM&Jh zk=W)cvqt^fhP65vrh~1mq#QxK_|J5R=jZ4pW-VZPn^rT-HrI&b#6Bas_)}Zh>?uH+v-zwte6KG~JI1*!W@KWTv zI`muGotp|eS2+})T-2FUYucf?SBa@C3`vehM)h5MY+BA{QOxiALgV6X7 zK4phQZ&uUIvPOU3%Q~>>xU_2Kly=TbE@x(}(~4&u-mmJ>-5mMwwH)wwSVM_b%%PVj zlDdev0iE%R8H$eY4cgG|@qV+RZaZU8KeXkyw0ZE5sx~lH^2 z3Wh+!HCSCUIXJG#K|lOp%0Le1C#a=E>e)#J*gZn9ime+$>LP@o`r-E~of3R4VJu^Z zAIF!SvH-m${_&?NIrmE!p2t^11A%yp#LmcCO^67Jw_kJL%@r+S##E&$Ohxy zgML^&YBD||4EZXFGNR*ZzG`!uhHm91mk|f6Q{wUxx4B_m@1dFVsV152Dexf(@q7gk zb-G-Ylzei}If7F@1h2t&9QxI;1&YvN>so~8y`D#FTHNnQ$MmH%Gf~ar?Y8Y$Mh6RW zD|*u26vb#PN38|HxzP!bchh7Oq*}Zta?8Wp=(2kwoWhRoyt^X$t!hjCa7Q4%I-_oy z-()rExYaoUMj)Kd=t2vi3|LC24JA?R@?T|)WdJFd5^5tOyHj!!@Zf>k z<#n9miSpe>xMz4CGOuktEI=+U31TjjM`82`*?*uOG`rt0ayC_+;AL}&PLLTwsqgDzV;O%xw(_r z1fvD!<5I7r)z-;N2Am_=L58#54o9TR6U~SIil;5!NN#9|Wafz39G}YR^Ex?@93MDc zz7OWmNtB!!py!M4$=o+oC>Aw*=oK}b(qJZxDoU=CI!xB!;ApHe*DNvTCc)n)I;zbQ zDNERvq6X<{v7Ii0)GHHU+e$Dp%lb=8_+?HtJMvI8BbMS3gw5fG943#j1?%(B022xDC9`u!rac;s?Ap#Rr6BAZ~!U)Rinh9vK{5kz8 zDZ@X_6NTjB9REmY&|93wmEg;WR4m36NCXr|zyE=OHW1SzkCfdyxa_f}*&&YqR;dDK zwYuk+v2TA_WKL(!E8|&JagojDQE0cpu7Bhg{0HNWUVZx$PqM4BCQxYtVBhn+bWjN| zP5?iwNYBqKf4^2Dy*bpBx?$XrbMeS^fHJI2q&*Mvd{WVb&scAr2K#mcf?fNT)D0^Ji45Kx5+W%D$db-GAMGm-5dd8cQQpk09hOfo2cLG z0y+`aH?~W7-Ow&yK)+w|T+&+hQ)IHGO*es}BhfI3q2Pm_9yN78r#D%>Gvz~Xnu?Wj zg7Z;#DsrRgz}Z3IkO|wdt)+q&0sYy*z%bJCZdl*Wl#nfwBGdeP%p|TVlxCwkw}UyX zqGnfL$M2NuOs5Qi^Ke<`QJ6_?{Q6VeC@m6X&8><|&h&6DX9i>ppQ*B@pPcOIsY)tq zP6I8UTZvB3Gopx0CTo!Nw~S_$QftKwM+_&op-eeX?D9?_X~u@u3J@ohjhWbV8#^QP zv!Wo@$lNIj)O|qS{s0lf!j?b?_MO;vP^UzR08*8>kdu<)@Cm(pzyElXyt@2Hc@#2O zGBGb1B?9ettg;>Sj)J|sB-!QdG)6SIbRbVG&*%g0bTZ9%EPd_tmb>ZO?8H?x42$H* zFMYn;<@fEot0~9WCGzTCbKn}gzCz}K)jH5{#_Xetk^4hFQS8{{811B9;5*Cj4o3oI zc1NcVTsvTj-RGm>!(8W|!&kYbjln#5ptg0le%#@MLszS7*7%FG87lXZS(y4j=m%H0JyegN^F*#5H$*6 zpK%&%ye6hb=0=8#*zZlE$_WUMKpJfVUQvRVv7e?X_$m1rQgA1%G1=OLOLYwO84%9Y zUmT0NDx3uep@#rzg&S&A+LUo@WbPLtSkQ@mS9>w{a`z3w;K3#(FH4I&Cc^ACWdXikHo^#H4_-5kurC4; zX3@)CRZMTHduAUk*mu|XF~vp4>4ifOki~Xi8d1vN2m$WpeJRsw<)Oqldn@WH{Q?H( zNCp$!*-t}h7=i)tm3h$u5UZhXIi;*;Y00PLWop61L^!cxJ25YnY7?_}&|hBhWCgEQ z+dH)MK9jb-NVfl$xV&;ImIiA{Ige*2%1fJq4G0>_xECo@EH}zn%Epj5z`p)^wyw7> z93v$;97%(M(erDJ>Ha|kDyNfXQR3U`sgml{_}Uz*N>9%3+oOe>E9_j=!|de~^fspQ ziHRB?idKjdmNGj~C_AhYq*|qt9u(B_2`;H+X~b^65x@MV2zlj+6i9(-UJ>Ux{mg4O zm{z55WTPU1px1;})Sh0_= z`X-Yjq|;&fJY7|NjGqgW66GGgCr_AgJxpKoeLeW1)~Bmd(>@-PamYoc@G16$KRqgL zrr+y+?V4;17Za<_miLNi+4DGcw(-#$Ph$$31M;I$AJr#vi=wzD=!g#v@UFW)%<6lP z9FvAlE`%Za<>iNWFZwO%6H&d&J4_6wEaOs8vC9FU+Y!Ge7&gBf>&V}?s3|E|b+#PR zBSY{Yb})9P)9U?_iTkBDufmZ|Ud`HNajsE4a=^33W{n#iWKV@Qw;J?He_YMXOhSF` z%gU=UgGVZTsSVbpbcN<3Y3@&?P-JGEFXXhnc&b8Zf)!DdDEZW0e`IH9T&S65EY4o> zsdlL#n~{r~cHh_8IAi(BE#46-7Nq%T4pYb&_~>#n82n`>Zk@x5ZJP@;Qv!Q*Z^&v^ zf7Zen4)>VeHqbXt`INgp%&)Mmrb8^qJs@7s7~k(({IWD%D@PfIVICo$EFx{sb3%2T zyqCPNnQ|WjU-scZ!nzk;atEx=Q+;(nV}c}yg^H*ft`IzEmRNHbWEC<~eR;5rB*$2Y zM;p^=KmZFv#+DkX&hs(F0HkSvs$ObpRT-v9SD;#uG=}uTu9tR*mUImgkiF0Qwr5Oh z>Ck_*eQGPpEKyRH2w^8DaD7@$N%X>oA4G}Gy_lBOI|RhL_#uY6 z-DKDSTFSvw;iKC*GQM-K8-S|hG*iF zi$OEv`%zl1q3>Z}=WgjUk!+ zoY16qkwO)tt?8MZ@5T3o=Ka@+vxp^{iq1P)!>>(v%^B2`N1pYK&gQO^=4`zV<3oN7W(MG@HD)!+>Xfg0+Zh7B3I*?^ zR2t#UF5D;9jyCv|QO~oEAuqQ`ykLhr^H2F_U%#R;_EFlIR7HB+N4g9Yc2o{izI>b|+f)3) z`6%jnh=nQX$Y7?OsRnPWs4(Uc$0#&9*^2_bCtB%oJy<6wIpwiAM6Z#UOGhh170G1J zg=RB1Jr}~#JI1u8GKuv*3r7?TX)MJAk&5&vXN%fQinN($Gx=y_BT^p9J1R(7{*cY( zbYE8p3pr?y#$Vwp`OZvb?(o{}v9k<}!%_3}vL5z;xKa3tG`)= zoq*SA*(2#A4~@uU7<{T?K+9>$KkS*KH`{;53wwhGwOkPf=}7`@+WPR;XnzG6HiC}W z`$PR#EV=1*A8@5w**~z0p{TI8jT6QMuzKQ9FJx)McRR_Y`+1UPt$lb0!=>MOCJc}L z&{YSX#|hqv&ap=T#`_yPsb`v>?&dryX?>O-w&N62nr6{dAy1Zv@Ug*6u@l+GcM)pA zIr6v&9WOV^nkdSRVXHyVef0!Z-9W^QK(ptx{OKOSfcX{ z!JSTQ+h0PfIcjmW#tuhcOl3SQ@Q@8`Dg!jVu`rrVLol_t_pmBW(K@_7kgi%_PWJ)x zpimjw5*7M)?1wU|PWVnegru)F+MPO_dLqy?oaFLhq~L2G>g)MxaZC_k^A^EKcaN-{ zIO1reD?v|^BPdWseO42lwPXjpy_s^p_LWbhQah=ErM9(IL#pF#h}# ziY%L>`=#o|)g=+bN!Z+F{q|8+AN-=;PTrdlc9uSO-Z&>~3Cn|@eL>%U;ka>k9JTm~ z@>6hFg1PUGv^U$2kP?Be5DZQ7ogZ?k9=)0Fkb>uYNNIqy`6u_<)O=FXxDAa8lCmoA z*U}!kA98VKstDOsv;?H1>$b&NBL&w4+~>v}*o0G7VKNQs!WB6V3e}^Lbe1_?`)bRs zH?tCij>j3OO9PwQY;rearN6uRK!CFrZ^!+-Lvc|JsHvog?m%0ve)m~mSst0-g!f8z zKJr%+E{9--yvfdRWxGAQuAn)imj_~gc#XN#NZ1NP3{RBJq2F+YEf#xdeX`8g5Qoe| zQmiP9z1z-(tKm)nodC{GIuz~w2t|`utqVa~vSkyhWQO)d7fj!P)r)JxTM}=XC8%~J z%g`h0+=kDQT84SZu-nwqGg#5W~BlAKfDd?$TGqWVH$KQ0{ai{mwA@DJ~H(&B056dey2>{pkq+8!Ogd04I< z>!iqvb|XvO(_y}qfhxTX9<7vm`-wdrgYVd;mIT=R@|XLhwWmVLDB<_hs0IV5K(Zb4 zfmZ1TdI}VC(4?zU%8sb>w6cp?!J#NM!3vl|(NZ}Hqa~VV4opPcl-n}gD zR(%_j5NZ&{L=EG|9O8f_K;>~$mGeI8tAM_+&rUttahfi&4JI2l66i9?e%zHJLZ`3Q znOugYN&TDOS)p><&Yc8mPEUs&Op=DuSZtoTJJ~H7Yw?%3znlJ|%m3rNHs6>|x)fAC zW#cNK=2w>``Xn>!;q$O`#kG5&UB^r;ZT;460281zPhQli#)sPWaVVB>SIDCRRo_Q> zOT~$@V#98NE*q3K2VHdWxe20m)Tyy{{i-fgw79FEzW_deIi-cKC5`HvpZt`9pKw8d z-+9`^&tQ!_83JsJsQuLT9JWq>VvpWKB;97=y zb>hAbk})Gmn(d@in4*ZXBeE+?2ea$+J-j~Cmn@YXdes*0p97T-Ynor7P#Aqm$AE+9 zJT|qBg)0ElFGp4rQh2hC;15u&`*4Y1suOFRXhLrZwu-T;Qv^;$?`=xdN6TQVOA@@( zq{TE+sM{Q|YM3L8BR+ghn^{IhK%lnpS!0;2M+Zm;c(`Ol5_Q}bvS?A4I!)c&H|8&X zul9*1%$rvmSa0*4Hy5~x@!$KuP-4H>+8s_B<~94SsmEQ;rN7y4W0CZ_?Hq61oV0ua z&Zt`9L1Q6`V#pMz$f=4aFiG0V-eX^mEh<(i{)Nl3AlgWH*+|{|XNY8IcS!y#;xL0k zyQk}%iJgM(is9J{d%F@`SRVH)wL_P)1!x&qa%Fmms-_$a;0#y-S;jL|SI`D2vWmC5 zVd6xNNvz%QqhFdhT6OCgPe1?a6$o#(f{;%`($MRNrOEbPX{V}O^E}3-sgA)_bu44e z1gnZA{+Wc;QNb#_X86&Gt_)%ka*w(0LU*o?D*s!iI5?YP9zHgk5wqvm#X>E|no%o9 z!{Z5W?jN1&KT~|XzUy-Oj*F#RCaK)IIm2TrqY+=ol_PKlQHKI3CA<}GZ=DBO4$v~mdKN#uY?ky)<>zfDT^y(w+j0v(aQ zF_33g_wlj;H_f1c4(0<2>^{v|fR=sy;UB|)>&TY{hSn@ueILy%X=xA2oXejpCLZ*_9-rkRg^FG1iy2%(Ks82FB(QW^h|>3knk@qz(BJ^=uZ>* zCuw!R7dqEIfpz0u8sOr5&2_#v&?=gB#QU&vV>{?_5$QbwO{V7oshLA^b!!N*_NG?N zCmo}XAD+)Uc-y)fX;qrlYoAP8hbu4=i)vf#7lpXymUb)cU+zhy_>B~KcstHoaC&@pls1pEDUWU9Jj~B~mUz+}A0>w< zHt)7(s|GM7-&7+}?_i50V-Z@-N^T{5&$e4)5DU}IIAYsUbf1@`oC(e*^g&3w<`Vy#RObxa!u1+ATqVKkoqM5@K{W*FDISGFv_}l9`ZHRS_$&i zHjp`o^Fr7O>AuWjrWbQ=sdgRH8)h{lUhVC;s7)1Kry+?U^&vd_j}y8{#JprJNq8p` zcjzsSPRCenFIgKa8q8-m%I;g(nLN=}^=Xcm1J!ui*<{bi-0vQ2d?`9U_1#w1Y`r~@ z7;msP(5HL7Vv$NFPDd}N|+CvDMiC(+2^GTlq#W|Ol zrIw`%GnH|Ua@mh%<$k_0fUI~duo-u2Gq@!GA$a|L-OE6XL&2#LHH@O9o z0F`L%*I>tBSo+5_8LUGhHq;x3?s+f37+ h&Dq%xIV4YX^k~LbeQ4npn03EdmMo` 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 diff --git a/MQTTSNGateway/Gateway Overview.pdf b/MQTTSNGateway/Gateway Overview.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d00eca80c0f6d0bf1dccc2771c80bba98c298116 GIT binary patch literal 117278 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 literal 0 HcmV?d00001 From bb72c590c6cff8677a546ee37c24b09f485008f3 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Thu, 13 May 2021 13:09:28 +0900 Subject: [PATCH 34/67] Fix of #221 Signed-off-by: tomoaki --- MQTTSNGateway/src/MQTTSNGWClient.cpp | 11 ++++--- MQTTSNGateway/src/MQTTSNGWClient.h | 6 ++-- MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp | 2 +- .../src/MQTTSNGWSubscribeHandler.cpp | 2 +- MQTTSNGateway/src/MQTTSNGWTopic.cpp | 30 ++++++++++++++----- MQTTSNGateway/src/MQTTSNGWTopic.h | 6 ++-- 6 files changed, 34 insertions(+), 23 deletions(-) diff --git a/MQTTSNGateway/src/MQTTSNGWClient.cpp b/MQTTSNGateway/src/MQTTSNGWClient.cpp index bafb99b..f61ac92 100644 --- a/MQTTSNGateway/src/MQTTSNGWClient.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClient.cpp @@ -182,15 +182,14 @@ void Client::clearWaitedSubTopicId(void) _waitedSubTopicIdMap.clear(); } -void Client::setWaitedPubTopicId(uint16_t msgId, uint16_t topicId, - MQTTSN_topicTypes type) +void Client::setWaitedPubTopicId(uint16_t msgId, uint16_t topicId, MQTTSN_topicid* topic) { - _waitedPubTopicIdMap.add(msgId, topicId, type); + _waitedPubTopicIdMap.add(msgId, topicId, topic); } -void Client::setWaitedSubTopicId(uint16_t msgId, uint16_t topicId, - MQTTSN_topicTypes type) + +void Client::setWaitedSubTopicId(uint16_t msgId, uint16_t topicId, MQTTSN_topicid* topic) { - _waitedSubTopicIdMap.add(msgId, topicId, type); + _waitedSubTopicIdMap.add(msgId, topicId, topic); } bool Client::checkTimeover(void) diff --git a/MQTTSNGateway/src/MQTTSNGWClient.h b/MQTTSNGateway/src/MQTTSNGWClient.h index 55685f0..c50df2a 100644 --- a/MQTTSNGateway/src/MQTTSNGWClient.h +++ b/MQTTSNGateway/src/MQTTSNGWClient.h @@ -198,10 +198,8 @@ public: 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); + void setWaitedPubTopicId(uint16_t msgId, uint16_t topicId, MQTTSN_topicid* topic); + void setWaitedSubTopicId(uint16_t msgId, uint16_t topicId, MQTTSN_topicid* topic); bool checkTimeover(void); void updateStatus(MQTTSNPacket*); diff --git a/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp b/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp index 8b79935..6c3a8be 100644 --- a/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp @@ -126,7 +126,7 @@ MQTTGWPacket* MQTTSNPublishHandler::handlePublish(Client* client, /* Save a msgId & a TopicId pare for PUBACK */ if (msgId && qos > 0 && qos < 3) { - client->setWaitedPubTopicId(msgId, topicid.data.id, topicid.type); + client->setWaitedPubTopicId(msgId, topicid.data.id, &topicid); } pub.payload = (char*) payload; diff --git a/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp index 3f0d5f0..906e3fa 100644 --- a/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp @@ -111,7 +111,7 @@ MQTTGWPacket* MQTTSNSubscribeHandler::handleSubscribe(Client* client, subscribe->setSUBSCRIBE(topicstr, (uint8_t) qos, (uint16_t) msgId); } - client->setWaitedSubTopicId(msgId, topicId, topicFilter.type); + client->setWaitedSubTopicId(msgId, topicId, &topicFilter); if (!client->isAggregated()) { diff --git a/MQTTSNGateway/src/MQTTSNGWTopic.cpp b/MQTTSNGateway/src/MQTTSNGWTopic.cpp index 43bf82e..710c5ca 100644 --- a/MQTTSNGateway/src/MQTTSNGWTopic.cpp +++ b/MQTTSNGateway/src/MQTTSNGWTopic.cpp @@ -397,14 +397,22 @@ uint8_t Topics::getCount(void) /*===================================== Class TopicIdMap =====================================*/ -TopicIdMapElement::TopicIdMapElement(uint16_t msgId, uint16_t topicId, - MQTTSN_topicTypes type) +TopicIdMapElement::TopicIdMapElement(uint16_t msgId, uint16_t topicId, MQTTSN_topicid* topic) { _msgId = msgId; _topicId = topicId; - _type = type; + _type = topic->type; + _wildcard = 0; _next = nullptr; _prev = nullptr; + + if (_type == MQTTSN_TOPIC_TYPE_NORMAL) + { + if ( strchr(topic->data.long_.name, '*') != 0 || strchr(topic->data.long_.name, '+') != 0 ) + { + _wildcard = 1; + } + } } TopicIdMapElement::~TopicIdMapElement() @@ -419,7 +427,14 @@ MQTTSN_topicTypes TopicIdMapElement::getTopicType(void) uint16_t TopicIdMapElement::getTopicId(void) { - return _topicId; + if (_wildcard > 0) + { + return 0; + } + else + { + return _topicId; + } } TopicIdMap::TopicIdMap() @@ -456,11 +471,10 @@ TopicIdMapElement* TopicIdMap::getElement(uint16_t msgId) return 0; } -TopicIdMapElement* TopicIdMap::add(uint16_t msgId, uint16_t topicId, - MQTTSN_topicTypes type) +TopicIdMapElement* TopicIdMap::add(uint16_t msgId, uint16_t topicId, MQTTSN_topicid* topic) { if (_cnt > _maxInflight * 2 - || (topicId == 0 && type != MQTTSN_TOPIC_TYPE_SHORT)) + || (topicId == 0 && topic->type != MQTTSN_TOPIC_TYPE_SHORT)) { return 0; } @@ -469,7 +483,7 @@ TopicIdMapElement* TopicIdMap::add(uint16_t msgId, uint16_t topicId, erase(msgId); } - TopicIdMapElement* elm = new TopicIdMapElement(msgId, topicId, type); + TopicIdMapElement* elm = new TopicIdMapElement(msgId, topicId, topic); if (elm == 0) { return 0; diff --git a/MQTTSNGateway/src/MQTTSNGWTopic.h b/MQTTSNGateway/src/MQTTSNGWTopic.h index 6946b1c..b7f6866 100644 --- a/MQTTSNGateway/src/MQTTSNGWTopic.h +++ b/MQTTSNGateway/src/MQTTSNGWTopic.h @@ -81,7 +81,7 @@ class TopicIdMapElement { friend class TopicIdMap; public: - TopicIdMapElement(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type); + TopicIdMapElement(uint16_t msgId, uint16_t topicId, MQTTSN_topicid* topic); ~TopicIdMapElement(); MQTTSN_topicTypes getTopicType(void); uint16_t getTopicId(void); @@ -89,6 +89,7 @@ public: private: uint16_t _msgId; uint16_t _topicId; + uint8_t _wildcard; MQTTSN_topicTypes _type; TopicIdMapElement* _next; TopicIdMapElement* _prev; @@ -100,8 +101,7 @@ public: TopicIdMap(); ~TopicIdMap(); TopicIdMapElement* getElement(uint16_t msgId); - TopicIdMapElement* add(uint16_t msgId, uint16_t topicId, - MQTTSN_topicTypes type); + TopicIdMapElement* add(uint16_t msgId, uint16_t topicId, MQTTSN_topicid* topic); void erase(uint16_t msgId); void clear(void); private: From dcde0bf4ff47ccc6bbccb9a994cb0290aed1d5e5 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Thu, 13 May 2021 13:37:55 +0900 Subject: [PATCH 35/67] Bug Fix of wildcard character Signed-off-by: tomoaki --- MQTTSNGateway/src/MQTTSNGWTopic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MQTTSNGateway/src/MQTTSNGWTopic.cpp b/MQTTSNGateway/src/MQTTSNGWTopic.cpp index 710c5ca..692ff87 100644 --- a/MQTTSNGateway/src/MQTTSNGWTopic.cpp +++ b/MQTTSNGateway/src/MQTTSNGWTopic.cpp @@ -408,7 +408,7 @@ TopicIdMapElement::TopicIdMapElement(uint16_t msgId, uint16_t topicId, MQTTSN_to if (_type == MQTTSN_TOPIC_TYPE_NORMAL) { - if ( strchr(topic->data.long_.name, '*') != 0 || strchr(topic->data.long_.name, '+') != 0 ) + if ( strchr(topic->data.long_.name, '#') != 0 || strchr(topic->data.long_.name, '+') != 0 ) { _wildcard = 1; } From fa7daac109b2948ad857614da351f7ae55edea0d Mon Sep 17 00:00:00 2001 From: tomoaki Date: Thu, 13 May 2021 15:09:04 +0900 Subject: [PATCH 36/67] Bugfix of #225 Signed-off-by: tomoaki --- MQTTSNGateway/src/MQTTGWPublishHandler.cpp | 9 ++++++++- MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp | 8 +++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/MQTTSNGateway/src/MQTTGWPublishHandler.cpp b/MQTTSNGateway/src/MQTTGWPublishHandler.cpp index e73a7cc..dfa8928 100644 --- a/MQTTSNGateway/src/MQTTGWPublishHandler.cpp +++ b/MQTTSNGateway/src/MQTTGWPublishHandler.cpp @@ -127,8 +127,15 @@ void MQTTGWPublishHandler::handlePublish(Client* client, MQTTGWPacket* packet) /* add the Topic and get a TopicId */ topic = client->getTopics()->add(&topicId); - id = topic->getTopicId(); + if (topic == nullptr) + { + WRITELOG("%sMQTTGWPublishHandler Can't Add a Topic. MAX_TOPIC_PAR_CLIENT is exceeded.%s\n", + ERRMSG_HEADER, ERRMSG_FOOTER); + delete snPacket; + return; + } + id = topic->getTopicId(); if (id > 0) { /* create REGISTER */ diff --git a/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp index 906e3fa..2b4f0a6 100644 --- a/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp @@ -68,6 +68,12 @@ MQTTGWPacket* MQTTSNSubscribeHandler::handleSubscribe(Client* client, { topic = client->getTopics()->add(topic->getTopicName()->c_str(), topic->getTopicId()); + if (topic == nullptr) + { + WRITELOG("%s Client(%s) can't add the Topic.%s\n", + ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); + goto RespExit; + } } else { @@ -90,7 +96,7 @@ MQTTGWPacket* MQTTSNSubscribeHandler::handleSubscribe(Client* client, { WRITELOG("%s Client(%s) can't add the Topic.%s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); - return nullptr; + goto RespExit; } } topicId = topic->getTopicId(); From d567b0ba7f661508907c3408496e439788d209d1 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Thu, 13 May 2021 19:46:02 +0900 Subject: [PATCH 37/67] Bugfix of test Signed-off-by: tomoaki --- MQTTSNGateway/src/tests/TestTopicIdMap.cpp | 69 ++++++++++++++-------- MQTTSNGateway/src/tests/TestTopicIdMap.h | 2 +- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/MQTTSNGateway/src/tests/TestTopicIdMap.cpp b/MQTTSNGateway/src/tests/TestTopicIdMap.cpp index ce3ecb3..26b5312 100644 --- a/MQTTSNGateway/src/tests/TestTopicIdMap.cpp +++ b/MQTTSNGateway/src/tests/TestTopicIdMap.cpp @@ -32,13 +32,13 @@ TestTopicIdMap::~TestTopicIdMap() } -bool TestTopicIdMap::testGetElement(uint16_t msgid, uint16_t id, MQTTSN_topicTypes type) +bool TestTopicIdMap::testGetElement(uint16_t msgid, uint16_t id, MQTTSN_topicid* topic) { TopicIdMapElement* elm = _map->getElement((uint16_t)msgid ); if ( elm ) { //printf("msgid=%d id=%d type=%d\n", msgid, elm->getTopicId(), elm->getTopicType()); - return elm->getTopicId() == id && elm->getTopicType() == type; + return elm->getTopicId() == id && elm->getTopicType() == topic->type; } //printf("msgid=%d\n", msgid); return false; @@ -49,144 +49,161 @@ bool TestTopicIdMap::testGetElement(uint16_t msgid, uint16_t id, MQTTSN_topicTyp void TestTopicIdMap::test(void) { uint16_t id[MAXID]; + MQTTSN_topicid topicId; + topicId.data.long_.name = const_cast("topic/test"); + topicId.type = MQTTSN_TOPIC_TYPE_NORMAL; for ( int i = 0; i < MAXID; i++ ) { id[i] = i + 1; - _map->add(id[i], id[i], MQTTSN_TOPIC_TYPE_NORMAL); + + _map->add(id[i], id[i], &topicId); } for ( int i = 0; i < MAX_INFLIGHTMESSAGES * 2 + 1; i++ ) { - assert(testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_NORMAL)); + assert(testGetElement(id[i], id[i], &topicId)); } for ( int i = MAX_INFLIGHTMESSAGES * 2 + 1; i < MAXID; i++ ) { - assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_NORMAL)); + assert(!testGetElement(id[i], id[i], &topicId)); } + topicId.type = MQTTSN_TOPIC_TYPE_PREDEFINED; for ( int i = 0; i < MAX_INFLIGHTMESSAGES * 2 + 1; i++ ) { - assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_PREDEFINED)); + assert(!testGetElement(id[i], id[i], &topicId)); } for ( int i = 0; i < 5; i++ ) { _map->erase(id[i]); } + + topicId.type = MQTTSN_TOPIC_TYPE_NORMAL; for ( int i = 0; i < 5; i++ ) { - assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_NORMAL)); + + assert(!testGetElement(id[i], id[i], &topicId)); } for ( int i = 5; i < MAX_INFLIGHTMESSAGES * 2 + 1; i++ ) { - assert(testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_NORMAL)); + assert(testGetElement(id[i], id[i], &topicId)); } for ( int i = MAX_INFLIGHTMESSAGES * 2 + 1; i < MAXID; i++ ) { - assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_NORMAL)); + assert(!testGetElement(id[i], id[i], &topicId)); } _map->clear(); for ( int i = 0; i < MAXID; i++ ) { - assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_NORMAL)); + assert(!testGetElement(id[i], id[i], &topicId)); } + topicId.type = MQTTSN_TOPIC_TYPE_SHORT; + for ( int i = 0; i < MAXID; i++ ) { - _map->add(id[i], id[i], MQTTSN_TOPIC_TYPE_SHORT); + _map->add(id[i], id[i], &topicId); } for ( int i = 0; i < MAX_INFLIGHTMESSAGES * 2 + 1; i++ ) { - assert(testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_SHORT)); + assert(testGetElement(id[i], id[i], &topicId)); } for ( int i = MAX_INFLIGHTMESSAGES * 2 + 1; i < MAXID; i++ ) { - assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_SHORT)); + assert(!testGetElement(id[i], id[i], &topicId)); } + topicId.type = MQTTSN_TOPIC_TYPE_NORMAL; for ( int i = 0; i < MAX_INFLIGHTMESSAGES * 2 + 1; i++ ) { - assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_NORMAL)); + assert(!testGetElement(id[i], id[i], &topicId)); } for ( int i = 0; i < 5; i++ ) { _map->erase(id[i]); } + + topicId.type = MQTTSN_TOPIC_TYPE_SHORT; for ( int i = 0; i < 5; i++ ) { - assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_SHORT)); + assert(!testGetElement(id[i], id[i], &topicId)); } for ( int i = 5; i < MAX_INFLIGHTMESSAGES * 2 + 1; i++ ) { - assert(testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_SHORT)); + assert(testGetElement(id[i], id[i], &topicId)); } for ( int i = MAX_INFLIGHTMESSAGES * 2 + 1; i < MAXID; i++ ) { - assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_SHORT)); + assert(!testGetElement(id[i], id[i], &topicId)); } _map->clear(); for ( int i = 0; i < MAXID; i++ ) { - assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_SHORT)); + assert(!testGetElement(id[i], id[i], &topicId)); } + topicId.type = MQTTSN_TOPIC_TYPE_PREDEFINED; for ( int i = 0; i < MAXID; i++ ) { - _map->add(id[i], id[i], MQTTSN_TOPIC_TYPE_PREDEFINED); + _map->add(id[i], id[i], &topicId); } for ( int i = 0; i < MAX_INFLIGHTMESSAGES * 2 + 1; i++ ) { - assert(testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_PREDEFINED)); + assert(testGetElement(id[i], id[i], &topicId)); } for ( int i = MAX_INFLIGHTMESSAGES * 2 + 1; i < MAXID; i++ ) { - assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_PREDEFINED)); + assert(!testGetElement(id[i], id[i], &topicId)); } + topicId.type = MQTTSN_TOPIC_TYPE_SHORT; for ( int i = 0; i < MAX_INFLIGHTMESSAGES * 2 + 1; i++ ) { - assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_SHORT)); + assert(!testGetElement(id[i], id[i], &topicId)); } for ( int i = 0; i < 5; i++ ) { _map->erase(id[i]); } + + topicId.type = MQTTSN_TOPIC_TYPE_PREDEFINED; for ( int i = 0; i < 5; i++ ) { - assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_PREDEFINED)); + assert(!testGetElement(id[i], id[i], &topicId)); } for ( int i = 5; i < MAX_INFLIGHTMESSAGES * 2 + 1; i++ ) { - assert(testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_PREDEFINED)); + assert(testGetElement(id[i], id[i], &topicId)); } for ( int i = MAX_INFLIGHTMESSAGES * 2 + 1; i < MAXID; i++ ) { - assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_PREDEFINED)); + assert(!testGetElement(id[i], id[i], &topicId)); } _map->clear(); for ( int i = 0; i < MAXID; i++ ) { - assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_PREDEFINED)); + assert(!testGetElement(id[i], id[i], &topicId)); } printf("[ OK ]\n"); } diff --git a/MQTTSNGateway/src/tests/TestTopicIdMap.h b/MQTTSNGateway/src/tests/TestTopicIdMap.h index 3edceb1..29cd5bd 100644 --- a/MQTTSNGateway/src/tests/TestTopicIdMap.h +++ b/MQTTSNGateway/src/tests/TestTopicIdMap.h @@ -24,7 +24,7 @@ public: TestTopicIdMap(); ~TestTopicIdMap(); void test(void); - bool testGetElement(uint16_t msgid, uint16_t id, MQTTSN_topicTypes type); + bool testGetElement(uint16_t msgid, uint16_t id, MQTTSN_topicid* topic); private: TopicIdMap* _map; From c65d66e3d365793357b727c37415ca89d52a4ab5 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Thu, 13 May 2021 20:45:54 +0900 Subject: [PATCH 38/67] Bugfix of #230 Signed-off-by: tomoaki --- MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp b/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp index 6c3a8be..25e0628 100644 --- a/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp @@ -240,16 +240,25 @@ void MQTTSNPublishHandler::handleRegAck(Client* client, MQTTSNPacket* packet) return; } + /* get PUBLISH message */ MQTTSNPacket* regAck = client->getWaitREGACKPacketList()->getPacket( msgId); if (regAck != nullptr) { client->getWaitREGACKPacketList()->erase(msgId); - Event* ev = new Event(); - ev->setClientSendEvent(client, regAck); - _gateway->getClientSendQue()->post(ev); + if (rc != MQTTSN_RC_ACCEPTED) + { + delete regAck; + } + else + { + Event* ev = new Event(); + ev->setClientSendEvent(client, regAck); + _gateway->getClientSendQue()->post(ev); + } } + if (client->isHoldPingReqest() && client->getWaitREGACKPacketList()->getCount() == 0) { From 9c9de103df72436d9717d168975262e50f7fb50d Mon Sep 17 00:00:00 2001 From: tomoaki Date: Fri, 14 May 2021 14:31:00 +0900 Subject: [PATCH 39/67] Fix of Mac copile error Signed-off-by: tomoaki --- MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp b/MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp index 06bd7f7..4be4eae 100644 --- a/MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp +++ b/MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp @@ -11,7 +11,7 @@ * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: - * Tomoaki Yamaguchi - initial API and implementation + * Tomoaki Yamaguchi - initial API and implementation **************************************************************************************/ #include @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include From f079211ea71019a15f692f2c403fde08c04bf44b Mon Sep 17 00:00:00 2001 From: tomoaki Date: Sat, 15 May 2021 18:32:05 +0900 Subject: [PATCH 40/67] upgrade and bugfix for a test Signed-off-by: tomoaki --- .cproject | 4 +- .../GatewayTester/samples/mainTest.cpp | 138 +++-- MQTTSNGateway/GatewayTester/src/LGwProxy.cpp | 30 +- MQTTSNGateway/GatewayTester/src/LGwProxy.h | 5 + .../GatewayTester/src/LMqttsnClient.cpp | 19 +- .../GatewayTester/src/LMqttsnClient.h | 2 + .../GatewayTester/src/LMqttsnClientApp.h | 4 + .../GatewayTester/src/LPublishManager.cpp | 11 +- .../GatewayTester/src/LPublishManager.h | 4 +- .../GatewayTester/src/LSubscribeManager.cpp | 1 + MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp | 28 +- MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp | 532 +++++++++--------- MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp | 4 +- 13 files changed, 448 insertions(+), 334 deletions(-) diff --git a/.cproject b/.cproject index 6c81531..409af95 100644 --- a/.cproject +++ b/.cproject @@ -133,7 +133,7 @@ - + @@ -273,7 +273,7 @@ - + diff --git a/MQTTSNGateway/GatewayTester/samples/mainTest.cpp b/MQTTSNGateway/GatewayTester/samples/mainTest.cpp index 934a419..8aaa641 100644 --- a/MQTTSNGateway/GatewayTester/samples/mainTest.cpp +++ b/MQTTSNGateway/GatewayTester/samples/mainTest.cpp @@ -51,25 +51,25 @@ extern LScreen* theScreen; /*------------------------------------------------------ * UDP Configuration (theNetcon) *------------------------------------------------------*/ -UDPCONF = { - "GatewayTestClient", // ClientId - {225,1,1,1}, // Multicast group IP - 1883, // Multicast group Port - 20020, // Local PortNo -}; +UDPCONF = +{ "GatewayTestClient", // ClientId + { 225, 1, 1, 1 }, // Multicast group IP + 1883, // Multicast group Port + 20020, // Local PortNo + }; /*------------------------------------------------------ * Client Configuration (theMqcon) *------------------------------------------------------*/ -MQTTSNCONF = { - 60, //KeepAlive [seconds] - true, //Clean session - 300, //Sleep duration [seconds] - "", //WillTopic - "", //WillMessage - 0, //WillQos - false //WillRetain -}; +MQTTSNCONF = +{ 60, //KeepAlive [seconds] + true, //Clean session + 300, //Sleep duration [seconds] + "", //WillTopic + "", //WillMessage + 0, //WillQos + false //WillRetain + }; /*------------------------------------------------------ * Define Topics @@ -83,32 +83,31 @@ const char* topic52 = "ty4tw/topic5/2"; const char* topic53 = "ty4tw/topic5/3"; const char* topic50 = "ty4tw/topic5/+"; - /*------------------------------------------------------ * Callback routines for Subscribed Topics *------------------------------------------------------*/ int on_Topic01(uint8_t* pload, uint16_t ploadlen) { DISPLAY("\n\nTopic1 recv.\n"); - char c = pload[ploadlen-1]; - pload[ploadlen-1]= 0; // set null terminator - DISPLAY("Payload -->%s%c<--\n\n",pload, c); + char c = pload[ploadlen - 1]; + pload[ploadlen - 1] = 0; // set null terminator + DISPLAY("Payload -->%s%c<--\n\n", pload, c); return 0; } int on_Topic02(uint8_t* pload, uint16_t ploadlen) { DISPLAY("\n\nTopic2 recv.\n"); - pload[ploadlen-1]= 0; // set null terminator - DISPLAY("Payload -->%s <--\n\n",pload); + pload[ploadlen - 1] = 0; // set null terminator + DISPLAY("Payload -->%s <--\n\n", pload); return 0; } int on_Topic03(uint8_t* pload, uint16_t ploadlen) { DISPLAY("\n\nNew callback recv Topic3\n"); - pload[ploadlen-1]= 0; // set null terminator - DISPLAY("Payload -->%s <--\n\n",pload); + pload[ploadlen - 1] = 0; // set null terminator + DISPLAY("Payload -->%s <--\n\n", pload); return 0; } @@ -116,26 +115,26 @@ int on_Topic03(uint8_t* pload, uint16_t ploadlen) * A Link list of Callback routines and Topics *------------------------------------------------------*/ -SUBSCRIBE_LIST = {// e.g. SUB(TopicType, topicName, TopicId, callback, QoSx), - SUB(MQTTSN_TOPIC_TYPE_NORMAL, topic1, 0, on_Topic01, QoS1), - SUB(MQTTSN_TOPIC_TYPE_NORMAL, topic2, 0, on_Topic02, QoS1), - END_OF_SUBSCRIBE_LIST - }; - +SUBSCRIBE_LIST = +{ // e.g. SUB(TopicType, topicName, TopicId, callback, QoSx), + SUB(MQTTSN_TOPIC_TYPE_NORMAL, topic1, 0, on_Topic01, QoS1), + SUB(MQTTSN_TOPIC_TYPE_NORMAL, topic2, 0, on_Topic02, QoS1), + END_OF_SUBSCRIBE_LIST +}; /*------------------------------------------------------ * Test functions *------------------------------------------------------*/ void subscribePredefTopic1(void) { - SUBSCRIBE(1, on_Topic03, QoS1); + SUBSCRIBE(1, on_Topic03, QoS1); } void publishTopic1(void) { char payload[300]; sprintf(payload, "publish \"ty4tw/Topic1\" \n"); - PUBLISH(topic1,(uint8_t*)payload, strlen(payload), QoS0); + PUBLISH(topic1, (uint8_t* )payload, strlen(payload), QoS0); } void subscribeTopic10(void) @@ -147,11 +146,9 @@ void publishTopic2(void) { char payload[300]; sprintf(payload, "publish \"ty4tw/topic2\" \n"); - PUBLISH(topic2,(uint8_t*)payload, strlen(payload), QoS1); + PUBLISH(topic2, (uint8_t* )payload, strlen(payload), QoS1); } - - void unsubscribe(void) { UNSUBSCRIBE(topic2); @@ -167,7 +164,7 @@ void test3(void) char payload[300]; sprintf(payload, "TEST3 "); uint8_t qos = 0; - PUBLISH(topic2,(uint8_t*)payload, strlen(payload), qos); + PUBLISH(topic2, (uint8_t* )payload, strlen(payload), qos); } void disconnect(void) @@ -180,48 +177,71 @@ void asleep(void) DISCONNECT(theMqcon.sleepDuration); } +void onconnect(void) +{ + ONCONNECT(); +} + +void connect(void) +{ + CONNECT(); +} + + +void DisableAutoPingreq(void) +{ + SetAutoPingReqMode(false); +} + /*------------------------------------------------------ * 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("Step0:Subscribe predef topic1", subscribePredefTopic1), - TEST("Step1:Publish topic1", publishTopic1), - TEST("Step2:Publish topic2", publishTopic2), - TEST("Step3:Subscribe PreDefined topic10. ID is not defined.", subscribeTopic10), - TEST("Step4:Publish topic2", publishTopic2), - TEST("Step5:Unsubscribe topic2", unsubscribe), - TEST("Step6:Publish topic2", publishTopic2), - TEST("Step7:subscribe again", subscribechangeCallback), - TEST("Step8:Publish topic2", publishTopic2), - TEST("Step9:Sleep ", asleep), - TEST("Step10:Publish topic1", publishTopic1), - TEST("Step11:Disconnect", disconnect), - END_OF_TEST_LIST - }; - +TEST_LIST = +{ // e.g. TEST( Label, Test), + TEST("Step0:Connect", connect), + TEST("Step1:Subscribe list", onconnect), + TEST("Step2:Subscribe predef topic1", subscribePredefTopic1), + TEST("Step3:Publish topic1", publishTopic1), + TEST("Step4:Publish topic2", publishTopic2), + TEST("Step5:Subscribe PreDefined topic10. ID is not defined.", subscribeTopic10), + TEST("Step6:Publish topic2", publishTopic2), + TEST("Step7:Unsubscribe topic2", unsubscribe), + TEST("Step8:Publish topic2", publishTopic2), + TEST("Step9:subscribe again", subscribechangeCallback), + TEST("Step10:Publish topic2", publishTopic2), + TEST("Step11:Sleep ", asleep), + TEST("Step12:Publish topic1", publishTopic1), + TEST("Step13:Disconnect", disconnect), + TEST("Step14:Publish topic2", publishTopic1), + TEST("Step15:Connect", connect), + TEST("Step16:Publish topic2", publishTopic2), + TEST("Step17:Auto Pingreq mode off", DisableAutoPingreq), + TEST("Step18:Publish topic2", publishTopic1), + TEST("Step19:Disconnect", disconnect), + END_OF_TEST_LIST +}; /*------------------------------------------------------ * List of tasks is valid in case of line23 of * LMqttsnClientApp.h is uncommented. * #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 - }; - +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) { - SetForwarderMode(false); + SetForwarderMode(false); } - /***************** END OF PROGRAM ********************/ diff --git a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp index cdacac1..3b5c89d 100644 --- a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp +++ b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp @@ -57,6 +57,8 @@ LGwProxy::LGwProxy() _initialized = 0; _isForwarderMode = false; _isQoSMinus1Mode = false; + _isPingReqMode = true; + _isAutoConnectMode = true; } LGwProxy::~LGwProxy() @@ -231,9 +233,12 @@ int LGwProxy::getConnectResponce(void) void LGwProxy::reconnect(void) { - D_MQTTLOG("...Gateway reconnect\r\n"); - _status = GW_DISCONNECTED; - connect(); + if (_isAutoConnectMode) + { + D_MQTTLOG("...Gateway reconnect\r\n"); + _status = GW_DISCONNECTED; + connect(); + } } void LGwProxy::disconnect(uint16_t secs) @@ -395,7 +400,7 @@ int LGwProxy::getMessage(void) } else if (_mqttsnMsg[0] == MQTTSN_TYPE_DISCONNECT) { - _status = GW_LOST; + _status = GW_DISCONNECTED; _gwAliveTimer.stop(); _keepAliveTimer.stop(); } @@ -586,7 +591,7 @@ uint16_t LGwProxy::getNextMsgId(void) void LGwProxy::checkPingReq(void) { - if ( _isQoSMinus1Mode ) + if (_isQoSMinus1Mode || _isPingReqMode == false) { return; } @@ -671,3 +676,18 @@ void LGwProxy::setQoSMinus1Mode(bool valid) { _isQoSMinus1Mode = valid; } + +void LGwProxy::setPingReqMode(bool valid) +{ + _isPingReqMode = valid; +} + +void LGwProxy::setAutoConnectMode(bool valid) +{ + _isAutoConnectMode = valid; +} + +uint8_t LGwProxy::getStatus(void) +{ + return _status; +} diff --git a/MQTTSNGateway/GatewayTester/src/LGwProxy.h b/MQTTSNGateway/GatewayTester/src/LGwProxy.h index 814affc..4a3b8fb 100644 --- a/MQTTSNGateway/GatewayTester/src/LGwProxy.h +++ b/MQTTSNGateway/GatewayTester/src/LGwProxy.h @@ -67,6 +67,8 @@ public: void setAdvertiseDuration(uint16_t duration); void setForwarderMode(bool valid); void setQoSMinus1Mode(bool valid); + void setPingReqMode(bool valid); + void setAutoConnectMode(bool valid); void reconnect(void); int writeMsg(const uint8_t* msg); void setPingReqTimer(void); @@ -74,6 +76,7 @@ public: LTopicTable* getTopicTable(void); LRegisterManager* getRegisterManager(void); const char* getClientId(void); + uint8_t getStatus(void); private: int readMsg(void); void writeGwMsg(void); @@ -111,6 +114,8 @@ private: uint16_t _tWake; bool _isForwarderMode; bool _isQoSMinus1Mode; + bool _isPingReqMode; + bool _isAutoConnectMode; char _msg[MQTTSN_MAX_MSG_LENGTH + 1]; }; diff --git a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp index b6759dc..2982060 100644 --- a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp +++ b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp @@ -77,6 +77,8 @@ int main(int argc, char** argv) break; } } + theClient->setAutoConnectMode(false); + theClient->getPublishManager()->setAutoConnectMode(false); #endif setup(); @@ -98,7 +100,7 @@ int main(int argc, char** argv) ======================================*/ LMqttsnClient::LMqttsnClient() { - + _isAutoConnect = true; } LMqttsnClient::~LMqttsnClient() @@ -205,10 +207,20 @@ void LMqttsnClient::disconnect(uint16_t sleepInSecs) void LMqttsnClient::run() { - _gwProxy.connect(); + if (_isAutoConnect) + { + _gwProxy.connect(); + } _taskMgr.run(); } +void LMqttsnClient::setAutoConnectMode(uint8_t flg) +{ + _isAutoConnect = flg; + _pubMgr.setAutoConnectMode(flg); + _gwProxy.setAutoConnectMode(flg); +} + void LMqttsnClient::setSleepMode(uint32_t duration) { // ToDo: set WDT and sleep mode @@ -227,7 +239,10 @@ void LMqttsnClient::setSleepDuration(uint32_t duration) void LMqttsnClient::onConnect(void) { + if (_isAutoConnect) + { _subMgr.onConnect(); + } } const char* LMqttsnClient::getClientId(void) diff --git a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h index de60310..ce152ef 100644 --- a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h +++ b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h @@ -63,6 +63,7 @@ public: void addTask(bool test); void setSleepDuration(uint32_t duration); void setSleepMode(uint32_t duration); + void setAutoConnectMode(uint8_t flg); void sleep(void); const char* getClientId(void); uint16_t getTopicId(const char* topicName); @@ -78,6 +79,7 @@ private: LSubscribeManager _subMgr; LGwProxy _gwProxy; uint32_t _sleepDuration; + uint8_t _isAutoConnect; }; diff --git a/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h b/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h index b848e4c..947c5d5 100644 --- a/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h +++ b/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h @@ -92,6 +92,7 @@ typedef enum #define SUBSCRIBE(...) theClient->subscribe(__VA_ARGS__) #define UNSUBSCRIBE(...) theClient->unsubscribe(__VA_ARGS__) #define DISCONNECT(...) theClient->disconnect(__VA_ARGS__) +#define ONCONNECT() theClient->getSubscribeManager()->onConnect() #define TASK_LIST TaskList theTaskList[] #define TASK(...) {__VA_ARGS__, 0, 0} @@ -104,8 +105,11 @@ 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(__VA_ARGS__) #define SetQoSMinus1Mode(...) theClient->getGwProxy()->setQoSMinus1Mode(__VA_ARGS__) +#define SetAutoConnectMode(...) theClient->setAutoConnectMode(__VA_ARGS__) +#define SetAutoPingReqMode(...) theClient->getGwProxy()->setPingReqMode(__VA_ARGS__) #ifdef CLIENT_MODE #define DISPLAY(...) diff --git a/MQTTSNGateway/GatewayTester/src/LPublishManager.cpp b/MQTTSNGateway/GatewayTester/src/LPublishManager.cpp index 78a84db..3632e0b 100644 --- a/MQTTSNGateway/GatewayTester/src/LPublishManager.cpp +++ b/MQTTSNGateway/GatewayTester/src/LPublishManager.cpp @@ -44,6 +44,7 @@ LPublishManager::LPublishManager() _last = 0; _elmCnt = 0; _publishedFlg = SAVE_TASK_INDEX; + _autoConnectFlg = false; } LPublishManager::~LPublishManager() @@ -115,7 +116,10 @@ void LPublishManager::sendPublish(PubElement* elm) return; } - theClient->getGwProxy()->connect(); + if (_autoConnectFlg) + { + theClient->getGwProxy()->connect(); + } uint8_t msg[MQTTSN_MAX_MSG_LENGTH + 1]; uint8_t org = 0; @@ -310,6 +314,11 @@ void LPublishManager::checkTimeout(void) } } +void LPublishManager::setAutoConnectMode(bool flg) +{ + _autoConnectFlg = flg; +} + PubElement* LPublishManager::getElement(uint16_t msgId) { PubElement* elm = _first; diff --git a/MQTTSNGateway/GatewayTester/src/LPublishManager.h b/MQTTSNGateway/GatewayTester/src/LPublishManager.h index 6085218..6520733 100644 --- a/MQTTSNGateway/GatewayTester/src/LPublishManager.h +++ b/MQTTSNGateway/GatewayTester/src/LPublishManager.h @@ -70,6 +70,7 @@ public: void sendSuspend(const char* topicName, uint16_t topicId, uint8_t topicType); bool isDone(void); bool isMaxFlight(void); + void setAutoConnectMode(bool); private: PubElement* getElement(uint16_t msgId); PubElement* getElement(const char* topicName); @@ -84,7 +85,8 @@ private: PubElement* _last; uint8_t _elmCnt; uint8_t _publishedFlg; + uint8_t _autoConnectFlg; }; - + } /* tomyAsyncClient */ #endif /* PUBLISHMANAGER_H_ */ diff --git a/MQTTSNGateway/GatewayTester/src/LSubscribeManager.cpp b/MQTTSNGateway/GatewayTester/src/LSubscribeManager.cpp index 5158003..03a4bbf 100644 --- a/MQTTSNGateway/GatewayTester/src/LSubscribeManager.cpp +++ b/MQTTSNGateway/GatewayTester/src/LSubscribeManager.cpp @@ -122,6 +122,7 @@ void LSubscribeManager::send(SubElement* elm) { return; } + uint8_t msg[MQTTSN_MAX_MSG_LENGTH + 1]; if (elm->topicType == MQTTSN_TOPIC_TYPE_PREDEFINED) { diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp index 467cd8a..ed3fa70 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp @@ -54,7 +54,7 @@ void BrokerRecvTask::run(void) { struct timeval timeout; MQTTGWPacket* packet = nullptr; - int rc; + int rc; Event* ev = nullptr; fd_set rset; fd_set wset; @@ -100,6 +100,7 @@ void BrokerRecvTask::run(void) { /* Check sockets is ready to read */ int activity = select(maxSock + 1, &rset, 0, 0, &timeout); + if (activity > 0) { client = _gateway->getClientList()->getClient(0); @@ -134,17 +135,26 @@ void BrokerRecvTask::run(void) { if (rc == 0) // Disconnected { + WRITELOG( + "%s BrokerRecvTask %s is disconnected by the broker.%s\n", + ERRMSG_HEADER, + client->getClientId(), + ERRMSG_FOOTER); + client->getNetwork()->close(); + client->disconnected(); + + /* client->getNetwork()->close(); delete packet; - /* delete client when the client is not authorized & session is clean */ - _gateway->getClientList()->erase(client); if (client) { client = client->getNextClient(); } continue; + */ + } else if (rc == -1) { @@ -165,7 +175,7 @@ void BrokerRecvTask::run(void) else if (rc == -3) { WRITELOG( - "%s BrokerRecvTask can't get memories for the packet %s%s\n", + "%s BrokerRecvTask can't allocate memories for the packet %s%s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); @@ -173,22 +183,26 @@ void BrokerRecvTask::run(void) delete packet; - if ((rc == -1 || rc == -2) + if ((rc == -1 || rc == -2) && (client->isActive() || client->isSleep() || client->isAwake())) { /* disconnect the client */ + /* packet = new MQTTGWPacket(); packet->setHeader(DISCONNECT); ev = new Event(); ev->setBrokerRecvEvent(client, packet); _gateway->getPacketEventQue()->post(ev); + */ + client->getNetwork()->close(); + client->disconnected(); } } } - } - nextClient: client = client->getNextClient(); + } + nextClient: client = client->getNextClient(); } } } diff --git a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp index 779def3..c399696 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp @@ -29,10 +29,10 @@ char* currentDateTime(void); =====================================*/ ClientRecvTask::ClientRecvTask(Gateway* gateway) { - _gateway = gateway; - _gateway->attach((Thread*) this); - _sensorNetwork = _gateway->getSensorNetwork(); - setTaskName("ClientRecvTask"); + _gateway = gateway; + _gateway->attach((Thread*) this); + _sensorNetwork = _gateway->getSensorNetwork(); + setTaskName("ClientRecvTask"); } ClientRecvTask::~ClientRecvTask() @@ -45,7 +45,7 @@ ClientRecvTask::~ClientRecvTask() */ void ClientRecvTask::initialize(int argc, char** argv) { - _sensorNetwork->initialize(); + _sensorNetwork->initialize(); } /* @@ -55,287 +55,307 @@ void ClientRecvTask::initialize(int argc, char** argv) */ void ClientRecvTask::run() { - Event* ev = nullptr; - AdapterManager* adpMgr = _gateway->getAdapterManager(); - QoSm1Proxy* qosm1Proxy = adpMgr->getQoSm1Proxy(); - int clientType = - adpMgr->isAggregaterActive() ? AGGREGATER_TYPE : TRANSPEARENT_TYPE; - ClientList* clientList = _gateway->getClientList(); - EventQue* packetEventQue = _gateway->getPacketEventQue(); + Event* ev = nullptr; + AdapterManager* adpMgr = _gateway->getAdapterManager(); + QoSm1Proxy* qosm1Proxy = adpMgr->getQoSm1Proxy(); + int clientType = + adpMgr->isAggregaterActive() ? AGGREGATER_TYPE : TRANSPEARENT_TYPE; + ClientList* clientList = _gateway->getClientList(); + EventQue* packetEventQue = _gateway->getPacketEventQue(); + EventQue* clientsendQue = _gateway->getClientSendQue(); - char buf[128]; + char buf[128]; - while (true) - { - Client* client = nullptr; - Forwarder* fwd = nullptr; - WirelessNodeId nodeId; + while (true) + { + Client* client = nullptr; + Forwarder* fwd = nullptr; + WirelessNodeId nodeId; - MQTTSNPacket* packet = new MQTTSNPacket(); - int packetLen = packet->recv(_sensorNetwork); + MQTTSNPacket* packet = new MQTTSNPacket(); + int packetLen = packet->recv(_sensorNetwork); - if (CHK_SIGINT) - { - WRITELOG("%s %s stopped.\n", currentDateTime(), getTaskName()); - delete packet; - return; - } + if (CHK_SIGINT) + { + WRITELOG("%s %s stopped.\n", currentDateTime(), getTaskName()); + delete packet; + return; + } - if (packetLen < 2) - { - delete packet; - continue; - } + if (packetLen < 2) + { + delete packet; + continue; + } - if (packet->getType() <= MQTTSN_ADVERTISE - || packet->getType() == MQTTSN_GWINFO) - { - delete packet; - continue; - } + if (packet->getType() <= MQTTSN_ADVERTISE + || packet->getType() == MQTTSN_GWINFO) + { + delete packet; + continue; + } - if (packet->getType() == MQTTSN_SEARCHGW) - { - /* write log and post Event */ - log(0, packet, 0); - ev = new Event(); - ev->setBrodcastEvent(packet); - packetEventQue->post(ev); - continue; - } + if (packet->getType() == MQTTSN_SEARCHGW) + { + /* write log and post Event */ + log(0, packet, 0); + ev = new Event(); + ev->setBrodcastEvent(packet); + packetEventQue->post(ev); + continue; + } - SensorNetAddress* senderAddr = - _gateway->getSensorNetwork()->getSenderAddress(); + SensorNetAddress* senderAddr = + _gateway->getSensorNetwork()->getSenderAddress(); - if (packet->getType() == MQTTSN_ENCAPSULATED) - { - fwd = - _gateway->getAdapterManager()->getForwarderList()->getForwarder( - senderAddr); + if (packet->getType() == MQTTSN_ENCAPSULATED) + { + fwd = + _gateway->getAdapterManager()->getForwarderList()->getForwarder( + senderAddr); - if (fwd != nullptr) - { - MQTTSNString fwdName = MQTTSNString_initializer; - fwdName.cstring = const_cast(fwd->getName()); - log(0, packet, &fwdName); + if (fwd != nullptr) + { + MQTTSNString fwdName = MQTTSNString_initializer; + fwdName.cstring = const_cast(fwd->getName()); + log(0, packet, &fwdName); - /* get the packet from the encapsulation message */ - MQTTSNGWEncapsulatedPacket encap; - encap.desirialize(packet->getPacketData(), - packet->getPacketLength()); - nodeId.setId(encap.getWirelessNodeId()); - client = fwd->getClient(&nodeId); - packet = encap.getMQTTSNPacket(); - } - } - else - { - /* Check the client belonging to QoS-1Proxy ? */ + /* 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 + { + /* Check the client belonging to QoS-1Proxy ? */ - if (qosm1Proxy->isActive()) - { - const char* clientName = qosm1Proxy->getClientId(senderAddr); + if (qosm1Proxy->isActive()) + { + const char* clientName = qosm1Proxy->getClientId(senderAddr); - if (clientName != nullptr) - { - client = qosm1Proxy->getClient(); + if (clientName != nullptr) + { + client = qosm1Proxy->getClient(); - if (!packet->isQoSMinusPUBLISH()) - { - 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; - } - } - } + if (!packet->isQoSMinusPUBLISH()) + { + 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; + } + } + } - if (client == nullptr) - { - client = _gateway->getClientList()->getClient(senderAddr); - } - } + if (client == nullptr) + { + client = _gateway->getClientList()->getClient(senderAddr); + } + } - if (client != nullptr) - { - /* write log and post Event */ - log(client, packet, 0); - ev = new Event(); - ev->setClientRecvEvent(client, packet); - packetEventQue->post(ev); - } - else - { - /* new client */ - if (packet->getType() == MQTTSN_CONNECT) - { - MQTTSNPacket_connectData data; - memset(&data, 0, sizeof(MQTTSNPacket_connectData)); - if (!packet->getCONNECT(&data)) - { - log(0, packet, &data.clientID); - WRITELOG("%s CONNECT message form %s is incorrect.%s\n", - ERRMSG_HEADER, senderAddr->sprint(buf), - ERRMSG_FOOTER); - delete packet; - continue; - } + if (client != nullptr) + { + log(client, packet, 0); - client = clientList->getClient(&data.clientID); + if (client->isDisconnect() && packet->getType() != MQTTSN_CONNECT) + { + WRITELOG( + "%s MQTTSNGWClientRecvTask %s is not connecting.%s\n", + ERRMSG_HEADER, + client->getClientId(), ERRMSG_FOOTER); - if (fwd != nullptr) - { - if (client == nullptr) - { - /* create a new client */ - client = clientList->createClient(0, &data.clientID, - clientType); - } - /* Add to a forwarded client list of forwarder. */ - fwd->addClient(client, &nodeId); - } - else - { - if (client) - { - /* Authentication is not required */ - if (_gateway->getGWParams()->clientAuthentication - == false) - { - client->setClientAddress(senderAddr); - } - } - else - { - /* create a new client */ - client = clientList->createClient(senderAddr, - &data.clientID, clientType); - } - } + /* send DISCONNECT to the client, if it is not connected */ + MQTTSNPacket* snPacket = new MQTTSNPacket(); + snPacket->setDISCONNECT(0); + ev = new Event(); + ev->setClientSendEvent(client, snPacket); + clientsendQue->post(ev); + delete packet; + continue; + } + else + { + ev = new Event(); + ev->setClientRecvEvent(client, packet); + packetEventQue->post(ev); + } + } + else + { + /* new client */ + if (packet->getType() == MQTTSN_CONNECT) + { + MQTTSNPacket_connectData data; + memset(&data, 0, sizeof(MQTTSNPacket_connectData)); + if (!packet->getCONNECT(&data)) + { + log(0, packet, &data.clientID); + WRITELOG("%s CONNECT message form %s is incorrect.%s\n", + ERRMSG_HEADER, senderAddr->sprint(buf), + ERRMSG_FOOTER); + delete packet; + continue; + } - log(client, packet, &data.clientID); + client = clientList->getClient(&data.clientID); - if (client == nullptr) - { - WRITELOG( - "%s Client(%s) was rejected. CONNECT message has been discarded.%s\n", - ERRMSG_HEADER, senderAddr->sprint(buf), - ERRMSG_FOOTER); - delete packet; - continue; - } + if (fwd != nullptr) + { + if (client == nullptr) + { + /* create a new client */ + client = clientList->createClient(0, &data.clientID, + clientType); + } + /* Add to a forwarded client list of forwarder. */ + fwd->addClient(client, &nodeId); + } + else + { + if (client) + { + /* Authentication is not required */ + if (_gateway->getGWParams()->clientAuthentication + == false) + { + client->setClientAddress(senderAddr); + } + } + else + { + /* create a new client */ + client = clientList->createClient(senderAddr, + &data.clientID, clientType); + } + } - /* post Client RecvEvent */ - ev = new Event(); - ev->setClientRecvEvent(client, packet); - packetEventQue->post(ev); - } - else - { - log(client, packet, 0); - if (packet->getType() == MQTTSN_ENCAPSULATED) - { - WRITELOG( - "%s MQTTSNGWClientRecvTask 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 MQTTSNGWClientRecvTask Client(%s) is not connecting. message has been discarded.%s\n", - ERRMSG_HEADER, senderAddr->sprint(buf), - ERRMSG_FOOTER); - } - delete packet; - } - } - } + log(client, packet, &data.clientID); + + if (client == nullptr) + { + WRITELOG( + "%s Client(%s) was rejected. CONNECT message has been discarded.%s\n", + ERRMSG_HEADER, senderAddr->sprint(buf), + ERRMSG_FOOTER); + delete packet; + continue; + } + + /* post Client RecvEvent */ + ev = new Event(); + ev->setClientRecvEvent(client, packet); + packetEventQue->post(ev); + } + else + { + log(client, packet, 0); + if (packet->getType() == MQTTSN_ENCAPSULATED) + { + WRITELOG( + "%s MQTTSNGWClientRecvTask 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 MQTTSNGWClientRecvTask Client(%s) is not connecting. message has been discarded.%s\n", + ERRMSG_HEADER, + senderAddr->sprint(buf), ERRMSG_FOOTER); + } + delete packet; + } + } + } } void ClientRecvTask::log(Client* client, MQTTSNPacket* packet, MQTTSNString* id) { - const char* clientId; - char cstr[MAX_CLIENTID_LENGTH + 1]; + const char* clientId; + char cstr[MAX_CLIENTID_LENGTH + 1]; - if (id) - { - 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) - { - clientId = client->getClientId(); - } - else - { - clientId = UNKNOWNCL; - } + if (id) + { + 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) + { + clientId = client->getClientId(); + } + else + { + clientId = UNKNOWNCL; + } - log(clientId, packet); + log(clientId, packet); } void ClientRecvTask::log(const char* clientId, MQTTSNPacket* packet) { - char pbuf[ SIZE_OF_LOG_PACKET * 3 + 1]; - char msgId[6]; + char pbuf[ SIZE_OF_LOG_PACKET * 3 + 1]; + 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; - } + 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/MQTTSNGWPublishHandler.cpp b/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp index 25e0628..7b007e2 100644 --- a/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp @@ -121,12 +121,14 @@ MQTTGWPacket* MQTTSNPublishHandler::handlePublish(Client* client, { pub.topic = (char*) topic->getTopicName()->data(); pub.topiclen = topic->getTopicName()->length(); + topicid.data.long_.name = pub.topic; + topicid.data.long_.len = pub.topiclen; } } /* Save a msgId & a TopicId pare for PUBACK */ if (msgId && qos > 0 && qos < 3) { - client->setWaitedPubTopicId(msgId, topicid.data.id, &topicid); + client->setWaitedPubTopicId(msgId, topicid.data.id, &topicid); } pub.payload = (char*) payload; From dc3142f2f0d3da100b1a52d8e1a31c862a4af41f Mon Sep 17 00:00:00 2001 From: tomoaki Date: Sat, 15 May 2021 18:32:43 +0900 Subject: [PATCH 41/67] Bugfix of #196, #214, #222 Signed-off-by: tomoaki --- MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp | 21 -------------------- MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp | 10 ++++------ 2 files changed, 4 insertions(+), 27 deletions(-) diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp index ed3fa70..c74d0d3 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp @@ -142,19 +142,6 @@ void BrokerRecvTask::run(void) ERRMSG_FOOTER); client->getNetwork()->close(); client->disconnected(); - - /* - client->getNetwork()->close(); - delete packet; - - - if (client) - { - client = client->getNextClient(); - } - continue; - */ - } else if (rc == -1) { @@ -188,14 +175,6 @@ void BrokerRecvTask::run(void) || client->isSleep() || client->isAwake())) { - /* disconnect the client */ - /* - packet = new MQTTGWPacket(); - packet->setHeader(DISCONNECT); - ev = new Event(); - ev->setBrokerRecvEvent(client, packet); - _gateway->getPacketEventQue()->post(ev); - */ client->getNetwork()->close(); client->disconnected(); } diff --git a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp index c399696..ae7aeee 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp @@ -166,10 +166,8 @@ void ClientRecvTask::run() if (client->isDisconnect() && packet->getType() != MQTTSN_CONNECT) { - WRITELOG( - "%s MQTTSNGWClientRecvTask %s is not connecting.%s\n", - ERRMSG_HEADER, - client->getClientId(), ERRMSG_FOOTER); + WRITELOG("%s MQTTSNGWClientRecvTask %s is not connecting.%s\n", + ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); /* send DISCONNECT to the client, if it is not connected */ MQTTSNPacket* snPacket = new MQTTSNPacket(); @@ -268,8 +266,8 @@ void ClientRecvTask::run() { WRITELOG( "%s MQTTSNGWClientRecvTask Client(%s) is not connecting. message has been discarded.%s\n", - ERRMSG_HEADER, - senderAddr->sprint(buf), ERRMSG_FOOTER); + ERRMSG_HEADER, senderAddr->sprint(buf), + ERRMSG_FOOTER); } delete packet; } From ae0cc2ec61c75ddd5b22e27e1cecc806a32feee5 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Sun, 16 May 2021 15:45:38 +0900 Subject: [PATCH 42/67] waste removal Signed-off-by: tomoaki e --- MQTTSNGateway/src/linux/Threading.cpp | 39 +++++++++++---------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/MQTTSNGateway/src/linux/Threading.cpp b/MQTTSNGateway/src/linux/Threading.cpp index 4341034..703dd19 100644 --- a/MQTTSNGateway/src/linux/Threading.cpp +++ b/MQTTSNGateway/src/linux/Threading.cpp @@ -121,44 +121,37 @@ Mutex::~Mutex(void) void Mutex::lock(void) { + int rc = 0; if (_pmutex) { - pthread_mutex_lock(_pmutex); + rc = pthread_mutex_lock(_pmutex); } else { - try - { - if (pthread_mutex_lock(&_mutex)) - { - throw Exception("Mutex lock error", errno); - } - } catch (char* errmsg) - { - throw Exception("The same thread can't acquire a mutex twice", errno); - } + rc = pthread_mutex_lock(&_mutex); + } + + if (rc) + { + throw Exception("Mutex lock error", errno); } } void Mutex::unlock(void) { - + int rc = 0; if (_pmutex) { - pthread_mutex_unlock(_pmutex); + rc = pthread_mutex_unlock(_pmutex); } else { - try - { - if (pthread_mutex_unlock(&_mutex)) - { - throw Exception("Mutex unlock error", errno); - } - } catch (char* errmsg) - { - throw Exception("Mutex can't unlock.", -1); - } + rc = pthread_mutex_unlock(&_mutex); + } + + if (rc) + { + throw Exception("Mutex lock error", errno); } } From cd6b1151a3137aa133e18684d76035888a5ee16d Mon Sep 17 00:00:00 2001 From: tomoaki Date: Mon, 17 May 2021 09:50:30 +0900 Subject: [PATCH 43/67] Add Test fucntions Signed-off-by: tomoaki --- .../GatewayTester/samples/mainTest.cpp | 44 ++++++++++++++++--- MQTTSNGateway/GatewayTester/src/LGwProxy.cpp | 5 +++ MQTTSNGateway/GatewayTester/src/LGwProxy.h | 11 ++--- .../GatewayTester/src/LMqttsnClientApp.h | 2 +- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/MQTTSNGateway/GatewayTester/samples/mainTest.cpp b/MQTTSNGateway/GatewayTester/samples/mainTest.cpp index 8aaa641..6d0c426 100644 --- a/MQTTSNGateway/GatewayTester/samples/mainTest.cpp +++ b/MQTTSNGateway/GatewayTester/samples/mainTest.cpp @@ -78,6 +78,7 @@ const char* topic1 = "ty4tw/topic1"; const char* topic2 = "ty4tw/topic2"; const char* topic3 = "ty4tw/topic3"; const char* topic4 = "ty4tw/topic4"; +const char* topic40 = "ty4tw/#"; const char* topic51 = "ty4tw/topic5/1"; const char* topic52 = "ty4tw/topic5/2"; const char* topic53 = "ty4tw/topic5/3"; @@ -111,6 +112,14 @@ int on_Topic03(uint8_t* pload, uint16_t ploadlen) return 0; } +int on_TopicWildcard(uint8_t* pload, uint16_t ploadlen) +{ + DISPLAY("\n\nNew callback recv TopicWildcard\n"); + pload[ploadlen - 1] = 0; // set null terminator + DISPLAY("Payload -->%s <--\n\n", pload); + return 0; +} + /*------------------------------------------------------ * A Link list of Callback routines and Topics *------------------------------------------------------*/ @@ -137,11 +146,6 @@ void publishTopic1(void) PUBLISH(topic1, (uint8_t* )payload, strlen(payload), QoS0); } -void subscribeTopic10(void) -{ - SUBSCRIBE(10, on_Topic02, QoS1); -} - void publishTopic2(void) { char payload[300]; @@ -149,6 +153,24 @@ void publishTopic2(void) PUBLISH(topic2, (uint8_t* )payload, strlen(payload), QoS1); } +void publishTopic4(void) +{ + char payload[300]; + sprintf(payload, "publish \"ty4tw/topic40\" \n"); + PUBLISH(topic4, (uint8_t* )payload, strlen(payload), QoS1); +} + +void subscribeTopic10(void) +{ + SUBSCRIBE(10, on_Topic02, QoS1); +} + +void subscribeWildcardTopic(void) +{ + SUBSCRIBE(topic40, on_Topic04, QoS1); +} + + void unsubscribe(void) { UNSUBSCRIBE(topic2); @@ -187,12 +209,16 @@ void connect(void) CONNECT(); } - void DisableAutoPingreq(void) { SetAutoPingReqMode(false); } +void CleanSessionOff(void) +{ + SetCleanSession(false); +} + /*------------------------------------------------------ * A List of Test functions is valid in case of * line 23 of LMqttsnClientApp.h is commented out. @@ -212,6 +238,12 @@ TEST_LIST = TEST("Step8:Publish topic2", publishTopic2), TEST("Step9:subscribe again", subscribechangeCallback), TEST("Step10:Publish topic2", publishTopic2), + + TEST("Step10:Reset Clean Session", CleanSessionOff), + + // SUBSCRIBE wildcard topic topic4 + TEST("Step9:subscribe wildcard topic", subscribechangeCallback), + TEST("Step11:Sleep ", asleep), TEST("Step12:Publish topic1", publishTopic1), TEST("Step13:Disconnect", disconnect), diff --git a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp index 3b5c89d..9ff58ae 100644 --- a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp +++ b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp @@ -687,6 +687,11 @@ void LGwProxy::setAutoConnectMode(bool valid) _isAutoConnectMode = valid; } +void LGwProxy::setCleanSession(bool valid) +{ + _cleanSession = valid; +} + uint8_t LGwProxy::getStatus(void) { return _status; diff --git a/MQTTSNGateway/GatewayTester/src/LGwProxy.h b/MQTTSNGateway/GatewayTester/src/LGwProxy.h index 4a3b8fb..dcd8415 100644 --- a/MQTTSNGateway/GatewayTester/src/LGwProxy.h +++ b/MQTTSNGateway/GatewayTester/src/LGwProxy.h @@ -68,7 +68,8 @@ public: void setForwarderMode(bool valid); void setQoSMinus1Mode(bool valid); void setPingReqMode(bool valid); - void setAutoConnectMode(bool valid); + void setAutoConnectMode(bool valid); + void setCleanSession(bool valid); void reconnect(void); int writeMsg(const uint8_t* msg); void setPingReqTimer(void); @@ -112,10 +113,10 @@ private: LTimer _keepAliveTimer; uint16_t _tSleep; uint16_t _tWake; - bool _isForwarderMode; - bool _isQoSMinus1Mode; - bool _isPingReqMode; - bool _isAutoConnectMode; + bool _isForwarderMode; + bool _isQoSMinus1Mode; + bool _isPingReqMode; + bool _isAutoConnectMode; char _msg[MQTTSN_MAX_MSG_LENGTH + 1]; }; diff --git a/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h b/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h index 947c5d5..54d216b 100644 --- a/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h +++ b/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h @@ -110,7 +110,7 @@ typedef enum #define SetQoSMinus1Mode(...) theClient->getGwProxy()->setQoSMinus1Mode(__VA_ARGS__) #define SetAutoConnectMode(...) theClient->setAutoConnectMode(__VA_ARGS__) #define SetAutoPingReqMode(...) theClient->getGwProxy()->setPingReqMode(__VA_ARGS__) - +#define SetCleanSessionMode(...) theClient->getGwProxy()->setCleanSession(__VA_ARGS__) #ifdef CLIENT_MODE #define DISPLAY(...) #define PROMPT(...) From a7133dd751dc40b241b54802ccf64c855f5a2ed6 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Mon, 17 May 2021 15:26:01 +0900 Subject: [PATCH 44/67] Bugfix of #230 c65d66e reverted Signed-off-by: tomoaki --- MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp b/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp index 7b007e2..9c52028 100644 --- a/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp @@ -249,16 +249,9 @@ void MQTTSNPublishHandler::handleRegAck(Client* client, MQTTSNPacket* packet) if (regAck != nullptr) { client->getWaitREGACKPacketList()->erase(msgId); - if (rc != MQTTSN_RC_ACCEPTED) - { - delete regAck; - } - else - { - Event* ev = new Event(); - ev->setClientSendEvent(client, regAck); - _gateway->getClientSendQue()->post(ev); - } + Event* ev = new Event(); + ev->setClientSendEvent(client, regAck); + _gateway->getClientSendQue()->post(ev); } if (client->isHoldPingReqest() From 57f8effb7d03bf852ac7d88d0cc7ca4ed64ca615 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 18 May 2021 20:33:38 +0900 Subject: [PATCH 45/67] Bugfix of #238 This reverts commit 69fd222d6070a5e9ec02c90b03a7bb0671ca0db0. --- MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp b/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp index 9c52028..ebbe8cd 100644 --- a/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp @@ -42,6 +42,7 @@ MQTTGWPacket* MQTTSNPublishHandler::handlePublish(Client* client, int qos; uint8_t retained; uint16_t msgId; + uint16_t tid; uint8_t* payload; MQTTSN_topicid topicid; int payloadlen; @@ -69,6 +70,7 @@ MQTTGWPacket* MQTTSNPublishHandler::handlePublish(Client* client, pub.header.bits.dup = dup; pub.header.bits.qos = (qos == 3 ? 0 : qos); pub.header.bits.retain = retained; + tid = topicid.data.id; Topic* topic = nullptr; @@ -128,7 +130,7 @@ MQTTGWPacket* MQTTSNPublishHandler::handlePublish(Client* client, /* Save a msgId & a TopicId pare for PUBACK */ if (msgId && qos > 0 && qos < 3) { - client->setWaitedPubTopicId(msgId, topicid.data.id, &topicid); + client->setWaitedPubTopicId(msgId, tid, &topicid); } pub.payload = (char*) payload; From 9cb991b7740602fa498623b49d96779351ea6775 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 18 May 2021 20:41:38 +0900 Subject: [PATCH 46/67] Copy config files to bin directory Signed-off-by: tomoaki --- MQTTSNGateway/build.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MQTTSNGateway/build.sh b/MQTTSNGateway/build.sh index f56afc1..bb56302 100755 --- a/MQTTSNGateway/build.sh +++ b/MQTTSNGateway/build.sh @@ -14,4 +14,6 @@ else make MQTTSNPacket make MQTT-SNGateway make MQTT-SNLogmonitor + cd ../MQTTSNGateway + cp *.conf ./bin/ fi \ No newline at end of file From aa98498e5743941e3df8ba33ed383ef4c38d512d Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 18 May 2021 20:42:22 +0900 Subject: [PATCH 47/67] Update README Signed-off-by: tomoaki --- MQTTSNGateway/README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/MQTTSNGateway/README.md b/MQTTSNGateway/README.md index 9d40bf6..16839a1 100644 --- a/MQTTSNGateway/README.md +++ b/MQTTSNGateway/README.md @@ -17,8 +17,8 @@ MQTT-SNGateway and MQTT-SNLogmonitor (executable programs) are built in the Buil ### **step2. Execute the Gateway.** ```` - -$ ./bin/MQTT-SNGateway +$ cd bin +$ ./MQTT-SNGateway ```` If you get the error message as follows: ```` @@ -27,7 +27,7 @@ ABORT Gateway!!! ```` You have to start using sudo command only once for the first time. ```` -$ sudo ./bin/MQTT-SNGateway +$ sudo ./MQTT-SNGateway ```` ### **How to Change the configuration of the gateway** @@ -117,8 +117,11 @@ ShearedMemory=YES; Restart the gateway with sudo only once to create shared memories. open ssh terminal and execute LogMonitor. - -`$ ./bin/MQTT-SNLogmonitor` + +``` + $ cd bin + $ ./MQTT-SNLogmonitor +``` Now you can get the Log on your terminal. From 5fbd32151edffb45ebc4408de01ba2f3791dbdeb Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 18 May 2021 20:43:40 +0900 Subject: [PATCH 48/67] Update Test for debug Signed-off-by: tomoaki --- .../GatewayTester/samples/ClientPub/mainPub.cpp | 2 +- MQTTSNGateway/GatewayTester/samples/mainTest.cpp | 13 ++++++------- MQTTSNGateway/GatewayTester/src/LGwProxy.cpp | 2 +- MQTTSNGateway/GatewayTester/src/LGwProxy.h | 2 +- MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp | 5 +++-- MQTTSNGateway/GatewayTester/src/LMqttsnClient.h | 2 +- MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h | 3 ++- .../GatewayTester/src/LSubscribeManager.cpp | 10 +++++++--- MQTTSNGateway/GatewayTester/src/LSubscribeManager.h | 2 +- 9 files changed, 23 insertions(+), 18 deletions(-) diff --git a/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp b/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp index c9a571c..9b6b78e 100644 --- a/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp +++ b/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp @@ -117,7 +117,7 @@ void publishTopic57(void) char payload[300]; sprintf(payload, "publish \"ty4tw/topic57\" \n"); uint8_t qos = 0; - PUBLISH(topic2,(uint8_t*)payload, strlen(payload), qos); + PUBLISH(topic57, (uint8_t* )payload, strlen(payload), qos); } diff --git a/MQTTSNGateway/GatewayTester/samples/mainTest.cpp b/MQTTSNGateway/GatewayTester/samples/mainTest.cpp index 6d0c426..c091ec3 100644 --- a/MQTTSNGateway/GatewayTester/samples/mainTest.cpp +++ b/MQTTSNGateway/GatewayTester/samples/mainTest.cpp @@ -136,13 +136,13 @@ SUBSCRIBE_LIST = *------------------------------------------------------*/ void subscribePredefTopic1(void) { - SUBSCRIBE(1, on_Topic03, QoS1); + SUBSCRIBE_PREDEF(1, on_Topic03, QoS1); } void publishTopic1(void) { char payload[300]; - sprintf(payload, "publish \"ty4tw/Topic1\" \n"); + sprintf(payload, "publish \"ty4tw/topic1\" \n"); PUBLISH(topic1, (uint8_t* )payload, strlen(payload), QoS0); } @@ -162,12 +162,12 @@ void publishTopic4(void) void subscribeTopic10(void) { - SUBSCRIBE(10, on_Topic02, QoS1); + SUBSCRIBE_PREDEF(10, on_Topic02, QoS1); } void subscribeWildcardTopic(void) { - SUBSCRIBE(topic40, on_Topic04, QoS1); + SUBSCRIBE(topic50, on_TopicWildcard, QoS1); } @@ -239,10 +239,9 @@ TEST_LIST = TEST("Step9:subscribe again", subscribechangeCallback), TEST("Step10:Publish topic2", publishTopic2), - TEST("Step10:Reset Clean Session", CleanSessionOff), + //TEST("Step10:Reset Clean Session", CleanSessionOff), - // SUBSCRIBE wildcard topic topic4 - TEST("Step9:subscribe wildcard topic", subscribechangeCallback), + //TEST("Step9:subscribe wildcard topic", subscribechangeCallback), TEST("Step11:Sleep ", asleep), TEST("Step12:Publish topic1", publishTopic1), diff --git a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp index 9ff58ae..0a79cbe 100644 --- a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp +++ b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp @@ -687,7 +687,7 @@ void LGwProxy::setAutoConnectMode(bool valid) _isAutoConnectMode = valid; } -void LGwProxy::setCleanSession(bool valid) +void LGwProxy::setSessionMode(bool valid) { _cleanSession = valid; } diff --git a/MQTTSNGateway/GatewayTester/src/LGwProxy.h b/MQTTSNGateway/GatewayTester/src/LGwProxy.h index dcd8415..659b662 100644 --- a/MQTTSNGateway/GatewayTester/src/LGwProxy.h +++ b/MQTTSNGateway/GatewayTester/src/LGwProxy.h @@ -69,7 +69,7 @@ public: void setQoSMinus1Mode(bool valid); void setPingReqMode(bool valid); void setAutoConnectMode(bool valid); - void setCleanSession(bool valid); + void setSessionMode(bool valid); void reconnect(void); int writeMsg(const uint8_t* msg); void setPingReqTimer(void); diff --git a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp index 2982060..f467a9f 100644 --- a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp +++ b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp @@ -185,9 +185,10 @@ void LMqttsnClient::subscribe(const char* topicName, TopicCallback onPublish, ui _subMgr.subscribe(topicName, onPublish, qos); } -void LMqttsnClient::subscribe(uint16_t topicId, TopicCallback onPublish, uint8_t qos) +void LMqttsnClient::subscribePredefinedId(uint16_t topicId, TopicCallback onPublish, + uint8_t qos) { - _subMgr.subscribe(topicId, onPublish, qos); + _subMgr.subscribePredefinedId(topicId, onPublish, qos); } void LMqttsnClient::unsubscribe(const char* topicName) diff --git a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h index ce152ef..de72eb9 100644 --- a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h +++ b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h @@ -54,7 +54,7 @@ public: void publish(uint16_t topicId, Payload* payload, 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 subscribePredefinedId(uint16_t topicId, TopicCallback onPublish, uint8_t qos); void unsubscribe(const char* topicName); void unsubscribe(const uint16_t topicId); void disconnect(uint16_t sleepInSecs); diff --git a/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h b/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h index 54d216b..06bd545 100644 --- a/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h +++ b/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h @@ -90,6 +90,7 @@ typedef enum #define CONNECT(...) theClient->getGwProxy()->connect(__VA_ARGS__) #define PUBLISH(...) theClient->publish(__VA_ARGS__) #define SUBSCRIBE(...) theClient->subscribe(__VA_ARGS__) +#define SUBSCRIBE_PREDEF(...) theClient->subscribePredefinedId(__VA_ARGS__) #define UNSUBSCRIBE(...) theClient->unsubscribe(__VA_ARGS__) #define DISCONNECT(...) theClient->disconnect(__VA_ARGS__) #define ONCONNECT() theClient->getSubscribeManager()->onConnect() @@ -110,7 +111,7 @@ typedef enum #define SetQoSMinus1Mode(...) theClient->getGwProxy()->setQoSMinus1Mode(__VA_ARGS__) #define SetAutoConnectMode(...) theClient->setAutoConnectMode(__VA_ARGS__) #define SetAutoPingReqMode(...) theClient->getGwProxy()->setPingReqMode(__VA_ARGS__) -#define SetCleanSessionMode(...) theClient->getGwProxy()->setCleanSession(__VA_ARGS__) +#define SetCleanSession(...) theClient->getGwProxy()->setSessionMode(__VA_ARGS__) #ifdef CLIENT_MODE #define DISPLAY(...) #define PROMPT(...) diff --git a/MQTTSNGateway/GatewayTester/src/LSubscribeManager.cpp b/MQTTSNGateway/GatewayTester/src/LSubscribeManager.cpp index 03a4bbf..8630c29 100644 --- a/MQTTSNGateway/GatewayTester/src/LSubscribeManager.cpp +++ b/MQTTSNGateway/GatewayTester/src/LSubscribeManager.cpp @@ -67,7 +67,9 @@ void LSubscribeManager::onConnect(void) { if ( theOnPublishList[i].type == MQTTSN_TOPIC_TYPE_PREDEFINED) { - subscribe(theOnPublishList[i].id, theOnPublishList[i].pubCallback, theOnPublishList[i].qos); + subscribePredefinedId(theOnPublishList[i].id, + theOnPublishList[i].pubCallback, + theOnPublishList[i].qos); } else { @@ -170,7 +172,7 @@ void LSubscribeManager::subscribe(const char* topicName, TopicCallback onPublish send(elm); } -void LSubscribeManager::subscribe(uint16_t topicId, TopicCallback onPublish, uint8_t qos) +void LSubscribeManager::subscribePredefinedId(uint16_t topicId, TopicCallback onPublish, uint8_t qos) { SubElement* elm = add(MQTTSN_TYPE_SUBSCRIBE, 0, MQTTSN_TOPIC_TYPE_PREDEFINED, topicId, qos, onPublish); send(elm); @@ -263,7 +265,9 @@ void LSubscribeManager::responce(const uint8_t* msg) } else { - DISPLAY("\033[0m\033[0;31m UNSUBACK Invalid messageId. \033[0m\033[0;37m\n\n"); + DISPLAY( + "\033[0m\033[0;31m UNSUBACK Invalid messageId=%04x. \033[0m\033[0;37m\n\n", + msgId); } } } diff --git a/MQTTSNGateway/GatewayTester/src/LSubscribeManager.h b/MQTTSNGateway/GatewayTester/src/LSubscribeManager.h index 1db3617..6c56055 100644 --- a/MQTTSNGateway/GatewayTester/src/LSubscribeManager.h +++ b/MQTTSNGateway/GatewayTester/src/LSubscribeManager.h @@ -56,7 +56,7 @@ public: ~LSubscribeManager(); void onConnect(void); void subscribe(const char* topicName, TopicCallback onPublish, uint8_t qos); - void subscribe(uint16_t topicId, TopicCallback onPublish, uint8_t qos); + void subscribePredefinedId(uint16_t topicId, TopicCallback onPublish, uint8_t qos); void unsubscribe(const char* topicName); void unsubscribe(uint16_t topicId); void responce(const uint8_t* msg); From 15c527e0731b33095fb01af1b268d1c844a217c6 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 18 May 2021 20:55:48 +0900 Subject: [PATCH 49/67] Bugfix of #221 Signed-off-by: tomoaki --- MQTTSNGateway/src/MQTTGWPublishHandler.cpp | 25 ++++++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/MQTTSNGateway/src/MQTTGWPublishHandler.cpp b/MQTTSNGateway/src/MQTTGWPublishHandler.cpp index dfa8928..2bdc98d 100644 --- a/MQTTSNGateway/src/MQTTGWPublishHandler.cpp +++ b/MQTTSNGateway/src/MQTTGWPublishHandler.cpp @@ -102,16 +102,18 @@ void MQTTGWPublishHandler::handlePublish(Client* client, MQTTGWPacket* packet) topicId.type = tp->getType(); topicId.data.long_.len = pub.topiclen; topicId.data.long_.name = pub.topic; - topicId.data.id = tp->getTopicId(); } else { - /* This message might be subscribed with wild card. */ + /* This message might be subscribed with wild card or not cleanSession*/ topicId.type = MQTTSN_TOPIC_TYPE_NORMAL; Topic* topic = client->getTopics()->match(&topicId); - if (topic == nullptr) + + if (topic == nullptr && client->isCleanSession()) { - WRITELOG(" Invalid Topic. PUBLISH message is canceled.\n"); + WRITELOG( + "%sMQTTGWPublishHandler Invalid Topic. PUBLISH message is discarded.%s\n", + ERRMSG_HEADER, ERRMSG_FOOTER); if (pub.header.bits.qos == 1) { replyACK(client, &pub, PUBACK); @@ -125,16 +127,24 @@ void MQTTGWPublishHandler::handlePublish(Client* client, MQTTGWPacket* packet) return; } + if (topic == nullptr) + { + topicId.type = MQTTSN_TOPIC_TYPE_NORMAL; + topicId.data.long_.len = pub.topiclen; + topicId.data.long_.name = pub.topic; + topicId.data.id = 0; + } + /* add the Topic and get a TopicId */ topic = client->getTopics()->add(&topicId); if (topic == nullptr) { - WRITELOG("%sMQTTGWPublishHandler Can't Add a Topic. MAX_TOPIC_PAR_CLIENT is exceeded.%s\n", + WRITELOG( + "%sMQTTGWPublishHandler Can't Add a Topic. MAX_TOPIC_PAR_CLIENT is exceeded. PUBLISH message is discarded.%s\n", ERRMSG_HEADER, ERRMSG_FOOTER); delete snPacket; return; } - id = topic->getTopicId(); if (id > 0) { @@ -165,7 +175,8 @@ void MQTTGWPublishHandler::handlePublish(Client* client, MQTTGWPacket* packet) } else { - WRITELOG("%sMQTTGWPublishHandler Can't create a Topic.%s\n", + WRITELOG( + "%sMQTTGWPublishHandler Can't create a Topic. PUBLISH message is discarded.%s\n", ERRMSG_HEADER, ERRMSG_FOOTER); delete snPacket; return; From 26e4e0d91a3c574f9b7e28e2eb35cf6392da276e Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 18 May 2021 20:57:03 +0900 Subject: [PATCH 50/67] Add function for a test Signed-off-by: tomoaki --- .settings/org.eclipse.cdt.codan.core.prefs | 77 +++++++++++++++++++ .settings/org.eclipse.cdt.ui.prefs | 2 + MQTTSNGateway/src/MQTTSNGWClient.cpp | 5 ++ MQTTSNGateway/src/MQTTSNGWClient.h | 1 + .../src/MQTTSNGWSubscribeHandler.cpp | 3 +- 5 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 .settings/org.eclipse.cdt.codan.core.prefs create mode 100644 .settings/org.eclipse.cdt.ui.prefs diff --git a/.settings/org.eclipse.cdt.codan.core.prefs b/.settings/org.eclipse.cdt.codan.core.prefs new file mode 100644 index 0000000..a159526 --- /dev/null +++ b/.settings/org.eclipse.cdt.codan.core.prefs @@ -0,0 +1,77 @@ +eclipse.preferences.version=1 +fr.ac6.mcu.ide.source.checker.libnano.problem=Error +fr.ac6.mcu.ide.source.checker.libnano.problem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Float formatting support\\")"} +org.eclipse.cdt.codan.checkers.errnoreturn=Warning +org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"No return\\")",implicit\=>false} +org.eclipse.cdt.codan.checkers.errreturnvalue=Error +org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused return value\\")"} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Nesting comments\\")"} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Line comments\\")"} +org.eclipse.cdt.codan.checkers.noreturn=Error +org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"No return value\\")",implicit\=>false} +org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error +org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Abstract class cannot be instantiated\\")"} +org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error +org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Ambiguous problem\\")"} +org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning +org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Assignment in condition\\")"} +org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error +org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Assignment to itself\\")"} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"No break at end of case\\")",no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false,enable_fallthrough_quickfix_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning +org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Catching by reference is recommended\\")",unknown\=>false,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error +org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Circular inheritance\\")"} +org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning +org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Class members should be properly initialized\\")",skip\=>true} +org.eclipse.cdt.codan.internal.checkers.DecltypeAutoProblem=Error +org.eclipse.cdt.codan.internal.checkers.DecltypeAutoProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid 'decltype(auto)' specifier\\")"} +org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Field cannot be resolved\\")"} +org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Function cannot be resolved\\")"} +org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error +org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid arguments\\")"} +org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error +org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid template argument\\")"} +org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error +org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Label statement not found\\")"} +org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error +org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Member declaration not found\\")"} +org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Method cannot be resolved\\")"} +org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info +org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Name convention for function\\")",pattern\=>"^[a-z]",macro\=>true,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning +org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Class has a virtual method and non-virtual destructor\\")"} +org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error +org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid overload\\")"} +org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error +org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid redeclaration\\")"} +org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error +org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid redefinition\\")"} +org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Return with parenthesis\\")"} +org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Format String Vulnerability\\")"} +org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning +org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Statement has no effect\\")",macro\=>true,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning +org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Suggested parenthesis around expression\\")",paramNot\=>false} +org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning +org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Suspicious semicolon\\")",else\=>false,afterelse\=>false} +org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Type cannot be resolved\\")"} +org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning +org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused function declaration\\")",macro\=>true} +org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning +org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused static function\\")",macro\=>true} +org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning +org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused variable declaration in file scope\\")",macro\=>true,exceptions\=>("@(\#)","$Id")} +org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Symbol is not resolved\\")"} +org.eclipse.cdt.qt.core.qtproblem=Warning +org.eclipse.cdt.qt.core.qtproblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_ON_FILE_OPEN\=>true,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>null} diff --git a/.settings/org.eclipse.cdt.ui.prefs b/.settings/org.eclipse.cdt.ui.prefs new file mode 100644 index 0000000..4ee12a4 --- /dev/null +++ b/.settings/org.eclipse.cdt.ui.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +formatter_settings_version=1 diff --git a/MQTTSNGateway/src/MQTTSNGWClient.cpp b/MQTTSNGateway/src/MQTTSNGWClient.cpp index f61ac92..11ecc71 100644 --- a/MQTTSNGateway/src/MQTTSNGWClient.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClient.cpp @@ -323,6 +323,11 @@ void Client::tryConnect(void) _status = Cstat_TryConnecting; } +bool Client::isCleanSession(void) +{ + return _sessionStatus; +} + bool Client::isConnectSendable(void) { if (_status == Cstat_Lost || _status == Cstat_TryConnecting) diff --git a/MQTTSNGateway/src/MQTTSNGWClient.h b/MQTTSNGateway/src/MQTTSNGWClient.h index c50df2a..6d063f9 100644 --- a/MQTTSNGateway/src/MQTTSNGWClient.h +++ b/MQTTSNGateway/src/MQTTSNGWClient.h @@ -254,6 +254,7 @@ public: bool isSecureNetwork(void); bool isSensorNetStable(void); bool isWaitWillMsg(void); + bool isCleanSession(void); void holdPingRequest(void); void resetPingRequest(void); diff --git a/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp index 2b4f0a6..9b39030 100644 --- a/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp @@ -63,6 +63,7 @@ MQTTGWPacket* MQTTSNSubscribeHandler::handleSubscribe(Client* client, if (!topic) { + /* Search the topic in Client common topic table */ topic = _gateway->getTopics()->getTopicById(&topicFilter); if (topic) { @@ -133,7 +134,7 @@ MQTTGWPacket* MQTTSNSubscribeHandler::handleSubscribe(Client* client, RespExit: MQTTSNPacket* sSuback = new MQTTSNPacket(); sSuback->setSUBACK(qos, topicFilter.data.id, msgId, - MQTTSN_RC_NOT_SUPPORTED); + MQTTSN_RC_REJECTED_INVALID_TOPIC_ID); evsuback = new Event(); evsuback->setClientSendEvent(client, sSuback); _gateway->getClientSendQue()->post(evsuback); From 74fa104c64a0fd097eb6983ffda2bff05714c1d7 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 18 May 2021 20:57:30 +0900 Subject: [PATCH 51/67] add LoRaLink config Signed-off-by: tomoaki --- MQTTSNGateway/gateway.conf | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/MQTTSNGateway/gateway.conf b/MQTTSNGateway/gateway.conf index e13c853..0d52f06 100644 --- a/MQTTSNGateway/gateway.conf +++ b/MQTTSNGateway/gateway.conf @@ -31,7 +31,7 @@ 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/ @@ -63,6 +63,11 @@ Baudrate=38400 SerialDevice=/dev/ttyUSB0 ApiMode=2 +# LoRaLink +BaudrateLoRaLink=115200 +DeviceRxLoRaLink=/dev/loralinkRx +DeviceTxLoRaLink=/dev/loralinkTx + # LOG ShearedMemory=NO; From 740faeb09fa882671f50818f8c261cc5188a6107 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 18 May 2021 21:07:24 +0900 Subject: [PATCH 52/67] update test Signed-off-by: tomoaki --- MQTTSNGateway/GatewayTester/samples/mainTest.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/MQTTSNGateway/GatewayTester/samples/mainTest.cpp b/MQTTSNGateway/GatewayTester/samples/mainTest.cpp index c091ec3..c24ad33 100644 --- a/MQTTSNGateway/GatewayTester/samples/mainTest.cpp +++ b/MQTTSNGateway/GatewayTester/samples/mainTest.cpp @@ -239,10 +239,6 @@ TEST_LIST = TEST("Step9:subscribe again", subscribechangeCallback), TEST("Step10:Publish topic2", publishTopic2), - //TEST("Step10:Reset Clean Session", CleanSessionOff), - - //TEST("Step9:subscribe wildcard topic", subscribechangeCallback), - TEST("Step11:Sleep ", asleep), TEST("Step12:Publish topic1", publishTopic1), TEST("Step13:Disconnect", disconnect), From 982e6d488448f53780c988f7ec928401485157a9 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 25 May 2021 11:50:58 +0900 Subject: [PATCH 53/67] Add ClientPool Clients are created and kept in the pool at first. ClientList gets a free client from the pool. Signed-off-by: tomoaki --- MQTTSNGateway/src/MQTTSNGWClient.cpp | 5 +- MQTTSNGateway/src/MQTTSNGWClient.h | 4 +- MQTTSNGateway/src/MQTTSNGWClientList.cpp | 119 +++++++++++++++++++---- MQTTSNGateway/src/MQTTSNGWClientList.h | 23 ++++- 4 files changed, 125 insertions(+), 26 deletions(-) diff --git a/MQTTSNGateway/src/MQTTSNGWClient.cpp b/MQTTSNGateway/src/MQTTSNGWClient.cpp index 11ecc71..ddd4adc 100644 --- a/MQTTSNGateway/src/MQTTSNGWClient.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClient.cpp @@ -32,14 +32,15 @@ char* currentDateTime(void); Class Client =====================================*/ static const char* theClientStatus[] = -{ "Disconnected", "TryConnecting", "Connecting", "Active", "Asleep", "Awake", +{ "InPool", "Disconnected", "TryConnecting", "Connecting", "Active", "Asleep", + "Awake", "Lost" }; Client::Client(bool secure) { _packetId = 0; _snMsgId = 0; - _status = Cstat_Disconnected; + _status = Cstat_Free; _keepAliveMsec = 0; _topics = new Topics(); _clientId = nullptr; diff --git a/MQTTSNGateway/src/MQTTSNGWClient.h b/MQTTSNGateway/src/MQTTSNGWClient.h index 6d063f9..7b7db4e 100644 --- a/MQTTSNGateway/src/MQTTSNGWClient.h +++ b/MQTTSNGateway/src/MQTTSNGWClient.h @@ -152,7 +152,8 @@ private: =====================================*/ typedef enum { - Cstat_Disconnected = 0, + Cstat_Free = 0, + Cstat_Disconnected, Cstat_TryConnecting, Cstat_Connecting, Cstat_Active, @@ -176,6 +177,7 @@ class Forwarder; class Client { friend class ClientList; + friend class ClientsPool; public: Client(bool secure = false); Client(uint8_t maxInflightMessages, bool secure); diff --git a/MQTTSNGateway/src/MQTTSNGWClientList.cpp b/MQTTSNGateway/src/MQTTSNGWClientList.cpp index d40c0fc..0d1ad0d 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientList.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientList.cpp @@ -20,18 +20,20 @@ #include using namespace MQTTSNGW; -extern Gateway* theGateway; +char* currentDateTime(void); /*===================================== Class ClientList =====================================*/ const char* common_topic = "*"; -ClientList::ClientList() +ClientList::ClientList(Gateway* gw) { _clientCnt = 0; _authorize = false; _firstClient = nullptr; _endClient = nullptr; + _clientsPool = new ClientsPool(); + _gateway = gw; } ClientList::~ClientList() @@ -46,12 +48,19 @@ ClientList::~ClientList() delete cl; cl = ncl; }; + + if (_clientsPool) + { + delete _clientsPool; + } _mutex.unlock(); } void ClientList::initialize(bool aggregate) { - if (theGateway->getGWParams()->clientAuthentication) + _clientsPool->allocate(_gateway->getGWParams()->maxClients); + + if (_gateway->getGWParams()->clientAuthentication) { int type = TRANSPEARENT_TYPE; if (aggregate) @@ -62,7 +71,7 @@ void ClientList::initialize(bool aggregate) _authorize = true; } - if (theGateway->getGWParams()->predefinedTopic) + if (_gateway->getGWParams()->predefinedTopic) { setPredefinedTopics(aggregate); } @@ -70,20 +79,21 @@ void ClientList::initialize(bool aggregate) void ClientList::setClientList(int type) { - if (!createList(theGateway->getGWParams()->clientListName, type)) + if (!createList(_gateway->getGWParams()->clientListName, type)) { throw EXCEPTION( - "ClientList::setClientList No client list defined by config file.", 0); + "ClientList::setClientList Client list not found!", 0); } } void ClientList::setPredefinedTopics(bool aggrecate) { - if (!readPredefinedList(theGateway->getGWParams()->predefinedTopicFileName, + if (!readPredefinedList(_gateway->getGWParams()->predefinedTopicFileName, aggrecate)) { throw EXCEPTION( - "ClientList::setPredefinedTopics No predefindTopi list defined by config file.",0); + "ClientList::setPredefinedTopics PredefindTopic list not found!", + 0); } } @@ -158,7 +168,7 @@ bool ClientList::createList(const char* fileName, int type) } else if (forwarder && type == FORWARDER_TYPE) { - theGateway->getAdapterManager()->getForwarderList()->addForwarder( + _gateway->getAdapterManager()->getForwarderList()->addForwarder( &netAddr, &clientId); } else if (type == TRANSPEARENT_TYPE) @@ -338,22 +348,23 @@ Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, 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); + Client* client = getClient(addr); if (client) { return client; } - /* creat a new client */ - client = new Client(secure); + /* acquire a free client */ + client = _clientsPool->getClient(); + + if (!client) + { + WRITELOG("%s%sMax number of Clients%s\n", currentDateTime(), + ERRMSG_HEADER, ERRMSG_FOOTER); + return nullptr; + } + + client->disconnected(); if (addr) { client->setClientAddress(addr); @@ -411,7 +422,7 @@ Client* ClientList::createPredefinedTopic(MQTTSNString* clientId, if (strcmp(clientId->cstring, common_topic) == 0) { - theGateway->getTopics()->add((const char*) topicName.c_str(), topicId); + _gateway->getTopics()->add((const char*) topicName.c_str(), topicId); return nullptr; } else @@ -473,3 +484,69 @@ bool ClientList::isAuthorized() return _authorize; } +/****************************** + * Class ClientsPool + ******************************/ + +ClientsPool::ClientsPool() +{ + _clientCnt = 0; + _firstClient = nullptr; + _endClient = nullptr; +} + +ClientsPool::~ClientsPool() +{ + Client* cl = _firstClient; + Client* ncl; + + while (cl != nullptr) + { + ncl = cl->_nextClient; + delete cl; + cl = ncl; + }; +} + +void ClientsPool::allocate(int maxClients) +{ + Client* cl = nullptr; + + _firstClient = new Client(); + + for (int i = 0; i < maxClients; i++) + { + if ((cl = new Client()) == nullptr) + { + throw Exception( + "ClientsPool::Can't allocate max number of clients\n", 0); + } + cl->_nextClient = _firstClient; + _firstClient = cl; + _clientCnt++; + } + +} + +Client* ClientsPool::getClient(void) +{ + while (_firstClient != nullptr) + { + Client* cl = _firstClient; + _firstClient = cl->_nextClient; + cl->_nextClient = nullptr; + _clientCnt--; + return cl; + } + return nullptr; +} + +void ClientsPool::setClient(Client* client) +{ + if (client) + { + client->_nextClient = _firstClient; + _firstClient = client; + _clientCnt++; + } +} diff --git a/MQTTSNGateway/src/MQTTSNGWClientList.h b/MQTTSNGateway/src/MQTTSNGWClientList.h index e3542bb..33424be 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientList.h +++ b/MQTTSNGateway/src/MQTTSNGWClientList.h @@ -30,13 +30,31 @@ namespace MQTTSNGW class Client; +/*===================================== + Class ClientsPool + =====================================*/ +class ClientsPool +{ +public: + ClientsPool(); + ~ClientsPool(); + void allocate(int maxClients); + Client* getClient(void); + void setClient(Client* client); + +private: + Client* _firstClient; + Client* _endClient; + int _clientCnt; +}; + /*===================================== Class ClientList =====================================*/ class ClientList { public: - ClientList(); + ClientList(Gateway* gw); ~ClientList(); void initialize(bool aggregate); @@ -57,7 +75,8 @@ public: private: bool readPredefinedList(const char* fileName, bool _aggregate); - Gateway* _gateway { nullptr }; + ClientsPool* _clientsPool; + Gateway* _gateway; Client* createPredefinedTopic(MQTTSNString* clientId, string topicName, uint16_t toipcId, bool _aggregate); Client* _firstClient; From 55128f0f0e5a8abdf509680a4b357c785de6f0f2 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Wed, 2 Jun 2021 20:15:52 +0900 Subject: [PATCH 54/67] =?UTF-8?q?Add=20Bluetooth=20classic=E3=80=80as=20a?= =?UTF-8?q?=20sensor=20network=20#69,=20#195,=20#90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I think the architecture of the ble sensor network, which does not use threads per socket, can be applied to DTLS. Known bug: Occasionally a timeout error occurs when connecting to RFCOMM. BLE is not supported yet. I need help to do it. Signed-off-by: tomoaki --- .cproject | 18 +- .settings/language.settings.xml | 4 +- MQTTSNGateway/GatewayTester/Makefile | 3 +- MQTTSNGateway/GatewayTester/README.md | 62 +- .../samples/ClientPub/mainPub.cpp | 8 + .../samples/ClientPubQoS-1/mainPubQoS-1.cpp | 8 + .../samples/ClientSub/mainSub.cpp | 8 + .../GatewayTester/samples/mainTest.cpp | 34 +- MQTTSNGateway/GatewayTester/src/LGwProxy.cpp | 8 +- MQTTSNGateway/GatewayTester/src/LGwProxy.h | 3 +- .../GatewayTester/src/LMqttsnClient.cpp | 13 +- .../GatewayTester/src/LMqttsnClient.h | 2 +- .../GatewayTester/src/LMqttsnClientApp.h | 33 +- .../GatewayTester/src/LNetworkBle.cpp | 295 ++++++++++ MQTTSNGateway/GatewayTester/src/LNetworkBle.h | 106 ++++ .../GatewayTester/src/LNetworkUdp.cpp | 9 +- MQTTSNGateway/GatewayTester/src/LNetworkUdp.h | 7 +- MQTTSNGateway/README.md | 7 +- MQTTSNGateway/gateway.conf | 4 + MQTTSNGateway/src/CMakeLists.txt | 17 +- MQTTSNGateway/src/MQTTGWConnectionHandler.cpp | 26 +- MQTTSNGateway/src/MQTTGWPacket.cpp | 32 +- MQTTSNGateway/src/MQTTGWPublishHandler.cpp | 92 ++- MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp | 17 +- .../src/MQTTSNAggregateConnectionHandler.cpp | 21 +- MQTTSNGateway/src/MQTTSNGWAdapter.cpp | 16 +- MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp | 18 +- .../src/MQTTSNGWAggregateTopicTable.cpp | 6 +- MQTTSNGateway/src/MQTTSNGWAggregater.cpp | 3 +- MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp | 67 +-- MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp | 42 +- MQTTSNGateway/src/MQTTSNGWClient.cpp | 25 +- MQTTSNGateway/src/MQTTSNGWClientList.cpp | 143 +++-- MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp | 528 +++++++++--------- MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp | 28 +- .../src/MQTTSNGWConnectionHandler.cpp | 33 +- .../src/MQTTSNGWEncapsulatedPacket.cpp | 18 +- MQTTSNGateway/src/MQTTSNGWForwarder.cpp | 8 +- MQTTSNGateway/src/MQTTSNGWMessageIdTable.cpp | 13 +- MQTTSNGateway/src/MQTTSNGWPacket.cpp | 91 ++- .../src/MQTTSNGWPacketHandleTask.cpp | 15 +- MQTTSNGateway/src/MQTTSNGWProcess.cpp | 67 +-- MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp | 63 +-- .../src/MQTTSNGWSubscribeHandler.cpp | 62 +- MQTTSNGateway/src/MQTTSNGWTopic.cpp | 32 +- MQTTSNGateway/src/MQTTSNGWTopic.h | 2 +- MQTTSNGateway/src/MQTTSNGateway.cpp | 37 +- MQTTSNGateway/src/MQTTSNGateway.h | 7 +- MQTTSNGateway/src/linux/Threading.cpp | 2 +- MQTTSNGateway/src/linux/Threading.h | 2 +- MQTTSNGateway/src/linux/ble/SensorNetwork.cpp | 425 ++++++++++++++ MQTTSNGateway/src/linux/ble/SensorNetwork.h | 104 ++++ MQTTSNGateway/src/linux/udp/SensorNetwork.cpp | 2 +- travis-build.sh | 2 + 54 files changed, 1764 insertions(+), 934 deletions(-) create mode 100644 MQTTSNGateway/GatewayTester/src/LNetworkBle.cpp create mode 100644 MQTTSNGateway/GatewayTester/src/LNetworkBle.h create mode 100644 MQTTSNGateway/src/linux/ble/SensorNetwork.cpp create mode 100644 MQTTSNGateway/src/linux/ble/SensorNetwork.h diff --git a/.cproject b/.cproject index 409af95..6a486ab 100644 --- a/.cproject +++ b/.cproject @@ -97,11 +97,13 @@ @@ -133,7 +135,11 @@ - + + + + + @@ -273,9 +279,9 @@ - + - + diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index f8d47a4..659286b 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -11,7 +11,7 @@ - + @@ -33,7 +33,7 @@ - + diff --git a/MQTTSNGateway/GatewayTester/Makefile b/MQTTSNGateway/GatewayTester/Makefile index 0ed4a27..c94b65e 100644 --- a/MQTTSNGateway/GatewayTester/Makefile +++ b/MQTTSNGateway/GatewayTester/Makefile @@ -20,6 +20,7 @@ CPPSRCS := \ $(SUBDIR)/LGwProxy.cpp \ $(SUBDIR)/LMqttsnClient.cpp \ $(SUBDIR)/LNetworkUdp.cpp \ +$(SUBDIR)/LNetworkBle.cpp \ $(SUBDIR)/LPublishManager.cpp \ $(SUBDIR)/LRegisterManager.cpp \ $(SUBDIR)/LSubscribeManager.cpp \ @@ -41,7 +42,7 @@ DEFS := LIBS += LDFLAGS := CXXFLAGS := -Wall -O3 -std=c++11 -LDADD := +LDADD := -lbluetooth OUTDIR := Build PROG := $(OUTDIR)/$(PROGTEST) diff --git a/MQTTSNGateway/GatewayTester/README.md b/MQTTSNGateway/GatewayTester/README.md index 2efa9bb..a0f4bad 100644 --- a/MQTTSNGateway/GatewayTester/README.md +++ b/MQTTSNGateway/GatewayTester/README.md @@ -1,7 +1,7 @@ -###Gateway Test Program. +# Gateway Test Program. **sample/mainTest.cpp** is a Test sample coading. Each test is described as one function. test1(), test2()... -```` +``` /*------------------------------------------------------ * Test functions * @@ -25,37 +25,51 @@ Each test is described as one function. test1(), test2()... void test1(void) { - char payload[300]; - sprintf(payload, "ESP8266-08b133 "); - uint8_t qos = 0; - PUBLISH(topic1,(uint8_t*)payload, strlen(payload), qos); + char payload[300]; + sprintf(payload, "ESP8266-08b133 "); + uint8_t qos = 0; + PUBLISH(topic1,(uint8_t*)payload, strlen(payload), qos); } void test2(void) { - uint8_t qos = 1; - SUBSCRIBE(topic2, on_publish02, qos); + uint8_t qos = 1; + SUBSCRIBE(topic2, on_publish02, qos); } -```` +``` **TEST_LIST** is a test senario. Test functions are executed one by one. -```` +``` /*------------------------------------------------------ * A List of Test Tasks *------------------------------------------------------*/ TEST_LIST = {// e.g. TEST( Label, Test), - TEST("Publish topic1", test1), - TEST("Subscribe topic2", test2), - TEST("Publish topic2", test3), - TEST("Unsubscribe topic2", test4), - TEST("Publish topic2", test3), - TEST("Disconnect", test5), - END_OF_TEST_LIST - }; -```` + TEST("Publish topic1", test1), + TEST("Subscribe topic2", test2), + TEST("Publish topic2", test3), + TEST("Unsubscribe topic2", test4), + TEST("Publish topic2", test3), + TEST("Disconnect", test5), + END_OF_TEST_LIST + }; + +``` +## step1. Define a sensor network -### **step1. Build ** -```` +**UDP** or **Bluetooth** is available as a sensor network. +Uncomment a line \#define UDP or BLE in LMqttsnClientApp.h file. +``` + +/*====================================== + * Program mode Flag + ======================================*/ +//#define CLIENT_MODE +#define UDP +//#define BLE +``` + +## step2. Build +``` $ git clone https://github.com/eclipse/paho.mqtt-sn.embedded-c $ cd paho.mqtt-sn.embedded-c/MQTTSNGateway/GatewayTester $ make @@ -65,9 +79,9 @@ $ make clean MQTT-SNGatewayTester program is copied into ../../../ directory. -### **step2. Execute Gateway Tester.** +## **step3. Execute Gateway Tester.** -```` +``` $ cd ../../.. $ ./MQTT-SNGatewayTester @@ -116,4 +130,4 @@ recved 192.168.11.17 :10000 08 13 20 00 01 00 01 00 Execute Publish topic1 Test ? ( Y/N ) : -```` +``` diff --git a/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp b/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp index 9b6b78e..0646ef4 100644 --- a/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp +++ b/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp @@ -58,6 +58,14 @@ UDPCONF = { 20010, // Local PortNo }; +/*------------------------------------------------------ + * BLE Configuration (theNetcon) + *------------------------------------------------------*/ +BLECONF = { "GatewayTestClient", // ClientId + { 0x60, 0x57, 0x18, 0x06, 0x8b, 0x72 }, // GW Address + 1, // Rfcomm channel + }; + /*------------------------------------------------------ * Client Configuration (theMqcon) *------------------------------------------------------*/ diff --git a/MQTTSNGateway/GatewayTester/samples/ClientPubQoS-1/mainPubQoS-1.cpp b/MQTTSNGateway/GatewayTester/samples/ClientPubQoS-1/mainPubQoS-1.cpp index 34151ed..2412485 100644 --- a/MQTTSNGateway/GatewayTester/samples/ClientPubQoS-1/mainPubQoS-1.cpp +++ b/MQTTSNGateway/GatewayTester/samples/ClientPubQoS-1/mainPubQoS-1.cpp @@ -58,6 +58,14 @@ UDPCONF = { 20001, // Local PortNo }; +/*------------------------------------------------------ + * BLE Configuration (theNetcon) + *------------------------------------------------------*/ +BLECONF = { "GatewayTestClient", // ClientId + { 0x60, 0x57, 0x18, 0x06, 0x8b, 0x72 }, // GW Address + 1, // Rfcomm channel + }; + /*------------------------------------------------------ * Client Configuration (theMqcon) *------------------------------------------------------*/ diff --git a/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp b/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp index 9bf8c1b..2cb03ec 100644 --- a/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp +++ b/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp @@ -58,6 +58,14 @@ UDPCONF = { 20011, // Local PortNo }; +/*------------------------------------------------------ + * BLE Configuration (theNetcon) + *------------------------------------------------------*/ +BLECONF = { "GatewayTestClient", // ClientId + { 0x44, 0x1C, 0xA8, 0x16, 0x94, 0x94 }, // GW Address + 1, // Rfcomm channel + }; + /*------------------------------------------------------ * Client Configuration (theMqcon) *------------------------------------------------------*/ diff --git a/MQTTSNGateway/GatewayTester/samples/mainTest.cpp b/MQTTSNGateway/GatewayTester/samples/mainTest.cpp index c24ad33..316343e 100644 --- a/MQTTSNGateway/GatewayTester/samples/mainTest.cpp +++ b/MQTTSNGateway/GatewayTester/samples/mainTest.cpp @@ -51,25 +51,31 @@ extern LScreen* theScreen; /*------------------------------------------------------ * UDP Configuration (theNetcon) *------------------------------------------------------*/ -UDPCONF = -{ "GatewayTestClient", // ClientId +UDPCONF = { "GatewayTestClient", // ClientId { 225, 1, 1, 1 }, // Multicast group IP - 1883, // Multicast group Port - 20020, // Local PortNo - }; + 1883, // Multicast group Port + 20020, // Local PortNo + }; + +/*------------------------------------------------------ + * BLE Configuration (theNetcon) + *------------------------------------------------------*/ +BLECONF = { "GatewayTestClient", // ClientId + { 0x60, 0x57, 0x18, 0x06, 0x8b, 0x72 }, // GW Address + 1, // Rfcomm channel + }; /*------------------------------------------------------ * Client Configuration (theMqcon) *------------------------------------------------------*/ -MQTTSNCONF = -{ 60, //KeepAlive [seconds] - true, //Clean session - 300, //Sleep duration [seconds] - "", //WillTopic - "", //WillMessage - 0, //WillQos - false //WillRetain - }; +MQTTSNCONF = { 60, //KeepAlive [seconds] + true, //Clean session + 300, //Sleep duration [seconds] + "", //WillTopic + "", //WillMessage + 0, //WillQos + false //WillRetain + }; /*------------------------------------------------------ * Define Topics diff --git a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp index 0a79cbe..3214608 100644 --- a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp +++ b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp @@ -66,7 +66,7 @@ LGwProxy::~LGwProxy() _topicTbl.clearTopic(); } -void LGwProxy::initialize(LUdpConfig netconf, LMqttsnConfig mqconf) +void LGwProxy::initialize(SENSORNET_CONFIG_t netconf, LMqttsnConfig mqconf) { _network.initialize(netconf); _clientId = netconf.clientId; @@ -87,6 +87,12 @@ void LGwProxy::connect() { pos = _msg; + if (!_network.isBroadcastable() && _status == GW_LOST) + { + _status = GW_CONNECTING; + continue; + } + if (_status == GW_LOST) { diff --git a/MQTTSNGateway/GatewayTester/src/LGwProxy.h b/MQTTSNGateway/GatewayTester/src/LGwProxy.h index 659b662..1523c8f 100644 --- a/MQTTSNGateway/GatewayTester/src/LGwProxy.h +++ b/MQTTSNGateway/GatewayTester/src/LGwProxy.h @@ -23,6 +23,7 @@ #include "LMqttsnClientApp.h" #include "LNetworkUdp.h" +#include "LNetworkBle.h" #include "LRegisterManager.h" #include "LTimer.h" #include "LTopicTable.h" @@ -54,7 +55,7 @@ public: LGwProxy(); ~LGwProxy(); - void initialize(LUdpConfig netconf, LMqttsnConfig mqconf); + void initialize(SENSORNET_CONFIG_t netconf, LMqttsnConfig mqconf); void connect(void); void disconnect(uint16_t sec = 0); int getMessage(void); diff --git a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp index f467a9f..9e00556 100644 --- a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp +++ b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp @@ -29,7 +29,7 @@ extern TaskList theTaskList[]; extern TestList theTestList[]; extern OnPublishList theOnPublishList[]; extern MQTTSNCONF; -extern UDPCONF; +extern SENSORNET_CONFIG_t theNetcon; extern void setup(void); /*===================================== @@ -50,7 +50,14 @@ int main(int argc, char** argv) #ifndef CLIENT_MODE char c = 0; printf("\n%s", PAHO_COPYRIGHT4); - printf("\n%s\n", PAHO_COPYRIGHT0); + printf("\n%s", PAHO_COPYRIGHT0); +#if defined(UDP) + printf(" UDP\n"); +#elif defined(BLE) + printf(" BLE\n"); +#else + printf("\n"); +#endif printf("%s\n", PAHO_COPYRIGHT1); printf("%s\n", PAHO_COPYRIGHT2); printf(" *\n%s\n", PAHO_COPYRIGHT3); @@ -108,7 +115,7 @@ LMqttsnClient::~LMqttsnClient() } -void LMqttsnClient::initialize(LUdpConfig netconf, LMqttsnConfig mqconf) +void LMqttsnClient::initialize(SENSORNET_CONFIG_t netconf, LMqttsnConfig mqconf) { _gwProxy.initialize(netconf, mqconf); setSleepDuration(mqconf.sleepDuration); diff --git a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h index de72eb9..1da241a 100644 --- a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h +++ b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h @@ -58,7 +58,7 @@ public: void unsubscribe(const char* topicName); void unsubscribe(const uint16_t topicId); void disconnect(uint16_t sleepInSecs); - void initialize(LUdpConfig netconf, LMqttsnConfig mqconf); + void initialize(SENSORNET_CONFIG_t netconf, LMqttsnConfig mqconf); void run(void); void addTask(bool test); void setSleepDuration(uint32_t duration); diff --git a/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h b/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h index 06bd545..eb591c9 100644 --- a/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h +++ b/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h @@ -21,11 +21,12 @@ * Program mode Flag ======================================*/ //#define CLIENT_MODE - +#define UDP +//#define BLE /*====================================== * Debug Flag ======================================*/ -//#define DEBUG_NW +#define DEBUG_NW //#define DEBUG_MQTTSN /**************************************** @@ -55,7 +56,8 @@ typedef signed int int32_t; Application config structures *****************************************/ -struct LMqttsnConfig{ +struct LMqttsnConfig +{ uint16_t keepAlive; bool cleanSession; uint32_t sleepDuration; @@ -65,13 +67,21 @@ struct LMqttsnConfig{ bool willRetain; }; -struct LUdpConfig{ +struct LUdpConfig +{ const char* clientId; uint8_t ipAddress[4]; uint16_t gPortNo; uint16_t uPortNo; }; +struct LBleConfig +{ + const char* clientId; + uint8_t gwAddress[6]; + uint8_t channel; +}; + typedef enum { @@ -85,7 +95,19 @@ typedef enum MACROs for Application =======================================*/ #define MQTTSN_CONFIG MqttsnConfig theMqttsnConfig +#define MQTTSNCONF LMqttsnConfig theMqcon + +#ifdef UDP #define NETWORK_CONFIG UdpConfig theNetworkConfig +#define UDPCONF LUdpConfig theNetcon +#define BLECONF LBleConfig theConf +#define SENSORNET_CONFIG_t LUdpConfig +#else +#define NETWORK_CONFIG BleConfig theNetworkConfig +#define BLECONF LBleConfig theNetcon +#define UDPCONF LUdpConfig theConf +#define SENSORNET_CONFIG_t LBleConfig +#endif #define CONNECT(...) theClient->getGwProxy()->connect(__VA_ARGS__) #define PUBLISH(...) theClient->publish(__VA_ARGS__) @@ -104,8 +126,7 @@ typedef enum #define SUBSCRIBE_LIST OnPublishList theOnPublishList[] #define SUB(...) {__VA_ARGS__} #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(__VA_ARGS__) #define SetQoSMinus1Mode(...) theClient->getGwProxy()->setQoSMinus1Mode(__VA_ARGS__) diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkBle.cpp b/MQTTSNGateway/GatewayTester/src/LNetworkBle.cpp new file mode 100644 index 0000000..fc21cf6 --- /dev/null +++ b/MQTTSNGateway/GatewayTester/src/LNetworkBle.cpp @@ -0,0 +1,295 @@ +/************************************************************************************** + * Copyright (c) 2021, 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 "LMqttsnClientApp.h" +#ifdef BLE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "LNetworkBle.h" +#include "LTimer.h" +#include "LScreen.h" + +using namespace std; +using namespace linuxAsyncClient; + +extern uint16_t getUint16(const uint8_t* pos); +extern uint32_t getUint32(const uint8_t* pos); +extern LScreen* theScreen; +extern bool theClientMode; +extern LBleConfig theNetcon; +/*========================================= + Class LNetwork + =========================================*/ +LNetwork::LNetwork() +{ + _sleepflg = false; + _returnCode = 0; +} + +LNetwork::~LNetwork() +{ + +} + +int LNetwork::broadcast(const uint8_t* xmitData, uint16_t dataLen) +{ + return LBlePort::unicast(xmitData, dataLen); +} + +int LNetwork::unicast(const uint8_t* xmitData, uint16_t dataLen) +{ + return LBlePort::unicast(xmitData, dataLen); +} + +uint8_t* LNetwork::getMessage(int* len) +{ + *len = 0; + if (checkRecvBuf()) + { + uint16_t recvLen = LBlePort::recv(_rxDataBuf, MQTTSN_MAX_PACKET_SIZE, false); + + if (recvLen < 0) + { + *len = recvLen; + return 0; + } + else + { + if (_rxDataBuf[0] == 0x01) + { + *len = getUint16(_rxDataBuf + 1); + } + else + { + *len = _rxDataBuf[0]; + } + //if(recvLen != *len){ + // *len = 0; + // return 0; + //}else{ + return _rxDataBuf; + //} + } + } + return 0; +} + +void LNetwork::setGwAddress(void) +{ +} + +void LNetwork::setFixedGwAddress(void) +{ + _channel = LBlePort::_channel; + memcpy(_gwAddress, theNetcon.gwAddress, 6); +} + +bool LNetwork::initialize(LBleConfig config) +{ + return LBlePort::open(config); +} + +void LNetwork::setSleep() +{ + _sleepflg = true; +} + +bool LNetwork::isBroadcastable() +{ + return false; +} + +/*========================================= + Class BleStack + =========================================*/ +LBlePort::LBlePort() +{ + _disconReq = false; + _sockBle = 0; + _channel = 0; +} + +LBlePort::~LBlePort() +{ + close(); +} + +void LBlePort::close() +{ + if (_sockBle > 0) + { + ::close(_sockBle); + _sockBle = 0; + } +} + +bool LBlePort::open(LBleConfig config) +{ + const int reuse = 1; + uint8_t* gw = config.gwAddress + 5; + for (int i = 0; i < 6; i++) + { + *(_gwAddress + i) = *gw--; + } + _channel = config.channel; + + if (_channel == 0 || _gwAddress == 0 || _devAddress == 0) + { + D_NWLOG("\033[0m\033[0;31merror BLE Address in BlePort::open\033[0m\033[0;37m\n"); + DISPLAY("\033[0m\033[0;31m\nerror BLE Address in BlePort::open\033[0m\033[0;37m\n"); + return false; + } + + _sockBle = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + if (_sockBle < 0) + { + D_NWLOG("\033[0m\033[0;31merror Can't create socket in BlePort::open\033[0m\033[0;37m\n"); + DISPLAY("\033[0m\033[0;31m\nerror Can't create socket in BlePort::open\033[0m\033[0;37m\n"); + return false; + } + + setsockopt(_sockBle, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); + + struct sockaddr_rc addru = { 0 }; + addru.rc_family = AF_BLUETOOTH; + addru.rc_channel = _channel; + memcpy(&addru.rc_bdaddr, _gwAddress, 6); + + char bufgw[30]; + ba2str(&addru.rc_bdaddr, bufgw); + DISPLAY("GW MAC = %s RFCOMM CH = %d\n", bufgw, addru.rc_channel); + + // connect to server + errno = 0; + int status = connect(_sockBle, (struct sockaddr *) &addru, sizeof(addru)); + if (status < 0) + { + D_NWLOG("\033[0m\033[0;31merror = %d Can't connect to GW in BlePort::open\033[0m\033[0;37m\n", errno); + DISPLAY("\033[0m\033[0;31mCan't connect to GW Ble socket in BlePort::open\033[0m\033[0;37m\n"); + close(); + return false; + } + return true; +} + +int LBlePort::unicast(const uint8_t* buf, uint32_t length) +{ + int status = ::write(_sockBle, buf, length); + if (status < 0) + { + D_NWLOG("errno == %d in LBlePort::unicast\n", errno); + DISPLAY("errno == %d in LBlePort::unicast\n", errno); + } + else + { + D_NWLOG("sendto %-2d", _channel); + for (uint16_t i = 0; i < length; i++) + { + D_NWLOG(" %02x", *(buf + i)); + } + D_NWLOG("\n"); + + if (!theClientMode) + { + char sbuf[SCREEN_BUFF_SIZE]; + int pos = 0; + sprintf(sbuf, "\033[0;34msendto %-2dch", _channel); + pos = strlen(sbuf); + for (uint16_t i = 0; i < length; i++) + { + sprintf(sbuf + pos, " %02x", *(buf + i)); + if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20) // -20 for Escape sequence + { + break; + } + pos += 3; + } + sprintf(sbuf + strlen(sbuf), "\033[0;37m\n"); + theScreen->display(sbuf); + } + } + return status; +} + +bool LBlePort::checkRecvBuf() +{ + uint8_t buf[2]; + if (::recv(_sockBle, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0) + { + return true; + } + return false; +} + +int LBlePort::recv(uint8_t* buf, uint16_t length, bool flg) +{ + int flags = flg ? MSG_DONTWAIT : 0; + int status = ::recv(_sockBle, buf, length, flags); + + if (status < 0 && errno != EAGAIN) + { + D_NWLOG("\033[0m\033[0;31merrno == %d in BlePort::recv \033[0m\033[0;37m\n", errno); + DISPLAY("\033[0m\033[0;31merrno == %d in BlePort::recv \033[0m\033[0;37m\n", errno); + } + else if (status > 0) + { + D_NWLOG("\nrecved "); + for (uint16_t i = 0; i < status; i++) + { + D_NWLOG(" %02x", *(buf + i)); + } + D_NWLOG("\n"); + + if (!theClientMode) + { + char sbuf[SCREEN_BUFF_SIZE]; + int pos = 0; + sprintf(sbuf, "\033[0;34mrecved "); + pos = strlen(sbuf); + for (uint16_t i = 0; i < status; i++) + { + sprintf(sbuf + pos, " %02x", *(buf + i)); + if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20) + { + break; + } + pos += 3; + } + sprintf(sbuf + strlen(sbuf), "\033[0;37m\n"); + theScreen->display(sbuf); + } + return status; + } + else + { + return 0; + } + return status; +} + +#endif + diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkBle.h b/MQTTSNGateway/GatewayTester/src/LNetworkBle.h new file mode 100644 index 0000000..f2aab0c --- /dev/null +++ b/MQTTSNGateway/GatewayTester/src/LNetworkBle.h @@ -0,0 +1,106 @@ +/************************************************************************************** + * Copyright (c) 2021, 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 NETWORKBLE_H_ +#define NETWORKBLE_H_ + +#include "LMqttsnClientApp.h" +#ifdef BLE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define SOCKET_MAXHOSTNAME 200 +#define SOCKET_MAXCONNECTIONS 5 +#define SOCKET_MAXRECV 500 +#define SOCKET_MAXBUFFER_LENGTH 500 // buffer size + +#define STAT_UNICAST 1 +#define STAT_MULTICAST 2 + +using namespace std; + +namespace linuxAsyncClient +{ +/*======================================== + Class LBlePort + =======================================*/ +class LBlePort +{ + friend class LNetwork; +public: + LBlePort(); + virtual ~LBlePort(); + + bool open(LBleConfig config); + + int unicast(const uint8_t* buf, uint32_t length); + int recv(uint8_t* buf, uint16_t len, bool nonblock); + bool checkRecvBuf(); + bool isUnicast(); + +private: + void close(); + + int _sockBle; + uint8_t _devAddress[6]; + uint8_t _gwAddress[6]; + uint8_t _channel; + bool _disconReq; + +}; + +#define NO_ERROR 0 +#define PACKET_EXCEEDS_LENGTH 1 +/*=========================================== + Class Network + ============================================*/ +class LNetwork: public LBlePort +{ +public: + LNetwork(); + ~LNetwork(); + + int broadcast(const uint8_t* payload, uint16_t payloadLen); + int unicast(const uint8_t* payload, uint16_t payloadLen); + void setGwAddress(void); + void resetGwAddress(void); + void setFixedGwAddress(void); + bool initialize(LBleConfig config); + uint8_t* getMessage(int* len); + bool isBroadcastable(); + +private: + void setSleep(); + int readApiFrame(void); + + int _returnCode; + bool _sleepflg; + uint8_t _rxDataBuf[MQTTSN_MAX_PACKET_SIZE + 1]; // defined in MqttsnClientApp.h + +}; + +} /* end of namespace */ +#endif /* BLE */ +#endif /* NETWORKBLE_H_ */ diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp b/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp index 9471792..93d112f 100644 --- a/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp +++ b/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp @@ -13,6 +13,8 @@ * Contributors: * Tomoaki Yamaguchi - initial API and implementation and/or initial documentation **************************************************************************************/ +#include "LMqttsnClientApp.h" +#ifdef UDP #include #include @@ -29,7 +31,6 @@ #include "LTimer.h" #include "LScreen.h" -#include "LMqttsnClientApp.h" using namespace std; using namespace linuxAsyncClient; @@ -111,6 +112,10 @@ void LNetwork::setSleep(){ _sleepflg = true; } +bool LNetwork::isBroadcastable() +{ + return true; +} /*========================================= Class udpStack =========================================*/ @@ -385,5 +390,5 @@ int LUdpPort::recvfrom (uint8_t* buf, uint16_t length, int flags, uint32_t* ipAd return status; } - +#endif diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkUdp.h b/MQTTSNGateway/GatewayTester/src/LNetworkUdp.h index 2430d37..5189f67 100644 --- a/MQTTSNGateway/GatewayTester/src/LNetworkUdp.h +++ b/MQTTSNGateway/GatewayTester/src/LNetworkUdp.h @@ -17,6 +17,9 @@ #ifndef NETWORKUDP_H_ #define NETWORKUDP_H_ +#include "LMqttsnClientApp.h" +#ifdef UDP + #include #include #include @@ -27,7 +30,6 @@ #include #include -#include "LMqttsnClientApp.h" #define SOCKET_MAXHOSTNAME 200 #define SOCKET_MAXCONNECTIONS 5 @@ -89,6 +91,7 @@ public: void setFixedGwAddress(void); bool initialize(LUdpConfig config); uint8_t* getMessage(int* len); + bool isBroadcastable(); private: void setSleep(); int readApiFrame(void); @@ -103,6 +106,6 @@ private: }; - } /* end of namespace */ +#endif /* UDP */ #endif /* NETWORKUDP_H_ */ diff --git a/MQTTSNGateway/README.md b/MQTTSNGateway/README.md index 16839a1..7af1f07 100644 --- a/MQTTSNGateway/README.md +++ b/MQTTSNGateway/README.md @@ -7,7 +7,7 @@ This Gateway can run as a transparent or aggregating Gateway by specifying the g ```` $ git clone -b develop https://github.com/eclipse/paho.mqtt-sn.embedded-c $ cd paho.mqtt-sn.embedded-c/MQTTSNGateway -$ ./build.sh {udp|udp6|xbee|loralink} +$ ./build.sh [udp|udp6|xbee|loralink | ble] ```` In order to build a gateway, an argument is required. @@ -50,6 +50,7 @@ ClientAuthentication=NO AggregatingGateway=NO QoS-1=NO Forwarder=NO +MaxNumberOfClients=30; #ClientsList=/path/to/your_clients.conf @@ -91,6 +92,9 @@ BaudrateLoRaLink=115200 DeviceRxLoRaLink=/dev/ttyLoRaLinkRx DeviceTxLoRaLink=/dev/ttyLoRaLinkTx +# BLE RFCOMM +BleAddress=60:57:18:06:8B:72.* + # LOG ShearedMemory=NO; @@ -106,6 +110,7 @@ Format of the file is ClientId and SensorNetwork Address. e.g. IP address and Po 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. +**MaxNumberOfClients** Maximum number of clients allocated. ### ** How to monitor the gateway from remote. ** Change gateway.conf as follows: diff --git a/MQTTSNGateway/gateway.conf b/MQTTSNGateway/gateway.conf index 0d52f06..3321576 100644 --- a/MQTTSNGateway/gateway.conf +++ b/MQTTSNGateway/gateway.conf @@ -27,6 +27,7 @@ ClientAuthentication=NO AggregatingGateway=NO QoS-1=NO Forwarder=NO +MaxNumberOfClients=30; #ClientsList=/path/to/your_clients.conf @@ -68,6 +69,9 @@ BaudrateLoRaLink=115200 DeviceRxLoRaLink=/dev/loralinkRx DeviceTxLoRaLink=/dev/loralinkTx +# BLE RFCOMM +BleAddress=60:57:18:06:8B:72.* + # LOG ShearedMemory=NO; diff --git a/MQTTSNGateway/src/CMakeLists.txt b/MQTTSNGateway/src/CMakeLists.txt index 1a1f4ac..a1606a6 100644 --- a/MQTTSNGateway/src/CMakeLists.txt +++ b/MQTTSNGateway/src/CMakeLists.txt @@ -87,12 +87,27 @@ TARGET_INCLUDE_DIRECTORIES(mqtt-sngateway_common /usr/local/opt/openssl/include ) +IF(SENSORNET MATCHES "ble") + TARGET_LINK_LIBRARIES(mqtt-sngateway_common PRIVATE MQTTSNPacket pthread ssl - crypto) + crypto + bluetooth + ) +ELSE() + +TARGET_LINK_LIBRARIES(mqtt-sngateway_common + PRIVATE + MQTTSNPacket + pthread + ssl + crypto + ) + +ENDIF() ADD_EXECUTABLE(MQTT-SNGateway mainGateway.cpp diff --git a/MQTTSNGateway/src/MQTTGWConnectionHandler.cpp b/MQTTSNGateway/src/MQTTGWConnectionHandler.cpp index f3bb526..621b950 100644 --- a/MQTTSNGateway/src/MQTTGWConnectionHandler.cpp +++ b/MQTTSNGateway/src/MQTTGWConnectionHandler.cpp @@ -30,8 +30,7 @@ MQTTGWConnectionHandler::~MQTTGWConnectionHandler() } -void MQTTGWConnectionHandler::handleConnack(Client* client, - MQTTGWPacket* packet) +void MQTTGWConnectionHandler::handleConnack(Client* client, MQTTGWPacket* packet) { uint8_t rc = MQTT_SERVER_UNAVAILABLE; Connack resp; @@ -45,35 +44,28 @@ void MQTTGWConnectionHandler::handleConnack(Client* client, else if (resp.rc == MQTT_UNACCEPTABLE_PROTOCOL_VERSION) { rc = MQTTSN_RC_NOT_SUPPORTED; - WRITELOG( - " ClientID : %s Requested Protocol version is not supported.\n", - client->getClientId()); + WRITELOG(" ClientID : %s Requested Protocol version is not supported.\n", client->getClientId()); } else if (resp.rc == MQTT_IDENTIFIER_REJECTED) { rc = MQTTSN_RC_NOT_SUPPORTED; - WRITELOG( - " ClientID : %s ClientID is collect UTF-8 but not allowed by the Server.\n", - client->getClientId()); + WRITELOG(" ClientID : %s ClientID is collect UTF-8 but not allowed by the Server.\n", client->getClientId()); } else if (resp.rc == MQTT_SERVER_UNAVAILABLE) { rc = MQTTSN_RC_REJECTED_CONGESTED; - WRITELOG( - " ClientID : %s The Network Connection has been made but the MQTT service is unavailable.\n", + WRITELOG(" ClientID : %s The Network Connection has been made but the MQTT service is unavailable.\n", client->getClientId()); } else if (resp.rc == MQTT_BAD_USERNAME_OR_PASSWORD) { rc = MQTTSN_RC_NOT_SUPPORTED; - WRITELOG( - " Gateway Configuration Error: The data in the user name or password is malformed.\n"); + WRITELOG(" Gateway Configuration Error: The data in the user name or password is malformed.\n"); } else if (resp.rc == MQTT_NOT_AUTHORIZED) { rc = MQTTSN_RC_NOT_SUPPORTED; - WRITELOG( - " Gateway Configuration Error: The Client is not authorized to connect.\n"); + WRITELOG(" Gateway Configuration Error: The Client is not authorized to connect.\n"); } MQTTSNPacket* snPacket = new MQTTSNPacket(); @@ -85,8 +77,7 @@ void MQTTGWConnectionHandler::handleConnack(Client* client, _gateway->getClientSendQue()->post(ev1); } -void MQTTGWConnectionHandler::handlePingresp(Client* client, - MQTTGWPacket* packet) +void MQTTGWConnectionHandler::handlePingresp(Client* client, MQTTGWPacket* packet) { MQTTSNPacket* snPacket = new MQTTSNPacket(); snPacket->setPINGRESP(); @@ -96,8 +87,7 @@ void MQTTGWConnectionHandler::handlePingresp(Client* client, _gateway->getClientSendQue()->post(ev1); } -void MQTTGWConnectionHandler::handleDisconnect(Client* client, - MQTTGWPacket* packet) +void MQTTGWConnectionHandler::handleDisconnect(Client* client, MQTTGWPacket* packet) { MQTTSNPacket* snPacket = new MQTTSNPacket(); snPacket->setDISCONNECT(0); diff --git a/MQTTSNGateway/src/MQTTGWPacket.cpp b/MQTTSNGateway/src/MQTTGWPacket.cpp index e3277db..921bcee 100644 --- a/MQTTSNGateway/src/MQTTGWPacket.cpp +++ b/MQTTSNGateway/src/MQTTGWPacket.cpp @@ -28,10 +28,8 @@ void writeInt(unsigned char** pptr, int msgId); /** * List of the predefined MQTT v3 packet names. */ -static const char* mqtt_packet_names[] = -{ "RESERVED", "CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL", - "PUBCOMP", "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK", "PINGREQ", - "PINGRESP", "DISCONNECT" }; +static const char* mqtt_packet_names[] = { "RESERVED", "CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL", "PUBCOMP", + "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK", "PINGREQ", "PINGRESP", "DISCONNECT" }; /** * Encodes the message length according to the MQTT algorithm @@ -50,7 +48,8 @@ int MQTTPacket_encode(char* buf, int length) if (length > 0) d |= 0x80; buf[rc++] = d; - } while (length > 0); + } + while (length > 0); return rc; } @@ -206,7 +205,8 @@ int MQTTGWPacket::recv(Network* network) } _remainingLength += (c & 127) * multiplier; multiplier *= 128; - } while ((c & 128) != 0); + } + while ((c & 128) != 0); if (_remainingLength > 0) { @@ -243,9 +243,8 @@ int MQTTGWPacket::send(Network* network) int MQTTGWPacket::getAck(Ack* ack) { - if (PUBACK != _header.bits.type && PUBREC != _header.bits.type - && PUBREL != _header.bits.type && PUBCOMP != _header.bits.type - && UNSUBACK != _header.bits.type) + if (PUBACK != _header.bits.type && PUBREC != _header.bits.type && PUBREL != _header.bits.type + && PUBCOMP != _header.bits.type && UNSUBACK != _header.bits.type) { return 0; } @@ -305,18 +304,15 @@ int MQTTGWPacket::getPUBLISH(Publish* pub) return 1; } -int MQTTGWPacket::setCONNECT(Connect* connect, unsigned char* username, - unsigned char* password) +int MQTTGWPacket::setCONNECT(Connect* connect, unsigned char* username, unsigned char* password) { clearData(); _header = connect->header; - _remainingLength = ((connect->version == 3) ? 12 : 10) - + (int) strlen(connect->clientID) + 2; + _remainingLength = ((connect->version == 3) ? 12 : 10) + (int) strlen(connect->clientID) + 2; if (connect->flags.bits.will) { - _remainingLength += (int) strlen(connect->willTopic) + 2 - + (int) strlen(connect->willMsg) + 2; + _remainingLength += (int) strlen(connect->willTopic) + 2 + (int) strlen(connect->willMsg) + 2; } if (connect->flags.bits.username) { @@ -365,8 +361,7 @@ int MQTTGWPacket::setCONNECT(Connect* connect, unsigned char* username, return 1; } -int MQTTGWPacket::setSUBSCRIBE(const char* topic, unsigned char qos, - unsigned short msgId) +int MQTTGWPacket::setSUBSCRIBE(const char* topic, unsigned char qos, unsigned short msgId) { clearData(); _header.byte = 0; @@ -640,8 +635,7 @@ MQTTGWPacket& MQTTGWPacket::operator =(MQTTGWPacket& packet) UTF8String MQTTGWPacket::getTopic(void) { - UTF8String str = - { 0, nullptr }; + UTF8String str = { 0, nullptr }; if (_header.bits.type == SUBSCRIBE || _header.bits.type == UNSUBSCRIBE) { char* ptr = (char*) (_data + 2); diff --git a/MQTTSNGateway/src/MQTTGWPublishHandler.cpp b/MQTTSNGateway/src/MQTTGWPublishHandler.cpp index 2bdc98d..6185b92 100644 --- a/MQTTSNGateway/src/MQTTGWPublishHandler.cpp +++ b/MQTTSNGateway/src/MQTTGWPublishHandler.cpp @@ -40,7 +40,7 @@ void MQTTGWPublishHandler::handlePublish(Client* client, MQTTGWPacket* packet) if (!client->isActive() && !client->isSleep() && !client->isAwake()) { WRITELOG("%s The client is neither active nor sleep %s%s\n", - ERRMSG_HEADER, client->getStatus(), ERRMSG_FOOTER); + ERRMSG_HEADER, client->getStatus(), ERRMSG_FOOTER); return; } @@ -66,9 +66,8 @@ void MQTTGWPublishHandler::handlePublish(Client* client, MQTTGWPacket* packet) *msg = *packet; if (msg->getType() == 0) { - WRITELOG( - "%s MQTTGWPublishHandler::handlePublish can't allocate memories for Packet.%s\n", - ERRMSG_HEADER, ERRMSG_FOOTER); + WRITELOG("%s MQTTGWPublishHandler::handlePublish can't allocate memories for Packet.%s\n", + ERRMSG_HEADER, ERRMSG_FOOTER); delete msg; return; } @@ -105,15 +104,14 @@ void MQTTGWPublishHandler::handlePublish(Client* client, MQTTGWPacket* packet) } else { - /* This message might be subscribed with wild card or not cleanSession*/ + /* This message might be subscribed with wild card or not cleanSession*/ topicId.type = MQTTSN_TOPIC_TYPE_NORMAL; Topic* topic = client->getTopics()->match(&topicId); - if (topic == nullptr && client->isCleanSession()) + if (topic == nullptr && client->isCleanSession()) { - WRITELOG( - "%sMQTTGWPublishHandler Invalid Topic. PUBLISH message is discarded.%s\n", - ERRMSG_HEADER, ERRMSG_FOOTER); + WRITELOG("%sMQTTGWPublishHandler Invalid Topic. PUBLISH message is discarded.%s\n", + ERRMSG_HEADER, ERRMSG_FOOTER); if (pub.header.bits.qos == 1) { replyACK(client, &pub, PUBACK); @@ -127,20 +125,20 @@ void MQTTGWPublishHandler::handlePublish(Client* client, MQTTGWPacket* packet) return; } - if (topic == nullptr) - { - topicId.type = MQTTSN_TOPIC_TYPE_NORMAL; - topicId.data.long_.len = pub.topiclen; - topicId.data.long_.name = pub.topic; - topicId.data.id = 0; - } + if (topic == nullptr) + { + topicId.type = MQTTSN_TOPIC_TYPE_NORMAL; + topicId.data.long_.len = pub.topiclen; + topicId.data.long_.name = pub.topic; + topicId.data.id = 0; + } /* add the Topic and get a TopicId */ topic = client->getTopics()->add(&topicId); if (topic == nullptr) { - WRITELOG( - "%sMQTTGWPublishHandler Can't Add a Topic. MAX_TOPIC_PAR_CLIENT is exceeded. PUBLISH message is discarded.%s\n", + WRITELOG( + "%sMQTTGWPublishHandler Can't Add a Topic. MAX_TOPIC_PAR_CLIENT is exceeded. PUBLISH message is discarded.%s\n", ERRMSG_HEADER, ERRMSG_FOOTER); delete snPacket; return; @@ -165,29 +163,23 @@ void MQTTGWPublishHandler::handlePublish(Client* client, MQTTGWPacket* packet) /* send PUBLISH */ topicId.data.id = id; - snPacket->setPUBLISH((uint8_t) pub.header.bits.dup, - (int) pub.header.bits.qos, - (uint8_t) pub.header.bits.retain, (uint16_t) pub.msgId, - topicId, (uint8_t*) pub.payload, pub.payloadlen); - client->getWaitREGACKPacketList()->setPacket(snPacket, - regackMsgId); + snPacket->setPUBLISH((uint8_t) pub.header.bits.dup, (int) pub.header.bits.qos, (uint8_t) pub.header.bits.retain, + (uint16_t) pub.msgId, topicId, (uint8_t*) pub.payload, pub.payloadlen); + client->getWaitREGACKPacketList()->setPacket(snPacket, regackMsgId); return; } else { - WRITELOG( - "%sMQTTGWPublishHandler Can't create a Topic. PUBLISH message is discarded.%s\n", - ERRMSG_HEADER, ERRMSG_FOOTER); + WRITELOG("%sMQTTGWPublishHandler Can't create a Topic. PUBLISH message is discarded.%s\n", + ERRMSG_HEADER, ERRMSG_FOOTER); delete snPacket; return; } } } - snPacket->setPUBLISH((uint8_t) pub.header.bits.dup, - (int) pub.header.bits.qos, (uint8_t) pub.header.bits.retain, - (uint16_t) pub.msgId, topicId, (uint8_t*) pub.payload, - pub.payloadlen); + snPacket->setPUBLISH((uint8_t) pub.header.bits.dup, (int) pub.header.bits.qos, (uint8_t) pub.header.bits.retain, + (uint16_t) pub.msgId, topicId, (uint8_t*) pub.payload, pub.payloadlen); Event* ev1 = new Event(); ev1->setClientSendEvent(client, snPacket); _gateway->getClientSendQue()->post(ev1); @@ -207,8 +199,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(); @@ -220,13 +211,11 @@ void MQTTGWPublishHandler::handlePuback(Client* client, MQTTGWPacket* packet) _gateway->getClientSendQue()->post(ev1); return; } - WRITELOG( - " PUBACK from the Broker is invalid. PacketID : %04X ClientID : %s \n", - (uint16_t) ack.msgId, client->getClientId()); + WRITELOG(" PUBACK from the Broker is invalid. PacketID : %04X ClientID : %s \n", (uint16_t) ack.msgId, + client->getClientId()); } -void MQTTGWPublishHandler::handleAck(Client* client, MQTTGWPacket* packet, - int type) +void MQTTGWPublishHandler::handleAck(Client* client, MQTTGWPacket* packet, int type) { Ack ack; packet->getAck(&ack); @@ -264,13 +253,11 @@ void MQTTGWPublishHandler::handleAck(Client* client, MQTTGWPacket* packet, } } -void MQTTGWPublishHandler::handleAggregatePuback(Client* client, - MQTTGWPacket* packet) +void MQTTGWPublishHandler::handleAggregatePuback(Client* client, MQTTGWPacket* packet) { uint16_t msgId = packet->getMsgId(); uint16_t clientMsgId = 0; - Client* newClient = _gateway->getAdapterManager()->convertClient(msgId, - &clientMsgId); + Client* newClient = _gateway->getAdapterManager()->convertClient(msgId, &clientMsgId); if (newClient != nullptr) { packet->setMsgId((int) clientMsgId); @@ -278,13 +265,11 @@ void MQTTGWPublishHandler::handleAggregatePuback(Client* client, } } -void MQTTGWPublishHandler::handleAggregateAck(Client* client, - MQTTGWPacket* packet, int type) +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); + Client* newClient = _gateway->getAdapterManager()->convertClient(msgId, &clientMsgId); if (newClient != nullptr) { packet->setMsgId((int) clientMsgId); @@ -292,16 +277,14 @@ void MQTTGWPublishHandler::handleAggregateAck(Client* client, } } -void MQTTGWPublishHandler::handleAggregatePubrel(Client* client, - MQTTGWPacket* packet) +void MQTTGWPublishHandler::handleAggregatePubrel(Client* client, MQTTGWPacket* packet) { Publish pub; packet->getPUBLISH(&pub); replyACK(client, &pub, PUBCOMP); } -void MQTTGWPublishHandler::handleAggregatePublish(Client* client, - MQTTGWPacket* packet) +void MQTTGWPublishHandler::handleAggregatePublish(Client* client, MQTTGWPacket* packet) { Publish pub; packet->getPUBLISH(&pub); @@ -310,9 +293,7 @@ void MQTTGWPublishHandler::handleAggregatePublish(Client* client, Topic topic = Topic(topicName, MQTTSN_TOPIC_TYPE_NORMAL); // ToDo: need to refactor - ClientTopicElement* elm = - _gateway->getAdapterManager()->getAggregater()->getClientElement( - &topic); + ClientTopicElement* elm = _gateway->getAdapterManager()->getAggregater()->getClientElement(&topic); while (elm != nullptr) { @@ -322,9 +303,8 @@ void MQTTGWPublishHandler::handleAggregatePublish(Client* client, if (msg->getType() == 0) { - WRITELOG( - "%s MQTTGWPublishHandler::handleAggregatePublish can't allocate memories for Packet.%s\n", - ERRMSG_HEADER, ERRMSG_FOOTER); + WRITELOG("%s MQTTGWPublishHandler::handleAggregatePublish can't allocate memories for Packet.%s\n", + ERRMSG_HEADER, ERRMSG_FOOTER); delete msg; break; } diff --git a/MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp b/MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp index dd7425b..9569442 100644 --- a/MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp +++ b/MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp @@ -61,8 +61,7 @@ void MQTTGWSubscribeHandler::handleSuback(Client* client, MQTTGWPacket* packet) } } -void MQTTGWSubscribeHandler::handleUnsuback(Client* client, - MQTTGWPacket* packet) +void MQTTGWSubscribeHandler::handleUnsuback(Client* client, MQTTGWPacket* packet) { Ack ack; packet->getAck(&ack); @@ -73,14 +72,11 @@ void MQTTGWSubscribeHandler::handleUnsuback(Client* client, _gateway->getClientSendQue()->post(evt); } -void MQTTGWSubscribeHandler::handleAggregateSuback(Client* client, - MQTTGWPacket* packet) +void MQTTGWSubscribeHandler::handleAggregateSuback(Client* client, MQTTGWPacket* packet) { uint16_t msgId = packet->getMsgId(); uint16_t clientMsgId = 0; - Client* newClient = - _gateway->getAdapterManager()->getAggregater()->convertClient(msgId, - &clientMsgId); + Client* newClient = _gateway->getAdapterManager()->getAggregater()->convertClient(msgId, &clientMsgId); if (newClient != nullptr) { packet->setMsgId((int) clientMsgId); @@ -88,14 +84,11 @@ void MQTTGWSubscribeHandler::handleAggregateSuback(Client* client, } } -void MQTTGWSubscribeHandler::handleAggregateUnsuback(Client* client, - MQTTGWPacket* 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); + Client* newClient = _gateway->getAdapterManager()->getAggregater()->convertClient(msgId, &clientMsgId); if (newClient != nullptr) { packet->setMsgId((int) clientMsgId); diff --git a/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.cpp b/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.cpp index b7a3a71..8e81351 100644 --- a/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.cpp @@ -26,8 +26,7 @@ using namespace MQTTSNGW; /*===================================== Class MQTTSNAggregateConnectionHandler =====================================*/ -MQTTSNAggregateConnectionHandler::MQTTSNAggregateConnectionHandler( - Gateway* gateway) +MQTTSNAggregateConnectionHandler::MQTTSNAggregateConnectionHandler(Gateway* gateway) { _gateway = gateway; } @@ -40,8 +39,7 @@ MQTTSNAggregateConnectionHandler::~MQTTSNAggregateConnectionHandler() /* * CONNECT */ -void MQTTSNAggregateConnectionHandler::handleConnect(Client* client, - MQTTSNPacket* packet) +void MQTTSNAggregateConnectionHandler::handleConnect(Client* client, MQTTSNPacket* packet) { MQTTSNPacket_connectData data; if (packet->getCONNECT(&data) == 0) @@ -86,8 +84,7 @@ void MQTTSNAggregateConnectionHandler::handleConnect(Client* client, { if (tp->getType() == MQTTSN_TOPIC_TYPE_NORMAL) { - _gateway->getAdapterManager()->getAggregater()->removeAggregateTopic( - tp, client); + _gateway->getAdapterManager()->getAggregater()->removeAggregateTopic(tp, client); } tp = topics->getNextTopic(tp); } @@ -124,8 +121,7 @@ void MQTTSNAggregateConnectionHandler::handleConnect(Client* client, /* * WILLMSG */ -void MQTTSNAggregateConnectionHandler::handleWillmsg(Client* client, - MQTTSNPacket* packet) +void MQTTSNAggregateConnectionHandler::handleWillmsg(Client* client, MQTTSNPacket* packet) { if (!client->isWaitWillMsg()) { @@ -160,8 +156,7 @@ void MQTTSNAggregateConnectionHandler::handleWillmsg(Client* client, /* * DISCONNECT */ -void MQTTSNAggregateConnectionHandler::handleDisconnect(Client* client, - MQTTSNPacket* packet) +void MQTTSNAggregateConnectionHandler::handleDisconnect(Client* client, MQTTSNPacket* packet) { MQTTSNPacket* snMsg = new MQTTSNPacket(); snMsg->setDISCONNECT(0); @@ -173,11 +168,9 @@ void MQTTSNAggregateConnectionHandler::handleDisconnect(Client* client, /* * PINGREQ */ -void MQTTSNAggregateConnectionHandler::handlePingreq(Client* client, - MQTTSNPacket* packet) +void MQTTSNAggregateConnectionHandler::handlePingreq(Client* client, MQTTSNPacket* packet) { - if ((client->isSleep() || client->isAwake()) - && client->getClientSleepPacket()) + if ((client->isSleep() || client->isAwake()) && client->getClientSleepPacket()) { sendStoredPublish(client); client->holdPingRequest(); diff --git a/MQTTSNGateway/src/MQTTSNGWAdapter.cpp b/MQTTSNGateway/src/MQTTSNGWAdapter.cpp index 78994bf..8e0e347 100644 --- a/MQTTSNGateway/src/MQTTSNGWAdapter.cpp +++ b/MQTTSNGateway/src/MQTTSNGWAdapter.cpp @@ -63,13 +63,12 @@ void Adapter::setup(const char* adpterName, AdapterType adapterType) string nameSecure = string(adpterName) + "-S"; idSecure.cstring = const_cast(nameSecure.c_str()); - Client* client = _gateway->getClientList()->createClient(0, &id, true, - false, TRANSPEARENT_TYPE); + 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); + TRANSPEARENT_TYPE); setClient(client, true); client->setAdapterType(adapterType); } @@ -173,9 +172,8 @@ void Adapter::send(MQTTSNPacket* packet, Client* client) } else { - WRITELOG( - "%s %s No Secure connections %s 's packet is discarded.%s\n", - ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); + WRITELOG("%s %s No Secure connections %s 's packet is discarded.%s\n", + ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); return; } } @@ -243,8 +241,7 @@ Proxy::~Proxy(void) void Proxy::checkConnection(Client* client) { - if (client->isDisconnect() - || (client->isConnecting() && _responseTimer.isTimeup())) + if (client->isDisconnect() || (client->isConnecting() && _responseTimer.isTimeup())) { client->connectSended(); _responseTimer.start(PROXY_RESPONSE_DURATION * 1000UL); @@ -258,8 +255,7 @@ void Proxy::checkConnection(Client* client) ev->setClientRecvEvent(client, packet); _gateway->getPacketEventQue()->post(ev); } - else if ((client->isActive() && _keepAliveTimer.isTimeup()) - || (_isWaitingResp && _responseTimer.isTimeup())) + else if ((client->isActive() && _keepAliveTimer.isTimeup()) || (_isWaitingResp && _responseTimer.isTimeup())) { MQTTSNPacket* packet = new MQTTSNPacket(); MQTTSNString clientId = MQTTSNString_initializer; diff --git a/MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp b/MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp index 5061ed7..4fb4282 100644 --- a/MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp +++ b/MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp @@ -39,8 +39,7 @@ AdapterManager::AdapterManager(Gateway* gw) _aggregater = new Aggregater(gw); } -void AdapterManager::initialize(char* gwName, bool aggregate, bool forwarder, - bool qosM1) +void AdapterManager::initialize(char* gwName, bool aggregate, bool forwarder, bool qosM1) { if (aggregate) { @@ -91,8 +90,7 @@ Aggregater* AdapterManager::getAggregater(void) bool AdapterManager::isAggregatedClient(Client* client) { - if (!_aggregater->isActive() || client->isQoSm1() || client->isAggregater() - || client->isQoSm1Proxy()) + if (!_aggregater->isActive() || client->isQoSm1() || client->isAggregater() || client->isQoSm1Proxy()) { return false; } @@ -128,8 +126,7 @@ Client* AdapterManager::getClient(Client* client) return newClient; } -int AdapterManager::unicastToClient(Client* client, MQTTSNPacket* packet, - ClientSendTask* task) +int AdapterManager::unicastToClient(Client* client, MQTTSNPacket* packet, ClientSendTask* task) { char pbuf[SIZE_OF_LOG_PACKET * 3]; Forwarder* fwd = client->getForwarder(); @@ -141,10 +138,8 @@ int AdapterManager::unicastToClient(Client* client, MQTTSNPacket* packet, WirelessNodeId* wnId = fwd->getWirelessNodeId(client); encap.setWirelessNodeId(wnId); task->log(client, packet); - WRITELOG(FORMAT_Y_W_G, currentDateTime(), encap.getName(), RIGHTARROW, - fwd->getId(), encap.print(pbuf)); - rc = encap.unicast(_gateway->getSensorNetwork(), - fwd->getSensorNetAddr()); + WRITELOG(FORMAT_Y_W_G, currentDateTime(), encap.getName(), RIGHTARROW, fwd->getId(), encap.print(pbuf)); + rc = encap.unicast(_gateway->getSensorNetwork(), fwd->getSensorNetAddr()); } else { @@ -159,8 +154,7 @@ int AdapterManager::unicastToClient(Client* client, MQTTSNPacket* packet, } else { - rc = packet->unicast(_gateway->getSensorNetwork(), - client->getSensorNetAddress()); + rc = packet->unicast(_gateway->getSensorNetwork(), client->getSensorNetAddress()); } } return rc; diff --git a/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.cpp b/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.cpp index ed912eb..e5703d6 100644 --- a/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.cpp +++ b/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.cpp @@ -129,8 +129,7 @@ ClientTopicElement* AggregateTopicElement::getFirstClientTopicElement(void) return _head; } -ClientTopicElement* AggregateTopicElement::getNextClientTopicElement( - ClientTopicElement* elmClient) +ClientTopicElement* AggregateTopicElement::getNextClientTopicElement(ClientTopicElement* elmClient) { return elmClient->_next; } @@ -262,8 +261,7 @@ void AggregateTopicTable::erase(AggregateTopicElement* elmTopic) } } -AggregateTopicElement* AggregateTopicTable::getAggregateTopicElement( - Topic* topic) +AggregateTopicElement* AggregateTopicTable::getAggregateTopicElement(Topic* topic) { AggregateTopicElement* elm = _head; diff --git a/MQTTSNGateway/src/MQTTSNGWAggregater.cpp b/MQTTSNGateway/src/MQTTSNGWAggregater.cpp index 79bdc61..17da79f 100644 --- a/MQTTSNGateway/src/MQTTSNGWAggregater.cpp +++ b/MQTTSNGateway/src/MQTTSNGWAggregater.cpp @@ -84,8 +84,7 @@ uint16_t Aggregater::getMsgId(Client* client, uint16_t clientMsgId) return _msgIdTable.getMsgId(client, clientMsgId); } -AggregateTopicElement* Aggregater::addAggregateTopic(Topic* topic, - Client* client) +AggregateTopicElement* Aggregater::addAggregateTopic(Topic* topic, Client* client) { return _topicTable.add(topic, client); } diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp index c74d0d3..98f0eb6 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp @@ -54,7 +54,7 @@ void BrokerRecvTask::run(void) { struct timeval timeout; MQTTGWPacket* packet = nullptr; - int rc; + int rc; Event* ev = nullptr; fd_set rset; fd_set wset; @@ -135,53 +135,43 @@ void BrokerRecvTask::run(void) { if (rc == 0) // Disconnected { - WRITELOG( - "%s BrokerRecvTask %s is disconnected by the broker.%s\n", - ERRMSG_HEADER, - client->getClientId(), - ERRMSG_FOOTER); - client->getNetwork()->close(); - client->disconnected(); + WRITELOG("%s BrokerRecvTask %s is disconnected by the broker.%s\n", + ERRMSG_HEADER, client->getClientId(), + ERRMSG_FOOTER); + client->getNetwork()->close(); + client->disconnected(); } else if (rc == -1) { - WRITELOG( - "%s BrokerRecvTask can't receive a packet from the broker errno=%d %s%s\n", - ERRMSG_HEADER, errno, - client->getClientId(), - ERRMSG_FOOTER); + WRITELOG("%s BrokerRecvTask can't receive a packet from the broker errno=%d %s%s\n", + ERRMSG_HEADER, errno, client->getClientId(), + ERRMSG_FOOTER); } else if (rc == -2) { WRITELOG( "%s BrokerRecvTask receive invalid length of packet from the broker. DISCONNECT %s %s\n", - ERRMSG_HEADER, - client->getClientId(), + ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); } else if (rc == -3) { - WRITELOG( - "%s BrokerRecvTask can't allocate memories for the packet %s%s\n", - ERRMSG_HEADER, - client->getClientId(), - ERRMSG_FOOTER); + WRITELOG("%s BrokerRecvTask can't allocate memories for the packet %s%s\n", + ERRMSG_HEADER, client->getClientId(), + ERRMSG_FOOTER); } delete packet; - if ((rc == -1 || rc == -2) - && (client->isActive() - || client->isSleep() - || client->isAwake())) + if ((rc == -1 || rc == -2) && (client->isActive() || client->isSleep() || client->isAwake())) { - client->getNetwork()->close(); - client->disconnected(); + client->getNetwork()->close(); + client->disconnected(); } } } - } - nextClient: client = client->getNextClient(); + } + nextClient: client = client->getNextClient(); } } } @@ -200,31 +190,26 @@ int BrokerRecvTask::log(Client* client, MQTTGWPacket* packet) switch (packet->getType()) { case CONNACK: - WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), LEFTARROWB, - client->getClientId(), packet->print(pbuf)); + WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), LEFTARROWB, client->getClientId(), packet->print(pbuf)); break; case PUBLISH: - WRITELOG(FORMAT_W_MSGID_Y_W_NL, currentDateTime(), packet->getName(), - packet->getMsgId(msgId), LEFTARROWB, client->getClientId(), - packet->print(pbuf)); + WRITELOG(FORMAT_W_MSGID_Y_W_NL, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROWB, + client->getClientId(), packet->print(pbuf)); break; case PUBACK: case PUBREC: case PUBREL: case PUBCOMP: - WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), - packet->getMsgId(msgId), LEFTARROWB, client->getClientId(), - packet->print(pbuf)); + WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROWB, + client->getClientId(), packet->print(pbuf)); break; case SUBACK: case UNSUBACK: - WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), - packet->getMsgId(msgId), LEFTARROWB, client->getClientId(), - packet->print(pbuf)); + WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROWB, + client->getClientId(), packet->print(pbuf)); break; case PINGRESP: - WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), LEFTARROWB, - client->getClientId(), packet->print(pbuf)); + WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), LEFTARROWB, client->getClientId(), packet->print(pbuf)); break; default: WRITELOG("Type=%x\n", packet->getType()); diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp index 42d5fd0..e061d0c 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp @@ -94,28 +94,20 @@ void BrokerSendTask::run() if (client->isSecureNetwork()) { - 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); + 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( - (const char*) _gwparams->brokerName, - (const char*) _gwparams->port); + rc = client->getNetwork()->connect((const char*) _gwparams->brokerName, (const char*) _gwparams->port); } if (!rc) { /* disconnect the broker and the client */ - WRITELOG( - "%s BrokerSendTask: %s can't connect to the broker. errno=%d %s %s\n", - ERRMSG_HEADER, client->getClientId(), errno, - strerror(errno), ERRMSG_FOOTER); + WRITELOG("%s BrokerSendTask: %s can't connect to the broker. errno=%d %s %s\n", + ERRMSG_HEADER, client->getClientId(), errno, strerror(errno), ERRMSG_FOOTER); delete ev; client->getNetwork()->close(); continue; @@ -139,10 +131,8 @@ void BrokerSendTask::run() } else { - WRITELOG( - "%s BrokerSendTask: %s can't send a packet to the broker. errno=%d %s %s\n", - ERRMSG_HEADER, client->getClientId(), - rc == -1 ? errno : 0, strerror(errno), ERRMSG_FOOTER); + WRITELOG("%s BrokerSendTask: %s can't send a packet to the broker. errno=%d %s %s\n", + ERRMSG_HEADER, client->getClientId(), rc == -1 ? errno : 0, strerror(errno), ERRMSG_FOOTER); if ( errno != EBADF) { client->getNetwork()->close(); @@ -174,12 +164,11 @@ void BrokerSendTask::log(Client* client, MQTTGWPacket* packet) { case CONNECT: WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), - RIGHTARROWB, client->getClientId(), packet->print(pbuf)); + RIGHTARROWB, client->getClientId(), packet->print(pbuf)); break; case PUBLISH: - WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), - packet->getMsgId(msgId), RIGHTARROWB, client->getClientId(), - packet->print(pbuf)); + WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), packet->getMsgId(msgId), RIGHTARROWB, + client->getClientId(), packet->print(pbuf)); break; case SUBSCRIBE: case UNSUBSCRIBE: @@ -187,17 +176,16 @@ void BrokerSendTask::log(Client* client, MQTTGWPacket* packet) case PUBREC: case PUBREL: case PUBCOMP: - WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), - packet->getMsgId(msgId), RIGHTARROWB, client->getClientId(), - packet->print(pbuf)); + WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), packet->getMsgId(msgId), RIGHTARROWB, + client->getClientId(), packet->print(pbuf)); break; case PINGREQ: WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), - RIGHTARROWB, client->getClientId(), packet->print(pbuf)); + RIGHTARROWB, client->getClientId(), packet->print(pbuf)); break; case DISCONNECT: WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), - RIGHTARROWB, client->getClientId(), packet->print(pbuf)); + RIGHTARROWB, client->getClientId(), packet->print(pbuf)); break; default: break; diff --git a/MQTTSNGateway/src/MQTTSNGWClient.cpp b/MQTTSNGateway/src/MQTTSNGWClient.cpp index ddd4adc..594ac1e 100644 --- a/MQTTSNGateway/src/MQTTSNGWClient.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClient.cpp @@ -31,16 +31,14 @@ char* currentDateTime(void); /*===================================== Class Client =====================================*/ -static const char* theClientStatus[] = -{ "InPool", "Disconnected", "TryConnecting", "Connecting", "Active", "Asleep", - "Awake", +static const char* theClientStatus[] = { "InPool", "Disconnected", "TryConnecting", "Connecting", "Active", "Asleep", "Awake", "Lost" }; Client::Client(bool secure) { _packetId = 0; _snMsgId = 0; - _status = Cstat_Free; + _status = Cstat_Free; _keepAliveMsec = 0; _topics = new Topics(); _clientId = nullptr; @@ -121,13 +119,11 @@ int Client::setClientSleepPacket(MQTTGWPacket* packet) int rc = _clientSleepPacketQue.post(packet); if (rc) { - WRITELOG("%s %s is sleeping. the packet was saved.\n", - currentDateTime(), _clientId); + WRITELOG("%s %s is sleeping. the packet was saved.\n", currentDateTime(), _clientId); } else { - WRITELOG("%s %s is sleeping but discard the packet.\n", - currentDateTime(), _clientId); + WRITELOG("%s %s is sleeping but discard the packet.\n", currentDateTime(), _clientId); } return rc; } @@ -147,13 +143,11 @@ int Client::setProxyPacket(MQTTSNPacket* packet) int rc = _proxyPacketQue.post(packet); if (rc) { - WRITELOG("%s %s is Disconnected. the packet was saved.\n", - currentDateTime(), _clientId); + 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); + WRITELOG("%s %s is Disconnected and discard the packet.\n", currentDateTime(), _clientId); } return rc; } @@ -231,8 +225,7 @@ bool Client::erasable(void) void Client::updateStatus(MQTTSNPacket* packet) { - if (((_status == Cstat_Disconnected) || (_status == Cstat_Lost)) - && packet->getType() == MQTTSN_CONNECT) + if (((_status == Cstat_Disconnected) || (_status == Cstat_Lost)) && packet->getType() == MQTTSN_CONNECT) { setKeepAlive(packet); } @@ -288,7 +281,7 @@ void Client::updateStatus(MQTTSNPacket* packet) default: break; } - } DEBUGLOG("Client Status = %s\n", theClientStatus[_status]); + }DEBUGLOG("Client Status = %s\n", theClientStatus[_status]); } void Client::updateStatus(ClientStatus stat) @@ -326,7 +319,7 @@ void Client::tryConnect(void) bool Client::isCleanSession(void) { - return _sessionStatus; + return _sessionStatus; } bool Client::isConnectSendable(void) diff --git a/MQTTSNGateway/src/MQTTSNGWClientList.cpp b/MQTTSNGateway/src/MQTTSNGWClientList.cpp index 0d1ad0d..9f6b0ea 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientList.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientList.cpp @@ -32,8 +32,8 @@ ClientList::ClientList(Gateway* gw) _authorize = false; _firstClient = nullptr; _endClient = nullptr; - _clientsPool = new ClientsPool(); - _gateway = gw; + _clientsPool = new ClientsPool(); + _gateway = gw; } ClientList::~ClientList() @@ -49,18 +49,18 @@ ClientList::~ClientList() cl = ncl; }; - if (_clientsPool) - { - delete _clientsPool; - } + if (_clientsPool) + { + delete _clientsPool; + } _mutex.unlock(); } void ClientList::initialize(bool aggregate) { - _clientsPool->allocate(_gateway->getGWParams()->maxClients); + _clientsPool->allocate(_gateway->getGWParams()->maxClients); - if (_gateway->getGWParams()->clientAuthentication) + if (_gateway->getGWParams()->clientAuthentication) { int type = TRANSPEARENT_TYPE; if (aggregate) @@ -71,7 +71,7 @@ void ClientList::initialize(bool aggregate) _authorize = true; } - if (_gateway->getGWParams()->predefinedTopic) + if (_gateway->getGWParams()->predefinedTopic) { setPredefinedTopics(aggregate); } @@ -79,21 +79,17 @@ void ClientList::initialize(bool aggregate) void ClientList::setClientList(int type) { - if (!createList(_gateway->getGWParams()->clientListName, type)) + if (!createList(_gateway->getGWParams()->clientListName, type)) { - throw EXCEPTION( - "ClientList::setClientList Client list not found!", 0); + throw EXCEPTION("ClientList::setClientList Client list not found!", 0); } } void ClientList::setPredefinedTopics(bool aggrecate) { - if (!readPredefinedList(_gateway->getGWParams()->predefinedTopicFileName, - aggrecate)) + if (!readPredefinedList(_gateway->getGWParams()->predefinedTopicFileName, aggrecate)) { - throw EXCEPTION( - "ClientList::setPredefinedTopics PredefindTopic list not found!", - 0); + throw EXCEPTION("ClientList::setPredefinedTopics PredefindTopic list not found!", 0); } } @@ -161,15 +157,13 @@ bool ClientList::createList(const char* fileName, int type) 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)) + if ((qos_1 && type == QOSM1PROXY_TYPE) || (!qos_1 && type == AGGREGATER_TYPE)) { createClient(&netAddr, &clientId, stable, secure, type); } else if (forwarder && type == FORWARDER_TYPE) { - _gateway->getAdapterManager()->getForwarderList()->addForwarder( - &netAddr, &clientId); + _gateway->getAdapterManager()->getForwarderList()->addForwarder(&netAddr, &clientId); } else if (type == TRANSPEARENT_TYPE) { @@ -230,8 +224,7 @@ bool ClientList::readPredefinedList(const char* fileName, bool aggregate) } else { - WRITELOG("ClientList can not open the Predefined Topic List. %s\n", - fileName); + WRITELOG("ClientList can not open the Predefined Topic List. %s\n", fileName); return false; } return rc; @@ -327,8 +320,7 @@ Client* ClientList::getClient(MQTTSNString* clientId) while (client != nullptr) { - if (strncmp((const char*) client->getClientId(), clID, - MQTTSNstrlen(*clientId)) == 0) + if (strncmp((const char*) client->getClientId(), clID, MQTTSNstrlen(*clientId)) == 0) { _mutex.unlock(); return client; @@ -339,14 +331,12 @@ Client* ClientList::getClient(MQTTSNString* clientId) return 0; } -Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, - int type) +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* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, bool unstableLine, bool secure, int type) { Client* client = getClient(addr); if (client) @@ -355,16 +345,16 @@ Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, } /* acquire a free client */ - client = _clientsPool->getClient(); + client = _clientsPool->getClient(); if (!client) { - WRITELOG("%s%sMax number of Clients%s\n", currentDateTime(), - ERRMSG_HEADER, ERRMSG_FOOTER); - return nullptr; + WRITELOG("%s%sMax number of Clients%s\n", currentDateTime(), + ERRMSG_HEADER, ERRMSG_FOOTER); + return nullptr; } - client->disconnected(); + client->disconnected(); if (addr) { client->setClientAddress(addr); @@ -410,19 +400,17 @@ Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, return client; } -Client* ClientList::createPredefinedTopic(MQTTSNString* clientId, - string topicName, uint16_t topicId, bool aggregate) +Client* ClientList::createPredefinedTopic(MQTTSNString* clientId, string topicName, uint16_t topicId, bool aggregate) { if (topicId == 0) { - WRITELOG("Invalid TopicId. Predefined Topic %s, TopicId is 0. \n", - topicName.c_str()); + WRITELOG("Invalid TopicId. Predefined Topic %s, TopicId is 0. \n", topicName.c_str()); return nullptr; } if (strcmp(clientId->cstring, common_topic) == 0) { - _gateway->getTopics()->add((const char*) topicName.c_str(), topicId); + _gateway->getTopics()->add((const char*) topicName.c_str(), topicId); return nullptr; } else @@ -490,63 +478,62 @@ bool ClientList::isAuthorized() ClientsPool::ClientsPool() { - _clientCnt = 0; - _firstClient = nullptr; - _endClient = nullptr; + _clientCnt = 0; + _firstClient = nullptr; + _endClient = nullptr; } ClientsPool::~ClientsPool() { - Client* cl = _firstClient; - Client* ncl; + Client* cl = _firstClient; + Client* ncl; - while (cl != nullptr) - { - ncl = cl->_nextClient; - delete cl; - cl = ncl; - }; + while (cl != nullptr) + { + ncl = cl->_nextClient; + delete cl; + cl = ncl; + }; } void ClientsPool::allocate(int maxClients) { - Client* cl = nullptr; + Client* cl = nullptr; - _firstClient = new Client(); + _firstClient = new Client(); - for (int i = 0; i < maxClients; i++) - { - if ((cl = new Client()) == nullptr) - { - throw Exception( - "ClientsPool::Can't allocate max number of clients\n", 0); - } - cl->_nextClient = _firstClient; - _firstClient = cl; - _clientCnt++; - } + for (int i = 0; i < maxClients; i++) + { + if ((cl = new Client()) == nullptr) + { + throw Exception("ClientsPool::Can't allocate max number of clients\n", 0); + } + cl->_nextClient = _firstClient; + _firstClient = cl; + _clientCnt++; + } } Client* ClientsPool::getClient(void) { - while (_firstClient != nullptr) - { - Client* cl = _firstClient; - _firstClient = cl->_nextClient; - cl->_nextClient = nullptr; - _clientCnt--; - return cl; - } - return nullptr; + while (_firstClient != nullptr) + { + Client* cl = _firstClient; + _firstClient = cl->_nextClient; + cl->_nextClient = nullptr; + _clientCnt--; + return cl; + } + return nullptr; } void ClientsPool::setClient(Client* client) { - if (client) - { - client->_nextClient = _firstClient; - _firstClient = client; - _clientCnt++; - } + if (client) + { + client->_nextClient = _firstClient; + _firstClient = client; + _clientCnt++; + } } diff --git a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp index ae7aeee..bd7017c 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp @@ -29,23 +29,18 @@ char* currentDateTime(void); =====================================*/ ClientRecvTask::ClientRecvTask(Gateway* gateway) { - _gateway = gateway; - _gateway->attach((Thread*) this); - _sensorNetwork = _gateway->getSensorNetwork(); - setTaskName("ClientRecvTask"); + _gateway = gateway; + _gateway->attach((Thread*) this); + _sensorNetwork = _gateway->getSensorNetwork(); + setTaskName("ClientRecvTask"); } ClientRecvTask::~ClientRecvTask() { - } -/** - * Initialize SensorNetwork - */ void ClientRecvTask::initialize(int argc, char** argv) { - _sensorNetwork->initialize(); } /* @@ -55,305 +50,286 @@ void ClientRecvTask::initialize(int argc, char** argv) */ void ClientRecvTask::run() { - Event* ev = nullptr; - AdapterManager* adpMgr = _gateway->getAdapterManager(); - QoSm1Proxy* qosm1Proxy = adpMgr->getQoSm1Proxy(); - int clientType = - adpMgr->isAggregaterActive() ? AGGREGATER_TYPE : TRANSPEARENT_TYPE; - ClientList* clientList = _gateway->getClientList(); - EventQue* packetEventQue = _gateway->getPacketEventQue(); - EventQue* clientsendQue = _gateway->getClientSendQue(); + Event* ev = nullptr; + AdapterManager* adpMgr = _gateway->getAdapterManager(); + QoSm1Proxy* qosm1Proxy = adpMgr->getQoSm1Proxy(); + int clientType = adpMgr->isAggregaterActive() ? AGGREGATER_TYPE : TRANSPEARENT_TYPE; + ClientList* clientList = _gateway->getClientList(); + EventQue* packetEventQue = _gateway->getPacketEventQue(); + EventQue* clientsendQue = _gateway->getClientSendQue(); - char buf[128]; + char buf[128]; - while (true) - { - Client* client = nullptr; - Forwarder* fwd = nullptr; - WirelessNodeId nodeId; + while (true) + { + Client* client = nullptr; + Forwarder* fwd = nullptr; + WirelessNodeId nodeId; - MQTTSNPacket* packet = new MQTTSNPacket(); - int packetLen = packet->recv(_sensorNetwork); + MQTTSNPacket* packet = new MQTTSNPacket(); + int packetLen = packet->recv(_sensorNetwork); - if (CHK_SIGINT) - { - WRITELOG("%s %s stopped.\n", currentDateTime(), getTaskName()); - delete packet; - return; - } + if (CHK_SIGINT) + { + WRITELOG("%s %s stopped.\n", currentDateTime(), getTaskName()); + delete packet; + return; + } - if (packetLen < 2) - { - delete packet; - continue; - } + if (packetLen < 2) + { + delete packet; + continue; + } - if (packet->getType() <= MQTTSN_ADVERTISE - || packet->getType() == MQTTSN_GWINFO) - { - delete packet; - continue; - } + if (packet->getType() <= MQTTSN_ADVERTISE || packet->getType() == MQTTSN_GWINFO) + { + delete packet; + continue; + } - if (packet->getType() == MQTTSN_SEARCHGW) - { - /* write log and post Event */ - log(0, packet, 0); - ev = new Event(); - ev->setBrodcastEvent(packet); - packetEventQue->post(ev); - continue; - } + if (packet->getType() == MQTTSN_SEARCHGW) + { + /* write log and post Event */ + log(0, packet, 0); + ev = new Event(); + ev->setBrodcastEvent(packet); + packetEventQue->post(ev); + continue; + } - SensorNetAddress* senderAddr = - _gateway->getSensorNetwork()->getSenderAddress(); + SensorNetAddress* senderAddr = _gateway->getSensorNetwork()->getSenderAddress(); - if (packet->getType() == MQTTSN_ENCAPSULATED) - { - fwd = - _gateway->getAdapterManager()->getForwarderList()->getForwarder( - senderAddr); + if (packet->getType() == MQTTSN_ENCAPSULATED) + { + fwd = _gateway->getAdapterManager()->getForwarderList()->getForwarder(senderAddr); - if (fwd != nullptr) - { - MQTTSNString fwdName = MQTTSNString_initializer; - fwdName.cstring = const_cast(fwd->getName()); - log(0, packet, &fwdName); + if (fwd != nullptr) + { + MQTTSNString fwdName = MQTTSNString_initializer; + fwdName.cstring = const_cast(fwd->getName()); + log(0, packet, &fwdName); - /* get the packet from the encapsulation message */ - MQTTSNGWEncapsulatedPacket encap; - encap.desirialize(packet->getPacketData(), - packet->getPacketLength()); - nodeId.setId(encap.getWirelessNodeId()); - client = fwd->getClient(&nodeId); - packet = encap.getMQTTSNPacket(); - } - } - else - { - /* Check the client belonging to QoS-1Proxy ? */ + /* 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 + { + /* Check the client belonging to QoS-1Proxy ? */ - if (qosm1Proxy->isActive()) - { - const char* clientName = qosm1Proxy->getClientId(senderAddr); + if (qosm1Proxy->isActive()) + { + const char* clientName = qosm1Proxy->getClientId(senderAddr); - if (clientName != nullptr) - { - client = qosm1Proxy->getClient(); + if (clientName != nullptr) + { + client = qosm1Proxy->getClient(); - if (!packet->isQoSMinusPUBLISH()) - { - 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; - } - } - } + if (!packet->isQoSMinusPUBLISH()) + { + 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; + } + } + } - if (client == nullptr) - { - client = _gateway->getClientList()->getClient(senderAddr); - } - } + if (client == nullptr) + { + client = _gateway->getClientList()->getClient(senderAddr); + } + } - if (client != nullptr) - { - log(client, packet, 0); + if (client != nullptr) + { + log(client, packet, 0); - if (client->isDisconnect() && packet->getType() != MQTTSN_CONNECT) - { - WRITELOG("%s MQTTSNGWClientRecvTask %s is not connecting.%s\n", - ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); + if (client->isDisconnect() && packet->getType() != MQTTSN_CONNECT) + { + WRITELOG("%s MQTTSNGWClientRecvTask %s is not connecting.%s\n", + ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); - /* send DISCONNECT to the client, if it is not connected */ - MQTTSNPacket* snPacket = new MQTTSNPacket(); - snPacket->setDISCONNECT(0); - ev = new Event(); - ev->setClientSendEvent(client, snPacket); - clientsendQue->post(ev); - delete packet; - continue; - } - else - { - ev = new Event(); - ev->setClientRecvEvent(client, packet); - packetEventQue->post(ev); - } - } - else - { - /* new client */ - if (packet->getType() == MQTTSN_CONNECT) - { - MQTTSNPacket_connectData data; - memset(&data, 0, sizeof(MQTTSNPacket_connectData)); - if (!packet->getCONNECT(&data)) - { - log(0, packet, &data.clientID); - WRITELOG("%s CONNECT message form %s is incorrect.%s\n", - ERRMSG_HEADER, senderAddr->sprint(buf), - ERRMSG_FOOTER); - delete packet; - continue; - } + /* send DISCONNECT to the client, if it is not connected */ + MQTTSNPacket* snPacket = new MQTTSNPacket(); + snPacket->setDISCONNECT(0); + ev = new Event(); + ev->setClientSendEvent(client, snPacket); + clientsendQue->post(ev); + delete packet; + continue; + } + else + { + ev = new Event(); + ev->setClientRecvEvent(client, packet); + packetEventQue->post(ev); + } + } + else + { + /* new client */ + if (packet->getType() == MQTTSN_CONNECT) + { + MQTTSNPacket_connectData data; + memset(&data, 0, sizeof(MQTTSNPacket_connectData)); + if (!packet->getCONNECT(&data)) + { + log(0, packet, &data.clientID); + WRITELOG("%s CONNECT message form %s is incorrect.%s\n", + ERRMSG_HEADER, senderAddr->sprint(buf), + ERRMSG_FOOTER); + delete packet; + continue; + } - client = clientList->getClient(&data.clientID); + client = clientList->getClient(&data.clientID); - if (fwd != nullptr) - { - if (client == nullptr) - { - /* create a new client */ - client = clientList->createClient(0, &data.clientID, - clientType); - } - /* Add to a forwarded client list of forwarder. */ - fwd->addClient(client, &nodeId); - } - else - { - if (client) - { - /* Authentication is not required */ - if (_gateway->getGWParams()->clientAuthentication - == false) - { - client->setClientAddress(senderAddr); - } - } - else - { - /* create a new client */ - client = clientList->createClient(senderAddr, - &data.clientID, clientType); - } - } + if (fwd != nullptr) + { + if (client == nullptr) + { + /* create a new client */ + client = clientList->createClient(0, &data.clientID, clientType); + } + /* Add to a forwarded client list of forwarder. */ + fwd->addClient(client, &nodeId); + } + else + { + if (client) + { + /* Authentication is not required */ + if (_gateway->getGWParams()->clientAuthentication == false) + { + client->setClientAddress(senderAddr); + } + } + else + { + /* create a new client */ + client = clientList->createClient(senderAddr, &data.clientID, clientType); + } + } - log(client, packet, &data.clientID); + log(client, packet, &data.clientID); - if (client == nullptr) - { - WRITELOG( - "%s Client(%s) was rejected. CONNECT message has been discarded.%s\n", - ERRMSG_HEADER, senderAddr->sprint(buf), - ERRMSG_FOOTER); - delete packet; - continue; - } + if (client == nullptr) + { + WRITELOG("%s Client(%s) was rejected. CONNECT message has been discarded.%s\n", + ERRMSG_HEADER, senderAddr->sprint(buf), + ERRMSG_FOOTER); + delete packet; + continue; + } - /* post Client RecvEvent */ - ev = new Event(); - ev->setClientRecvEvent(client, packet); - packetEventQue->post(ev); - } - else - { - log(client, packet, 0); - if (packet->getType() == MQTTSN_ENCAPSULATED) - { - WRITELOG( - "%s MQTTSNGWClientRecvTask 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 MQTTSNGWClientRecvTask Client(%s) is not connecting. message has been discarded.%s\n", - ERRMSG_HEADER, senderAddr->sprint(buf), - ERRMSG_FOOTER); - } - delete packet; - } - } - } + /* post Client RecvEvent */ + ev = new Event(); + ev->setClientRecvEvent(client, packet); + packetEventQue->post(ev); + } + else + { + log(client, packet, 0); + if (packet->getType() == MQTTSN_ENCAPSULATED) + { + WRITELOG( + "%s MQTTSNGWClientRecvTask 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 MQTTSNGWClientRecvTask Client(%s) is not connecting. message has been discarded.%s\n", + ERRMSG_HEADER, senderAddr->sprint(buf), + ERRMSG_FOOTER); + } + delete packet; + } + } + } } void ClientRecvTask::log(Client* client, MQTTSNPacket* packet, MQTTSNString* id) { - const char* clientId; - char cstr[MAX_CLIENTID_LENGTH + 1]; + const char* clientId; + char cstr[MAX_CLIENTID_LENGTH + 1]; - if (id) - { - 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) - { - clientId = client->getClientId(); - } - else - { - clientId = UNKNOWNCL; - } + if (id) + { + 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) + { + clientId = client->getClientId(); + } + else + { + clientId = UNKNOWNCL; + } - log(clientId, packet); + log(clientId, packet); } void ClientRecvTask::log(const char* clientId, MQTTSNPacket* packet) { - char pbuf[ SIZE_OF_LOG_PACKET * 3 + 1]; - char msgId[6]; + char pbuf[ SIZE_OF_LOG_PACKET * 3 + 1]; + 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; - } + 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/MQTTSNGWClientSendTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp index 4211d5e..7b07389 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp @@ -63,9 +63,8 @@ void ClientSendTask::run() if (packet->broadcast(_sensorNetwork) < 0) { - WRITELOG( - "%s ClientSendTask can't multicast a packet Error=%d%s\n", - ERRMSG_HEADER, errno, ERRMSG_FOOTER); + WRITELOG("%s ClientSendTask can't multicast a packet Error=%d%s\n", + ERRMSG_HEADER, errno, ERRMSG_FOOTER); } } else @@ -85,12 +84,9 @@ void ClientSendTask::run() if (rc < 0) { - WRITELOG( - "%s ClientSendTask can't send a packet to the client %s. Error=%d%s\n", - ERRMSG_HEADER, - (client ? - (const char*) client->getClientId() : UNKNOWNCL), - errno, ERRMSG_FOOTER); + WRITELOG("%s ClientSendTask can't send a packet to the client %s. Error=%d%s\n", + ERRMSG_HEADER, (client ? (const char*) client->getClientId() : UNKNOWNCL), + errno, ERRMSG_FOOTER); } } delete ev; @@ -101,15 +97,14 @@ void ClientSendTask::log(Client* client, MQTTSNPacket* packet) { char pbuf[SIZE_OF_LOG_PACKET * 3 + 1]; char msgId[6]; - const char* clientId = - client ? (const char*) client->getClientId() : UNKNOWNCL; + const char* clientId = client ? (const char*) client->getClientId() : UNKNOWNCL; switch (packet->getType()) { case MQTTSN_ADVERTISE: case MQTTSN_GWINFO: WRITELOG(FORMAT_Y_W_G, currentDateTime(), packet->getName(), RIGHTARROW, - CLIENTS, packet->print(pbuf)); + CLIENTS, packet->print(pbuf)); break; case MQTTSN_CONNACK: case MQTTSN_DISCONNECT: @@ -118,13 +113,11 @@ void ClientSendTask::log(Client* client, MQTTSNPacket* packet) case MQTTSN_WILLTOPICRESP: case MQTTSN_WILLMSGRESP: case MQTTSN_PINGRESP: - WRITELOG(FORMAT_Y_W_G, currentDateTime(), packet->getName(), RIGHTARROW, - clientId, packet->print(pbuf)); + WRITELOG(FORMAT_Y_W_G, currentDateTime(), packet->getName(), RIGHTARROW, clientId, packet->print(pbuf)); break; case MQTTSN_REGISTER: case MQTTSN_PUBLISH: - WRITELOG(FORMAT_W_MSGID_W_G, currentDateTime(), packet->getName(), - packet->getMsgId(msgId), RIGHTARROW, clientId, + WRITELOG(FORMAT_W_MSGID_W_G, currentDateTime(), packet->getName(), packet->getMsgId(msgId), RIGHTARROW, clientId, packet->print(pbuf)); break; case MQTTSN_REGACK: @@ -134,8 +127,7 @@ void ClientSendTask::log(Client* client, MQTTSNPacket* packet) case MQTTSN_PUBCOMP: case MQTTSN_SUBACK: case MQTTSN_UNSUBACK: - WRITELOG(FORMAT_W_MSGID_W_G, currentDateTime(), packet->getName(), - packet->getMsgId(msgId), RIGHTARROW, clientId, + WRITELOG(FORMAT_W_MSGID_W_G, currentDateTime(), packet->getName(), packet->getMsgId(msgId), RIGHTARROW, clientId, packet->print(pbuf)); break; default: diff --git a/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp b/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp index f0133ff..69f3b41 100644 --- a/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp @@ -42,8 +42,7 @@ MQTTSNConnectionHandler::~MQTTSNConnectionHandler() void MQTTSNConnectionHandler::sendADVERTISE() { MQTTSNPacket* adv = new MQTTSNPacket(); - adv->setADVERTISE(_gateway->getGWParams()->gatewayId, - _gateway->getGWParams()->keepAlive); + adv->setADVERTISE(_gateway->getGWParams()->gatewayId, _gateway->getGWParams()->keepAlive); Event* ev1 = new Event(); ev1->setBrodcastEvent(adv); //broadcast _gateway->getClientSendQue()->post(ev1); @@ -67,8 +66,7 @@ void MQTTSNConnectionHandler::handleSearchgw(MQTTSNPacket* packet) /* * CONNECT */ -void MQTTSNConnectionHandler::handleConnect(Client* client, - MQTTSNPacket* packet) +void MQTTSNConnectionHandler::handleConnect(Client* client, MQTTSNPacket* packet) { MQTTSNPacket_connectData data; if (packet->getCONNECT(&data) == 0) @@ -149,8 +147,7 @@ void MQTTSNConnectionHandler::handleConnect(Client* client, /* CONNECT message was not qued in. * create CONNECT message & send it to the broker */ MQTTGWPacket* mqMsg = new MQTTGWPacket(); - mqMsg->setCONNECT(client->getConnectData(), - (unsigned char*) _gateway->getGWParams()->loginId, + mqMsg->setCONNECT(client->getConnectData(), (unsigned char*) _gateway->getGWParams()->loginId, (unsigned char*) _gateway->getGWParams()->password); Event* ev1 = new Event(); ev1->setBrokerSendEvent(client, mqMsg); @@ -161,8 +158,7 @@ void MQTTSNConnectionHandler::handleConnect(Client* client, /* * WILLTOPIC */ -void MQTTSNConnectionHandler::handleWilltopic(Client* client, - MQTTSNPacket* packet) +void MQTTSNConnectionHandler::handleWilltopic(Client* client, MQTTSNPacket* packet) { int willQos; uint8_t willRetain; @@ -192,8 +188,7 @@ void MQTTSNConnectionHandler::handleWilltopic(Client* client, /* * WILLMSG */ -void MQTTSNConnectionHandler::handleWillmsg(Client* client, - MQTTSNPacket* packet) +void MQTTSNConnectionHandler::handleWillmsg(Client* client, MQTTSNPacket* packet) { if (!client->isWaitWillMsg()) { @@ -216,8 +211,7 @@ void MQTTSNConnectionHandler::handleWillmsg(Client* client, /* create CONNECT message */ MQTTGWPacket* mqttPacket = new MQTTGWPacket(); connectData->willMsg = client->getWillMsg(); - mqttPacket->setCONNECT(connectData, - (unsigned char*) _gateway->getGWParams()->loginId, + mqttPacket->setCONNECT(connectData, (unsigned char*) _gateway->getGWParams()->loginId, (unsigned char*) _gateway->getGWParams()->password); /* Send CONNECT to the broker */ @@ -231,8 +225,7 @@ void MQTTSNConnectionHandler::handleWillmsg(Client* client, /* * DISCONNECT */ -void MQTTSNConnectionHandler::handleDisconnect(Client* client, - MQTTSNPacket* packet) +void MQTTSNConnectionHandler::handleDisconnect(Client* client, MQTTSNPacket* packet) { uint16_t duration = 0; @@ -258,8 +251,7 @@ void MQTTSNConnectionHandler::handleDisconnect(Client* client, /* * WILLTOPICUPD */ -void MQTTSNConnectionHandler::handleWilltopicupd(Client* client, - MQTTSNPacket* packet) +void MQTTSNConnectionHandler::handleWilltopicupd(Client* client, MQTTSNPacket* packet) { /* send NOT_SUPPORTED responce to the client */ MQTTSNPacket* respMsg = new MQTTSNPacket(); @@ -272,8 +264,7 @@ void MQTTSNConnectionHandler::handleWilltopicupd(Client* client, /* * WILLMSGUPD */ -void MQTTSNConnectionHandler::handleWillmsgupd(Client* client, - MQTTSNPacket* packet) +void MQTTSNConnectionHandler::handleWillmsgupd(Client* client, MQTTSNPacket* packet) { /* send NOT_SUPPORTED responce to the client */ MQTTSNPacket* respMsg = new MQTTSNPacket(); @@ -286,11 +277,9 @@ void MQTTSNConnectionHandler::handleWillmsgupd(Client* client, /* * PINGREQ */ -void MQTTSNConnectionHandler::handlePingreq(Client* client, - MQTTSNPacket* packet) +void MQTTSNConnectionHandler::handlePingreq(Client* client, MQTTSNPacket* packet) { - if ((client->isSleep() || client->isAwake()) - && client->getClientSleepPacket()) + if ((client->isSleep() || client->isAwake()) && client->getClientSleepPacket()) { sendStoredPublish(client); client->holdPingRequest(); diff --git a/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.cpp b/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.cpp index dccde79..24c2afe 100644 --- a/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.cpp +++ b/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.cpp @@ -22,9 +22,7 @@ using namespace MQTTSNGW; using namespace std; WirelessNodeId::WirelessNodeId() : - _len - { 0 }, _nodeId - { 0 } + _len { 0 }, _nodeId { 0 } { } @@ -78,17 +76,13 @@ bool WirelessNodeId::operator ==(WirelessNodeId& id) * Class MQTTSNGWEncapsulatedPacket */ MQTTSNGWEncapsulatedPacket::MQTTSNGWEncapsulatedPacket() : - _mqttsn - { 0 }, _ctrl - { 0 } + _mqttsn { 0 }, _ctrl { 0 } { } MQTTSNGWEncapsulatedPacket::MQTTSNGWEncapsulatedPacket(MQTTSNPacket* packet) : - _mqttsn - { packet }, _ctrl - { 0 } + _mqttsn { packet }, _ctrl { 0 } { } @@ -98,8 +92,7 @@ MQTTSNGWEncapsulatedPacket::~MQTTSNGWEncapsulatedPacket() /* Do not delete the MQTTSNPacket. MQTTSNPacket is deleted by delete Event */ } -int MQTTSNGWEncapsulatedPacket::unicast(SensorNetwork* network, - SensorNetAddress* sendTo) +int MQTTSNGWEncapsulatedPacket::unicast(SensorNetwork* network, SensorNetAddress* sendTo) { uint8_t buf[MQTTSNGW_MAX_PACKET_SIZE]; int len = serialize(buf); @@ -121,8 +114,7 @@ int MQTTSNGWEncapsulatedPacket::serialize(uint8_t* buf) return buf[0] + len; } -int MQTTSNGWEncapsulatedPacket::desirialize(unsigned char* buf, - unsigned short len) +int MQTTSNGWEncapsulatedPacket::desirialize(unsigned char* buf, unsigned short len) { if (_mqttsn) { diff --git a/MQTTSNGateway/src/MQTTSNGWForwarder.cpp b/MQTTSNGateway/src/MQTTSNGWForwarder.cpp index 92875f3..a157747 100644 --- a/MQTTSNGateway/src/MQTTSNGWForwarder.cpp +++ b/MQTTSNGateway/src/MQTTSNGWForwarder.cpp @@ -64,8 +64,7 @@ Forwarder* ForwarderList::getForwarder(SensorNetAddress* addr) return p; } -Forwarder* ForwarderList::addForwarder(SensorNetAddress* addr, - MQTTSNString* forwarderId) +Forwarder* ForwarderList::addForwarder(SensorNetAddress* addr, MQTTSNString* forwarderId) { Forwarder* fdr = new Forwarder(addr, forwarderId); if (_head == nullptr) @@ -251,10 +250,7 @@ SensorNetAddress* Forwarder::getSensorNetAddr(void) */ ForwarderElement::ForwarderElement() : - _client - { 0 }, _wirelessNodeId - { 0 }, _next - { 0 } + _client { 0 }, _wirelessNodeId { 0 }, _next { 0 } { } diff --git a/MQTTSNGateway/src/MQTTSNGWMessageIdTable.cpp b/MQTTSNGateway/src/MQTTSNGWMessageIdTable.cpp index 63e32a2..8db2cb1 100644 --- a/MQTTSNGateway/src/MQTTSNGWMessageIdTable.cpp +++ b/MQTTSNGateway/src/MQTTSNGWMessageIdTable.cpp @@ -45,8 +45,7 @@ MessageIdTable::~MessageIdTable() _mutex.unlock(); } -MessageIdElement* MessageIdTable::add(Aggregater* aggregater, Client* client, - uint16_t clientMsgId) +MessageIdElement* MessageIdTable::add(Aggregater* aggregater, Client* client, uint16_t clientMsgId) { if (_cnt > _maxSize) { @@ -194,18 +193,12 @@ uint16_t MessageIdTable::getMsgId(Client* client, uint16_t clientMsgId) * Class MessageIdElement ===============================*/ MessageIdElement::MessageIdElement(void) : - _msgId - { 0 }, _clientMsgId - { 0 }, _client - { nullptr }, _next - { nullptr }, _prev - { nullptr } + _msgId { 0 }, _clientMsgId { 0 }, _client { nullptr }, _next { nullptr }, _prev { nullptr } { } -MessageIdElement::MessageIdElement(uint16_t msgId, Client* client, - uint16_t clientMsgId) : +MessageIdElement::MessageIdElement(uint16_t msgId, Client* client, uint16_t clientMsgId) : MessageIdElement() { _msgId = msgId; diff --git a/MQTTSNGateway/src/MQTTSNGWPacket.cpp b/MQTTSNGateway/src/MQTTSNGWPacket.cpp index 0e1f2ec..c82466b 100644 --- a/MQTTSNGateway/src/MQTTSNGWPacket.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPacket.cpp @@ -149,8 +149,7 @@ int MQTTSNPacket::setADVERTISE(uint8_t gatewayid, uint16_t duration) { unsigned char buf[5]; int buflen = sizeof(buf); - int len = MQTTSNSerialize_advertise(buf, buflen, (unsigned char) gatewayid, - (unsigned short) duration); + int len = MQTTSNSerialize_advertise(buf, buflen, (unsigned char) gatewayid, (unsigned short) duration); return desirialize(buf, len); } @@ -158,8 +157,7 @@ int MQTTSNPacket::setGWINFO(uint8_t gatewayId) { unsigned char buf[3]; int buflen = sizeof(buf); - int len = MQTTSNSerialize_gwinfo(buf, buflen, (unsigned char) gatewayId, 0, - 0); + int len = MQTTSNSerialize_gwinfo(buf, buflen, (unsigned char) gatewayId, 0, 0); return desirialize(buf, len); } @@ -202,45 +200,37 @@ int MQTTSNPacket::setWILLMSGREQ(void) return desirialize(buf, len); } -int MQTTSNPacket::setREGISTER(uint16_t topicId, uint16_t msgId, - MQTTSNString* topicName) +int MQTTSNPacket::setREGISTER(uint16_t topicId, uint16_t msgId, MQTTSNString* topicName) { unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE]; int buflen = sizeof(buf); - int len = MQTTSNSerialize_register(buf, buflen, (unsigned short) topicId, - (unsigned short) msgId, topicName); + int len = MQTTSNSerialize_register(buf, buflen, (unsigned short) topicId, (unsigned short) msgId, topicName); return desirialize(buf, len); } -int MQTTSNPacket::setREGACK(uint16_t topicId, uint16_t msgId, - uint8_t returnCode) +int MQTTSNPacket::setREGACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode) { unsigned char buf[7]; int buflen = sizeof(buf); - int len = MQTTSNSerialize_regack(buf, buflen, (unsigned short) topicId, - (unsigned short) msgId, (unsigned char) returnCode); + int len = MQTTSNSerialize_regack(buf, buflen, (unsigned short) topicId, (unsigned short) msgId, (unsigned char) returnCode); return desirialize(buf, len); } -int MQTTSNPacket::setPUBLISH(uint8_t dup, int qos, uint8_t retained, - uint16_t msgId, MQTTSN_topicid topic, uint8_t* payload, +int MQTTSNPacket::setPUBLISH(uint8_t dup, int qos, uint8_t retained, uint16_t msgId, MQTTSN_topicid topic, uint8_t* payload, uint16_t payloadlen) { unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE]; int 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); + 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); } -int MQTTSNPacket::setPUBACK(uint16_t topicId, uint16_t msgId, - uint8_t returnCode) +int MQTTSNPacket::setPUBACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode) { unsigned char buf[7]; int buflen = sizeof(buf); - int len = MQTTSNSerialize_puback(buf, buflen, (unsigned short) topicId, - (unsigned short) msgId, (unsigned char) returnCode); + int len = MQTTSNSerialize_puback(buf, buflen, (unsigned short) topicId, (unsigned short) msgId, (unsigned char) returnCode); return desirialize(buf, len); } @@ -268,13 +258,12 @@ int MQTTSNPacket::setPUBCOMP(uint16_t msgId) return desirialize(buf, len); } -int MQTTSNPacket::setSUBACK(int qos, uint16_t topicId, uint16_t msgId, - uint8_t returnCode) +int MQTTSNPacket::setSUBACK(int qos, uint16_t topicId, uint16_t msgId, uint8_t returnCode) { unsigned char buf[8]; int buflen = sizeof(buf); - int len = MQTTSNSerialize_suback(buf, buflen, qos, (unsigned short) topicId, - (unsigned short) msgId, (unsigned char) returnCode); + int len = MQTTSNSerialize_suback(buf, buflen, qos, (unsigned short) topicId, (unsigned short) msgId, + (unsigned char) returnCode); return desirialize(buf, len); } @@ -336,8 +325,7 @@ int MQTTSNPacket::setPINGREQ(MQTTSNString* clientId) int MQTTSNPacket::getSERCHGW(uint8_t* radius) { - return MQTTSNDeserialize_searchgw((unsigned char*) radius, - (unsigned char*) _buf, _bufLen); + return MQTTSNDeserialize_searchgw((unsigned char*) radius, (unsigned char*) _buf, _bufLen); } int MQTTSNPacket::getCONNECT(MQTTSNPacket_connectData* data) @@ -350,11 +338,9 @@ int MQTTSNPacket::getCONNACK(uint8_t* returnCode) return MQTTSNSerialize_connack(_buf, _bufLen, (int) *returnCode); } -int MQTTSNPacket::getWILLTOPIC(int* willQoS, uint8_t* willRetain, - MQTTSNString* willTopic) +int MQTTSNPacket::getWILLTOPIC(int* willQoS, uint8_t* willRetain, MQTTSNString* willTopic) { - return MQTTSNDeserialize_willtopic((int*) willQoS, - (unsigned char*) willRetain, willTopic, _buf, _bufLen); + return MQTTSNDeserialize_willtopic((int*) willQoS, (unsigned char*) willRetain, willTopic, _buf, _bufLen); } int MQTTSNPacket::getWILLMSG(MQTTSNString* willmsg) @@ -362,34 +348,28 @@ int MQTTSNPacket::getWILLMSG(MQTTSNString* willmsg) return MQTTSNDeserialize_willmsg(willmsg, _buf, _bufLen); } -int MQTTSNPacket::getREGISTER(uint16_t* topicId, uint16_t* msgId, - MQTTSNString* topicName) +int MQTTSNPacket::getREGISTER(uint16_t* topicId, uint16_t* msgId, MQTTSNString* topicName) { - return MQTTSNDeserialize_register((unsigned short*) topicId, - (unsigned short*) msgId, topicName, _buf, _bufLen); + return MQTTSNDeserialize_register((unsigned short*) topicId, (unsigned short*) msgId, topicName, _buf, _bufLen); } -int MQTTSNPacket::getREGACK(uint16_t* topicId, uint16_t* msgId, - uint8_t* returnCode) +int MQTTSNPacket::getREGACK(uint16_t* topicId, uint16_t* msgId, uint8_t* returnCode) { - return MQTTSNDeserialize_regack((unsigned short*) topicId, - (unsigned short*) msgId, (unsigned char*) returnCode, _buf, _bufLen); + return MQTTSNDeserialize_regack((unsigned short*) topicId, (unsigned short*) msgId, (unsigned char*) returnCode, _buf, + _bufLen); } -int MQTTSNPacket::getPUBLISH(uint8_t* dup, int* qos, uint8_t* retained, - uint16_t* msgId, MQTTSN_topicid* topic, uint8_t** payload, - int* payloadlen) +int MQTTSNPacket::getPUBLISH(uint8_t* dup, int* qos, uint8_t* retained, uint16_t* msgId, MQTTSN_topicid* topic, + uint8_t** payload, int* payloadlen) { - return MQTTSNDeserialize_publish((unsigned char*) dup, qos, - (unsigned char*) retained, (unsigned short*) msgId, topic, + return MQTTSNDeserialize_publish((unsigned char*) dup, qos, (unsigned char*) retained, (unsigned short*) msgId, topic, (unsigned char**) payload, (int*) payloadlen, _buf, _bufLen); } -int MQTTSNPacket::getPUBACK(uint16_t* topicId, uint16_t* msgId, - uint8_t* returnCode) +int MQTTSNPacket::getPUBACK(uint16_t* topicId, uint16_t* msgId, uint8_t* returnCode) { - return MQTTSNDeserialize_puback((unsigned short*) topicId, - (unsigned short*) msgId, (unsigned char*) returnCode, _buf, _bufLen); + return MQTTSNDeserialize_puback((unsigned short*) topicId, (unsigned short*) msgId, (unsigned char*) returnCode, _buf, + _bufLen); } int MQTTSNPacket::getACK(uint16_t* msgId) @@ -398,17 +378,14 @@ int MQTTSNPacket::getACK(uint16_t* msgId) return MQTTSNDeserialize_ack(&type, (unsigned short*) msgId, _buf, _bufLen); } -int MQTTSNPacket::getSUBSCRIBE(uint8_t* dup, int* qos, uint16_t* msgId, - MQTTSN_topicid* topicFilter) +int MQTTSNPacket::getSUBSCRIBE(uint8_t* dup, int* qos, uint16_t* msgId, MQTTSN_topicid* topicFilter) { - return MQTTSNDeserialize_subscribe((unsigned char*) dup, qos, - (unsigned short*) msgId, topicFilter, _buf, _bufLen); + return MQTTSNDeserialize_subscribe((unsigned char*) dup, qos, (unsigned short*) msgId, topicFilter, _buf, _bufLen); } int MQTTSNPacket::getUNSUBSCRIBE(uint16_t* msgId, MQTTSN_topicid* topicFilter) { - return MQTTSNDeserialize_unsubscribe((unsigned short*) msgId, topicFilter, - _buf, _bufLen); + return MQTTSNDeserialize_unsubscribe((unsigned short*) msgId, topicFilter, _buf, _bufLen); } int MQTTSNPacket::getPINGREQ(void) @@ -428,11 +405,9 @@ int MQTTSNPacket::getDISCONNECT(uint16_t* duration) return rc; } -int MQTTSNPacket::getWILLTOPICUPD(uint8_t* willQoS, uint8_t* willRetain, - MQTTSNString* willTopic) +int MQTTSNPacket::getWILLTOPICUPD(uint8_t* willQoS, uint8_t* willRetain, MQTTSNString* willTopic) { - return MQTTSNDeserialize_willtopicupd((int*) willQoS, - (unsigned char*) willRetain, willTopic, _buf, _bufLen); + return MQTTSNDeserialize_willtopicupd((int*) willQoS, (unsigned char*) willRetain, willTopic, _buf, _bufLen); } int MQTTSNPacket::getWILLMSGUPD(MQTTSNString* willMsg) diff --git a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp index b9726d9..5b09b14 100644 --- a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp @@ -125,8 +125,7 @@ void PacketHandleTask::run() if (_advertiseTimer.isTimeup()) { _mqttsnConnection->sendADVERTISE(); - _advertiseTimer.start( - _gateway->getGWParams()->keepAlive * 1000UL); + _advertiseTimer.start(_gateway->getGWParams()->keepAlive * 1000UL); } /*------ Check Adapters Connect or PINGREQ ------*/ @@ -180,8 +179,7 @@ void PacketHandleTask::run() } } -void PacketHandleTask::aggregatePacketHandler(Client*client, - MQTTSNPacket* packet) +void PacketHandleTask::aggregatePacketHandler(Client*client, MQTTSNPacket* packet) { switch (packet->getType()) { @@ -238,8 +236,7 @@ void PacketHandleTask::aggregatePacketHandler(Client*client, } } -void PacketHandleTask::aggregatePacketHandler(Client*client, - MQTTGWPacket* packet) +void PacketHandleTask::aggregatePacketHandler(Client*client, MQTTGWPacket* packet) { switch (packet->getType()) { @@ -275,8 +272,7 @@ void PacketHandleTask::aggregatePacketHandler(Client*client, } } -void PacketHandleTask::transparentPacketHandler(Client*client, - MQTTSNPacket* packet) +void PacketHandleTask::transparentPacketHandler(Client*client, MQTTSNPacket* packet) { switch (packet->getType()) { @@ -333,8 +329,7 @@ void PacketHandleTask::transparentPacketHandler(Client*client, } } -void PacketHandleTask::transparentPacketHandler(Client*client, - MQTTGWPacket* packet) +void PacketHandleTask::transparentPacketHandler(Client*client, MQTTGWPacket* packet) { switch (packet->getType()) { diff --git a/MQTTSNGateway/src/MQTTSNGWProcess.cpp b/MQTTSNGateway/src/MQTTSNGWProcess.cpp index 55bc475..55d1ae6 100644 --- a/MQTTSNGateway/src/MQTTSNGWProcess.cpp +++ b/MQTTSNGateway/src/MQTTSNGWProcess.cpp @@ -163,7 +163,7 @@ int Process::getParam(const char* parameter, char* value) if ((fp = fopen(configPath.c_str(), "r")) == NULL) { - throw Exception("No config file:\n\nUsage: Command -f path/config_file_name\n", 0); + throw Exception("Config file not found:\n\nUsage: Command -f path/config_file_name\n", 0); } while (true) @@ -257,7 +257,7 @@ MultiTaskProcess::~MultiTaskProcess() { for (int i = 0; i < _threadCount; i++) { - _threadList[i]->stop(); + _threadList[i]->stop(); } } @@ -338,18 +338,18 @@ int MultiTaskProcess::getParam(const char* parameter, char* value) ======================================*/ Exception::Exception(const char* message, const int errNo) { - _message = message; + _message = message; _errNo = errNo; _fileName = nullptr; _functionName = nullptr; _line = 0; } -Exception::Exception(const char* message, const int errNo, const char* file, - const char* function, const int line) +Exception::Exception(const char* message, const int errNo, const char* file, const char* function, const int line) { - _message = message; + _message = message; _errNo = errNo; - _fileName = getFileName(file);; + _fileName = getFileName(file); + ; _functionName = function; _line = line; } @@ -388,39 +388,40 @@ void Exception::writeMessage() { if (_fileName == nullptr) { - if (_errNo == 0) - { - WRITELOG("%s%s %s%s\n", currentDateTime(), RED_HDR, _message, CLR_HDR); - } - else - { - WRITELOG("%s%s %s.\n errno=%d : %s%s\n", currentDateTime(), RED_HDR,_message, _errNo, strerror(_errNo), CLR_HDR); - } + if (_errNo == 0) + { + WRITELOG("%s%s %s%s\n", currentDateTime(), RED_HDR, _message, CLR_HDR); + } + else + { + WRITELOG("%s%s %s.\n errno=%d : %s%s\n", currentDateTime(), RED_HDR, _message, _errNo, + strerror(_errNo), CLR_HDR); + } } else { - if (_errNo == 0) - { - WRITELOG("%s%s %s. %s line %-4d %s()%s\n", - currentDateTime(), RED_HDR, _message, _fileName, _line, _functionName, CLR_HDR); - } - else - { - WRITELOG("%s%s %s. %s line %-4d %s()\n errno=%d : %s%s\n", - currentDateTime(), RED_HDR, _message, _fileName, _line, _functionName, _errNo, strerror(_errNo), CLR_HDR); - } + if (_errNo == 0) + { + WRITELOG("%s%s %s. %s line %-4d %s()%s\n", currentDateTime(), RED_HDR, _message, _fileName, _line, _functionName, + CLR_HDR); + } + else + { + WRITELOG("%s%s %s. %s line %-4d %s()\n errno=%d : %s%s\n", currentDateTime(), RED_HDR, _message, + _fileName, _line, _functionName, _errNo, strerror(_errNo), CLR_HDR); + } } } const char* Exception::getFileName(const char* file) { - for ( int len = strlen(file); len > 0; len-- ) - { - if (*(file + len) == '/') - { - return file + len + 1; - } - } - return file; + for (int len = strlen(file); len > 0; len--) + { + if (*(file + len) == '/') + { + return file + len + 1; + } + } + return file; } diff --git a/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp b/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp index ebbe8cd..3824173 100644 --- a/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp @@ -35,14 +35,13 @@ MQTTSNPublishHandler::~MQTTSNPublishHandler() } -MQTTGWPacket* MQTTSNPublishHandler::handlePublish(Client* client, - MQTTSNPacket* packet) +MQTTGWPacket* MQTTSNPublishHandler::handlePublish(Client* client, MQTTSNPacket* packet) { uint8_t dup; int qos; uint8_t retained; uint16_t msgId; - uint16_t tid; + uint16_t tid; uint8_t* payload; MQTTSN_topicid topicid; int payloadlen; @@ -54,15 +53,13 @@ MQTTGWPacket* MQTTSNPublishHandler::handlePublish(Client* client, { if (client->isQoSm1()) { - _gateway->getAdapterManager()->getQoSm1Proxy()->savePacket(client, - packet); + _gateway->getAdapterManager()->getQoSm1Proxy()->savePacket(client, packet); return nullptr; } } - if (packet->getPUBLISH(&dup, &qos, &retained, &msgId, &topicid, &payload, - &payloadlen) == 0) + if (packet->getPUBLISH(&dup, &qos, &retained, &msgId, &topicid, &payload, &payloadlen) == 0) { return nullptr; } @@ -70,7 +67,7 @@ MQTTGWPacket* MQTTSNPublishHandler::handlePublish(Client* client, pub.header.bits.dup = dup; pub.header.bits.qos = (qos == 3 ? 0 : qos); pub.header.bits.retain = retained; - tid = topicid.data.id; + tid = topicid.data.id; Topic* topic = nullptr; @@ -89,22 +86,19 @@ MQTTGWPacket* MQTTSNPublishHandler::handlePublish(Client* client, topic = _gateway->getTopics()->getTopicById(&topicid); if (topic) { - topic = client->getTopics()->add(topic->getTopicName()->c_str(), - topic->getTopicId()); + topic = client->getTopics()->add(topic->getTopicName()->c_str(), topic->getTopicId()); } } if (!topic && qos == 3) { - WRITELOG("%s Invalid TopicId.%s %s\n", ERRMSG_HEADER, - client->getClientId(), ERRMSG_FOOTER); + WRITELOG("%s Invalid TopicId.%s %s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); return nullptr; } if ((qos == 0 || qos == 3) && msgId > 0) { - WRITELOG("%s Invalid MsgId.%s %s\n", ERRMSG_HEADER, - client->getClientId(), ERRMSG_FOOTER); + WRITELOG("%s Invalid MsgId.%s %s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); return nullptr; } @@ -112,8 +106,7 @@ MQTTGWPacket* MQTTSNPublishHandler::handlePublish(Client* client, { /* Reply PubAck with INVALID_TOPIC_ID to the client */ MQTTSNPacket* pubAck = new MQTTSNPacket(); - pubAck->setPUBACK(topicid.data.id, msgId, - MQTTSN_RC_REJECTED_INVALID_TOPIC_ID); + pubAck->setPUBACK(topicid.data.id, msgId, MQTTSN_RC_REJECTED_INVALID_TOPIC_ID); Event* ev1 = new Event(); ev1->setClientSendEvent(client, pubAck); _gateway->getClientSendQue()->post(ev1); @@ -123,14 +116,14 @@ MQTTGWPacket* MQTTSNPublishHandler::handlePublish(Client* client, { pub.topic = (char*) topic->getTopicName()->data(); pub.topiclen = topic->getTopicName()->length(); - topicid.data.long_.name = pub.topic; - topicid.data.long_.len = pub.topiclen; + topicid.data.long_.name = pub.topic; + topicid.data.long_.len = pub.topiclen; } } /* Save a msgId & a TopicId pare for PUBACK */ if (msgId && qos > 0 && qos < 3) { - client->setWaitedPubTopicId(msgId, tid, &topicid); + client->setWaitedPubTopicId(msgId, tid, &topicid); } pub.payload = (char*) payload; @@ -139,8 +132,7 @@ MQTTGWPacket* MQTTSNPublishHandler::handlePublish(Client* client, MQTTGWPacket* publish = new MQTTGWPacket(); publish->setPUBLISH(&pub); - if (_gateway->getAdapterManager()->isAggregaterActive() - && client->isAggregated()) + if (_gateway->getAdapterManager()->isAggregaterActive() && client->isAggregated()) { return publish; } @@ -184,8 +176,7 @@ void MQTTSNPublishHandler::handlePuback(Client* client, MQTTSNPacket* packet) } } -void MQTTSNPublishHandler::handleAck(Client* client, MQTTSNPacket* packet, - uint8_t packetType) +void MQTTSNPublishHandler::handleAck(Client* client, MQTTSNPacket* packet, uint8_t packetType) { uint16_t msgId; @@ -245,19 +236,17 @@ void MQTTSNPublishHandler::handleRegAck(Client* client, MQTTSNPacket* packet) } /* get PUBLISH message */ - MQTTSNPacket* regAck = client->getWaitREGACKPacketList()->getPacket( - msgId); + MQTTSNPacket* regAck = client->getWaitREGACKPacketList()->getPacket(msgId); if (regAck != nullptr) { client->getWaitREGACKPacketList()->erase(msgId); - Event* ev = new Event(); - ev->setClientSendEvent(client, regAck); - _gateway->getClientSendQue()->post(ev); + Event* ev = new Event(); + ev->setClientSendEvent(client, regAck); + _gateway->getClientSendQue()->post(ev); } - if (client->isHoldPingReqest() - && client->getWaitREGACKPacketList()->getCount() == 0) + if (client->isHoldPingReqest() && client->getWaitREGACKPacketList()->getCount() == 0) { /* send PINGREQ to the broker */ client->resetPingRequest(); @@ -271,8 +260,7 @@ void MQTTSNPublishHandler::handleRegAck(Client* client, MQTTSNPacket* packet) } -void MQTTSNPublishHandler::handleAggregatePublish(Client* client, - MQTTSNPacket* packet) +void MQTTSNPublishHandler::handleAggregatePublish(Client* client, MQTTSNPacket* packet) { int msgId = 0; MQTTGWPacket* publish = handlePublish(client, packet); @@ -282,15 +270,11 @@ void MQTTSNPublishHandler::handleAggregatePublish(Client* client, { if (packet->isDuplicate()) { - msgId = - _gateway->getAdapterManager()->getAggregater()->getMsgId( - client, packet->getMsgId()); + msgId = _gateway->getAdapterManager()->getAggregater()->getMsgId(client, packet->getMsgId()); } else { - msgId = - _gateway->getAdapterManager()->getAggregater()->addMessageIdTable( - client, packet->getMsgId()); + msgId = _gateway->getAdapterManager()->getAggregater()->addMessageIdTable(client, packet->getMsgId()); } publish->setMsgId(msgId); } @@ -300,8 +284,7 @@ void MQTTSNPublishHandler::handleAggregatePublish(Client* client, } } -void MQTTSNPublishHandler::handleAggregateAck(Client* client, - MQTTSNPacket* packet, int type) +void MQTTSNPublishHandler::handleAggregateAck(Client* client, MQTTSNPacket* packet, int type) { if (type == MQTTSN_PUBREC) { diff --git a/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp index 9b39030..797e36b 100644 --- a/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp +++ b/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp @@ -34,8 +34,7 @@ MQTTSNSubscribeHandler::~MQTTSNSubscribeHandler() } -MQTTGWPacket* MQTTSNSubscribeHandler::handleSubscribe(Client* client, - MQTTSNPacket* packet) +MQTTGWPacket* MQTTSNSubscribeHandler::handleSubscribe(Client* client, MQTTSNPacket* packet) { uint8_t dup; int qos; @@ -63,16 +62,15 @@ MQTTGWPacket* MQTTSNSubscribeHandler::handleSubscribe(Client* client, if (!topic) { - /* Search the topic in Client common topic table */ + /* Search the topic in Client common topic table */ topic = _gateway->getTopics()->getTopicById(&topicFilter); if (topic) { - topic = client->getTopics()->add(topic->getTopicName()->c_str(), - topic->getTopicId()); + topic = client->getTopics()->add(topic->getTopicName()->c_str(), topic->getTopicId()); if (topic == nullptr) { - WRITELOG("%s Client(%s) can't add the Topic.%s\n", - ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); + WRITELOG("%s Client(%s) can't add the Topic.%s\n", + ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); goto RespExit; } } @@ -83,8 +81,7 @@ MQTTGWPacket* MQTTSNSubscribeHandler::handleSubscribe(Client* client, } topicId = topic->getTopicId(); subscribe = new MQTTGWPacket(); - subscribe->setSUBSCRIBE((char*) topic->getTopicName()->c_str(), - (uint8_t) qos, (uint16_t) msgId); + subscribe->setSUBSCRIBE((char*) topic->getTopicName()->c_str(), (uint8_t) qos, (uint16_t) msgId); } else if (topicFilter.type == MQTTSN_TOPIC_TYPE_NORMAL) @@ -96,15 +93,14 @@ MQTTGWPacket* MQTTSNSubscribeHandler::handleSubscribe(Client* client, if (topic == nullptr) { WRITELOG("%s Client(%s) can't add the Topic.%s\n", - ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); + ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); goto RespExit; } } topicId = topic->getTopicId(); subscribe = new MQTTGWPacket(); - subscribe->setSUBSCRIBE((char*) topic->getTopicName()->c_str(), - (uint8_t) qos, (uint16_t) msgId); + subscribe->setSUBSCRIBE((char*) topic->getTopicName()->c_str(), (uint8_t) qos, (uint16_t) msgId); } else //MQTTSN_TOPIC_TYPE_SHORT { @@ -133,16 +129,14 @@ MQTTGWPacket* MQTTSNSubscribeHandler::handleSubscribe(Client* client, } RespExit: MQTTSNPacket* sSuback = new MQTTSNPacket(); - sSuback->setSUBACK(qos, topicFilter.data.id, msgId, - MQTTSN_RC_REJECTED_INVALID_TOPIC_ID); + sSuback->setSUBACK(qos, topicFilter.data.id, msgId, MQTTSN_RC_REJECTED_INVALID_TOPIC_ID); evsuback = new Event(); evsuback->setClientSendEvent(client, sSuback); _gateway->getClientSendQue()->post(evsuback); return nullptr; } -MQTTGWPacket* MQTTSNSubscribeHandler::handleUnsubscribe(Client* client, - MQTTSNPacket* packet) +MQTTGWPacket* MQTTSNSubscribeHandler::handleUnsubscribe(Client* client, MQTTSNPacket* packet) { uint16_t msgId; MQTTSN_topicid topicFilter; @@ -209,8 +203,7 @@ MQTTGWPacket* MQTTSNSubscribeHandler::handleUnsubscribe(Client* client, } } -void MQTTSNSubscribeHandler::handleAggregateSubscribe(Client* client, - MQTTSNPacket* packet) +void MQTTSNSubscribeHandler::handleAggregateSubscribe(Client* client, MQTTSNPacket* packet) { MQTTGWPacket* subscribe = handleSubscribe(client, packet); @@ -219,21 +212,17 @@ void MQTTSNSubscribeHandler::handleAggregateSubscribe(Client* client, int msgId = 0; if (packet->isDuplicate()) { - msgId = _gateway->getAdapterManager()->getAggregater()->getMsgId( - client, packet->getMsgId()); + msgId = _gateway->getAdapterManager()->getAggregater()->getMsgId(client, packet->getMsgId()); } else { - msgId = - _gateway->getAdapterManager()->getAggregater()->addMessageIdTable( - client, packet->getMsgId()); + 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); + WRITELOG("%s MQTTSNSubscribeHandler can't create MessageIdTableElement %s%s\n", + ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); return; } @@ -241,8 +230,7 @@ void MQTTSNSubscribeHandler::handleAggregateSubscribe(Client* client, string* topicName = new string(str.data, str.len); // topicName is delete by topic Topic topic = Topic(topicName, MQTTSN_TOPIC_TYPE_NORMAL); - _gateway->getAdapterManager()->getAggregater()->addAggregateTopic( - &topic, client); + _gateway->getAdapterManager()->getAggregater()->addAggregateTopic(&topic, client); subscribe->setMsgId(msgId); Event* ev = new Event(); @@ -251,8 +239,7 @@ void MQTTSNSubscribeHandler::handleAggregateSubscribe(Client* client, } } -void MQTTSNSubscribeHandler::handleAggregateUnsubscribe(Client* client, - MQTTSNPacket* packet) +void MQTTSNSubscribeHandler::handleAggregateUnsubscribe(Client* client, MQTTSNPacket* packet) { MQTTGWPacket* unsubscribe = handleUnsubscribe(client, packet); if (unsubscribe != nullptr) @@ -260,29 +247,24 @@ void MQTTSNSubscribeHandler::handleAggregateUnsubscribe(Client* client, int msgId = 0; if (packet->isDuplicate()) { - msgId = _gateway->getAdapterManager()->getAggregater()->getMsgId( - client, packet->getMsgId()); + msgId = _gateway->getAdapterManager()->getAggregater()->getMsgId(client, packet->getMsgId()); } else { - msgId = - _gateway->getAdapterManager()->getAggregater()->addMessageIdTable( - client, packet->getMsgId()); + 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); + WRITELOG("%s MQTTSNUnsubscribeHandler can't create MessageIdTableElement %s%s\n", + ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER); return; } UTF8String str = unsubscribe->getTopic(); string* topicName = new string(str.data, str.len); // topicName is delete by topic Topic topic = Topic(topicName, MQTTSN_TOPIC_TYPE_NORMAL); - _gateway->getAdapterManager()->getAggregater()->removeAggregateTopic( - &topic, client); + _gateway->getAdapterManager()->getAggregater()->removeAggregateTopic(&topic, client); unsubscribe->setMsgId(msgId); Event* ev = new Event(); diff --git a/MQTTSNGateway/src/MQTTSNGWTopic.cpp b/MQTTSNGateway/src/MQTTSNGWTopic.cpp index 692ff87..68cf1fe 100644 --- a/MQTTSNGateway/src/MQTTSNGWTopic.cpp +++ b/MQTTSNGateway/src/MQTTSNGWTopic.cpp @@ -166,8 +166,7 @@ bool Topic::isMatch(string* topicName) void Topic::print(void) { - WRITELOG("TopicName=%s ID=%d Type=%d\n", _topicName->c_str(), _topicId, - _type); + WRITELOG("TopicName=%s ID=%d Type=%d\n", _topicName->c_str(), _topicId, _type); } /*===================================== @@ -402,16 +401,16 @@ TopicIdMapElement::TopicIdMapElement(uint16_t msgId, uint16_t topicId, MQTTSN_to _msgId = msgId; _topicId = topicId; _type = topic->type; - _wildcard = 0; + _wildcard = 0; _next = nullptr; _prev = nullptr; if (_type == MQTTSN_TOPIC_TYPE_NORMAL) { - if ( strchr(topic->data.long_.name, '#') != 0 || strchr(topic->data.long_.name, '+') != 0 ) - { - _wildcard = 1; - } + if (strchr(topic->data.long_.name, '#') != 0 || strchr(topic->data.long_.name, '+') != 0) + { + _wildcard = 1; + } } } @@ -427,14 +426,14 @@ MQTTSN_topicTypes TopicIdMapElement::getTopicType(void) uint16_t TopicIdMapElement::getTopicId(void) { - if (_wildcard > 0) - { - return 0; - } - else - { - return _topicId; - } + if (_wildcard > 0) + { + return 0; + } + else + { + return _topicId; + } } TopicIdMap::TopicIdMap() @@ -473,8 +472,7 @@ TopicIdMapElement* TopicIdMap::getElement(uint16_t msgId) TopicIdMapElement* TopicIdMap::add(uint16_t msgId, uint16_t topicId, MQTTSN_topicid* topic) { - if (_cnt > _maxInflight * 2 - || (topicId == 0 && topic->type != MQTTSN_TOPIC_TYPE_SHORT)) + if (_cnt > _maxInflight * 2 || (topicId == 0 && topic->type != MQTTSN_TOPIC_TYPE_SHORT)) { return 0; } diff --git a/MQTTSNGateway/src/MQTTSNGWTopic.h b/MQTTSNGateway/src/MQTTSNGWTopic.h index b7f6866..f796b8b 100644 --- a/MQTTSNGateway/src/MQTTSNGWTopic.h +++ b/MQTTSNGateway/src/MQTTSNGWTopic.h @@ -101,7 +101,7 @@ public: TopicIdMap(); ~TopicIdMap(); TopicIdMapElement* getElement(uint16_t msgId); - TopicIdMapElement* add(uint16_t msgId, uint16_t topicId, MQTTSN_topicid* topic); + TopicIdMapElement* add(uint16_t msgId, uint16_t topicId, MQTTSN_topicid* topic); void erase(uint16_t msgId); void clear(void); private: diff --git a/MQTTSNGateway/src/MQTTSNGateway.cpp b/MQTTSNGateway/src/MQTTSNGateway.cpp index 2e7b386..3ef0dab 100644 --- a/MQTTSNGateway/src/MQTTSNGateway.cpp +++ b/MQTTSNGateway/src/MQTTSNGateway.cpp @@ -35,7 +35,7 @@ Gateway::Gateway(void) theMultiTaskProcess = this; theProcess = this; _packetEventQue.setMaxSize(MAX_INFLIGHTMESSAGES * MAX_CLIENTS); - _clientList = new ClientList(); + _clientList = new ClientList(this); _adapterManager = new AdapterManager(this); _topics = new Topics(); _stopFlg = false; @@ -101,6 +101,11 @@ Gateway::~Gateway() free(_params.qosMinusClientListName); } + if (_params.bleAddress) + { + free(_params.bleAddress); + } + if (_adapterManager) { delete _adapterManager; @@ -114,7 +119,6 @@ Gateway::~Gateway() { delete _topics; } -// WRITELOG("Gateway is deleted normally.\r\n"); } int Gateway::getParam(const char* parameter, char* value) @@ -201,7 +205,7 @@ void Gateway::initialize(int argc, char** argv) _params.mqttVersion = atoi(param); } - _params.maxInflightMsgs = DEFAULT_MQTT_VERSION; + _params.maxInflightMsgs = MAX_INFLIGHTMESSAGES; if (getParam("MaxInflightMsgs", param) == 0) { _params.maxInflightMsgs = atoi(param); @@ -272,12 +276,25 @@ void Gateway::initialize(int argc, char** argv) } } + _params.maxClients = MAX_CLIENTS; + if (getParam("MaxNumberOfClients", param) == 0) + { + _params.maxClients = atoi(param); + } + + if (getParam("BleAddress", param) == 0) + { + _params.bleAddress = strdup(param); + } + /* Initialize adapters */ - _adapterManager->initialize(_params.gatewayName, _params.aggregatingGw, - _params.forwarder, _params.qosMinus1); + _adapterManager->initialize(_params.gatewayName, _params.aggregatingGw, _params.forwarder, _params.qosMinus1); /* Setup ClientList and Predefined topics */ _clientList->initialize(_params.aggregatingGw); + + /* SensorNetwork initialize */ + _sensorNetwork.initialize(); } void Gateway::run(void) @@ -291,8 +308,7 @@ void Gateway::run(void) WRITELOG(" *\n%s\n", PAHO_COPYRIGHT3); WRITELOG(" * Version: %s\n", PAHO_GATEWAY_VERSION); WRITELOG("%s\n", PAHO_COPYRIGHT4); - WRITELOG("\n%s %s has been started.\n\n", currentDateTime(), - _params.gatewayName); + WRITELOG("\n%s %s has been started.\n\n", currentDateTime(), _params.gatewayName); WRITELOG(" ConfigFile: %s\n", _params.configName); if (_params.clientListName) @@ -306,8 +322,8 @@ void Gateway::run(void) } WRITELOG(" SensorN/W: %s\n", _sensorNetwork.getDescription()); - WRITELOG(" Broker: %s : %s, %s\n", _params.brokerName, _params.port, - _params.portSecure); + WRITELOG(" Broker: %s : %s, %s\n", _params.brokerName, _params.port, _params.portSecure); + WRITELOG(" Max number of Clients: %d\n", _params.maxClients); WRITELOG(" RootCApath: %s\n", _params.rootCApath); WRITELOG(" RootCAfile: %s\n", _params.rootCAfile); WRITELOG(" CertKey: %s\n", _params.certKey); @@ -390,8 +406,7 @@ Topics* Gateway::getTopics(void) bool Gateway::hasSecureConnection(void) { - return (_params.certKey && _params.privateKey && _params.rootCApath - && _params.rootCAfile); + return (_params.certKey && _params.privateKey && _params.rootCApath && _params.rootCAfile); } /*===================================== Class EventQue diff --git a/MQTTSNGateway/src/MQTTSNGateway.h b/MQTTSNGateway/src/MQTTSNGateway.h index 1f6d6de..9e13ddd 100644 --- a/MQTTSNGateway/src/MQTTSNGateway.h +++ b/MQTTSNGateway/src/MQTTSNGateway.h @@ -167,6 +167,8 @@ public: bool aggregatingGw { false }; bool qosMinus1 { false }; bool forwarder { false }; + int maxClients {0}; + char* bleAddress { nullptr }; }; /*===================================== @@ -174,6 +176,7 @@ public: =====================================*/ class AdapterManager; class ClientList; +class ClientsPool; class Gateway: public MultiTaskProcess { @@ -201,13 +204,13 @@ public: private: GatewayParams _params; - ClientList* _clientList { nullptr }; + ClientList* _clientList; EventQue _packetEventQue; EventQue _brokerSendQue; EventQue _clientSendQue; LightIndicator _lightIndicator; SensorNetwork _sensorNetwork; - AdapterManager* _adapterManager { nullptr }; + AdapterManager* _adapterManager; Topics* _topics; bool _stopFlg; }; diff --git a/MQTTSNGateway/src/linux/Threading.cpp b/MQTTSNGateway/src/linux/Threading.cpp index 703dd19..db26fbc 100644 --- a/MQTTSNGateway/src/linux/Threading.cpp +++ b/MQTTSNGateway/src/linux/Threading.cpp @@ -524,7 +524,7 @@ bool Thread::equals(pthread_t *t1, pthread_t *t2) int Thread::start(void) { - Runnable* runnable = this; + Runnable* runnable = this; return pthread_create(&_threadID, 0, _run, runnable); } diff --git a/MQTTSNGateway/src/linux/Threading.h b/MQTTSNGateway/src/linux/Threading.h index 7a8f985..92b9270 100644 --- a/MQTTSNGateway/src/linux/Threading.h +++ b/MQTTSNGateway/src/linux/Threading.h @@ -95,7 +95,7 @@ private: class RingBuffer { public: - RingBuffer(const char* keyDirctory = MQTTSNGW_KEY_DIRECTORY); + RingBuffer(const char* keyDirctory = MQTTSNGW_KEY_DIRECTORY); ~RingBuffer(); void put(char* buffer); int get(char* buffer, int bufferLength); diff --git a/MQTTSNGateway/src/linux/ble/SensorNetwork.cpp b/MQTTSNGateway/src/linux/ble/SensorNetwork.cpp new file mode 100644 index 0000000..f5ef3fe --- /dev/null +++ b/MQTTSNGateway/src/linux/ble/SensorNetwork.cpp @@ -0,0 +1,425 @@ +/************************************************************************************** + * Copyright (c) 2016, Tomoaki Yamaguchi + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Tomoaki Yamaguchi - initial API and implementation and/or initial documentation + **************************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "SensorNetwork.h" +#include "MQTTSNGWProcess.h" + +using namespace std; +using namespace MQTTSNGW; + +/*=========================================== + * Class SensorNetAddreess + + * These 4 methods are minimum requirements for the SensorNetAddress class. + * isMatch(SensorNetAddress* ) + * operator =(SensorNetAddress& ) + * setAddress(string* ) + * sprint(char* ) + + * BlePort class requires these 3 methods. + * getIpAddress(void) + * getPortNo(void) + * setAddress(uint32_t BtAddr, uint16_t channel) + + ============================================*/ +bdaddr_t NullAddr = { 0, 0, 0, 0, 0, 0 }; + +SensorNetAddress::SensorNetAddress() +{ + _channel = 0; + bacpy(&_bdAddr, &NullAddr); +} + +SensorNetAddress::~SensorNetAddress() +{ + +} + +bdaddr_t* SensorNetAddress::getAddress(void) +{ + return &_bdAddr; +} + +uint16_t SensorNetAddress::getPortNo(void) +{ + return _channel; +} + +void SensorNetAddress::setAddress(bdaddr_t BdAddr, uint16_t channel) +{ + bacpy(&_bdAddr, &BdAddr); + _channel = channel; +} + +/** + * Set Address data to SensorNetAddress + * + * @param *dev_channel is "Device_Address.Channel" format string + * @return success = 0, Invalid format = -1 + * + * Valid channels are 1 to 30. + * + * Client01,XX:XX:XX:XX:XX:XX.1 + * + */ +int SensorNetAddress::setAddress(string* dev_channel) +{ + int rc = -1; + size_t pos = dev_channel->find_first_of("."); + + if (pos == string::npos) + { + _channel = 0; + memset(&_bdAddr, 0, sizeof(bdaddr_t)); + return rc; + } + + string dvAddr = dev_channel->substr(0, pos); + string strchannel = dev_channel->substr(pos + 1); + if (strchannel == "*") + { + _channel = 0; + } + else + { + _channel = atoi(strchannel.c_str()); + } + str2ba(dvAddr.c_str(), &_bdAddr); + + if ((_channel < 0 && _channel > 30) || bacmp(&_bdAddr, &NullAddr) == 0) + { + return rc; + } + return 0; +} + +bool SensorNetAddress::isMatch(SensorNetAddress* addr) +{ + return ((this->_channel == addr->_channel) && bacmp(&this->_bdAddr, &addr->_bdAddr) == 0); +} + +SensorNetAddress& SensorNetAddress::operator =(SensorNetAddress& addr) +{ + this->_channel = addr._channel; + this->_bdAddr = addr._bdAddr; + return *this; +} + +char* SensorNetAddress::sprint(char* buf) +{ + ba2str(const_cast(&_bdAddr), buf); + sprintf(buf + strlen(buf), ".%d", _channel); + return buf; +} + +/*================================================================ + Class SensorNetwork + + getDescpription( ) is used by Gateway::initialize( ) + initialize( ) is used by Gateway::initialize( ) + getSenderAddress( ) is used by ClientRecvTask::run( ) + broadcast( ) is used by MQTTSNPacket::broadcast( ) + unicast( ) is used by MQTTSNPacket::unicast( ) + read( ) is used by MQTTSNPacket::recv( ) + + ================================================================*/ + +SensorNetwork::SensorNetwork() +{ + +} + +SensorNetwork::~SensorNetwork() +{ +} + +int SensorNetwork::unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendToAddr) +{ + uint16_t ch = sendToAddr->getPortNo(); + BlePort* blep = &_rfPorts[ch - 1]; + int rc = 0; + errno = 0; + + if ((rc = blep->send(payload, (uint32_t) payloadLength)) < 0) + { + D_NWSTACK("errno == %d in BlePort::sendto %d\n", errno, ch); + } D_NWSTACK("sendto %u length = %d\n", ch, rc); + return rc; +} + +int SensorNetwork::broadcast(const uint8_t* payload, uint16_t payloadLength) +{ + int rc = 0; + + for (int i = 0; i < MAX_RFCOMM_CH; i++) + { + errno = 0; + if (_rfPorts[i].getSock() > 0) + { + if ((rc = _rfPorts[i].send(payload, (uint32_t) payloadLength)) < 0) + { + D_NWSTACK("errno == %d in BlePort::sendto %d\n", errno, i + 1); + }D_NWSTACK("sendto %u length = %d\n", i + 1, rc); + } + } + return rc; +} + +int SensorNetwork::read(uint8_t* buf, uint16_t bufLen) +{ + struct timeval timeout; + fd_set recvfds; + int maxSock = 0; + + timeout.tv_sec = 1; + timeout.tv_usec = 0; // 1 sec + FD_ZERO(&recvfds); + + for (int i = 0; i < MAX_RFCOMM_CH; i++) + { + if (_rfPorts[i]._rfCommSock > 0) + { + if (maxSock < _rfPorts[i]._rfCommSock) + { + maxSock = _rfPorts[i]._rfCommSock; + } + FD_SET(_rfPorts[i]._rfCommSock, &recvfds); + } + else if (_rfPorts[i]._listenSock > 0) + { + if (maxSock < _rfPorts[i]._listenSock) + { + maxSock = _rfPorts[i]._listenSock; + } + FD_SET(_rfPorts[i]._listenSock, &recvfds); + } + } + + int rc = 0; + if (select(maxSock + 1, &recvfds, 0, 0, &timeout) > 0) + { + WRITELOG("RECV\n"); + for (int i = 0; i < MAX_RFCOMM_CH; i++) + { + if (_rfPorts[i]._rfCommSock > 0) + { + if (FD_ISSET(_rfPorts[i]._rfCommSock, &recvfds)) + { + rc = _rfPorts[i].recv(buf, bufLen); + if (rc == -1) + { + _rfPorts[i].close(); + } + } + } + else if (_rfPorts[i]._listenSock > 0) + { + if (FD_ISSET(_rfPorts[i]._listenSock, &recvfds)) + { + int sock = _rfPorts[i].accept(&_senderAddr); + if (sock > 0) + { + _rfPorts[i]._rfCommSock = sock; + } + WRITELOG("accept sock= %d CH = %d\n", sock, i + 1); + } + } + } + } + return rc; +} + +/** + * Prepare UDP sockets and description of SensorNetwork like + * "UDP Multicast 225.1.1.1:1883 Gateway Port 10000". + * The description is for a start up prompt. + */ +void SensorNetwork::initialize(void) +{ + char param[MQTTSNGW_PARAM_MAX]; + string devAddr; + SensorNetAddress sa; + + /* + * theProcess->getParam( ) copies + * a text specified by "Key" into param[] from the Gateway.conf + * + * in Gateway.conf e.g. + * + * # BLE + * BleAddress=XX:XX:XX:XX:XX:XX.0 + * + */ + if (theProcess->getParam("BleAddress", param) == 0) + { + devAddr = param; + _description = "BLE RFCOMM "; + _description += param; + } + + errno = 0; + if (sa.setAddress(&devAddr) == -1) + { + throw EXCEPTION("Invalid BLE Address", errno); + } + + /* Prepare BLE sockets */ + WRITELOG("Initialize ble\n"); + int rc = MAX_RFCOMM_CH; + for (uint16_t i = 0; i < MAX_RFCOMM_CH; i++) + { + + rc += _rfPorts[i].open(sa.getAddress(), i + 1); + } + if (rc == 0) + { + throw EXCEPTION("Can't open BLE RFComms", errno); + } +} + +const char* SensorNetwork::getDescription(void) +{ + return _description.c_str(); +} + +SensorNetAddress* SensorNetwork::getSenderAddress(void) +{ + return &_senderAddr; +} + +/*========================================= + Class BleStack + =========================================*/ + +BlePort::BlePort() +{ + _disconReq = false; + _rfCommSock = 0; + _listenSock = 0; + _channel = 0; +} + +BlePort::~BlePort() +{ + close(); + + if (_listenSock > 0) + { + ::close(_listenSock); + } +} + +void BlePort::close(void) +{ + if (_rfCommSock > 0) + { + ::close(_rfCommSock); + _rfCommSock = 0; + } +} + +int BlePort::open(bdaddr_t* devAddr, uint16_t channel) +{ + const int reuse = 1; + + if (channel < 1 || channel > 30) + { + D_NWSTACK("error Channel undefined in BlePort::open\n"); + return 0; + } + + + /*------ Create unicast socket --------*/ + _listenSock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + if (_listenSock < 0) + { + D_NWSTACK("error can't create Rfcomm socket in BlePort::open\n"); + return 0; + } + + sockaddr_rc addru; + addru.rc_family = AF_BLUETOOTH; + addru.rc_channel = channel; + bacpy(&addru.rc_bdaddr, devAddr); + + uint8_t buf[20]; + ba2str(devAddr, (char*) buf); + setsockopt(_listenSock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); + errno = 0; + if (::bind(_listenSock, (sockaddr*) &addru, sizeof(addru)) < 0) + { + WRITELOG("\033[0m\033[0;31mCan't bind RFCOMM CH = %d %s\033[0m\033[0;37m\n", channel, strerror(errno)); + ::close(_listenSock); + return 0; + } + _channel = channel; + ::listen(_listenSock, 1); + WRITELOG("Listen RFCOMM CH = %d\n", channel); + return 1; +} + +int BlePort::send(const uint8_t* buf, uint32_t length) +{ + WRITELOG("sock = %d\n", _rfCommSock); + return ::send(_rfCommSock, buf, length, 0); +} + +int BlePort::recv(uint8_t* buf, uint16_t len) +{ + int rc = 0; + errno = 0; + + rc = ::read(_rfCommSock, buf, len); + if (rc < 0 && errno != EAGAIN) + { + D_NWSTACK("errno = %d in BlePort::recv\n", errno); + return -1; + } + return rc; +} + +int BlePort::accept(SensorNetAddress* addr) +{ + struct sockaddr_rc devAddr = { 0 }; + socklen_t opt = sizeof(devAddr); + + int sock = 0; + errno = 0; + + sock = ::accept(_listenSock, (sockaddr *) &devAddr, &opt); + if (sock < 0 && errno != EAGAIN) + { + D_NWSTACK("errno == %d in BlePort::recv\n", errno); + return -1; + } + bdaddr_t bdAddr = devAddr.rc_bdaddr; + addr->setAddress(bdAddr, _channel); + return sock; +} + +int BlePort::getSock(void) +{ + return _rfCommSock; +} diff --git a/MQTTSNGateway/src/linux/ble/SensorNetwork.h b/MQTTSNGateway/src/linux/ble/SensorNetwork.h new file mode 100644 index 0000000..7a4ffe8 --- /dev/null +++ b/MQTTSNGateway/src/linux/ble/SensorNetwork.h @@ -0,0 +1,104 @@ +/************************************************************************************** + * Copyright (c) 2016, Tomoaki Yamaguchi + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Tomoaki Yamaguchi - initial API and implementation and/or initial documentation + **************************************************************************************/ + +#ifndef SENSORNETWORK_H_ +#define SENSORNETWORK_H_ + +#include "MQTTSNGWDefines.h" +#include +#include + +using namespace std; + +namespace MQTTSNGW +{ + +#ifdef DEBUG_NWSTACK + #define D_NWSTACK(...) printf(__VA_ARGS__) +#else + #define D_NWSTACK(...) +#endif + +#define MAX_RFCOMM_CH 30 + +/*=========================================== + Class SensorNetAddreess + ============================================*/ +class SensorNetAddress +{ +public: + SensorNetAddress(); + ~SensorNetAddress(); + void setAddress(bdaddr_t bdAddr, uint16_t channel); + int setAddress(string* data); + uint16_t getPortNo(void); + bdaddr_t* getAddress(void); + bool isMatch(SensorNetAddress* addr); + SensorNetAddress& operator =(SensorNetAddress& addr); + char* sprint(char* buf); +private: + uint16_t _channel; + bdaddr_t _bdAddr; +}; + +/*======================================== + Class BlePort + =======================================*/ +class BlePort +{ + friend class SensorNetwork; +public: + BlePort(); + virtual ~BlePort(); + + int open(bdaddr_t* devAddress, uint16_t channel); + void close(void); + int send(const uint8_t* buf, uint32_t length); + int recv(uint8_t* buf, uint16_t len); + int getSock(void); + int accept(SensorNetAddress* addr); +private: + int _rfCommSock; + int _listenSock; + uint16_t _channel; + bool _disconReq; +}; + +/*=========================================== + Class SensorNetwork + ============================================*/ +class SensorNetwork +{ +public: + SensorNetwork(); + ~SensorNetwork(); + + int unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendto); + int broadcast(const uint8_t* payload, uint16_t payloadLength); + int read(uint8_t* buf, uint16_t bufLen); + void initialize(void); + const char* getDescription(void); + SensorNetAddress* getSenderAddress(void); + +private: + // sockets for RFCOMM + BlePort _rfPorts[MAX_RFCOMM_CH]; + SensorNetAddress _senderAddr; + string _description; +}; + +} +#endif /* SENSORNETWORK_H_ */ diff --git a/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp b/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp index eb0d038..0828dd6 100644 --- a/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp +++ b/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp @@ -142,7 +142,7 @@ char* SensorNetAddress::sprint(char* buf) In Gateway version 1.0 getDescpription( ) is used by Gateway::initialize( ) - initialize( ) is used by ClientSendTask::initialize( ) + initialize( ) is used by Gateway::initialize( ) getSenderAddress( ) is used by ClientRecvTask::run( ) broadcast( ) is used by MQTTSNPacket::broadcast( ) unicast( ) is used by MQTTSNPacket::unicast( ) diff --git a/travis-build.sh b/travis-build.sh index d8907ff..d2e7e4d 100755 --- a/travis-build.sh +++ b/travis-build.sh @@ -9,6 +9,8 @@ echo "travis build dir $TRAVIS_BUILD_DIR pwd $PWD" cmake .. -DSENSORNET=loralink make ctest -VV --timeout 600 +cmake .. -DSENSORNET=ble +make MQTT-SNGateway cmake .. -DSENSORNET=xbee make MQTT-SNGateway cmake .. -DSENSORNET=udp6 From de355e28b65827f3ac29a0aa7fc795f224bbc127 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Wed, 2 Jun 2021 20:42:07 +0900 Subject: [PATCH 55/67] Add apt install bluez and libbluetooth-dev Signed-off-by: tomoaki --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 029d9d3..aec373c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,8 @@ addons: - g++-4.8 - cmake - cmake-data + - bluez + - libbluetooth-dev script: - ./travis-build.sh From d3626bb68d7fa480a29031bb506da97cb555bdee Mon Sep 17 00:00:00 2001 From: tomoaki Date: Fri, 4 Jun 2021 13:01:47 +0900 Subject: [PATCH 56/67] Add a new sensor network Bluetooth RFCOMM Signed-off-by: tomoaki --- .cproject | 30 ++-- MQTTSNGateway/GatewayTester/Makefile | 2 +- .../samples/ClientPub/mainPub.cpp | 6 +- .../samples/ClientPubQoS-1/mainPubQoS-1.cpp | 6 +- .../samples/ClientSub/mainSub.cpp | 6 +- .../GatewayTester/samples/mainTest.cpp | 6 +- MQTTSNGateway/GatewayTester/src/LGwProxy.cpp | 16 +- MQTTSNGateway/GatewayTester/src/LGwProxy.h | 4 +- .../GatewayTester/src/LMqttsnClient.cpp | 10 +- .../GatewayTester/src/LMqttsnClient.h | 2 +- .../GatewayTester/src/LMqttsnClientApp.h | 15 +- .../{LNetworkBle.cpp => LNetworkRfcomm.cpp} | 93 +++++----- .../src/{LNetworkBle.h => LNetworkRfcomm.h} | 29 ++-- .../GatewayTester/src/LNetworkUdp.cpp | 35 ++-- MQTTSNGateway/GatewayTester/src/LNetworkUdp.h | 4 +- MQTTSNGateway/README.md | 6 +- MQTTSNGateway/build.sh | 2 +- MQTTSNGateway/gateway.conf | 4 +- MQTTSNGateway/src/CMakeLists.txt | 2 +- .../linux/{ble => rfcomm}/SensorNetwork.cpp | 33 ++-- .../src/linux/{ble => rfcomm}/SensorNetwork.h | 10 +- MQTTSNPacket/samples/linux/rfcomm/build | 14 ++ MQTTSNPacket/samples/linux/rfcomm/pub0sub1.c | 164 ++++++++++++++++++ MQTTSNPacket/samples/linux/rfcomm/qos-1pub.c | 68 ++++++++ .../samples/linux/rfcomm/qos-1pub_extended.c | 70 ++++++++ MQTTSNPacket/samples/linux/rfcomm/qos0pub.c | 93 ++++++++++ .../samples/linux/rfcomm/qos0pub_register.c | 120 +++++++++++++ MQTTSNPacket/samples/linux/rfcomm/qos1pub.c | 105 +++++++++++ MQTTSNPacket/samples/linux/rfcomm/rfcomm.c | 115 ++++++++++++ MQTTSNPacket/samples/linux/rfcomm/rfcomm.h | 21 +++ travis-build.sh | 2 +- 31 files changed, 928 insertions(+), 165 deletions(-) rename MQTTSNGateway/GatewayTester/src/{LNetworkBle.cpp => LNetworkRfcomm.cpp} (68%) rename MQTTSNGateway/GatewayTester/src/{LNetworkBle.h => LNetworkRfcomm.h} (87%) rename MQTTSNGateway/src/linux/{ble => rfcomm}/SensorNetwork.cpp (92%) rename MQTTSNGateway/src/linux/{ble => rfcomm}/SensorNetwork.h (95%) create mode 100644 MQTTSNPacket/samples/linux/rfcomm/build create mode 100644 MQTTSNPacket/samples/linux/rfcomm/pub0sub1.c create mode 100644 MQTTSNPacket/samples/linux/rfcomm/qos-1pub.c create mode 100644 MQTTSNPacket/samples/linux/rfcomm/qos-1pub_extended.c create mode 100644 MQTTSNPacket/samples/linux/rfcomm/qos0pub.c create mode 100644 MQTTSNPacket/samples/linux/rfcomm/qos0pub_register.c create mode 100644 MQTTSNPacket/samples/linux/rfcomm/qos1pub.c create mode 100644 MQTTSNPacket/samples/linux/rfcomm/rfcomm.c create mode 100644 MQTTSNPacket/samples/linux/rfcomm/rfcomm.h diff --git a/.cproject b/.cproject index 6a486ab..fcd0270 100644 --- a/.cproject +++ b/.cproject @@ -135,7 +135,7 @@ - + @@ -279,9 +279,9 @@ - + - + @@ -325,18 +325,6 @@ - - - - - - - - - - - - @@ -348,6 +336,18 @@ + + + + + + + + + + + + diff --git a/MQTTSNGateway/GatewayTester/Makefile b/MQTTSNGateway/GatewayTester/Makefile index c94b65e..73f7bb9 100644 --- a/MQTTSNGateway/GatewayTester/Makefile +++ b/MQTTSNGateway/GatewayTester/Makefile @@ -20,7 +20,7 @@ CPPSRCS := \ $(SUBDIR)/LGwProxy.cpp \ $(SUBDIR)/LMqttsnClient.cpp \ $(SUBDIR)/LNetworkUdp.cpp \ -$(SUBDIR)/LNetworkBle.cpp \ +$(SUBDIR)/LNetworkRfcomm.cpp \ $(SUBDIR)/LPublishManager.cpp \ $(SUBDIR)/LRegisterManager.cpp \ $(SUBDIR)/LSubscribeManager.cpp \ diff --git a/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp b/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp index 0646ef4..a398f6e 100644 --- a/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp +++ b/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp @@ -59,10 +59,10 @@ UDPCONF = { }; /*------------------------------------------------------ - * BLE Configuration (theNetcon) + * RFCOMM Configuration (theNetcon) *------------------------------------------------------*/ -BLECONF = { "GatewayTestClient", // ClientId - { 0x60, 0x57, 0x18, 0x06, 0x8b, 0x72 }, // GW Address +RFCOMMCONF = { "GatewayTestClient", // ClientId + "60:57:18:06:8B:72", // GW Address 1, // Rfcomm channel }; diff --git a/MQTTSNGateway/GatewayTester/samples/ClientPubQoS-1/mainPubQoS-1.cpp b/MQTTSNGateway/GatewayTester/samples/ClientPubQoS-1/mainPubQoS-1.cpp index 2412485..f7df9a7 100644 --- a/MQTTSNGateway/GatewayTester/samples/ClientPubQoS-1/mainPubQoS-1.cpp +++ b/MQTTSNGateway/GatewayTester/samples/ClientPubQoS-1/mainPubQoS-1.cpp @@ -59,10 +59,10 @@ UDPCONF = { }; /*------------------------------------------------------ - * BLE Configuration (theNetcon) + * RFCOMM Configuration (theNetcon) *------------------------------------------------------*/ -BLECONF = { "GatewayTestClient", // ClientId - { 0x60, 0x57, 0x18, 0x06, 0x8b, 0x72 }, // GW Address +RFCOMMCONF = { "GatewayTestClient", // ClientId + "60:57:18:06:8B:72", // GW Address 1, // Rfcomm channel }; diff --git a/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp b/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp index 2cb03ec..6f73e2a 100644 --- a/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp +++ b/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp @@ -59,10 +59,10 @@ UDPCONF = { }; /*------------------------------------------------------ - * BLE Configuration (theNetcon) + * RFCOMM Configuration (theNetcon) *------------------------------------------------------*/ -BLECONF = { "GatewayTestClient", // ClientId - { 0x44, 0x1C, 0xA8, 0x16, 0x94, 0x94 }, // GW Address +RFCOMMCONF = { "GatewayTestClient", // ClientId + "60:57:18:06:8B:72", // GW Address 1, // Rfcomm channel }; diff --git a/MQTTSNGateway/GatewayTester/samples/mainTest.cpp b/MQTTSNGateway/GatewayTester/samples/mainTest.cpp index 316343e..88feb03 100644 --- a/MQTTSNGateway/GatewayTester/samples/mainTest.cpp +++ b/MQTTSNGateway/GatewayTester/samples/mainTest.cpp @@ -58,10 +58,10 @@ UDPCONF = { "GatewayTestClient", // ClientId }; /*------------------------------------------------------ - * BLE Configuration (theNetcon) + * RFCOMM Configuration (theNetcon) *------------------------------------------------------*/ -BLECONF = { "GatewayTestClient", // ClientId - { 0x60, 0x57, 0x18, 0x06, 0x8b, 0x72 }, // GW Address +RFCOMMCONF = { "GatewayTestClient", // ClientId + "60:57:18:06:8B:72", // GW Address 1, // Rfcomm channel }; diff --git a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp index 3214608..7757533 100644 --- a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp +++ b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp @@ -66,16 +66,16 @@ LGwProxy::~LGwProxy() _topicTbl.clearTopic(); } -void LGwProxy::initialize(SENSORNET_CONFIG_t netconf, LMqttsnConfig mqconf) +void LGwProxy::initialize(SENSORNET_CONFIG_t* netconf, LMqttsnConfig* mqconf) { _network.initialize(netconf); - _clientId = netconf.clientId; - _willTopic = mqconf.willTopic; - _willMsg = mqconf.willMsg; - _qosWill = mqconf.willQos; - _retainWill = mqconf.willRetain; - _cleanSession = mqconf.cleanSession; - _tkeepAlive = mqconf.keepAlive; + _clientId = netconf->clientId; + _willTopic = mqconf->willTopic; + _willMsg = mqconf->willMsg; + _qosWill = mqconf->willQos; + _retainWill = mqconf->willRetain; + _cleanSession = mqconf->cleanSession; + _tkeepAlive = mqconf->keepAlive; _initialized = 1; } diff --git a/MQTTSNGateway/GatewayTester/src/LGwProxy.h b/MQTTSNGateway/GatewayTester/src/LGwProxy.h index 1523c8f..546b52d 100644 --- a/MQTTSNGateway/GatewayTester/src/LGwProxy.h +++ b/MQTTSNGateway/GatewayTester/src/LGwProxy.h @@ -23,7 +23,7 @@ #include "LMqttsnClientApp.h" #include "LNetworkUdp.h" -#include "LNetworkBle.h" +#include "LNetworkRfcomm.h" #include "LRegisterManager.h" #include "LTimer.h" #include "LTopicTable.h" @@ -55,7 +55,7 @@ public: LGwProxy(); ~LGwProxy(); - void initialize(SENSORNET_CONFIG_t netconf, LMqttsnConfig mqconf); + void initialize(SENSORNET_CONFIG_t* netconf, LMqttsnConfig* mqconf); void connect(void); void disconnect(uint16_t sec = 0); int getMessage(void); diff --git a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp index 9e00556..b20de1e 100644 --- a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp +++ b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp @@ -53,8 +53,8 @@ int main(int argc, char** argv) printf("\n%s", PAHO_COPYRIGHT0); #if defined(UDP) printf(" UDP\n"); -#elif defined(BLE) - printf(" BLE\n"); +#elif defined(RFCOMM) + printf(" RFCOMM\n"); #else printf("\n"); #endif @@ -90,7 +90,7 @@ int main(int argc, char** argv) setup(); theClient->addTask(theClientMode); - theClient->initialize( theNetcon, theMqcon); + theClient->initialize( &theNetcon, &theMqcon); do { theClient->run(); @@ -115,10 +115,10 @@ LMqttsnClient::~LMqttsnClient() } -void LMqttsnClient::initialize(SENSORNET_CONFIG_t netconf, LMqttsnConfig mqconf) +void LMqttsnClient::initialize(SENSORNET_CONFIG_t* netconf, LMqttsnConfig* mqconf) { _gwProxy.initialize(netconf, mqconf); - setSleepDuration(mqconf.sleepDuration); + setSleepDuration(mqconf->sleepDuration); } void LMqttsnClient::addTask(bool clientMode) diff --git a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h index 1da241a..d46c61f 100644 --- a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h +++ b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h @@ -58,7 +58,7 @@ public: void unsubscribe(const char* topicName); void unsubscribe(const uint16_t topicId); void disconnect(uint16_t sleepInSecs); - void initialize(SENSORNET_CONFIG_t netconf, LMqttsnConfig mqconf); + void initialize(SENSORNET_CONFIG_t* netconf, LMqttsnConfig* mqconf); void run(void); void addTask(bool test); void setSleepDuration(uint32_t duration); diff --git a/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h b/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h index eb591c9..caa390f 100644 --- a/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h +++ b/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h @@ -22,7 +22,7 @@ ======================================*/ //#define CLIENT_MODE #define UDP -//#define BLE +//#define RFCOMM /*====================================== * Debug Flag ======================================*/ @@ -75,10 +75,10 @@ struct LUdpConfig uint16_t uPortNo; }; -struct LBleConfig +struct LRfcommConfig { const char* clientId; - uint8_t gwAddress[6]; + const char* gwAddress; uint8_t channel; }; @@ -100,13 +100,16 @@ typedef enum #ifdef UDP #define NETWORK_CONFIG UdpConfig theNetworkConfig #define UDPCONF LUdpConfig theNetcon -#define BLECONF LBleConfig theConf +#define RFCOMMCONF LRfcommConfig theConf #define SENSORNET_CONFIG_t LUdpConfig #else +#ifdef RFCOMM #define NETWORK_CONFIG BleConfig theNetworkConfig -#define BLECONF LBleConfig theNetcon +#define RFCOMMCONF LRfcommConfig theNetcon #define UDPCONF LUdpConfig theConf -#define SENSORNET_CONFIG_t LBleConfig +#define SENSORNET_CONFIG_t LRfcommConfig +#endif +#error "UDP and RFCOMM are not defined in LMqttsnClientApp.h" #endif #define CONNECT(...) theClient->getGwProxy()->connect(__VA_ARGS__) diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkBle.cpp b/MQTTSNGateway/GatewayTester/src/LNetworkRfcomm.cpp similarity index 68% rename from MQTTSNGateway/GatewayTester/src/LNetworkBle.cpp rename to MQTTSNGateway/GatewayTester/src/LNetworkRfcomm.cpp index fc21cf6..f44e8eb 100644 --- a/MQTTSNGateway/GatewayTester/src/LNetworkBle.cpp +++ b/MQTTSNGateway/GatewayTester/src/LNetworkRfcomm.cpp @@ -14,7 +14,7 @@ * Tomoaki Yamaguchi - initial API and implementation and/or initial documentation **************************************************************************************/ #include "LMqttsnClientApp.h" -#ifdef BLE +#ifdef RFCOMM #include #include @@ -29,7 +29,7 @@ #include #include -#include "LNetworkBle.h" +#include "LNetworkRfcomm.h" #include "LTimer.h" #include "LScreen.h" @@ -40,7 +40,7 @@ extern uint16_t getUint16(const uint8_t* pos); extern uint32_t getUint32(const uint8_t* pos); extern LScreen* theScreen; extern bool theClientMode; -extern LBleConfig theNetcon; +extern LRfcommConfig theNetcon; /*========================================= Class LNetwork =========================================*/ @@ -57,12 +57,12 @@ LNetwork::~LNetwork() int LNetwork::broadcast(const uint8_t* xmitData, uint16_t dataLen) { - return LBlePort::unicast(xmitData, dataLen); + return LRfcommPort::unicast(xmitData, dataLen); } int LNetwork::unicast(const uint8_t* xmitData, uint16_t dataLen) { - return LBlePort::unicast(xmitData, dataLen); + return LRfcommPort::unicast(xmitData, dataLen); } uint8_t* LNetwork::getMessage(int* len) @@ -70,7 +70,7 @@ uint8_t* LNetwork::getMessage(int* len) *len = 0; if (checkRecvBuf()) { - uint16_t recvLen = LBlePort::recv(_rxDataBuf, MQTTSN_MAX_PACKET_SIZE, false); + uint16_t recvLen = LRfcommPort::recv(_rxDataBuf, MQTTSN_MAX_PACKET_SIZE, false); if (recvLen < 0) { @@ -87,12 +87,7 @@ uint8_t* LNetwork::getMessage(int* len) { *len = _rxDataBuf[0]; } - //if(recvLen != *len){ - // *len = 0; - // return 0; - //}else{ return _rxDataBuf; - //} } } return 0; @@ -104,13 +99,13 @@ void LNetwork::setGwAddress(void) void LNetwork::setFixedGwAddress(void) { - _channel = LBlePort::_channel; - memcpy(_gwAddress, theNetcon.gwAddress, 6); + _channel = LRfcommPort::_channel; + str2ba( theNetcon.gwAddress, (bdaddr_t*)_gwAddress); } -bool LNetwork::initialize(LBleConfig config) +bool LNetwork::initialize(LRfcommConfig* config) { - return LBlePort::open(config); + return LRfcommPort::open(config); } void LNetwork::setSleep() @@ -124,55 +119,51 @@ bool LNetwork::isBroadcastable() } /*========================================= - Class BleStack + Class RFCOMM Stack =========================================*/ -LBlePort::LBlePort() +LRfcommPort::LRfcommPort() { _disconReq = false; - _sockBle = 0; + _sockRfcomm = 0; _channel = 0; } -LBlePort::~LBlePort() +LRfcommPort::~LRfcommPort() { close(); } -void LBlePort::close() +void LRfcommPort::close() { - if (_sockBle > 0) + if (_sockRfcomm > 0) { - ::close(_sockBle); - _sockBle = 0; + ::close(_sockRfcomm); + _sockRfcomm = 0; } } -bool LBlePort::open(LBleConfig config) +bool LRfcommPort::open(LRfcommConfig* config) { const int reuse = 1; - uint8_t* gw = config.gwAddress + 5; - for (int i = 0; i < 6; i++) - { - *(_gwAddress + i) = *gw--; - } - _channel = config.channel; + str2ba(config->gwAddress, (bdaddr_t*)_gwAddress); + _channel = config->channel; - if (_channel == 0 || _gwAddress == 0 || _devAddress == 0) + if (_channel == 0 || _gwAddress == 0 ) { - D_NWLOG("\033[0m\033[0;31merror BLE Address in BlePort::open\033[0m\033[0;37m\n"); - DISPLAY("\033[0m\033[0;31m\nerror BLE Address in BlePort::open\033[0m\033[0;37m\n"); + D_NWLOG("\033[0m\033[0;31merror Bluetooth Address in LRfcommPort::open\033[0m\033[0;37m\n"); + DISPLAY("\033[0m\033[0;31m\nerror Bluetooth Address in LRfcommPort::open\033[0m\033[0;37m\n"); return false; } - _sockBle = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); - if (_sockBle < 0) + _sockRfcomm = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + if (_sockRfcomm < 0) { - D_NWLOG("\033[0m\033[0;31merror Can't create socket in BlePort::open\033[0m\033[0;37m\n"); - DISPLAY("\033[0m\033[0;31m\nerror Can't create socket in BlePort::open\033[0m\033[0;37m\n"); + D_NWLOG("\033[0m\033[0;31merror Can't create socket in LRfcommPort::open\033[0m\033[0;37m\n"); + DISPLAY("\033[0m\033[0;31m\nerror Can't create socket in LRfcommPort::open\033[0m\033[0;37m\n"); return false; } - setsockopt(_sockBle, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); + setsockopt(_sockRfcomm, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); struct sockaddr_rc addru = { 0 }; addru.rc_family = AF_BLUETOOTH; @@ -185,24 +176,24 @@ bool LBlePort::open(LBleConfig config) // connect to server errno = 0; - int status = connect(_sockBle, (struct sockaddr *) &addru, sizeof(addru)); + int status = connect(_sockRfcomm, (struct sockaddr *) &addru, sizeof(addru)); if (status < 0) { - D_NWLOG("\033[0m\033[0;31merror = %d Can't connect to GW in BlePort::open\033[0m\033[0;37m\n", errno); - DISPLAY("\033[0m\033[0;31mCan't connect to GW Ble socket in BlePort::open\033[0m\033[0;37m\n"); + D_NWLOG("\033[0m\033[0;31merror = %d Can't connect to GW in LRfcommPort::open\033[0m\033[0;37m\n", errno); + DISPLAY("\033[0m\033[0;31merror = %d Can't connect to GW Ble socket in LRfcommPort::open\033[0m\033[0;37m\n",errno); close(); return false; } return true; } -int LBlePort::unicast(const uint8_t* buf, uint32_t length) +int LRfcommPort::unicast(const uint8_t* buf, uint32_t length) { - int status = ::write(_sockBle, buf, length); + int status = ::write(_sockRfcomm, buf, length); if (status < 0) { - D_NWLOG("errno == %d in LBlePort::unicast\n", errno); - DISPLAY("errno == %d in LBlePort::unicast\n", errno); + D_NWLOG("errno == %d in LRfcommPort::unicast\n", errno); + DISPLAY("errno == %d in LRfcommPort::unicast\n", errno); } else { @@ -235,25 +226,25 @@ int LBlePort::unicast(const uint8_t* buf, uint32_t length) return status; } -bool LBlePort::checkRecvBuf() +bool LRfcommPort::checkRecvBuf() { uint8_t buf[2]; - if (::recv(_sockBle, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0) + if (::recv(_sockRfcomm, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0) { return true; } return false; } -int LBlePort::recv(uint8_t* buf, uint16_t length, bool flg) +int LRfcommPort::recv(uint8_t* buf, uint16_t length, bool flg) { int flags = flg ? MSG_DONTWAIT : 0; - int status = ::recv(_sockBle, buf, length, flags); + int status = ::recv(_sockRfcomm, buf, length, flags); if (status < 0 && errno != EAGAIN) { - D_NWLOG("\033[0m\033[0;31merrno == %d in BlePort::recv \033[0m\033[0;37m\n", errno); - DISPLAY("\033[0m\033[0;31merrno == %d in BlePort::recv \033[0m\033[0;37m\n", errno); + D_NWLOG("\033[0m\033[0;31merrno = %d in LRfcommPort::recv \033[0m\033[0;37m\n", errno); + DISPLAY("\033[0m\033[0;31merrno = %d in LRfcommPort::recv \033[0m\033[0;37m\n", errno); } else if (status > 0) { diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkBle.h b/MQTTSNGateway/GatewayTester/src/LNetworkRfcomm.h similarity index 87% rename from MQTTSNGateway/GatewayTester/src/LNetworkBle.h rename to MQTTSNGateway/GatewayTester/src/LNetworkRfcomm.h index f2aab0c..0228295 100644 --- a/MQTTSNGateway/GatewayTester/src/LNetworkBle.h +++ b/MQTTSNGateway/GatewayTester/src/LNetworkRfcomm.h @@ -14,11 +14,11 @@ * Tomoaki Yamaguchi - initial API and implementation and/or initial documentation **************************************************************************************/ -#ifndef NETWORKBLE_H_ -#define NETWORKBLE_H_ +#ifndef NETWORKRFCOMM_H_ +#define NETWORKRFCOMM_H_ #include "LMqttsnClientApp.h" -#ifdef BLE +#ifdef RFCOMM #include #include @@ -44,17 +44,15 @@ using namespace std; namespace linuxAsyncClient { /*======================================== - Class LBlePort + Class LRfcommPort =======================================*/ -class LBlePort +class LRfcommPort { friend class LNetwork; public: - LBlePort(); - virtual ~LBlePort(); - - bool open(LBleConfig config); - + LRfcommPort(); + virtual ~LRfcommPort(); + bool open(LRfcommConfig* config); int unicast(const uint8_t* buf, uint32_t length); int recv(uint8_t* buf, uint16_t len, bool nonblock); bool checkRecvBuf(); @@ -63,8 +61,7 @@ public: private: void close(); - int _sockBle; - uint8_t _devAddress[6]; + int _sockRfcomm; uint8_t _gwAddress[6]; uint8_t _channel; bool _disconReq; @@ -76,7 +73,7 @@ private: /*=========================================== Class Network ============================================*/ -class LNetwork: public LBlePort +class LNetwork: public LRfcommPort { public: LNetwork(); @@ -87,7 +84,7 @@ public: void setGwAddress(void); void resetGwAddress(void); void setFixedGwAddress(void); - bool initialize(LBleConfig config); + bool initialize(LRfcommConfig* config); uint8_t* getMessage(int* len); bool isBroadcastable(); @@ -102,5 +99,5 @@ private: }; } /* end of namespace */ -#endif /* BLE */ -#endif /* NETWORKBLE_H_ */ +#endif /* RFCOMM */ +#endif /* NETWORKRFCOM_H_ */ diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp b/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp index 93d112f..9a830b6 100644 --- a/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp +++ b/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp @@ -104,7 +104,7 @@ void LNetwork::resetGwAddress(void){ } -bool LNetwork::initialize(LUdpConfig config){ +bool LNetwork::initialize(LUdpConfig* config){ return LUdpPort::open(config); } @@ -119,43 +119,48 @@ bool LNetwork::isBroadcastable() /*========================================= Class udpStack =========================================*/ -LUdpPort::LUdpPort(){ +LUdpPort::LUdpPort() +{ _disconReq = false; _sockfdUcast = -1; _sockfdMcast = -1; _castStat = 0; } -LUdpPort::~LUdpPort(){ +LUdpPort::~LUdpPort() +{ close(); } void LUdpPort::close(){ - if(_sockfdMcast > 0){ + if(_sockfdMcast > 0) + { ::close( _sockfdMcast); _sockfdMcast = -1; - if(_sockfdUcast > 0){ + if(_sockfdUcast > 0) + { ::close( _sockfdUcast); _sockfdUcast = -1; } } } -bool LUdpPort::open(LUdpConfig config){ +bool LUdpPort::open(LUdpConfig* config) +{ const int reuse = 1; char loopch = 1; - uint8_t sav = config.ipAddress[3]; - config.ipAddress[3] = config.ipAddress[0]; - config.ipAddress[0] = sav; - sav = config.ipAddress[2]; - config.ipAddress[2] = config.ipAddress[1]; - config.ipAddress[1] = sav; + uint8_t sav = config->ipAddress[3]; + config->ipAddress[3] = config->ipAddress[0]; + config->ipAddress[0] = sav; + sav = config->ipAddress[2]; + config->ipAddress[2] = config->ipAddress[1]; + config->ipAddress[1] = sav; - _gPortNo = htons(config.gPortNo); - _gIpAddr = getUint32((const uint8_t*)config.ipAddress); - _uPortNo = htons(config.uPortNo); + _gPortNo = htons(config->gPortNo); + _gIpAddr = getUint32((const uint8_t*)config->ipAddress); + _uPortNo = htons(config->uPortNo); if( _gPortNo == 0 || _gIpAddr == 0 || _uPortNo == 0){ return false; diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkUdp.h b/MQTTSNGateway/GatewayTester/src/LNetworkUdp.h index 5189f67..6f7be33 100644 --- a/MQTTSNGateway/GatewayTester/src/LNetworkUdp.h +++ b/MQTTSNGateway/GatewayTester/src/LNetworkUdp.h @@ -51,7 +51,7 @@ public: LUdpPort(); virtual ~LUdpPort(); - bool open(LUdpConfig config); + bool open(LUdpConfig* config); int unicast(const uint8_t* buf, uint32_t length, uint32_t ipaddress, uint16_t port ); int multicast( const uint8_t* buf, uint32_t length ); @@ -89,7 +89,7 @@ public: void setGwAddress(void); void resetGwAddress(void); void setFixedGwAddress(void); - bool initialize(LUdpConfig config); + bool initialize(LUdpConfig* config); uint8_t* getMessage(int* len); bool isBroadcastable(); private: diff --git a/MQTTSNGateway/README.md b/MQTTSNGateway/README.md index 7af1f07..4bc5192 100644 --- a/MQTTSNGateway/README.md +++ b/MQTTSNGateway/README.md @@ -7,7 +7,7 @@ This Gateway can run as a transparent or aggregating Gateway by specifying the g ```` $ git clone -b develop https://github.com/eclipse/paho.mqtt-sn.embedded-c $ cd paho.mqtt-sn.embedded-c/MQTTSNGateway -$ ./build.sh [udp|udp6|xbee|loralink | ble] +$ ./build.sh [udp|udp6|xbee|loralink|rfcomm] ```` In order to build a gateway, an argument is required. @@ -92,8 +92,8 @@ BaudrateLoRaLink=115200 DeviceRxLoRaLink=/dev/ttyLoRaLinkRx DeviceTxLoRaLink=/dev/ttyLoRaLinkTx -# BLE RFCOMM -BleAddress=60:57:18:06:8B:72.* +# Bluetooth RFCOMM +RFCOMMAddress=60:57:18:06:8B:72.* # LOG ShearedMemory=NO; diff --git a/MQTTSNGateway/build.sh b/MQTTSNGateway/build.sh index bb56302..b5ed316 100755 --- a/MQTTSNGateway/build.sh +++ b/MQTTSNGateway/build.sh @@ -1,7 +1,7 @@ #!/bin/bash if [ $# -eq 0 ]; then - echo "Usage: build.sh { udp | udp6 | xbee | loralink }" + echo "Usage: build.sh [ udp | udp6 | xbee | loralink | rfcomm ]" else echo "Start building MQTT-SN Gateway" diff --git a/MQTTSNGateway/gateway.conf b/MQTTSNGateway/gateway.conf index 3321576..f6fb401 100644 --- a/MQTTSNGateway/gateway.conf +++ b/MQTTSNGateway/gateway.conf @@ -69,8 +69,8 @@ BaudrateLoRaLink=115200 DeviceRxLoRaLink=/dev/loralinkRx DeviceTxLoRaLink=/dev/loralinkTx -# BLE RFCOMM -BleAddress=60:57:18:06:8B:72.* +# Bluetooth RFCOMM +RFCOMMAddress=60:57:18:06:8B:72.* # LOG ShearedMemory=NO; diff --git a/MQTTSNGateway/src/CMakeLists.txt b/MQTTSNGateway/src/CMakeLists.txt index a1606a6..0b1c9d7 100644 --- a/MQTTSNGateway/src/CMakeLists.txt +++ b/MQTTSNGateway/src/CMakeLists.txt @@ -87,7 +87,7 @@ TARGET_INCLUDE_DIRECTORIES(mqtt-sngateway_common /usr/local/opt/openssl/include ) -IF(SENSORNET MATCHES "ble") +IF(SENSORNET MATCHES "rfcomm") TARGET_LINK_LIBRARIES(mqtt-sngateway_common PRIVATE diff --git a/MQTTSNGateway/src/linux/ble/SensorNetwork.cpp b/MQTTSNGateway/src/linux/rfcomm/SensorNetwork.cpp similarity index 92% rename from MQTTSNGateway/src/linux/ble/SensorNetwork.cpp rename to MQTTSNGateway/src/linux/rfcomm/SensorNetwork.cpp index f5ef3fe..e8d6bcd 100644 --- a/MQTTSNGateway/src/linux/ble/SensorNetwork.cpp +++ b/MQTTSNGateway/src/linux/rfcomm/SensorNetwork.cpp @@ -158,7 +158,7 @@ SensorNetwork::~SensorNetwork() int SensorNetwork::unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendToAddr) { uint16_t ch = sendToAddr->getPortNo(); - BlePort* blep = &_rfPorts[ch - 1]; + RfcommPort* blep = &_rfPorts[ch - 1]; int rc = 0; errno = 0; @@ -220,7 +220,6 @@ int SensorNetwork::read(uint8_t* buf, uint16_t bufLen) int rc = 0; if (select(maxSock + 1, &recvfds, 0, 0, &timeout) > 0) { - WRITELOG("RECV\n"); for (int i = 0; i < MAX_RFCOMM_CH; i++) { if (_rfPorts[i]._rfCommSock > 0) @@ -243,7 +242,6 @@ int SensorNetwork::read(uint8_t* buf, uint16_t bufLen) { _rfPorts[i]._rfCommSock = sock; } - WRITELOG("accept sock= %d CH = %d\n", sock, i + 1); } } } @@ -269,24 +267,24 @@ void SensorNetwork::initialize(void) * in Gateway.conf e.g. * * # BLE - * BleAddress=XX:XX:XX:XX:XX:XX.0 + * RFCOMM=XX:XX:XX:XX:XX:XX.0 * */ - if (theProcess->getParam("BleAddress", param) == 0) + if (theProcess->getParam("RFCOMMAddress", param) == 0) { devAddr = param; - _description = "BLE RFCOMM "; + _description = "Bluetooth RFCOMM "; _description += param; } errno = 0; if (sa.setAddress(&devAddr) == -1) { - throw EXCEPTION("Invalid BLE Address", errno); + throw EXCEPTION("Invalid Bluetooth Address", errno); } /* Prepare BLE sockets */ - WRITELOG("Initialize ble\n"); + WRITELOG("Initialize RFCOMM\n"); int rc = MAX_RFCOMM_CH; for (uint16_t i = 0; i < MAX_RFCOMM_CH; i++) { @@ -295,7 +293,7 @@ void SensorNetwork::initialize(void) } if (rc == 0) { - throw EXCEPTION("Can't open BLE RFComms", errno); + throw EXCEPTION("Can't open Bluetooth RFComms", errno); } } @@ -313,7 +311,7 @@ SensorNetAddress* SensorNetwork::getSenderAddress(void) Class BleStack =========================================*/ -BlePort::BlePort() +RfcommPort::RfcommPort() { _disconReq = false; _rfCommSock = 0; @@ -321,7 +319,7 @@ BlePort::BlePort() _channel = 0; } -BlePort::~BlePort() +RfcommPort::~RfcommPort() { close(); @@ -331,7 +329,7 @@ BlePort::~BlePort() } } -void BlePort::close(void) +void RfcommPort::close(void) { if (_rfCommSock > 0) { @@ -340,7 +338,7 @@ void BlePort::close(void) } } -int BlePort::open(bdaddr_t* devAddr, uint16_t channel) +int RfcommPort::open(bdaddr_t* devAddr, uint16_t channel) { const int reuse = 1; @@ -380,13 +378,12 @@ int BlePort::open(bdaddr_t* devAddr, uint16_t channel) return 1; } -int BlePort::send(const uint8_t* buf, uint32_t length) +int RfcommPort::send(const uint8_t* buf, uint32_t length) { - WRITELOG("sock = %d\n", _rfCommSock); return ::send(_rfCommSock, buf, length, 0); } -int BlePort::recv(uint8_t* buf, uint16_t len) +int RfcommPort::recv(uint8_t* buf, uint16_t len) { int rc = 0; errno = 0; @@ -400,7 +397,7 @@ int BlePort::recv(uint8_t* buf, uint16_t len) return rc; } -int BlePort::accept(SensorNetAddress* addr) +int RfcommPort::accept(SensorNetAddress* addr) { struct sockaddr_rc devAddr = { 0 }; socklen_t opt = sizeof(devAddr); @@ -419,7 +416,7 @@ int BlePort::accept(SensorNetAddress* addr) return sock; } -int BlePort::getSock(void) +int RfcommPort::getSock(void) { return _rfCommSock; } diff --git a/MQTTSNGateway/src/linux/ble/SensorNetwork.h b/MQTTSNGateway/src/linux/rfcomm/SensorNetwork.h similarity index 95% rename from MQTTSNGateway/src/linux/ble/SensorNetwork.h rename to MQTTSNGateway/src/linux/rfcomm/SensorNetwork.h index 7a4ffe8..1a90b42 100644 --- a/MQTTSNGateway/src/linux/ble/SensorNetwork.h +++ b/MQTTSNGateway/src/linux/rfcomm/SensorNetwork.h @@ -55,14 +55,14 @@ private: }; /*======================================== - Class BlePort + Class RfcommPort =======================================*/ -class BlePort +class RfcommPort { friend class SensorNetwork; public: - BlePort(); - virtual ~BlePort(); + RfcommPort(); + virtual ~RfcommPort(); int open(bdaddr_t* devAddress, uint16_t channel); void close(void); @@ -95,7 +95,7 @@ public: private: // sockets for RFCOMM - BlePort _rfPorts[MAX_RFCOMM_CH]; + RfcommPort _rfPorts[MAX_RFCOMM_CH]; SensorNetAddress _senderAddr; string _description; }; diff --git a/MQTTSNPacket/samples/linux/rfcomm/build b/MQTTSNPacket/samples/linux/rfcomm/build new file mode 100644 index 0000000..5c3702f --- /dev/null +++ b/MQTTSNPacket/samples/linux/rfcomm/build @@ -0,0 +1,14 @@ +rm -rf bin +mkdir bin +cd bin + +PKTSRC=../../../../src +SRC=.. +gcc -Wall -c $SRC/rfcomm.c -Os -s +gcc -Wall $SRC/qos0pub.c rfcomm.o -lbluetooth -I $PKTSRC $PKTSRC/MQTTSNSerializePublish.c $PKTSRC/MQTTSNPacket.c $PKTSRC/MQTTSNConnectClient.c -o qos0pub -Os -s +gcc -Wall $SRC/qos0pub_register.c rfcomm.o -lbluetooth -I $PKTSRC $PKTSRC/MQTTSNSerializePublish.c $PKTSRC/MQTTSNDeserializePublish.c $PKTSRC/MQTTSNPacket.c $PKTSRC/MQTTSNConnectClient.c -o qos0pub_register -Os -s +gcc -Wall $SRC/qos-1pub.c rfcomm.o -lbluetooth -I $PKTSRC $PKTSRC/MQTTSNSerializePublish.c $PKTSRC/MQTTSNPacket.c -o qos-1pub -Os -s +gcc -Wall $SRC/qos-1pub_extended.c rfcomm.o -lbluetooth -I $PKTSRC $PKTSRC/MQTTSNSerializePublish.c $PKTSRC/MQTTSNPacket.c -o qos-1pub_extended -Os -s +gcc -Wall $SRC/qos1pub.c rfcomm.o -lbluetooth -I $PKTSRC $PKTSRC/MQTTSNSerializePublish.c $PKTSRC/MQTTSNDeserializePublish.c $PKTSRC/MQTTSNPacket.c $PKTSRC/MQTTSNConnectClient.c -o qos1pub -Os -s +gcc -Wall $SRC/pub0sub1.c rfcomm.o -lbluetooth -I $PKTSRC $PKTSRC/MQTTSNSerializePublish.c $PKTSRC/MQTTSNDeserializePublish.c $PKTSRC/MQTTSNPacket.c $PKTSRC/MQTTSNConnectClient.c $PKTSRC/MQTTSNSubscribeClient.c -o pub0sub1 -Os -s +rm rfcomm.o diff --git a/MQTTSNPacket/samples/linux/rfcomm/pub0sub1.c b/MQTTSNPacket/samples/linux/rfcomm/pub0sub1.c new file mode 100644 index 0000000..b0ff3e2 --- /dev/null +++ b/MQTTSNPacket/samples/linux/rfcomm/pub0sub1.c @@ -0,0 +1,164 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + * Sergio R. Caprile - clarifications and/or documentation extension + * + * Description: + * Normal topic name is automatically registered at subscription, then + * a message is published and the node receives it itself + *******************************************************************************/ + +#include +#include +#include + +#include "MQTTSNPacket.h" +#include "rfcomm.h" + + +int main(int argc, char** argv) +{ + int rc = 0; + unsigned char buf[200]; + int buflen = sizeof(buf); + MQTTSN_topicid topic; + unsigned char* payload = (unsigned char*)"mypayload"; + int payloadlen = strlen((char*)payload); + int len = 0; + unsigned char dup = 0; + int qos = 1; + unsigned char retained = 0; + short packetid = 1; + char *topicname = "a long topic name"; + char *host = ""; + int channel = 1; + MQTTSNPacket_connectData options = MQTTSNPacket_connectData_initializer; + unsigned short topicid; + + if (argc > 1) + host = argv[1]; + + if (argc > 2) + channel = atoi(argv[2]); + + printf("Sending to address %s channel %d\n", host, channel); + if (rfcomm_open(host, channel) < 0) + { + goto exit; + } + + options.clientID.cstring = "pub0sub1 MQTT-SN"; + len = MQTTSNSerialize_connect(buf, buflen, &options); + rc = rfcomm_sendPacketBuffer(buf, len); + + /* wait for connack */ + if (MQTTSNPacket_read(buf, buflen, rfcomm_getdata) == MQTTSN_CONNACK) + { + int connack_rc = -1; + + if (MQTTSNDeserialize_connack(&connack_rc, buf, buflen) != 1 || connack_rc != 0) + { + printf("Unable to connect, return code %d\n", connack_rc); + goto exit; + } + else + printf("connected rc %d\n", connack_rc); + } + else + goto exit; + + + /* subscribe */ + printf("Subscribing\n"); + topic.type = MQTTSN_TOPIC_TYPE_NORMAL; + topic.data.long_.name = topicname; + topic.data.long_.len = strlen(topic.data.long_.name); + len = MQTTSNSerialize_subscribe(buf, buflen, 0, 2, packetid, &topic); + rc = rfcomm_sendPacketBuffer(buf, len); + + if (MQTTSNPacket_read(buf, buflen, rfcomm_getdata) == MQTTSN_SUBACK) /* wait for suback */ + { + unsigned short submsgid; + int granted_qos; + unsigned char returncode; + + rc = MQTTSNDeserialize_suback(&granted_qos, &topicid, &submsgid, &returncode, buf, buflen); + if (granted_qos != 2 || returncode != 0) + { + printf("granted qos != 2, %d return code %d\n", granted_qos, returncode); + goto exit; + } + else + printf("suback topic id %d\n", topicid); + } + else + goto exit; + + printf("Publishing\n"); + /* publish with short name */ + topic.type = MQTTSN_TOPIC_TYPE_NORMAL; + topic.data.id = topicid; + ++packetid; + len = MQTTSNSerialize_publish(buf, buflen, dup, qos, retained, packetid, + topic, payload, payloadlen); + rc = rfcomm_sendPacketBuffer(buf, len); + + /* wait for puback */ + if (MQTTSNPacket_read(buf, buflen, rfcomm_getdata) == MQTTSN_PUBACK) + { + unsigned short packet_id, topic_id; + unsigned char returncode; + + if (MQTTSNDeserialize_puback(&topic_id, &packet_id, &returncode, buf, buflen) != 1 || returncode != MQTTSN_RC_ACCEPTED) + printf("Unable to publish, return code %d\n", returncode); + else + printf("puback received, msgid %d topic id %d\n", packet_id, topic_id); + } + else + goto exit; + + printf("Receive publish\n"); + if (MQTTSNPacket_read(buf, buflen, rfcomm_getdata) == MQTTSN_PUBLISH) + { + unsigned short packet_id; + int qos, payloadlen; + unsigned char* payload; + unsigned char dup, retained; + MQTTSN_topicid pubtopic; + + if (MQTTSNDeserialize_publish(&dup, &qos, &retained, &packet_id, &pubtopic, + &payload, &payloadlen, buf, buflen) != 1) + printf("Error deserializing publish\n"); + else + printf("publish received, id %d qos %d\n", packet_id, qos); + + if (qos == 1) + { + len = MQTTSNSerialize_puback(buf, buflen, pubtopic.data.id, packet_id, MQTTSN_RC_ACCEPTED); + rc = rfcomm_sendPacketBuffer(buf, len); + if (rc == 0) + printf("puback sent\n"); + } + } + else + goto exit; + + len = MQTTSNSerialize_disconnect(buf, buflen, 0); + rc = rfcomm_sendPacketBuffer(buf, len); + +exit: + rfcomm_close(); + + return 0; +} diff --git a/MQTTSNPacket/samples/linux/rfcomm/qos-1pub.c b/MQTTSNPacket/samples/linux/rfcomm/qos-1pub.c new file mode 100644 index 0000000..3931870 --- /dev/null +++ b/MQTTSNPacket/samples/linux/rfcomm/qos-1pub.c @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + * Sergio R. Caprile - clarifications and/or documentation extension + * + * Description: + * A qos -1 message can be sent without connecting + * Short topic name used to avoid registration process + *******************************************************************************/ + +#include +#include +#include + +#include "MQTTSNPacket.h" +#include "rfcomm.h" + + +int main(int argc, char** argv) +{ + unsigned char buf[200]; + int buflen = sizeof(buf); + MQTTSN_topicid topic; + unsigned char* payload = (unsigned char*)"mypayload"; + int payloadlen = strlen((char*)payload); + int len = 0; + int dup = 0; + int qos = 3; + int retained = 0; + short packetid = 0; + char *host = ""; + int channel = 1; + + if (argc > 1) + host = argv[1]; + + if (argc > 2) + channel = atoi(argv[2]); + + printf("Sending to address %s channel %d\n", host, channel); + if (rfcomm_open(host, channel) < 0) + { + return -1; + } + + /* publish with short name */ + topic.type = MQTTSN_TOPIC_TYPE_SHORT; + memcpy(topic.data.short_name, "tt", 2); + len = MQTTSNSerialize_publish(buf, buflen, dup, qos, retained, packetid, + topic, payload, payloadlen); + + rfcomm_sendPacketBuffer(buf, len); + + rfcomm_close(); + + return 0; +} diff --git a/MQTTSNPacket/samples/linux/rfcomm/qos-1pub_extended.c b/MQTTSNPacket/samples/linux/rfcomm/qos-1pub_extended.c new file mode 100644 index 0000000..098de73 --- /dev/null +++ b/MQTTSNPacket/samples/linux/rfcomm/qos-1pub_extended.c @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + * Sergio R. Caprile - clarifications and/or documentation extension + * + * Description: + * Extension to the specs in which a node can send a normal (long) topic name inside the + * payload area to avoid the registration process and the usage of short/predefined types + *******************************************************************************/ + +#include +#include +#include + +#include "MQTTSNPacket.h" +#include "rfcomm.h" + + +int main(int argc, char** argv) +{ + unsigned char buf[200]; + int buflen = sizeof(buf); + MQTTSN_topicid topic; + unsigned char* payload = (unsigned char*)"mypayload"; + int payloadlen = strlen((char*)payload); + int len = 0; + int dup = 0; + int qos = 3; + int retained = 0; + short packetid = 0; + char *topicname = "a long topic name"; + char *host = ""; + int channel = 1; + + if (argc > 1) + host = argv[1]; + + if (argc > 2) + channel = atoi(argv[2]); + + printf("Sending to Address %s channel %d\n", host, channel); + if (rfcomm_open(host, channel) < 0) + { + return -1;; + } + + topic.type = MQTTSN_TOPIC_TYPE_NORMAL; + topic.data.long_.name = topicname; + topic.data.long_.len = strlen(topicname); + + len = MQTTSNSerialize_publish(buf, buflen, dup, qos, retained, packetid, + topic, payload, payloadlen); + + rfcomm_sendPacketBuffer(buf, len); + + rfcomm_close(); + + return 0; +} diff --git a/MQTTSNPacket/samples/linux/rfcomm/qos0pub.c b/MQTTSNPacket/samples/linux/rfcomm/qos0pub.c new file mode 100644 index 0000000..e2fa09b --- /dev/null +++ b/MQTTSNPacket/samples/linux/rfcomm/qos0pub.c @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + * Sergio R. Caprile - clarifications and/or documentation extension + * + * Description: + * Short topic name used to avoid registration process + *******************************************************************************/ + +#include +#include +#include + +#include "MQTTSNPacket.h" +#include "rfcomm.h" + + +int main(int argc, char** argv) +{ + int rc = 0; + unsigned char buf[200]; + int buflen = sizeof(buf); + MQTTSN_topicid topic; + unsigned char* payload = (unsigned char*)"mypayload"; + int payloadlen = strlen((char*)payload); + int len = 0; + int dup = 0; + int qos = 0; + int retained = 0; + short packetid = 0; +// char *topicname = "a long topic name"; + char *host = ""; + int channel = 1; + MQTTSNPacket_connectData options = MQTTSNPacket_connectData_initializer; + + if (argc > 1) + host = argv[1]; + + if (argc > 2) + channel = atoi(argv[2]); + + printf("Sending to address %s port %d\n", host, channel); + if (rfcomm_open(host, channel) < 0) + { + goto exit; + } + + options.clientID.cstring = "myclientid"; + len = MQTTSNSerialize_connect(buf, buflen, &options); + rc = rfcomm_sendPacketBuffer(buf, len); + + /* wait for connack */ + if (MQTTSNPacket_read(buf, buflen, rfcomm_getdata) == MQTTSN_CONNACK) + { + int connack_rc = -1; + + if (MQTTSNDeserialize_connack(&connack_rc, buf, buflen) != 1 || connack_rc != 0) + { + printf("Unable to connect, return code %d\n", connack_rc); + goto exit; + } + else + printf("connected rc %d\n", connack_rc); + } + else + goto exit; + + + /* publish with short name */ + topic.type = MQTTSN_TOPIC_TYPE_SHORT; + memcpy(topic.data.short_name, "tt", 2); + len = MQTTSNSerialize_publish(buf, buflen, dup, qos, retained, packetid, + topic, payload, payloadlen); + rc = rfcomm_sendPacketBuffer(buf, len); + + printf("rc %d from send packet for publish length %d\n", rc, len); + +exit: + rfcomm_close(); + + return 0; +} diff --git a/MQTTSNPacket/samples/linux/rfcomm/qos0pub_register.c b/MQTTSNPacket/samples/linux/rfcomm/qos0pub_register.c new file mode 100644 index 0000000..1be0d50 --- /dev/null +++ b/MQTTSNPacket/samples/linux/rfcomm/qos0pub_register.c @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + * Sergio R. Caprile - clarifications and/or documentation extension + * + * Description: + * Normal topic name used to show registration process + *******************************************************************************/ + +#include +#include +#include + +#include "MQTTSNPacket.h" +#include "rfcomm.h" + + +int main(int argc, char** argv) +{ + int rc = 0; + unsigned char buf[200]; + int buflen = sizeof(buf); + MQTTSN_topicid topic; + MQTTSNString topicstr; + unsigned char* payload = (unsigned char*)"mypayload"; + int payloadlen = strlen((char*)payload); + int len = 0; + int dup = 0; + int qos = 0; + int retained = 0; + short packetid = 0; + char *topicname = "a long topic name"; + char *host = ""; + int channel = 1; + MQTTSNPacket_connectData options = MQTTSNPacket_connectData_initializer; + unsigned short topicid; + + if (argc > 1) + host = argv[1]; + + if (argc > 2) + channel = atoi(argv[2]); + + printf("Sending to address %s channel %d\n", host, channel); + if (rfcomm_open(host, (unsigned char) channel) < 0) + { + goto exit; + } + + options.clientID.cstring = "myclientid"; + len = MQTTSNSerialize_connect(buf, buflen, &options); + rc = rfcomm_sendPacketBuffer(buf, len); + + /* wait for connack */ + if (MQTTSNPacket_read(buf, buflen, rfcomm_getdata) == MQTTSN_CONNACK) + { + int connack_rc = -1; + + if (MQTTSNDeserialize_connack(&connack_rc, buf, buflen) != 1 || connack_rc != 0) + { + printf("Unable to connect, return code %d\n", connack_rc); + goto exit; + } + else + printf("connected rc %d\n", connack_rc); + } + else + goto exit; + + /* register topic name */ + printf("Registering\n"); + topicstr.cstring = topicname; + topicstr.lenstring.len = strlen(topicname); + len = MQTTSNSerialize_register(buf, buflen, 0, packetid, &topicstr); + rc = rfcomm_sendPacketBuffer(buf, len); + + if (MQTTSNPacket_read(buf, buflen, rfcomm_getdata) == MQTTSN_REGACK) /* wait for regack */ + { + unsigned short submsgid; + unsigned char returncode; + + rc = MQTTSNDeserialize_regack(&topicid, &submsgid, &returncode, buf, buflen); + if (returncode != 0) + { + printf("return code %d\n", returncode); + goto exit; + } + else + printf("regack topic id %d\n", topicid); + } + else + goto exit; + + /* publish with obtained id */ + printf("Publishing\n"); + topic.type = MQTTSN_TOPIC_TYPE_NORMAL; + topic.data.id = topicid; + ++packetid; + len = MQTTSNSerialize_publish(buf, buflen, dup, qos, retained, packetid, + topic, payload, payloadlen); + rc = rfcomm_sendPacketBuffer(buf, len); + + printf("rc %d from send packet for publish length %d\n", rc, len); + +exit: + rfcomm_close(); + + return 0; +} diff --git a/MQTTSNPacket/samples/linux/rfcomm/qos1pub.c b/MQTTSNPacket/samples/linux/rfcomm/qos1pub.c new file mode 100644 index 0000000..1ab61be --- /dev/null +++ b/MQTTSNPacket/samples/linux/rfcomm/qos1pub.c @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + * Sergio R. Caprile - clarifications and/or documentation extension + * + * Description: + * Short topic name used to avoid registration process + *******************************************************************************/ + +#include +#include +#include + +#include "MQTTSNPacket.h" +#include "rfcomm.h" + + +int main(int argc, char** argv) +{ + unsigned char buf[200]; + int buflen = sizeof(buf); + MQTTSN_topicid topic; + unsigned char* payload = (unsigned char*)"mypayload"; + int payloadlen = strlen((char*)payload); + int len = 0; + int dup = 0; + int qos = 1; + int retained = 0; + short packetid = 1; + char *host = ""; + int channel = 1; + MQTTSNPacket_connectData options = MQTTSNPacket_connectData_initializer; + + if (argc > 1) + host = argv[1]; + + if (argc > 2) + channel = atoi(argv[2]); + + printf("Sending to address %s channel %d\n", host, channel); + if (rfcomm_open(host, channel) < 0) + { + goto exit; + } + + options.clientID.cstring = "myclientid"; + len = MQTTSNSerialize_connect(buf, buflen, &options); + rfcomm_sendPacketBuffer(buf, len); + + /* wait for connack */ + if (MQTTSNPacket_read(buf, buflen, rfcomm_getdata) == MQTTSN_CONNACK) + { + int connack_rc = -1; + + if (MQTTSNDeserialize_connack(&connack_rc, buf, buflen) != 1 || connack_rc != 0) + { + printf("Unable to connect, return code %d\n", connack_rc); + goto exit; + } + else + printf("connected rc %d\n", connack_rc); + } + else + goto exit; + + /* publish with short name */ + topic.type = MQTTSN_TOPIC_TYPE_SHORT; + memcpy(topic.data.short_name, "tt", 2); + len = MQTTSNSerialize_publish(buf, buflen - len, dup, qos, retained, packetid, + topic, payload, payloadlen); + rfcomm_sendPacketBuffer(buf, len); + + /* wait for puback */ + if (MQTTSNPacket_read(buf, buflen, rfcomm_getdata) == MQTTSN_PUBACK) + { + unsigned short packet_id, topic_id; + unsigned char returncode; + + if (MQTTSNDeserialize_puback(&topic_id, &packet_id, &returncode, buf, buflen) != 1 || returncode != MQTTSN_RC_ACCEPTED) + printf("Unable to publish, return code %d\n", returncode); + else + printf("puback received, id %d\n", packet_id); + } + else + goto exit; + + len = MQTTSNSerialize_disconnect(buf, buflen, 0); + rfcomm_sendPacketBuffer(buf, len); + +exit: + rfcomm_close(); + + return 0; +} diff --git a/MQTTSNPacket/samples/linux/rfcomm/rfcomm.c b/MQTTSNPacket/samples/linux/rfcomm/rfcomm.c new file mode 100644 index 0000000..8ade937 --- /dev/null +++ b/MQTTSNPacket/samples/linux/rfcomm/rfcomm.c @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2021 tomoaki@tomy-tech.com + * + * 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 implementation + *******************************************************************************/ +#if defined(WIN32) || defined(__APP__) +#error "Only available on Linux." +#endif + + +#if !defined(SOCKET_ERROR) + /** error in socket operation */ + #define SOCKET_ERROR -1 +#endif + +#define INVALID_SOCKET SOCKET_ERROR +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rfcomm.h" + +static int mysock = INVALID_SOCKET; + +int Socket_error(char* aString, int sock) +{ + if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS && errno != EWOULDBLOCK) + { + if (strcmp(aString, "shutdown") != 0 || (errno != ENOTCONN && errno != ECONNRESET)) + { + int orig_errno = errno; + char* errmsg = strerror(errno); + + printf("Socket error %d (%s) in %s for socket %d\n", orig_errno, errmsg, aString, sock); + } + } + return -errno; +} + + +int rfcomm_sendPacketBuffer(unsigned char* buf, int buflen) +{ + int rc = 0; + + if ((rc = write(mysock, buf, buflen)) == SOCKET_ERROR) + { + Socket_error("sendto", mysock); + } + else + { + rc = 0; + } + return rc; +} + + +int rfcomm_getdata(unsigned char* buf, int count) +{ + int rc = recv(mysock, buf, count, 0); + printf("received %d bytes count %d\n", rc, (int) count); + return rc; +} + +/** +return >=0 for a socket descriptor, <0 for an error code +*/ +int rfcomm_open(char* addr, unsigned char channel) +{ + const int reuse = 1; + + mysock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + if (mysock == INVALID_SOCKET) + return Socket_error("socket", mysock); + + setsockopt(mysock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); + + struct sockaddr_rc addru = { 0 }; + addru.rc_family = AF_BLUETOOTH; + addru.rc_channel = channel; + str2ba(addr, &addru.rc_bdaddr); + + // connect to server + errno = 0; + if (connect(mysock, (struct sockaddr *) &addru, sizeof(addru)) < 0) + { + rfcomm_close(); + return Socket_error("connect", mysock); + } + return mysock; +} + +int rfcomm_close() +{ + int rc; + + rc = shutdown(mysock, SHUT_WR); + rc = close(mysock); + mysock = INVALID_SOCKET; + return rc; +} diff --git a/MQTTSNPacket/samples/linux/rfcomm/rfcomm.h b/MQTTSNPacket/samples/linux/rfcomm/rfcomm.h new file mode 100644 index 0000000..1564d04 --- /dev/null +++ b/MQTTSNPacket/samples/linux/rfcomm/rfcomm.h @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + * Sergio R. Caprile - "commonalization" from prior samples and/or documentation extension + *******************************************************************************/ + +int rfcom_sendPacketBuffer(unsigned char* buf, int buflen); +int rfcomm_getdata(unsigned char* buf, int count); +int rfcomm_open(char* address, unsigned char channel); +int rfcomm_close(void); diff --git a/travis-build.sh b/travis-build.sh index d2e7e4d..1d0aa05 100755 --- a/travis-build.sh +++ b/travis-build.sh @@ -9,7 +9,7 @@ echo "travis build dir $TRAVIS_BUILD_DIR pwd $PWD" cmake .. -DSENSORNET=loralink make ctest -VV --timeout 600 -cmake .. -DSENSORNET=ble +cmake .. -DSENSORNET=rfcomm make MQTT-SNGateway cmake .. -DSENSORNET=xbee make MQTT-SNGateway From 85ae4e359646352423ba25fd5f3a67b23c70616c Mon Sep 17 00:00:00 2001 From: tomoaki Date: Mon, 7 Jun 2021 18:09:12 +0900 Subject: [PATCH 57/67] Update README Fix typo #240 Signed-off-by: tomoaki --- MQTTSNGateway/GatewayTester/README.md | 4 ++-- MQTTSNGateway/src/linux/Threading.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MQTTSNGateway/GatewayTester/README.md b/MQTTSNGateway/GatewayTester/README.md index a0f4bad..06c11b9 100644 --- a/MQTTSNGateway/GatewayTester/README.md +++ b/MQTTSNGateway/GatewayTester/README.md @@ -57,7 +57,7 @@ TEST_LIST = {// e.g. TEST( Label, Test), ## step1. Define a sensor network **UDP** or **Bluetooth** is available as a sensor network. -Uncomment a line \#define UDP or BLE in LMqttsnClientApp.h file. +Uncomment a line \#define UDP or RFCOMM in LMqttsnClientApp.h file. ``` /*====================================== @@ -65,7 +65,7 @@ Uncomment a line \#define UDP or BLE in LMqttsnClientApp.h file. ======================================*/ //#define CLIENT_MODE #define UDP -//#define BLE +//#define RFCOMM ``` ## step2. Build diff --git a/MQTTSNGateway/src/linux/Threading.h b/MQTTSNGateway/src/linux/Threading.h index 92b9270..677e7ee 100644 --- a/MQTTSNGateway/src/linux/Threading.h +++ b/MQTTSNGateway/src/linux/Threading.h @@ -95,7 +95,7 @@ private: class RingBuffer { public: - RingBuffer(const char* keyDirctory = MQTTSNGW_KEY_DIRECTORY); + RingBuffer(const char* keyDirectory = MQTTSNGW_KEY_DIRECTORY); ~RingBuffer(); void put(char* buffer); int get(char* buffer, int bufferLength); From 83c30d662f86a2f68b6deb4904db2331c9bedc37 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Mon, 7 Jun 2021 18:49:51 +0900 Subject: [PATCH 58/67] Bugfix check network status after initialization. future branch is merged into develop. #69 Change Tab to 4 spaces Signed-off-by: tomoaki --- MQTTSNGateway/GatewayTester/src/LGwProxy.cpp | 6 +- .../GatewayTester/src/LTaskManager.cpp | 246 +++++++++--------- 2 files changed, 130 insertions(+), 122 deletions(-) diff --git a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp index 7757533..cc1a495 100644 --- a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp +++ b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp @@ -68,7 +68,11 @@ LGwProxy::~LGwProxy() void LGwProxy::initialize(SENSORNET_CONFIG_t* netconf, LMqttsnConfig* mqconf) { - _network.initialize(netconf); + if (_network.initialize(netconf) == false) + { + DISPLAY("Can't open SensorNetwork\n"); + exit(-1); + } _clientId = netconf->clientId; _willTopic = mqconf->willTopic; _willMsg = mqconf->willMsg; diff --git a/MQTTSNGateway/GatewayTester/src/LTaskManager.cpp b/MQTTSNGateway/GatewayTester/src/LTaskManager.cpp index 1ec298b..b8ce3d6 100644 --- a/MQTTSNGateway/GatewayTester/src/LTaskManager.cpp +++ b/MQTTSNGateway/GatewayTester/src/LTaskManager.cpp @@ -14,7 +14,6 @@ * Tomoaki Yamaguchi - initial API and implementation and/or initial documentation **************************************************************************************/ - #include #include @@ -32,148 +31,153 @@ extern LMqttsnClient* theClient; extern LScreen* theScreen; extern bool theClientMode; /*===================================== - TaskManager + TaskManager ======================================*/ -LTaskManager::LTaskManager(void){ - _tasks = 0; - _tests = 0; - _index = 0; +LTaskManager::LTaskManager(void) +{ + _tasks = 0; + _tests = 0; + _index = 0; } -LTaskManager::~LTaskManager(void){ - +LTaskManager::~LTaskManager(void) +{ + } -void LTaskManager::add(TaskList* task){ +void LTaskManager::add(TaskList* task) +{ _tasks = task; } -void LTaskManager::add(TestList* test){ +void LTaskManager::add(TestList* test) +{ _tests = test; } -void LTaskManager::run(void){ - int i = 0; - char c = 0; - bool cancelFlg = false; - TestList test = {0}; - TaskList task = {0}; +void LTaskManager::run(void) +{ + int i = 0; + char c = 0; + bool cancelFlg = false; + TestList test = { 0 }; + TaskList task = { 0 }; - if ( !theClientMode ) - { - theClient->getGwProxy()->getMessage(); + if (!theClientMode) + { + theClient->getGwProxy()->getMessage(); - for (i = 0; _tests[i].testTask > test.testTask; i++) - { - PROMPT("Execute \"%s\" ? ( y/n ) : ", _tests[i].testLabel); - while (true) - { - if (CHECKKEYIN(&c)) - { - if ( toupper(c) == 'N' ) - { + for (i = 0; _tests[i].testTask > test.testTask; i++) + { + PROMPT("Execute \"%s\" ? ( y/n ) : ", _tests[i].testLabel); + while (true) + { + if (CHECKKEYIN(&c)) + { + if (toupper(c) == 'N') + { - DISPLAY("\033[0m\033[0;32m\n**** %s is canceled ****\033[0m\033[0;37m\n\n", _tests[i].testLabel); - theScreen->prompt(""); - cancelFlg = true; - break; - } - else if ( toupper(c) == 'Y' ) - { - DISPLAY("\033[0m\033[0;32m\n\n**** %s start ****\033[0m\033[0;37m\n", _tests[i].testLabel); - theScreen->prompt(""); - (_tests[i].testTask)(); - cancelFlg = false; - break; - } - } - else - { - theClient->getGwProxy()->getMessage(); - } - } + DISPLAY("\033[0m\033[0;32m\n**** %s is canceled ****\033[0m\033[0;37m\n\n", _tests[i].testLabel); + theScreen->prompt(""); + cancelFlg = true; + break; + } + else if (toupper(c) == 'Y') + { + DISPLAY("\033[0m\033[0;32m\n\n**** %s start ****\033[0m\033[0;37m\n", _tests[i].testLabel); + theScreen->prompt(""); + (_tests[i].testTask)(); + cancelFlg = false; + break; + } + } + else + { + theClient->getGwProxy()->getMessage(); + } + } - while ( true ) - { - do - { - theClient->getGwProxy()->getMessage(); - } - while(theClient->getPublishManager()->isMaxFlight() || - !theClient->getSubscribeManager()->isDone() || - !theClient->getRegisterManager()->isDone()); + while (true) + { + do + { + theClient->getGwProxy()->getMessage(); + } + while (theClient->getPublishManager()->isMaxFlight() || !theClient->getSubscribeManager()->isDone() + || !theClient->getRegisterManager()->isDone()); - if (theClient->getPublishManager()->isDone()) - { - break; - } - } - if ( !cancelFlg ) - { - DISPLAY("\033[0m\033[0;32m\n**** %s complete ****\033[0m\033[0;37m\n\n", _tests[i].testLabel); - } - } - DISPLAY("\033[0m\033[0;32m\n\n######### All tests complete! ###########\033[0m\033[0;37m\n\n"); - } - else - { - while (true) - { - theClient->getGwProxy()->getMessage(); - for (_index = 0; _tasks[_index].callback > task.callback; _index++) - { - if ((_tasks[_index].prevTime + _tasks[_index].interval <= time(NULL)) && - _tasks[_index].count == 0) - { - _tasks[_index].prevTime = time(NULL); - (_tasks[_index].callback)(); - } - } + if (theClient->getPublishManager()->isDone()) + { + break; + } + } + if (!cancelFlg) + { + DISPLAY("\033[0m\033[0;32m\n**** %s complete ****\033[0m\033[0;37m\n\n", _tests[i].testLabel); + } + } + DISPLAY("\033[0m\033[0;32m\n\n######### All tests complete! ###########\033[0m\033[0;37m\n\n"); + } + else + { + while (true) + { + theClient->getGwProxy()->getMessage(); + for (_index = 0; _tasks[_index].callback > task.callback; _index++) + { + if ((_tasks[_index].prevTime + _tasks[_index].interval <= time(NULL)) && _tasks[_index].count == 0) + { + _tasks[_index].prevTime = time(NULL); + (_tasks[_index].callback)(); + } + } - do - { - theClient->getGwProxy()->getMessage(); - } - while(theClient->getPublishManager()->isMaxFlight() || - !theClient->getSubscribeManager()->isDone() || - !theClient->getRegisterManager()->isDone()); + do + { + theClient->getGwProxy()->getMessage(); + } + while (theClient->getPublishManager()->isMaxFlight() || !theClient->getSubscribeManager()->isDone() + || !theClient->getRegisterManager()->isDone()); - if (theClient->getPublishManager()->isDone()) - { - break; - } - } - } + if (theClient->getPublishManager()->isDone()) + { + break; + } + } + } } -uint8_t LTaskManager::getIndex(void){ - return _index; +uint8_t LTaskManager::getIndex(void) +{ + return _index; } -void LTaskManager::done(uint8_t index){ - if (_tasks ) - { - if (_tasks[index].count > 0) - { - _tasks[index].count--; - } - } - if (_tests ) - { - if (_tests[index].count > 0) - { - _tests[index].count--; - } - } +void LTaskManager::done(uint8_t index) +{ + if (_tasks) + { + if (_tasks[index].count > 0) + { + _tasks[index].count--; + } + } + if (_tests) + { + if (_tests[index].count > 0) + { + _tests[index].count--; + } + } } -void LTaskManager::suspend(uint8_t index){ - if ( _tasks ) - { - _tasks[index].count++; - } - if ( _tests ) - { - _tests[index].count++; - } +void LTaskManager::suspend(uint8_t index) +{ + if (_tasks) + { + _tasks[index].count++; + } + if (_tests) + { + _tests[index].count++; + } } From 776099ebb30f0773ae3fc107335534d0b39129f2 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Fri, 11 Jun 2021 10:54:20 +0900 Subject: [PATCH 59/67] Bugfix Set a secure flag to a Client instance. Signed-off-by: tomoaki --- .cproject | 527 ++++++++--------------- .settings/language.settings.xml | 69 +-- MQTTSNGateway/src/MQTTSNGWClientList.cpp | 1 + MQTTSNGateway/src/linux/Network.cpp | 4 + MQTTSNGateway/src/linux/Network.h | 1 + 5 files changed, 204 insertions(+), 398 deletions(-) diff --git a/.cproject b/.cproject index fcd0270..6a07b71 100644 --- a/.cproject +++ b/.cproject @@ -1,354 +1,177 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index 659286b..6ac55d6 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -1,48 +1,25 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MQTTSNGateway/src/MQTTSNGWClientList.cpp b/MQTTSNGateway/src/MQTTSNGWClientList.cpp index 9f6b0ea..2a4dfe6 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientList.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientList.cpp @@ -380,6 +380,7 @@ Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, { client->setQoSm1(); } + client->getNetwork()->setSecure(secure); _mutex.lock(); diff --git a/MQTTSNGateway/src/linux/Network.cpp b/MQTTSNGateway/src/linux/Network.cpp index 4951f8d..bd5039a 100644 --- a/MQTTSNGateway/src/linux/Network.cpp +++ b/MQTTSNGateway/src/linux/Network.cpp @@ -656,3 +656,7 @@ bool Network::isSecure() return _secureFlg; } +void Network::setSecure(bool secureFlg) +{ + _secureFlg = secureFlg; +} diff --git a/MQTTSNGateway/src/linux/Network.h b/MQTTSNGateway/src/linux/Network.h index f5e15bd..57ed2ce 100644 --- a/MQTTSNGateway/src/linux/Network.h +++ b/MQTTSNGateway/src/linux/Network.h @@ -80,6 +80,7 @@ public: bool isValid(void); bool isSecure(void); int getSock(void); + void setSecure(bool secureFlg); private: static SSL_CTX* _ctx; From f2dcda358f21e264de57b47b00ab6165bab4da18 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Wed, 14 Jul 2021 11:28:20 +0900 Subject: [PATCH 60/67] Bugfix of #234 Signed-off-by: tomoaki --- MQTTSNGateway/src/MQTTSNGWClientList.cpp | 31 ++---------------------- MQTTSNGateway/src/MQTTSNGateway.cpp | 6 +++-- 2 files changed, 6 insertions(+), 31 deletions(-) diff --git a/MQTTSNGateway/src/MQTTSNGWClientList.cpp b/MQTTSNGateway/src/MQTTSNGWClientList.cpp index 2a4dfe6..bf96ce8 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientList.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientList.cpp @@ -423,37 +423,10 @@ Client* ClientList::createPredefinedTopic(MQTTSNString* clientId, string topicNa return nullptr; } - /* anonimous clients */ - if (_clientCnt > MAX_CLIENTS) - { - return nullptr; // full of clients - } - + client = createClient(NULL, clientId, aggregate); 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(); + return nullptr; } // create Topic & Add it diff --git a/MQTTSNGateway/src/MQTTSNGateway.cpp b/MQTTSNGateway/src/MQTTSNGateway.cpp index 3ef0dab..90c6f58 100644 --- a/MQTTSNGateway/src/MQTTSNGateway.cpp +++ b/MQTTSNGateway/src/MQTTSNGateway.cpp @@ -34,7 +34,6 @@ Gateway::Gateway(void) { theMultiTaskProcess = this; theProcess = this; - _packetEventQue.setMaxSize(MAX_INFLIGHTMESSAGES * MAX_CLIENTS); _clientList = new ClientList(this); _adapterManager = new AdapterManager(this); _topics = new Topics(); @@ -282,11 +281,14 @@ void Gateway::initialize(int argc, char** argv) _params.maxClients = atoi(param); } - if (getParam("BleAddress", param) == 0) + if (getParam("RFCOMMAddress", param) == 0) { _params.bleAddress = strdup(param); } + /* Setup max PacketEventQue size */ + _packetEventQue.setMaxSize(_params.maxInflightMsgs * _params.maxClients); + /* Initialize adapters */ _adapterManager->initialize(_params.gatewayName, _params.aggregatingGw, _params.forwarder, _params.qosMinus1); From fa0925d24e64b24fe6c314dba6feac7493b8e4ac Mon Sep 17 00:00:00 2001 From: tomoaki Date: Sun, 1 Aug 2021 19:27:17 +0900 Subject: [PATCH 61/67] settings was changed Signed-off-by: tomoaki --- .settings/language.settings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index 6ac55d6..ce51272 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -5,7 +5,7 @@ - + @@ -16,7 +16,7 @@ - + From 5fb4312aad43799921abd88743344a157a0e3221 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Fri, 11 Jun 2021 10:54:20 +0900 Subject: [PATCH 62/67] This branch for debugging DTLS #90, #150, #195, #227 The purpose of this branch is to share work in process. Change sellect() of UDP to poll() Rewrite UDP6 for DTLS6 Known bug: can't reconnect DTLS Signed-off-by: tomoaki --- .cproject | 541 +++---- .settings/language.settings.xml | 69 +- MQTTSNGateway/GatewayTester/Makefile | 21 +- MQTTSNGateway/GatewayTester/README.md | 142 +- MQTTSNGateway/GatewayTester/build.sh | 22 + .../samples/ClientPub/mainPub.cpp | 23 +- .../samples/ClientPubQoS-1/mainPubQoS-1.cpp | 23 +- .../samples/ClientSub/mainSub.cpp | 23 +- .../GatewayTester/samples/mainTest.cpp | 20 +- MQTTSNGateway/GatewayTester/src/LGwProxy.cpp | 9 + MQTTSNGateway/GatewayTester/src/LGwProxy.h | 4 + .../GatewayTester/src/LMqttsnClient.cpp | 6 + .../GatewayTester/src/LMqttsnClientApp.h | 60 +- .../GatewayTester/src/LNetworkDtls.cpp | 537 ++++++ .../GatewayTester/src/LNetworkDtls.h | 117 ++ .../GatewayTester/src/LNetworkDtls6.cpp | 533 ++++++ .../GatewayTester/src/LNetworkDtls6.h | 121 ++ .../GatewayTester/src/LNetworkRfcomm.cpp | 2 +- .../GatewayTester/src/LNetworkRfcomm.h | 1 - .../GatewayTester/src/LNetworkUdp.cpp | 626 +++---- MQTTSNGateway/GatewayTester/src/LNetworkUdp.h | 2 - .../GatewayTester/src/LNetworkUdp6.cpp | 433 +++++ .../GatewayTester/src/LNetworkUdp6.h | 113 ++ MQTTSNGateway/Makefile.org | 164 -- MQTTSNGateway/README.md | 247 ++- MQTTSNGateway/build.sh | 43 +- MQTTSNGateway/gateway.conf | 88 +- MQTTSNGateway/src/CMakeLists.txt | 10 +- MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp | 1 + MQTTSNGateway/src/MQTTSNGWClientList.cpp | 60 +- MQTTSNGateway/src/MQTTSNGWClientList.h | 1 + MQTTSNGateway/src/MQTTSNGWDefines.h | 14 +- MQTTSNGateway/src/MQTTSNGWPacket.cpp | 4 - MQTTSNGateway/src/MQTTSNGWPacket.h | 1 + .../src/MQTTSNGWPacketHandleTask.cpp | 1 + MQTTSNGateway/src/MQTTSNGWProcess.cpp | 64 +- MQTTSNGateway/src/MQTTSNGateway.cpp | 60 +- MQTTSNGateway/src/MQTTSNGateway.h | 7 +- MQTTSNGateway/src/linux/Network.cpp | 4 + MQTTSNGateway/src/linux/Network.h | 1 + .../src/linux/dtls/SensorNetwork.cpp | 1437 +++++++++++++++++ MQTTSNGateway/src/linux/dtls/SensorNetwork.h | 163 ++ .../src/linux/loralink/SensorNetwork.cpp | 18 +- .../src/linux/loralink/SensorNetwork.h | 9 +- .../src/linux/rfcomm/SensorNetwork.h | 6 - MQTTSNGateway/src/linux/udp/SensorNetwork.cpp | 311 ++-- MQTTSNGateway/src/linux/udp/SensorNetwork.h | 15 +- .../src/linux/udp6/SensorNetwork.cpp | 607 ++++--- MQTTSNGateway/src/linux/udp6/SensorNetwork.h | 90 +- MQTTSNGateway/src/linux/xbee/SensorNetwork.h | 7 - MQTTSNGateway/src/mainGateway.cpp | 1 - travis-build.sh | 9 +- 52 files changed, 5101 insertions(+), 1790 deletions(-) create mode 100755 MQTTSNGateway/GatewayTester/build.sh create mode 100644 MQTTSNGateway/GatewayTester/src/LNetworkDtls.cpp create mode 100644 MQTTSNGateway/GatewayTester/src/LNetworkDtls.h create mode 100644 MQTTSNGateway/GatewayTester/src/LNetworkDtls6.cpp create mode 100644 MQTTSNGateway/GatewayTester/src/LNetworkDtls6.h create mode 100644 MQTTSNGateway/GatewayTester/src/LNetworkUdp6.cpp create mode 100644 MQTTSNGateway/GatewayTester/src/LNetworkUdp6.h delete mode 100644 MQTTSNGateway/Makefile.org create mode 100644 MQTTSNGateway/src/linux/dtls/SensorNetwork.cpp create mode 100644 MQTTSNGateway/src/linux/dtls/SensorNetwork.h diff --git a/.cproject b/.cproject index fcd0270..a252276 100644 --- a/.cproject +++ b/.cproject @@ -1,354 +1,191 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index 659286b..3cabd84 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -1,48 +1,25 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MQTTSNGateway/GatewayTester/Makefile b/MQTTSNGateway/GatewayTester/Makefile index 73f7bb9..5cc07df 100644 --- a/MQTTSNGateway/GatewayTester/Makefile +++ b/MQTTSNGateway/GatewayTester/Makefile @@ -20,7 +20,10 @@ CPPSRCS := \ $(SUBDIR)/LGwProxy.cpp \ $(SUBDIR)/LMqttsnClient.cpp \ $(SUBDIR)/LNetworkUdp.cpp \ +$(SUBDIR)/LNetworkUdp6.cpp \ $(SUBDIR)/LNetworkRfcomm.cpp \ +$(SUBDIR)/LNetworkDtls.cpp \ +$(SUBDIR)/LNetworkDtls6.cpp \ $(SUBDIR)/LPublishManager.cpp \ $(SUBDIR)/LRegisterManager.cpp \ $(SUBDIR)/LSubscribeManager.cpp \ @@ -38,11 +41,13 @@ CXX := g++ CPPFLAGS += INCLUDES += -I$(SUBDIR) -DEFS := -LIBS += +DEF1 := +DEF2 := +DEFS := -D$(SN) $(DEF1) $(DEF2) +LIBS += -L/usr/local/lib -L/usr/local/opt/openssl LDFLAGS := CXXFLAGS := -Wall -O3 -std=c++11 -LDADD := -lbluetooth +LDADD := -lbluetooth -lssl -lcrypto OUTDIR := Build PROG := $(OUTDIR)/$(PROGTEST) @@ -76,23 +81,23 @@ $(PROGQOS): $(OBJS) $(OUTDIR)/$(SRCDIR)/$(SRCQOS)/$(QOSAPPL).o $(OUTDIR)/$(SUBDIR)/%.o:$(SUBDIR)/%.cpp @if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi - $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) $(DEFS) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $< + $(CXX) $(DEFS) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $< $(OUTDIR)/$(SRCDIR)/%.o:$(SRCDIR)/%.cpp @if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi - $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) $(DEFS) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $< + $(CXX) $(DEFS) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $< $(OUTDIR)/$(SRCDIR)/$(SRCPUB)/%.o:$(SRCDIR)/$(SRCPUB)%.cpp @if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi - $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) $(DEFS) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $< + $(CXX) $(DEFS) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $< $(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) $< + $(CXX) $(DEFS) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) -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) $< + $(CXX) $(DEFS) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $< clean: rm -rf $(OUTDIR) diff --git a/MQTTSNGateway/GatewayTester/README.md b/MQTTSNGateway/GatewayTester/README.md index 06c11b9..514d37d 100644 --- a/MQTTSNGateway/GatewayTester/README.md +++ b/MQTTSNGateway/GatewayTester/README.md @@ -2,27 +2,6 @@ **sample/mainTest.cpp** is a Test sample coading. Each test is described as one function. test1(), test2()... ``` -/*------------------------------------------------------ - * Test functions - * - * you can use 4 commands in Test functions - * - * 1) PUBLISH(const char* topicName, - * uint8_t* payload, - * uint16_t len, - * uint8_t qos, - * bool retain = false); - * - * 2) SUBSCRIBE(const char* topicName, - * TopicCallback onPublish, - * uint8_t qos); - * - * 3) UNSUBSCRIBE(const char* topicName); - * - * 4) DISCONNECT(uint16_t sleepInSecs); - * - *------------------------------------------------------*/ - void test1(void) { char payload[300]; @@ -36,8 +15,34 @@ void test2(void) uint8_t qos = 1; SUBSCRIBE(topic2, on_publish02, qos); } + + *--------------------------------------------------------------------------- + * + * 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() + *-------------------------------------------------------------------------- + ``` -**TEST_LIST** is a test senario. Test functions are executed one by one. +**TEST_LIST** is a test senario. Test functions are executed interactively. ``` /*------------------------------------------------------ * A List of Test Tasks @@ -54,80 +59,59 @@ TEST_LIST = {// e.g. TEST( Label, Test), }; ``` -## step1. Define a sensor network -**UDP** or **Bluetooth** is available as a sensor network. -Uncomment a line \#define UDP or RFCOMM in LMqttsnClientApp.h file. +**UDP**, **DTLS**, **UDP6**, **DTLS6** or **Bluetooth** is available as a sensor network. +``` +/*------------------------------------------------------ + * UDP, DTLS Configuration (theNetcon) + *------------------------------------------------------*/ +UDPCONF = { "GatewayTestClient", // ClientId + { 225, 1, 1, 1 }, // Multicast group IP + 1883, // Multicast group Port + 20020, // Local PortNo + }; + +/*------------------------------------------------------ + * UDP6, DTLS6 Configuration (theNetcon) + *------------------------------------------------------*/ +UDP6CONF = { "GatewayTestClient", // ClientId + "ff12::feed:caca:dead", // Multicast group IP + "wlp4s0", + 1883, // Multicast group Port + 20020, // Local PortNo + }; + +/*------------------------------------------------------ + * RFCOMM Configuration (theNetcon) + *------------------------------------------------------*/ +RFCOMMCONF = { "GatewayTestClient", // ClientId + "60:57:18:06:8B:72", // GW Address + 1, // Rfcomm channel + }; ``` -/*====================================== - * Program mode Flag - ======================================*/ -//#define CLIENT_MODE -#define UDP -//#define RFCOMM -``` -## step2. Build +## How to Build ``` -$ git clone https://github.com/eclipse/paho.mqtt-sn.embedded-c +copy codes from the github. $ cd paho.mqtt-sn.embedded-c/MQTTSNGateway/GatewayTester -$ make -$ make install -$ make clean +$ ./build.sh [udp | udp6 | dtls | dtls6 | rfcomm] ``` -MQTT-SNGatewayTester program is copied into ../../../ directory. -## **step3. Execute Gateway Tester.** - +## Execute Gateway Tester ``` -$ cd ../../.. -$ ./MQTT-SNGatewayTester +$ ./Build/MQTT-SNGatewayTester *************************************************************************** - * MQTT-SN Gateway Tester + * MQTT-SN Gateway Tester DTLS * Part of Project Paho in Eclipse * (http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt-sn.embedded-c.git/) * * Author : Tomoaki YAMAGUCHI - * Version: 0.0.0 + * Version: 2.0.0 *************************************************************************** - Attempting to Connect the Broker..... - -sendto 225.1.1.1 :1883 03 01 00 - -recved 192.168.11.5 :1883 03 01 00 -sendto 225.1.1.1 :1883 03 01 00 - -recved 192.168.11.5 :1883 03 01 00 - -recved 192.168.11.17 :10000 03 02 01 -sendto 192.168.11.17 :10000 13 04 0c 01 03 84 47 61 74 65 77 61 79 54 65 73 74 65 72 - -recved 192.168.11.17 :10000 02 06 -sendto 192.168.11.17 :10000 0c 07 00 77 69 6c 6c 54 6f 70 69 63 - -recved 192.168.11.17 :10000 02 08 -sendto 192.168.11.17 :10000 0d 09 77 69 6c 6c 4d 65 73 73 61 67 65 - -recved 192.168.11.17 :10000 03 05 00 - - - Connected to the Broker - - Attempting OnConnect..... -sendto 192.168.11.17 :10000 13 12 20 00 01 74 79 34 74 77 2f 63 6c 69 65 6e 74 49 64 - -recved 192.168.11.17 :10000 08 13 20 00 01 00 01 00 - - - SUBSCRIBE complete. ty4tw/clientId - - OnConnect complete - Test Ready. - -Execute Publish topic1 Test ? ( Y/N ) : +Execute "Step0:Connect" ? ( y/n ) : ``` diff --git a/MQTTSNGateway/GatewayTester/build.sh b/MQTTSNGateway/GatewayTester/build.sh new file mode 100755 index 0000000..290440b --- /dev/null +++ b/MQTTSNGateway/GatewayTester/build.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +DEF1="DEF1=${2}" +DEF2="DEF2=${3}" + +if [ $1 == "udp" ] ; then + make SN=UDP $DEF1 $DEF2 +elif [ $1 == "udp6" ] ; then + make SN=UDP6 $DEF1 $DEF2 +elif [ $1 == "rfcomm" ] ; then + make SN=RFCOMM $DEF1 $DEF2 +elif [ $1 == "dtls" ] ; then + make SN=DTLS $DEF1 $DEF2 +elif [ $1 == "dtls6" ] ; then + make SN=DTLS6 $DEF1 $DEF2 +elif [ $1 == "clean" ] ; then + make clean +else + echo "Usage: build.sh [ udp | udp6 | rfcomm | dtls | dtls6] | clean" +fi + + diff --git a/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp b/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp index a398f6e..80fe65a 100644 --- a/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp +++ b/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp @@ -51,17 +51,26 @@ extern LScreen* theScreen; /*------------------------------------------------------ * UDP Configuration (theNetcon) *------------------------------------------------------*/ -UDPCONF = { - "ClientPUB", // ClientId - {225,1,1,1}, // Multicast group IP - 1883, // Multicast group Port - 20010, // Local PortNo -}; +UDPCONF = { "ClientPUB", // ClientId + { 225, 1, 1, 1 }, // Multicast group IP + 1883, // Multicast group Port + 20010, // Local PortNo + }; + +/*------------------------------------------------------ + * UDP6 Configuration (theNetcon) + *------------------------------------------------------*/ +UDP6CONF = { "ClientPUB", // ClientId + "ff1e:feed:caca:dead::1", // Multicast group IP + "wlp4s0", // Network Interface + 1883, // Multicast group Port + 20020, // Local PortNo + }; /*------------------------------------------------------ * RFCOMM Configuration (theNetcon) *------------------------------------------------------*/ -RFCOMMCONF = { "GatewayTestClient", // ClientId +RFCOMMCONF = { "ClientPUB", // ClientId "60:57:18:06:8B:72", // GW Address 1, // Rfcomm channel }; diff --git a/MQTTSNGateway/GatewayTester/samples/ClientPubQoS-1/mainPubQoS-1.cpp b/MQTTSNGateway/GatewayTester/samples/ClientPubQoS-1/mainPubQoS-1.cpp index f7df9a7..ce44ba5 100644 --- a/MQTTSNGateway/GatewayTester/samples/ClientPubQoS-1/mainPubQoS-1.cpp +++ b/MQTTSNGateway/GatewayTester/samples/ClientPubQoS-1/mainPubQoS-1.cpp @@ -51,17 +51,26 @@ 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 -}; +UDPCONF = { "QoS-1_Client01", // ClientId + { 225, 1, 1, 1 }, // Multicast group IP + 1883, // Multicast group Port + 20001, // Local PortNo + }; + +/*------------------------------------------------------ + * UDP6 Configuration (theNetcon) + *------------------------------------------------------*/ +UDP6CONF = { "QoS-1_Client01", // ClientId + "ff1e:feed:caca:dead::1", // Multicast group IP + "wlp4s0", // Network Interface + 1883, // Multicast group Port + 20020, // Local PortNo + }; /*------------------------------------------------------ * RFCOMM Configuration (theNetcon) *------------------------------------------------------*/ -RFCOMMCONF = { "GatewayTestClient", // ClientId +RFCOMMCONF = { "QoS-1_Client01", // ClientId "60:57:18:06:8B:72", // GW Address 1, // Rfcomm channel }; diff --git a/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp b/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp index 6f73e2a..63cd404 100644 --- a/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp +++ b/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp @@ -51,17 +51,26 @@ extern LScreen* theScreen; /*------------------------------------------------------ * UDP Configuration (theNetcon) *------------------------------------------------------*/ -UDPCONF = { - "ClientSUB", // ClientId - {225,1,1,1}, // Multicast group IP - 1883, // Multicast group Port - 20011, // Local PortNo -}; +UDPCONF = { "ClientSUB", // ClientId + { 225, 1, 1, 1 }, // Multicast group IP + 1883, // Multicast group Port + 20011, // Local PortNo + }; + +/*------------------------------------------------------ + * UDP6 Configuration (theNetcon) + *------------------------------------------------------*/ +UDP6CONF = { "ClientSUB", // ClientId + "ff1e:feed:caca:dead::1", // Multicast group IP + "wlp4s0", // Network Interface + 1883, // Multicast group Port + 20020, // Local PortNo + }; /*------------------------------------------------------ * RFCOMM Configuration (theNetcon) *------------------------------------------------------*/ -RFCOMMCONF = { "GatewayTestClient", // ClientId +RFCOMMCONF = { "ClientSUB", // ClientId "60:57:18:06:8B:72", // GW Address 1, // Rfcomm channel }; diff --git a/MQTTSNGateway/GatewayTester/samples/mainTest.cpp b/MQTTSNGateway/GatewayTester/samples/mainTest.cpp index 88feb03..2210222 100644 --- a/MQTTSNGateway/GatewayTester/samples/mainTest.cpp +++ b/MQTTSNGateway/GatewayTester/samples/mainTest.cpp @@ -20,13 +20,13 @@ * * 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 ( const char* topicName, TopicCallback onPublish, uint8_t qos ); * - * void SUBSCRIBE ( uint16_t topicId, TopicCallback onPublish, uint8_t qos ); + * void SUBSCRIBE ( uint16_t topicId, TopicCallback onPublish, uint8_t qos ); * - * void UNSUBSCRIBE ( const char* topicName ); + * void UNSUBSCRIBE ( const char* topicName ); * - * void UNSUBSCRIBE ( uint16_t topicId ); + * void UNSUBSCRIBE ( uint16_t topicId ); * * void DISCONNECT ( uint16_t sleepInSecs ); * @@ -49,7 +49,7 @@ extern LMqttsnClient* theClient; extern LScreen* theScreen; /*------------------------------------------------------ - * UDP Configuration (theNetcon) + * UDP,DTLS Configuration (theNetcon) *------------------------------------------------------*/ UDPCONF = { "GatewayTestClient", // ClientId { 225, 1, 1, 1 }, // Multicast group IP @@ -57,6 +57,16 @@ UDPCONF = { "GatewayTestClient", // ClientId 20020, // Local PortNo }; +/*------------------------------------------------------ + * UDP6, DTLS6 Configuration (theNetcon) + *------------------------------------------------------*/ +UDP6CONF = { "GatewayTestClient", // ClientId + "ff1e:feed:caca:dead::1", // Multicast group IP + "wlp4s0", // Network Interface + 1883, // Multicast group Port + 20020, // Local PortNo + }; + /*------------------------------------------------------ * RFCOMM Configuration (theNetcon) *------------------------------------------------------*/ diff --git a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp index cc1a495..4a8a283 100644 --- a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp +++ b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp @@ -200,6 +200,15 @@ int LGwProxy::getConnectResponce(void) { _network.setGwAddress(); _gwId = _mqttsnMsg[1]; + +#if defined(DTLS) || defined(DTLS6) + if (_network.sslConnect() < 0) + { + DISPLAY( + "\033[0m\033[0;32m\n\nLGwProxy::getConnectResponce Can't connect the Gateway via SSL.\033[0m\033[0;37m\n\n"); + return 0; + } +#endif _status = GW_CONNECTING; } else if (_mqttsnMsg[0] == MQTTSN_TYPE_WILLTOPICREQ && _status == GW_WAIT_WILLTOPICREQ) diff --git a/MQTTSNGateway/GatewayTester/src/LGwProxy.h b/MQTTSNGateway/GatewayTester/src/LGwProxy.h index 546b52d..48bba97 100644 --- a/MQTTSNGateway/GatewayTester/src/LGwProxy.h +++ b/MQTTSNGateway/GatewayTester/src/LGwProxy.h @@ -23,7 +23,10 @@ #include "LMqttsnClientApp.h" #include "LNetworkUdp.h" +#include "LNetworkUdp6.h" #include "LNetworkRfcomm.h" +#include "LNetworkDtls.h" +#include "LNetworkDtls6.h" #include "LRegisterManager.h" #include "LTimer.h" #include "LTopicTable.h" @@ -43,6 +46,7 @@ using namespace std; #define GW_SLEEPING 10 #define GW_DISCONNECTED 11 #define GW_SLEPT 12 +#define SSL_CONNECTING 13 #define GW_WAIT_PINGRESP 1 diff --git a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp index b20de1e..0126a3e 100644 --- a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp +++ b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp @@ -53,8 +53,14 @@ int main(int argc, char** argv) printf("\n%s", PAHO_COPYRIGHT0); #if defined(UDP) printf(" UDP\n"); +#elif defined(UDP6) + printf(" UDP6\n"); #elif defined(RFCOMM) printf(" RFCOMM\n"); +#elif defined(DTLS) + printf(" DTLS\n"); +#elif defined(DTLS6) + printf(" DTLS6\n"); #else printf("\n"); #endif diff --git a/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h b/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h index caa390f..79e77b8 100644 --- a/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h +++ b/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h @@ -17,17 +17,16 @@ #ifndef MQTTSNCLIENTAPP_H_ #define MQTTSNCLIENTAPP_H_ +/*====================================== + * Debug Flag + ======================================*/ +//#define DEBUG_NW +//#define DEBUG_MQTTSN + /*====================================== * Program mode Flag ======================================*/ //#define CLIENT_MODE -#define UDP -//#define RFCOMM -/*====================================== - * Debug Flag - ======================================*/ -#define DEBUG_NW -//#define DEBUG_MQTTSN /**************************************** MQTT-SN Parameters @@ -75,6 +74,15 @@ struct LUdpConfig uint16_t uPortNo; }; +struct LUdp6Config +{ + const char* clientId; + const char* ipAddress; + const char *interface; + uint16_t gPortNo; + uint16_t uPortNo; +}; + struct LRfcommConfig { const char* clientId; @@ -97,20 +105,40 @@ typedef enum #define MQTTSN_CONFIG MqttsnConfig theMqttsnConfig #define MQTTSNCONF LMqttsnConfig theMqcon -#ifdef UDP -#define NETWORK_CONFIG UdpConfig theNetworkConfig +#if defined(UDP) #define UDPCONF LUdpConfig theNetcon -#define RFCOMMCONF LRfcommConfig theConf +#define UDP6CONF LUdp6Config theU6Conf +#define RFCOMMCONF LRfcommConfig theRfConf #define SENSORNET_CONFIG_t LUdpConfig -#else -#ifdef RFCOMM -#define NETWORK_CONFIG BleConfig theNetworkConfig + +#elif defined(UDP6) +#define UDP6CONF LUdp6Config theNetcon +#define UDPCONF LUdpConfig theUConf +#define RFCOMMCONF LRfcommConfig theRfConf +#define SENSORNET_CONFIG_t LUdp6Config + +#elif defined(RFCOMM) #define RFCOMMCONF LRfcommConfig theNetcon -#define UDPCONF LUdpConfig theConf +#define UDPCONF LUdpConfig theUConf +#define UDP6CONF LUdp6Config theU6Conf #define SENSORNET_CONFIG_t LRfcommConfig + +#elif defined(DTLS) +#define UDPCONF LUdpConfig theNetcon +#define UDP6CONF LUdp6Config theU6Conf +#define RFCOMMCONF LRfcommConfig theRfConf +#define SENSORNET_CONFIG_t LUdpConfig + +#elif defined(DTLS6) +#define UDPCONF LUdpConfig theUConf +#define UDP6CONF LUdp6Config theNetcon +#define RFCOMMCONF LRfcommConfig theRfConf +#define SENSORNET_CONFIG_t LUdp6Config +#else +#error "UDP, UDP6, DTLS, DTLS6 or RFCOMM is not defined in LMqttsnClientApp.h" #endif -#error "UDP and RFCOMM are not defined in LMqttsnClientApp.h" -#endif + + #define CONNECT(...) theClient->getGwProxy()->connect(__VA_ARGS__) #define PUBLISH(...) theClient->publish(__VA_ARGS__) diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkDtls.cpp b/MQTTSNGateway/GatewayTester/src/LNetworkDtls.cpp new file mode 100644 index 0000000..d861814 --- /dev/null +++ b/MQTTSNGateway/GatewayTester/src/LNetworkDtls.cpp @@ -0,0 +1,537 @@ +/************************************************************************************** + * 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 + **************************************************************************************/ +#ifdef DTLS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "LMqttsnClientApp.h" +#include "LNetworkDtls.h" +#include "LTimer.h" +#include "LScreen.h" + +using namespace std; +using namespace linuxAsyncClient; + +extern uint16_t getUint16(const uint8_t* pos); +extern uint32_t getUint32(const uint8_t* pos); +extern LScreen* theScreen; +extern bool theClientMode; + +/* Certificate verification. Returns 1 if trusted, else 0 */ +int verify_cert(int ok, X509_STORE_CTX *ctx); + +/*========================================= + Class LNetwork + =========================================*/ +LNetwork::LNetwork() +{ + _sleepflg = false; + resetGwAddress(); +} + +LNetwork::~LNetwork() +{ +} + +int LNetwork::broadcast(const uint8_t *xmitData, uint16_t dataLen) +{ + return LDtlsPort::multicast(xmitData, (uint32_t) dataLen); +} + +int LNetwork::unicast(const uint8_t *xmitData, uint16_t dataLen) +{ + return LDtlsPort::unicast(xmitData, dataLen); +} + + +uint8_t* LNetwork::getMessage(int *len) +{ + *len = 0; + uint16_t recvLen = 0; + if (checkRecvBuf()) + { + recvLen = LDtlsPort::recv(_rxDataBuf, MQTTSN_MAX_PACKET_SIZE, false, &_ipAddress, &_portNo); + if (_gwIpAddress && isUnicast() && (_ipAddress != _gwIpAddress) && (_portNo != _gwPortNo)) + { + return 0; + } + + if (recvLen < 0) + { + *len = recvLen; + return 0; + } + else + { + if (_rxDataBuf[0] == 0x01) + { + *len = getUint16(_rxDataBuf + 1); + } + else + { + *len = _rxDataBuf[0]; + } + return _rxDataBuf; + } + } + return 0; +} + +void LNetwork::setGwAddress(void) +{ + _gwPortNo = _portNo; + _gwIpAddress = _ipAddress; +} + +void LNetwork::resetGwAddress(void) +{ + _gwIpAddress = 0; + _gwPortNo = 0; +} + + +bool LNetwork::initialize(LUdpConfig *config) +{ + return LDtlsPort::open(config); +} + +void LNetwork::setSleep() +{ + _sleepflg = true; +} + +bool LNetwork::isBroadcastable() +{ + return true; +} + +int LNetwork::sslConnect(void) +{ + return LDtlsPort::sslConnect(_gwIpAddress, _gwPortNo); +} + +/*========================================= + Class DtlsPort + =========================================*/ +LDtlsPort::LDtlsPort() +{ + _disconReq = false; + _sockfdMcast = 0; + _sockfdSsl = 0; + _castStat = 0; +} + +LDtlsPort::~LDtlsPort() +{ + close(); +} + + +void LDtlsPort::close() +{ + if (_sockfdMcast > 0) + { + ::close(_sockfdMcast); + _sockfdMcast = 0; + if (_sockfdSsl > 0) + { + ::close(_sockfdSsl); + _sockfdSsl = 0; + } + } +} + +bool LDtlsPort::open(LUdpConfig *config) +{ + char errmsg[256]; + int optval = 0; + + uint8_t sav = config->ipAddress[3]; + config->ipAddress[3] = config->ipAddress[0]; + config->ipAddress[0] = sav; + sav = config->ipAddress[2]; + config->ipAddress[2] = config->ipAddress[1]; + config->ipAddress[1] = sav; + + _gIpAddr = getUint32((const uint8_t*) config->ipAddress); + _gPortNo = htons(config->gPortNo); + _uPortNo = htons(config->uPortNo); + + if (_gPortNo == 0 || _gIpAddr == 0 || _uPortNo == 0) + { + return false; + } + + SSL_load_error_strings(); + SSL_library_init(); + _ctx = SSL_CTX_new(DTLS_client_method()); + + if (_ctx == 0) + { + ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg)); + DISPLAY("SSL_CTX_new() %s\n", errmsg); + return false; + } + + /* Client certification and cookie are not required */ + SSL_CTX_set_verify(_ctx, SSL_VERIFY_PEER, verify_cert); + + /* setup Multicast socket */ + _sockfdMcast = socket(AF_INET, SOCK_DGRAM, 0); + if (_sockfdMcast < 0) + { + return false; + } + + struct sockaddr_in addrm; + addrm.sin_family = AF_INET; + addrm.sin_port = _gPortNo; + addrm.sin_addr.s_addr = INADDR_ANY; + + optval = 1; + setsockopt(_sockfdMcast, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + + if (::bind(_sockfdMcast, (struct sockaddr*) &addrm, sizeof(addrm)) < 0) + { + return false; + } + + optval = 1; + if (setsockopt(_sockfdMcast, IPPROTO_IP, IP_MULTICAST_LOOP, &optval, sizeof(optval)) < 0) + { + D_NWLOG("\033[0m\033[0;31merror IP_MULTICAST_LOOP in LDtlsPort::open\033[0m\033[0;37m\n"); + DISPLAY("\033[0m\033[0;31m\nerror IP_MULTICAST_LOOP in LDtlsPort::open\033[0m\033[0;37m\n"); + close(); + return false; + } + + ip_mreq mreq; + mreq.imr_interface.s_addr = INADDR_ANY; + mreq.imr_multiaddr.s_addr = _gIpAddr; + + if (setsockopt(_sockfdMcast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) + { + D_NWLOG("\033[0m\033[0;31merror IP_ADD_MEMBERSHIP in LDtlsPort::open\033[0m\033[0;37m\n"); + DISPLAY("\033[0m\033[0;31m\nerror IP_ADD_MEMBERSHIP in LDtlsPort::open\033[0m\033[0;37m\n"); + close(); + return false; + } + return true; +} + +bool LDtlsPort::isUnicast() +{ + return (_castStat == STAT_UNICAST); +} + + +int LDtlsPort::unicast(const uint8_t *buf, uint32_t length) +{ + int status = SSL_write(_ssl, buf, length); + if (status <= 0) + { + int rc = 0; + SSL_get_error(_ssl, rc); + D_NWLOG("errno == %d in LDtlsPort::unicast\n", rc); + DISPLAY("errno == %d in LDtlsPort::unicast\n", rc); + } + else + { + D_NWLOG("sendto gateway via DTLS "); + for (uint16_t i = 0; i < length; i++) + { + D_NWLOG(" %02x", *(buf + i)); + } + D_NWLOG("\n"); + + if (!theClientMode) + { + char sbuf[SCREEN_BUFF_SIZE]; + int pos = 0; + sprintf(sbuf, "\033[0;34msendto the gateway via SSL "); + pos = strlen(sbuf); + for (uint16_t i = 0; i < length; i++) + { + sprintf(sbuf + pos, " %02x", *(buf + i)); + if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20) // -20 for Escape sequence + { + break; + } + pos += 3; + } + sprintf(sbuf + strlen(sbuf), "\033[0;37m\n"); + theScreen->display(sbuf); + } + } + return status; +} + + +int LDtlsPort::multicast(const uint8_t *buf, uint32_t length) +{ + struct sockaddr_in dest; + dest.sin_family = AF_INET; + dest.sin_port = _gPortNo; + dest.sin_addr.s_addr = _gIpAddr; + + int status = ::sendto(_sockfdMcast, buf, length, 0, (const sockaddr*) &dest, sizeof(dest)); + if (status < 0) + { + D_NWLOG("\033[0m\033[0;31merrno == %d in LDtlsPort::multicast\033[0m\033[0;37m\n", errno); + DISPLAY("\033[0m\033[0;31merrno == %d in LDtlsPort::multicast\033[0m\033[0;37m\n", errno); + return errno; + } + else + { + D_NWLOG("sendto %-15s:%-6u", inet_ntoa(dest.sin_addr), htons(_gPortNo)); + + for (uint16_t i = 0; i < length; i++) + { + D_NWLOG(" %02x", *(buf + i)); + DISPLAY(" %02x", *(buf + i)); + } + D_NWLOG("\n"); + + if (!theClientMode) + { + char sbuf[SCREEN_BUFF_SIZE]; + int pos = 0; + sprintf(sbuf, "\033[0;34msendto %-15s:%-6u", inet_ntoa(dest.sin_addr), htons(_gPortNo)); + pos = strlen(sbuf); + for (uint16_t i = 0; i < length; i++) + { + sprintf(sbuf + pos, " %02x", *(buf + i)); + if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20) + { + break; + } + pos += 3; + } + sprintf(sbuf + strlen(sbuf), "\033[0;37m\n"); + theScreen->display(sbuf); + } + return status; + } + +} + +bool LDtlsPort::checkRecvBuf() +{ + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 50000; // 50 msec + + uint8_t buf[2]; + fd_set recvfds; + int maxSock = 0; + + FD_ZERO(&recvfds); + if (_sockfdMcast) + { + FD_SET(_sockfdMcast, &recvfds); + } + if (_sockfdSsl) + { + FD_SET(_sockfdSsl, &recvfds); + } + + if (_sockfdMcast > _sockfdSsl) + { + maxSock = _sockfdMcast; + } + else + { + maxSock = _sockfdSsl; + } + + select(maxSock + 1, &recvfds, 0, 0, &timeout); + + if (FD_ISSET(_sockfdMcast, &recvfds)) + { + if (::recv(_sockfdMcast, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0) + { + _castStat = STAT_MULTICAST; + return true; + } + } + else if (FD_ISSET(_sockfdSsl, &recvfds)) + { + if (::recv(_sockfdSsl, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0) + { + _castStat = STAT_SSL; + return true; + } + } + _castStat = 0; + return false; +} + +int LDtlsPort::recv(uint8_t *buf, uint16_t len, bool flg, uint32_t *ipAddressPtr, in_port_t *portPtr) +{ + int flags = flg ? MSG_DONTWAIT : 0; + return recvfrom(buf, len, flags, ipAddressPtr, portPtr); +} + +int LDtlsPort::recvfrom(uint8_t *buf, uint16_t length, int flags, uint32_t *ipAddressPtr, in_port_t *portPtr) +{ + struct sockaddr_in sender; + int status = 0; + socklen_t addrlen = sizeof(sender); + memset(&sender, 0, addrlen); + + if (_castStat == STAT_SSL) + { + D_NWLOG("Ucast "); + if (SSL_read(_ssl, buf, length) == 0) + { + return 0; + } + } + else if (_castStat == STAT_MULTICAST) + { + D_NWLOG("Mcast "); + status = ::recvfrom(_sockfdMcast, buf, length, flags, (struct sockaddr*) &sender, &addrlen); + } + else + { + return 0; + } + + if (status < 0 && errno != EAGAIN) + { + D_NWLOG("\033[0m\033[0;31merrno == %d in LDtlsPort::recvfrom \033[0m\033[0;37m\n", errno); + DISPLAY("\033[0m\033[0;31merrno == %d in LDtlsPort::recvfrom \033[0m\033[0;37m\n", errno); + } + else if (status > 0) + { + *ipAddressPtr = sender.sin_addr.s_addr; + *portPtr = sender.sin_port; + + D_NWLOG("recved %-15s:%-6u", inet_ntoa(sender.sin_addr), ntohs(*portPtr)); + + for (uint16_t i = 0; i < status; i++) + { + D_NWLOG(" %02x", *(buf + i)); + } + D_NWLOG("\n"); + + if (!theClientMode) + { + char sbuf[SCREEN_BUFF_SIZE]; + int pos = 0; + sprintf(sbuf, "\033[0;34mrecved %-15s:%-6u", inet_ntoa(sender.sin_addr), ntohs(*portPtr)); + pos = strlen(sbuf); + for (uint16_t i = 0; i < status; i++) + { + sprintf(sbuf + pos, " %02x", *(buf + i)); + if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20) + { + break; + } + pos += 3; + } + sprintf(sbuf + strlen(sbuf), "\033[0;37m\n"); + theScreen->display(sbuf); + } + return status; + } + else + { + return 0; + } + return status; +} + +int LDtlsPort::sslConnect(uint32_t ipAddress, in_port_t portNo) +{ + int reuse = 1; + if (_ssl != 0) + { + SSL_shutdown(_ssl); + SSL_free(_ssl); + _sockfdSsl = 0; + _ssl = 0; + } + + if (_sockfdSsl > 0) + { + D_NWLOG("LDtlsPort::sslConnect socket exists.\n"); + ::close(_sockfdSsl); + } + + _sockfdSsl = socket(AF_INET, SOCK_DGRAM, 0); + if (_sockfdSsl < 0) + { + D_NWLOG("LDtlsPort::sslConnect Can't create a socket\n"); + return -1; + } + setsockopt(_sockfdSsl, SOL_SOCKET, SO_REUSEADDR || SO_REUSEPORT, &reuse, sizeof(reuse)); + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = _uPortNo; + addr.sin_addr.s_addr = INADDR_ANY; + if (::bind(_sockfdSsl, (struct sockaddr*) &addr, sizeof(addr)) < 0) + { + D_NWLOG("LDtlsPort::sslConnect Can't bind a socket\n"); + return -1; + } + + struct sockaddr_in dest; + dest.sin_family = AF_INET; + dest.sin_port = portNo; + dest.sin_addr.s_addr = ipAddress; + int rc = 0; + errno = 0; + BIO *cbio = BIO_new_dgram(_sockfdSsl, BIO_NOCLOSE); + connect(_sockfdSsl, (sockaddr*) &dest, sizeof(sockaddr_in)); + BIO_ctrl(cbio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &dest); + _ssl = SSL_new(_ctx); + SSL_set_bio(_ssl, cbio, cbio); + + D_NWLOG("LDtlsPort::sslConnect connect to %-15s:%-6u\n", inet_ntoa(dest.sin_addr), htons(dest.sin_port)); + int stat = SSL_connect(_ssl); + if (stat != 1) + { + rc = -1; + D_NWLOG("SSL fail to connect\n"); + } + else + { + D_NWLOG("SSL connected\n"); + } + return rc; +} + +int verify_cert(int ok, X509_STORE_CTX *ctx) +{ + return 1; +} + + +#endif + diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkDtls.h b/MQTTSNGateway/GatewayTester/src/LNetworkDtls.h new file mode 100644 index 0000000..11bee40 --- /dev/null +++ b/MQTTSNGateway/GatewayTester/src/LNetworkDtls.h @@ -0,0 +1,117 @@ +/************************************************************************************** + * 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 NETWORKDTLS_H_ +#define NETWORKDTLS_H_ + +#ifdef DTLS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SOCKET_MAXHOSTNAME 200 +#define SOCKET_MAXCONNECTIONS 5 +#define SOCKET_MAXRECV 500 +#define SOCKET_MAXBUFFER_LENGTH 500 // buffer size + +#define STAT_UNICAST 1 +#define STAT_MULTICAST 2 +#define STAT_SSL 3 + +using namespace std; + +namespace linuxAsyncClient { +/*======================================== + Class LDtlsPort + =======================================*/ +class LDtlsPort +{ + friend class LNetwork; +public: + LDtlsPort(); + virtual ~LDtlsPort(); + + bool open(LUdpConfig* config); + + int unicast(const uint8_t *buf, uint32_t length); + int multicast( const uint8_t* buf, uint32_t length ); + int recv(uint8_t* buf, uint16_t len, bool nonblock, uint32_t* ipaddress, in_port_t* port ); + int recv(uint8_t* buf, int flags); + bool checkRecvBuf(); + bool isUnicast(); + SSL* getSSL(void); + int sslConnect(uint32_t ipAddress, in_port_t port); +private: + void close(); + int recvfrom ( uint8_t* buf, uint16_t len, int flags, uint32_t* ipaddress, in_port_t* port ); + + int _sockfdMcast; + int _sockfdSsl; + SSL_CTX *_ctx; + SSL *_ssl; + in_port_t _gPortNo; + in_port_t _uPortNo; + uint32_t _gIpAddr; + uint8_t _castStat; + bool _disconReq; + +}; + +#define NO_ERROR 0 +#define PACKET_EXCEEDS_LENGTH 1 +/*=========================================== + Class Network + ============================================*/ +class LNetwork: public LDtlsPort +{ +public: + LNetwork(); + ~LNetwork(); + + int broadcast(const uint8_t* payload, uint16_t payloadLen); + int unicast(const uint8_t* payload, uint16_t payloadLen); + void setGwAddress(void); + void resetGwAddress(void); + bool initialize(LUdpConfig* config); + uint8_t* getMessage(int* len); + bool isBroadcastable(); + int sslConnect(void); +private: + void setSleep(); + int readApiFrame(void); + + uint32_t _gwIpAddress; + uint32_t _ipAddress; + in_port_t _gwPortNo; + in_port_t _portNo; + int _returnCode; + bool _sleepflg; + uint8_t _rxDataBuf[MQTTSN_MAX_PACKET_SIZE + 1]; // defined in MqttsnClientApp.h + +}; + +} /* end of namespace */ +#endif /* DTLS */ +#endif /* NETWORKDTLS_H_ */ diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkDtls6.cpp b/MQTTSNGateway/GatewayTester/src/LNetworkDtls6.cpp new file mode 100644 index 0000000..d748acf --- /dev/null +++ b/MQTTSNGateway/GatewayTester/src/LNetworkDtls6.cpp @@ -0,0 +1,533 @@ +/************************************************************************************** + * Copyright (c) 2021, 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 + **************************************************************************************/ +#ifdef DTLS6 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "LMqttsnClientApp.h" +#include "LNetworkDtls6.h" +#include "LTimer.h" +#include "LScreen.h" + +using namespace std; +using namespace linuxAsyncClient; + +extern uint16_t getUint16(const uint8_t *pos); +extern uint32_t getUint32(const uint8_t *pos); +extern LScreen *theScreen; +extern bool theClientMode; + +/* Certificate verification. Returns 1 if trusted, else 0 */ +int verify_cert(int ok, X509_STORE_CTX *ctx); + +/*========================================= + Class LNetwork + =========================================*/ +LNetwork::LNetwork() +{ + _sleepflg = false; + resetGwAddress(); +} + +LNetwork::~LNetwork() +{ +} + +int LNetwork::broadcast(const uint8_t *xmitData, uint16_t dataLen) +{ + return LDtls6Port::multicast(xmitData, (uint32_t) dataLen); +} + +int LNetwork::unicast(const uint8_t *xmitData, uint16_t dataLen) +{ + return LDtls6Port::unicast(xmitData, dataLen); +} + +uint8_t* LNetwork::getMessage(int *len) +{ + *len = 0; + if (checkRecvBuf()) + { + uint16_t recvLen = LDtls6Port::recv(_rxDataBuf, MQTTSN_MAX_PACKET_SIZE, false, &_ipAddress, &_portNo); + int diffAddr = memcmp(_ipAddress.s6_addr, _gwIpAddress.s6_addr, sizeof(_gwIpAddress.s6_addr)); + if (isUnicast() && diffAddr && (_portNo != _gwPortNo)) + { + return 0; + } + + if (recvLen < 0) + { + *len = recvLen; + return 0; + } + else + { + if (_rxDataBuf[0] == 0x01) + { + *len = getUint16(_rxDataBuf + 1); + } + else + { + *len = _rxDataBuf[0]; + } + return _rxDataBuf; + } + } + return 0; +} + +void LNetwork::setGwAddress(void) +{ + _gwPortNo = _portNo; + memcpy(&_gwIpAddress.s6_addr, &_ipAddress.s6_addr, sizeof(_ipAddress.s6_addr)); + +} + +void LNetwork::resetGwAddress(void) +{ + memset(&_gwIpAddress, 0, sizeof(_gwIpAddress)); + _gwPortNo = 0; +} + +bool LNetwork::initialize(LUdp6Config *config) +{ + return LDtls6Port::open(config); +} + +void LNetwork::setSleep() +{ + _sleepflg = true; +} + +bool LNetwork::isBroadcastable() +{ + return true; +} + +int LNetwork::sslConnect(void) +{ + return LDtls6Port::sslConnect(_gwIpAddress, _gwPortNo); +} + +/*========================================= + Class Dtls6Port + =========================================*/ +LDtls6Port::LDtls6Port() +{ + _disconReq = false; + memset(_pollfds, 0, sizeof(_pollfds)); + _sock = 0; + _castStat = 0; + _ifIndex = 0; + _gIpAddrStr = NULL; +} + +LDtls6Port::~LDtls6Port() +{ + close(); + if (_gIpAddrStr) + { + free(_gIpAddrStr); + } +} + +void LDtls6Port::close() +{ + for (int i = 0; i < 2; i++) + { + if (_pollfds[i].fd > 0) + { + ::close(_pollfds[i].fd); + _pollfds[i].fd = 0; + } + } +} + +bool LDtls6Port::open(LUdp6Config *config) +{ + int optval = 1; + int sock = 0; + sockaddr_in6 addr6; + char errmsg[256]; + + _gPortNo = htons(config->gPortNo); + _uPortNo = htons(config->uPortNo); + + if (_gPortNo == 0 || _uPortNo == 0) + { + return false; + } + + SSL_load_error_strings(); + SSL_library_init(); + _ctx = SSL_CTX_new(DTLS_client_method()); + + if (_ctx == 0) + { + ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg)); + DISPLAY("SSL_CTX_new() %s\n", errmsg); + return false; + } + + /* Client certification and cookie are not required */ + SSL_CTX_set_verify(_ctx, SSL_VERIFY_PEER, verify_cert); + + if (strlen(config->interface) > 0) + { + _ifIndex = if_nametoindex(config->interface); + _interfaceName = config->interface; + } + + /* create a multicast socket */ + sock = socket(AF_INET6, SOCK_DGRAM, 0); + if (sock < 0) + { + return false; + } + + optval = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)); + + memset(&addr6, 0, sizeof(addr6)); + addr6.sin6_family = AF_INET6; + addr6.sin6_port = _gPortNo; + addr6.sin6_addr = in6addr_any; + + if (::bind(sock, (sockaddr*) &addr6, sizeof(addr6)) < 0) + { + D_NWLOG("\033[0m\033[0;31merror %s ::bind() in Udp6Port::open\033[0m\033[0;37m\n", strerror(errno)); + return false; + } + + ipv6_mreq addrm; + addrm.ipv6mr_interface = _ifIndex; + inet_pton(AF_INET6, config->ipAddress, &addrm.ipv6mr_multiaddr); + if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &addrm, sizeof(addrm)) < 0) + { + D_NWLOG("\033[0m\033[0;31merror %s IPV6_ADD_MEMBERSHIP in Udp6Port::open\033[0m\033[0;37m\n", strerror(errno)); + close(); + return false; + } + optval = 0; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &optval, sizeof(optval)) < 0) + { + D_NWLOG("\033[0m\033[0;31merror %s IPV6_MULTICAST_LOOP in Udp6Port::open\033[0m\033[0;37m\n", strerror(errno)); + close(); + return false; + } + _pollfds[1].fd = sock; + _pollfds[1].events = POLLIN; + _gIpAddr.sin6_family = AF_INET6; + _gIpAddr.sin6_port = _gPortNo; + memcpy(&_gIpAddr.sin6_addr, (const void*) &addrm.ipv6mr_multiaddr, sizeof(addrm.ipv6mr_multiaddr)); + _gIpAddrStr = strdup(config->ipAddress); + return true; +} + +bool LDtls6Port::isUnicast() +{ + return (_sock == _pollfds[0].fd && _sock > 0); +} + +int LDtls6Port::unicast(const uint8_t *buf, uint32_t length) +{ + int status = SSL_write(_ssl, buf, length); + if (status <= 0) + { + int rc = 0; + SSL_get_error(_ssl, rc); + DISPLAY("errno == %d in LDtls6Port::unicast\n", rc); + } + else + { + D_NWLOG("sendto gateway via DTLS "); + for (uint16_t i = 0; i < length; i++) + { + D_NWLOG(" %02x", *(buf + i)); + }D_NWLOG("\n"); + + if (!theClientMode) + { + char sbuf[SCREEN_BUFF_SIZE]; + int pos = 0; + sprintf(sbuf, "\033[0;34msendto the gateway via SSL "); + pos = strlen(sbuf); + for (uint16_t i = 0; i < length; i++) + { + sprintf(sbuf + pos, " %02x", *(buf + i)); + if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20) // -20 for Escape sequence + { + break; + } + pos += 3; + } + sprintf(sbuf + strlen(sbuf), "\033[0;37m\n"); + theScreen->display(sbuf); + } + } + return status; +} + +int LDtls6Port::multicast(const uint8_t *buf, uint32_t length) +{ + char sbuf[SCREEN_BUFF_SIZE]; + char portStr[8]; + sprintf(portStr, "%d", ntohs(_gPortNo)); + + int status = ::sendto(_pollfds[1].fd, buf, length, 0, (sockaddr*) &_gIpAddr, sizeof(_gIpAddr)); + if (status < 0) + { + D_NWLOG("multicast to [%s]:%-6s ", _gIpAddrStr, portStr);D_NWLOG("\033[0m\033[0;31merrno = %d %s in Udp6Port::multicast\033[0m\033[0;37m\n", errno, strerror(errno)); + return errno; + } + else + { + D_NWLOG("multicast to [%s]:%-6s", _gIpAddrStr, portStr); + for (uint16_t i = 0; i < length; i++) + { + D_NWLOG(" %02x", *(buf + i)); + }D_NWLOG("\n"); + + if (!theClientMode) + { + memset(sbuf, 0, SCREEN_BUFF_SIZE); + int pos = 0; + sprintf(sbuf, "\033[0;34mmulticast to [%s]:%-6s", _gIpAddrStr, portStr); + pos = strlen(sbuf); + for (uint16_t i = 0; i < length; i++) + { + sprintf(sbuf + pos, " %02x", *(buf + i)); + if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20) + { + break; + } + pos += 3; + } + sprintf(sbuf + strlen(sbuf), "\033[0;37m\n"); + theScreen->display(sbuf); + } + return status; + } +} + +bool LDtls6Port::checkRecvBuf() +{ + uint8_t buf[2]; + + int cnt = poll(_pollfds, 2, 2000); // Timeout 2secs + if (cnt == 0) + { + return false; + } + + if (_pollfds[0].revents & POLLIN) + { + if (::recv(_pollfds[0].fd, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0) + { + _castStat = STAT_SSL; + _sock = _pollfds[0].fd; + return true; + } + } + else if (_pollfds[1].revents & POLLIN) + { + if (::recv(_pollfds[1].fd, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0) + { + _castStat = STAT_MULTICAST; + _sock = _pollfds[1].fd; + return true; + } + } + return false; +} + +int LDtls6Port::recv(uint8_t *buf, uint16_t len, bool flg, in6_addr *ipAddressPtr, in_port_t *portPtr) +{ + int flags = flg ? MSG_DONTWAIT : 0; + return recvfrom(buf, len, flags, ipAddressPtr, portPtr); +} + +int LDtls6Port::recvfrom(uint8_t *buf, uint16_t length, int flags, in6_addr *ipAddressPtr, in_port_t *portPtr) +{ + sockaddr_in6 sender; + int status = 0; + socklen_t addrlen = sizeof(sender); + memset(&sender, 0, addrlen); + char addrBuf[INET6_ADDRSTRLEN]; + + if (_castStat == STAT_SSL) + { + D_NWLOG("Ucast "); + if (SSL_read(_ssl, buf, length) == 0) + { + return 0; + } + } + else if (_castStat == STAT_MULTICAST) + { + D_NWLOG("Mcast "); + status = ::recvfrom(_sock, buf, length, flags, (sockaddr*) &sender, &addrlen); + } + else + { + return 0; + } + + if (status < 0 && errno != EAGAIN) + { + D_NWLOG("\033[0m\033[0;31merrno == %d in LDtls6Port::recvfrom \033[0m\033[0;37m\n", errno); + DISPLAY("\033[0m\033[0;31merrno == %d in LDtls6Port::recvfrom \033[0m\033[0;37m\n", errno); + } + else if (status > 0) + { + inet_ntop(AF_INET6, &sender.sin6_addr, addrBuf, INET6_ADDRSTRLEN); + memcpy(ipAddressPtr->s6_addr, (const void*) sender.sin6_addr.s6_addr, sizeof(sender.sin6_addr.s6_addr)); + *portPtr = sender.sin6_port; + + D_NWLOG("recved %-15s:%-6u", addrBuf, htons(*portPtr)); + + for (uint16_t i = 0; i < status; i++) + { + D_NWLOG(" %02x", *(buf + i)); + }D_NWLOG("\n"); + + if (!theClientMode) + { + char sbuf[SCREEN_BUFF_SIZE]; + int pos = 0; + sprintf(sbuf, "\033[0;34mrecved %-15s:%-6u", addrBuf, htons(*portPtr)); + pos = strlen(sbuf); + for (uint16_t i = 0; i < status; i++) + { + sprintf(sbuf + pos, " %02x", *(buf + i)); + if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20) + { + break; + } + pos += 3; + } + sprintf(sbuf + strlen(sbuf), "\033[0;37m\n"); + theScreen->display(sbuf); + } + return status; + } + else + { + return 0; + } + return status; +} + +int LDtls6Port::sslConnect(in6_addr ipAddress, uint16_t portNo) +{ + int optval = 1; + int sock = _pollfds[0].fd; + + if (_ssl != 0) + { + SSL_free(_ssl); + } + + if (sock > 0) + { + ::close(sock); + } + + sock = socket(AF_INET6, SOCK_DGRAM, 0); + if (sock <= 0) + { + return -1; + } + optval = 1; + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)); + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR || SO_REUSEPORT, &optval, sizeof(optval)); + + if (_ifIndex > 0) + { +#ifdef __APPLE__ + setsockopt(sock, IPPROTO_IP, IP_BOUND_IF, &_ifIndex, sizeof(_ifIndex)); +#else + setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, _interfaceName.c_str(), _interfaceName.size()); +#endif + } + + struct sockaddr_in6 addr; + addr.sin6_family = AF_INET6; + addr.sin6_port = _uPortNo; + addr.sin6_addr = in6addr_any; + + if (::bind(sock, (struct sockaddr*) &addr, sizeof(addr)) < 0) + { + return -1; + } + _pollfds[0].fd = sock; + _pollfds[0].events = POLLIN; + + uint16_t listenPort = htons(portNo); + struct sockaddr_in6 dest; + dest.sin6_family = AF_INET6; + dest.sin6_port = htons(listenPort); + memcpy(dest.sin6_addr.s6_addr, (const void*) ipAddress.s6_addr, sizeof(ipAddress.s6_addr)); + + int rc = 0; + + BIO *cbio = BIO_new_dgram(sock, BIO_NOCLOSE); + connect(sock, (sockaddr*) &dest, sizeof(sockaddr_in6)); + BIO_ctrl(cbio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &dest); + _ssl = SSL_new(_ctx); + SSL_set_bio(_ssl, cbio, cbio); + +#ifdef DEBUG_NW + char addrBuf[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &dest.sin6_addr, addrBuf, INET6_ADDRSTRLEN); + D_NWLOG("connect to %-15s:%-6u\n", addrBuf, ntohs(dest.sin6_port)); +#endif + + errno = 0; + int stat = SSL_connect(_ssl); + if (stat != 1) + { + rc = -1; + D_NWLOG("SSL fail to connect %s\n",strerror(errno)); + } + else + { + D_NWLOG("SSL connected\n"); + } + return rc; +} + +int verify_cert(int ok, X509_STORE_CTX *ctx) +{ + return 1; +} + +#endif + diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkDtls6.h b/MQTTSNGateway/GatewayTester/src/LNetworkDtls6.h new file mode 100644 index 0000000..6177e4b --- /dev/null +++ b/MQTTSNGateway/GatewayTester/src/LNetworkDtls6.h @@ -0,0 +1,121 @@ +/************************************************************************************** + * Copyright (c) 2021, 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 NETWORKDTLS6_H_ +#define NETWORKDTLS6_H_ + +#ifdef DTLS6 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SOCKET_MAXHOSTNAME 200 +#define SOCKET_MAXCONNECTIONS 5 +#define SOCKET_MAXRECV 500 +#define SOCKET_MAXBUFFER_LENGTH 500 // buffer size + +#define STAT_UNICAST 1 +#define STAT_MULTICAST 2 +#define STAT_SSL 3 + +using namespace std; + +namespace linuxAsyncClient { +/*======================================== + Class LDtls6Port + =======================================*/ +class LDtls6Port +{ + friend class LNetwork; +public: + LDtls6Port(); + virtual ~LDtls6Port(); + + bool open(LUdp6Config* config); + + int unicast(const uint8_t *buf, uint32_t length); + int multicast( const uint8_t* buf, uint32_t length ); + int recv(uint8_t* buf, uint16_t len, bool nonblock, in6_addr* ipaddress, in_port_t* port ); + int recv(uint8_t* buf, int flags); + bool checkRecvBuf(); + bool isUnicast(); + SSL* getSSL(void); + int sslConnect(in6_addr ipAddress, uint16_t port); +private: + void close(); + int recvfrom ( uint8_t* buf, uint16_t len, int flags, in6_addr* ipaddress, in_port_t* port ); + + SSL_CTX *_ctx; + SSL *_ssl; + pollfd _pollfds[2]; + in_port_t _gPortNo; + in_port_t _uPortNo; + sockaddr_in6 _gIpAddr; + char *_gIpAddrStr; + uint32_t _ifIndex; + string _interfaceName; + uint8_t _castStat; + int _sock; + bool _disconReq; + +}; + +#define NO_ERROR 0 +#define PACKET_EXCEEDS_LENGTH 1 +/*=========================================== + Class Network + ============================================*/ +class LNetwork: public LDtls6Port +{ +public: + LNetwork(); + ~LNetwork(); + + int broadcast(const uint8_t* payload, uint16_t payloadLen); + int unicast(const uint8_t* payload, uint16_t payloadLen); + void setGwAddress(void); + void resetGwAddress(void); + bool initialize(LUdp6Config* config); + uint8_t* getMessage(int* len); + bool isBroadcastable(); + int sslConnect(void); +private: + void setSleep(); + int readApiFrame(void); + + in6_addr _gwIpAddress; + in6_addr _ipAddress; + in_port_t _gwPortNo; + in_port_t _portNo; + int _returnCode; + bool _sleepflg; + uint8_t _rxDataBuf[MQTTSN_MAX_PACKET_SIZE + 1]; // defined in MqttsnClientApp.h + +}; + +} /* end of namespace */ +#endif /* DTLS6 */ +#endif /* NETWORKDTLS6_H_ */ diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkRfcomm.cpp b/MQTTSNGateway/GatewayTester/src/LNetworkRfcomm.cpp index f44e8eb..e4b5a40 100644 --- a/MQTTSNGateway/GatewayTester/src/LNetworkRfcomm.cpp +++ b/MQTTSNGateway/GatewayTester/src/LNetworkRfcomm.cpp @@ -13,7 +13,6 @@ * Contributors: * Tomoaki Yamaguchi - initial API and implementation and/or initial documentation **************************************************************************************/ -#include "LMqttsnClientApp.h" #ifdef RFCOMM #include @@ -29,6 +28,7 @@ #include #include +#include "LMqttsnClientApp.h" #include "LNetworkRfcomm.h" #include "LTimer.h" #include "LScreen.h" diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkRfcomm.h b/MQTTSNGateway/GatewayTester/src/LNetworkRfcomm.h index 0228295..d96a5f8 100644 --- a/MQTTSNGateway/GatewayTester/src/LNetworkRfcomm.h +++ b/MQTTSNGateway/GatewayTester/src/LNetworkRfcomm.h @@ -17,7 +17,6 @@ #ifndef NETWORKRFCOMM_H_ #define NETWORKRFCOMM_H_ -#include "LMqttsnClientApp.h" #ifdef RFCOMM #include diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp b/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp index 9a830b6..25020f7 100644 --- a/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp +++ b/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp @@ -13,7 +13,6 @@ * Contributors: * Tomoaki Yamaguchi - initial API and implementation and/or initial documentation **************************************************************************************/ -#include "LMqttsnClientApp.h" #ifdef UDP #include @@ -27,89 +26,105 @@ #include #include +#include "LMqttsnClientApp.h" #include "LNetworkUdp.h" #include "LTimer.h" #include "LScreen.h" - using namespace std; using namespace linuxAsyncClient; -extern uint16_t getUint16(const uint8_t* pos); -extern uint32_t getUint32(const uint8_t* pos); -extern LScreen* theScreen; +extern uint16_t getUint16(const uint8_t *pos); +extern uint32_t getUint32(const uint8_t *pos); +extern LScreen *theScreen; extern bool theClientMode; /*========================================= - Class LNetwork + Class LNetwork =========================================*/ -LNetwork::LNetwork(){ - _sleepflg = false; - resetGwAddress(); +LNetwork::LNetwork() +{ + _sleepflg = false; + resetGwAddress(); } -LNetwork::~LNetwork(){ +LNetwork::~LNetwork() +{ } -int LNetwork::broadcast(const uint8_t* xmitData, uint16_t dataLen){ - return LUdpPort::multicast(xmitData, (uint32_t)dataLen); +int LNetwork::broadcast(const uint8_t *xmitData, uint16_t dataLen) +{ + return LUdpPort::multicast(xmitData, (uint32_t) dataLen); } -int LNetwork::unicast(const uint8_t* xmitData, uint16_t dataLen){ - return LUdpPort::unicast(xmitData, dataLen, _gwIpAddress, _gwPortNo); +int LNetwork::unicast(const uint8_t *xmitData, uint16_t dataLen) +{ + return LUdpPort::unicast(xmitData, dataLen, _gwIpAddress, _gwPortNo); } +uint8_t* LNetwork::getMessage(int *len) +{ + *len = 0; + if (checkRecvBuf()) + { + uint16_t recvLen = LUdpPort::recv(_rxDataBuf, MQTTSN_MAX_PACKET_SIZE, false, &_ipAddress, &_portNo); + if (_gwIpAddress && isUnicast() && (_ipAddress != _gwIpAddress) && (_portNo != _gwPortNo)) + { + return 0; + } -uint8_t* LNetwork::getMessage(int* len){ - *len = 0; - if (checkRecvBuf()){ - uint16_t recvLen = LUdpPort::recv(_rxDataBuf, MQTTSN_MAX_PACKET_SIZE, false, &_ipAddress, &_portNo); - if(_gwIpAddress && isUnicast() && (_ipAddress != _gwIpAddress) && (_portNo != _gwPortNo)){ - return 0; - } - - if(recvLen < 0){ - *len = recvLen; - return 0; - }else{ - if(_rxDataBuf[0] == 0x01){ - *len = getUint16(_rxDataBuf + 1 ); - }else{ - *len = _rxDataBuf[0]; - } - //if(recvLen != *len){ - // *len = 0; - // return 0; - //}else{ - return _rxDataBuf; - //} - } - } - return 0; + if (recvLen < 0) + { + *len = recvLen; + return 0; + } + else + { + if (_rxDataBuf[0] == 0x01) + { + *len = getUint16(_rxDataBuf + 1); + } + else + { + *len = _rxDataBuf[0]; + } + //if(recvLen != *len){ + // *len = 0; + // return 0; + //}else{ + return _rxDataBuf; + //} + } + } + return 0; } -void LNetwork::setGwAddress(void){ - _gwPortNo = _portNo; - _gwIpAddress = _ipAddress; +void LNetwork::setGwAddress(void) +{ + _gwPortNo = _portNo; + _gwIpAddress = _ipAddress; } -void LNetwork::setFixedGwAddress(void){ +void LNetwork::setFixedGwAddress(void) +{ _gwPortNo = LUdpPort::_gPortNo; _gwIpAddress = LUdpPort::_gIpAddr; } -void LNetwork::resetGwAddress(void){ - _gwIpAddress = 0; - _gwPortNo = 0; +void LNetwork::resetGwAddress(void) +{ + _gwIpAddress = 0; + _gwPortNo = 0; } - -bool LNetwork::initialize(LUdpConfig* config){ - return LUdpPort::open(config); +bool LNetwork::initialize(LUdpConfig *config) +{ + return LUdpPort::open(config); } -void LNetwork::setSleep(){ - _sleepflg = true; +void LNetwork::setSleep() +{ + _sleepflg = true; } bool LNetwork::isBroadcastable() @@ -117,7 +132,7 @@ bool LNetwork::isBroadcastable() return true; } /*========================================= - Class udpStack + Class udpStack =========================================*/ LUdpPort::LUdpPort() { @@ -132,267 +147,302 @@ LUdpPort::~LUdpPort() close(); } - -void LUdpPort::close(){ - if(_sockfdMcast > 0) - { - ::close( _sockfdMcast); - _sockfdMcast = -1; - if(_sockfdUcast > 0) - { - ::close( _sockfdUcast); - _sockfdUcast = -1; - } - } -} - -bool LUdpPort::open(LUdpConfig* config) +void LUdpPort::close() { - const int reuse = 1; - char loopch = 1; - - uint8_t sav = config->ipAddress[3]; - config->ipAddress[3] = config->ipAddress[0]; - config->ipAddress[0] = sav; - sav = config->ipAddress[2]; - config->ipAddress[2] = config->ipAddress[1]; - config->ipAddress[1] = sav; - - _gPortNo = htons(config->gPortNo); - _gIpAddr = getUint32((const uint8_t*)config->ipAddress); - _uPortNo = htons(config->uPortNo); - - if( _gPortNo == 0 || _gIpAddr == 0 || _uPortNo == 0){ - return false; - } - - _sockfdUcast = socket(AF_INET, SOCK_DGRAM, 0); - if (_sockfdUcast < 0){ - return false; - } - - setsockopt(_sockfdUcast, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); - - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = _uPortNo; - addr.sin_addr.s_addr = INADDR_ANY; - - if( ::bind ( _sockfdUcast, (struct sockaddr*)&addr, sizeof(addr)) <0){ - return false; - } - - _sockfdMcast = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (_sockfdMcast < 0){ - return false; - } - - struct sockaddr_in addrm; - addrm.sin_family = AF_INET; - addrm.sin_port = _gPortNo; - addrm.sin_addr.s_addr = htonl(INADDR_ANY); - - setsockopt(_sockfdMcast, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); - - if( ::bind ( _sockfdMcast, (struct sockaddr*)&addrm, sizeof(addrm)) <0){ - return false; - } - - if(setsockopt(_sockfdMcast, IPPROTO_IP, IP_MULTICAST_LOOP,(char*)&loopch, sizeof(loopch)) <0 ){ - D_NWLOG("\033[0m\033[0;31merror IP_MULTICAST_LOOP in UdpPPort::open\033[0m\033[0;37m\n"); - DISPLAY("\033[0m\033[0;31m\nerror IP_MULTICAST_LOOP in UdpPPort::open\033[0m\033[0;37m\n"); - close(); - return false; - } - - ip_mreq mreq; - mreq.imr_interface.s_addr = INADDR_ANY; - mreq.imr_multiaddr.s_addr = _gIpAddr; - - if( setsockopt(_sockfdMcast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq) )< 0){ - D_NWLOG("\033[0m\033[0;31merror IP_ADD_MEMBERSHIP in UdpPort::open\033[0m\033[0;37m\n"); - DISPLAY("\033[0m\033[0;31m\nerror IP_ADD_MEMBERSHIP in UdpPort::open\033[0m\033[0;37m\n"); - close(); - return false; - } - return true; + if (_sockfdMcast > 0) + { + ::close(_sockfdMcast); + _sockfdMcast = -1; + if (_sockfdUcast > 0) + { + ::close(_sockfdUcast); + _sockfdUcast = -1; + } + } } -bool LUdpPort::isUnicast(){ - return ( _castStat == STAT_UNICAST); +bool LUdpPort::open(LUdpConfig *config) +{ + int optval = 0; + + uint8_t sav = config->ipAddress[3]; + config->ipAddress[3] = config->ipAddress[0]; + config->ipAddress[0] = sav; + sav = config->ipAddress[2]; + config->ipAddress[2] = config->ipAddress[1]; + config->ipAddress[1] = sav; + + _gPortNo = htons(config->gPortNo); + _gIpAddr = getUint32((const uint8_t*) config->ipAddress); + _uPortNo = htons(config->uPortNo); + + if (_gPortNo == 0 || _gIpAddr == 0 || _uPortNo == 0) + { + return false; + } + + _sockfdUcast = socket(AF_INET, SOCK_DGRAM, 0); + if (_sockfdUcast < 0) + { + return false; + } + + optval = 1; + setsockopt(_sockfdUcast, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = _uPortNo; + addr.sin_addr.s_addr = INADDR_ANY; + + if (::bind(_sockfdUcast, (struct sockaddr*) &addr, sizeof(addr)) < 0) + { + return false; + } + + _sockfdMcast = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (_sockfdMcast < 0) + { + return false; + } + + sockaddr_in addrm; + addrm.sin_family = AF_INET; + addrm.sin_port = _gPortNo; + addrm.sin_addr.s_addr = INADDR_ANY; + + optval = 1; + setsockopt(_sockfdMcast, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + + if (::bind(_sockfdMcast, (struct sockaddr*) &addrm, sizeof(addrm)) < 0) + { + return false; + } + + ip_mreq mreq; + mreq.imr_interface.s_addr = INADDR_ANY; + mreq.imr_multiaddr.s_addr = _gIpAddr; + + if (setsockopt(_sockfdMcast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) + { + D_NWLOG("\033[0m\033[0;31merror IP_ADD_MEMBERSHIP in UdpPort::open\033[0m\033[0;37m\n"); + close(); + return false; + } + + optval= 1; + if (setsockopt(_sockfdMcast, IPPROTO_IP, IP_MULTICAST_LOOP, &optval, sizeof(optval)) < 0) + { + D_NWLOG("\033[0m\033[0;31merror IP_MULTICAST_LOOP in UdpPPort::open\033[0m\033[0;37m\n"); + close(); + return false; + } + return true; } - -int LUdpPort::unicast(const uint8_t* buf, uint32_t length, uint32_t ipAddress, uint16_t port ){ - struct sockaddr_in dest; - dest.sin_family = AF_INET; - dest.sin_port = port; - dest.sin_addr.s_addr = ipAddress; - - int status = ::sendto( _sockfdUcast, buf, length, 0, (const sockaddr*)&dest, sizeof(dest) ); - if( status < 0){ - D_NWLOG("errno == %d in UdpPort::unicast\n", errno); - DISPLAY("errno == %d in UdpPort::unicast\n", errno); - }else{ - D_NWLOG("sendto %-15s:%-6u",inet_ntoa(dest.sin_addr),htons(port)); - for(uint16_t i = 0; i < length ; i++){ - D_NWLOG(" %02x", *(buf + i)); - } - D_NWLOG("\n"); - - if ( !theClientMode ) - { - char sbuf[SCREEN_BUFF_SIZE]; - int pos = 0; - sprintf(sbuf,"\033[0;34msendto %-15s:%-6u",inet_ntoa(dest.sin_addr),htons(port)); - pos = strlen(sbuf); - for(uint16_t i = 0; i < length ; i++){ - sprintf(sbuf + pos, " %02x", *(buf + i)); - if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20 ) // -20 for Escape sequence - { - break; - } - pos += 3; - } - sprintf(sbuf + strlen(sbuf), "\033[0;37m\n"); - theScreen->display(sbuf); - } - } - return status; +bool LUdpPort::isUnicast() +{ + return (_castStat == STAT_UNICAST); } +int LUdpPort::unicast(const uint8_t *buf, uint32_t length, uint32_t ipAddress, uint16_t port) +{ + struct sockaddr_in dest; + dest.sin_family = AF_INET; + dest.sin_port = port; + dest.sin_addr.s_addr = ipAddress; -int LUdpPort::multicast( const uint8_t* buf, uint32_t length ){ - struct sockaddr_in dest; - dest.sin_family = AF_INET; - dest.sin_port = _gPortNo; - dest.sin_addr.s_addr = _gIpAddr; + int status = ::sendto(_sockfdUcast, buf, length, 0, (const sockaddr*) &dest, sizeof(dest)); + if (status < 0) + { + D_NWLOG("errno == %d in UdpPort::unicast\n", errno); + } + else + { + D_NWLOG("sendto %-15s:%-6u",inet_ntoa(dest.sin_addr),htons(port)); + for (uint16_t i = 0; i < length; i++) + { + D_NWLOG(" %02x", *(buf + i)); + } D_NWLOG("\n"); - int status = ::sendto( _sockfdMcast, buf, length, 0, (const sockaddr*)&dest, sizeof(dest) ); - if( status < 0){ - D_NWLOG("\033[0m\033[0;31merrno == %d in UdpPort::multicast\033[0m\033[0;37m\n", errno); - DISPLAY("\033[0m\033[0;31merrno == %d in UdpPort::multicast\033[0m\033[0;37m\n", errno); - return errno; - }else{ - D_NWLOG("sendto %-15s:%-6u",inet_ntoa(dest.sin_addr),htons(_gPortNo)); + if (!theClientMode) + { + char sbuf[SCREEN_BUFF_SIZE]; + int pos = 0; + sprintf(sbuf, "\033[0;34msendto %-15s:%-6u", inet_ntoa(dest.sin_addr), htons(port)); + pos = strlen(sbuf); + for (uint16_t i = 0; i < length; i++) + { + sprintf(sbuf + pos, " %02x", *(buf + i)); + if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20) // -20 for Escape sequence + { + break; + } + pos += 3; + } + sprintf(sbuf + strlen(sbuf), "\033[0;37m\n"); + } + } + return status; +} - for(uint16_t i = 0; i < length ; i++){ - D_NWLOG(" %02x", *(buf + i)); - DISPLAY(" %02x", *(buf + i)); - } - D_NWLOG("\n"); +int LUdpPort::multicast(const uint8_t *buf, uint32_t length) +{ + struct sockaddr_in dest; + dest.sin_family = AF_INET; + dest.sin_port = _gPortNo; + dest.sin_addr.s_addr = _gIpAddr; - if ( !theClientMode ) - { - char sbuf[SCREEN_BUFF_SIZE]; - int pos = 0; - sprintf(sbuf,"\033[0;34msendto %-15s:%-6u",inet_ntoa(dest.sin_addr),htons(_gPortNo)); - pos = strlen(sbuf); - for(uint16_t i = 0; i < length ; i++){ - sprintf(sbuf + pos, " %02x", *(buf + i)); - if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20 ) - { - break; - } - pos += 3; - } - sprintf(sbuf + strlen(sbuf), "\033[0;37m\n"); - theScreen->display(sbuf); - } - return status; - } + int status = ::sendto(_sockfdMcast, buf, length, 0, (const sockaddr*) &dest, sizeof(dest)); + if (status < 0) + { + D_NWLOG("\033[0m\033[0;31merrno == %d in UdpPort::multicast\033[0m\033[0;37m\n", errno); + return errno; + } + else + { + D_NWLOG("sendto %-15s:%-6u",inet_ntoa(dest.sin_addr),htons(_gPortNo)); + + for (uint16_t i = 0; i < length; i++) + { + D_NWLOG(" %02x", *(buf + i)); + } D_NWLOG("\n"); + + if (!theClientMode) + { + char sbuf[SCREEN_BUFF_SIZE]; + int pos = 0; + sprintf(sbuf, "\033[0;34msendto %-15s:%-6u", inet_ntoa(dest.sin_addr), htons(_gPortNo)); + pos = strlen(sbuf); + for (uint16_t i = 0; i < length; i++) + { + sprintf(sbuf + pos, " %02x", *(buf + i)); + if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20) + { + break; + } + pos += 3; + } + sprintf(sbuf + strlen(sbuf), "\033[0;37m\n"); + theScreen->display(sbuf); + } + return status; + } } -bool LUdpPort::checkRecvBuf(){ - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 50000; // 50 msec +bool LUdpPort::checkRecvBuf() +{ + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 50000; // 50 msec - uint8_t buf[2]; - fd_set recvfds; - int maxSock = 0; + uint8_t buf[2]; + fd_set recvfds; + int maxSock = 0; - FD_ZERO(&recvfds); - FD_SET(_sockfdUcast, &recvfds); - FD_SET(_sockfdMcast, &recvfds); + FD_ZERO(&recvfds); + FD_SET(_sockfdUcast, &recvfds); + FD_SET(_sockfdMcast, &recvfds); - if(_sockfdMcast > _sockfdUcast){ - maxSock = _sockfdMcast; - }else{ - maxSock = _sockfdUcast; - } + if (_sockfdMcast > _sockfdUcast) + { + maxSock = _sockfdMcast; + } + else + { + maxSock = _sockfdUcast; + } - select(maxSock + 1, &recvfds, 0, 0, &timeout); + select(maxSock + 1, &recvfds, 0, 0, &timeout); - if(FD_ISSET(_sockfdUcast, &recvfds)){ - if( ::recv(_sockfdUcast, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0){ - _castStat = STAT_UNICAST; - return true; - } - }else if(FD_ISSET(_sockfdMcast, &recvfds)){ - if( ::recv(_sockfdMcast, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0){ - _castStat = STAT_MULTICAST; - return true; - } - } - _castStat = 0; - return false; + if (FD_ISSET(_sockfdUcast, &recvfds)) + { + if (::recv(_sockfdUcast, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0) + { + _castStat = STAT_UNICAST; + return true; + } + } + else if (FD_ISSET(_sockfdMcast, &recvfds)) + { + if (::recv(_sockfdMcast, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0) + { + _castStat = STAT_MULTICAST; + return true; + } + } + _castStat = 0; + return false; } -int LUdpPort::recv(uint8_t* buf, uint16_t len, bool flg, uint32_t* ipAddressPtr, uint16_t* portPtr){ - int flags = flg ? MSG_DONTWAIT : 0; - return recvfrom (buf, len, flags, ipAddressPtr, portPtr ); +int LUdpPort::recv(uint8_t *buf, uint16_t len, bool flg, uint32_t *ipAddressPtr, uint16_t *portPtr) +{ + int flags = flg ? MSG_DONTWAIT : 0; + return recvfrom(buf, len, flags, ipAddressPtr, portPtr); } -int LUdpPort::recvfrom (uint8_t* buf, uint16_t length, int flags, uint32_t* ipAddressPtr, uint16_t* portPtr ){ - struct sockaddr_in sender; - int status; - socklen_t addrlen = sizeof(sender); - memset(&sender, 0, addrlen); +int LUdpPort::recvfrom(uint8_t *buf, uint16_t length, int flags, uint32_t *ipAddressPtr, uint16_t *portPtr) +{ + struct sockaddr_in sender; + int status; + socklen_t addrlen = sizeof(sender); + memset(&sender, 0, addrlen); - if(isUnicast()){ - status = ::recvfrom( _sockfdUcast, buf, length, flags, (struct sockaddr*)&sender, &addrlen ); - }else if(_castStat == STAT_MULTICAST){ - status = ::recvfrom( _sockfdMcast, buf, length, flags, (struct sockaddr*)&sender, &addrlen ); - }else{ - return 0; - } + if (isUnicast()) + { + D_NWLOG("Ucast "); + status = ::recvfrom(_sockfdUcast, buf, length, flags, (struct sockaddr*) &sender, &addrlen); + } + else if (_castStat == STAT_MULTICAST) + { + D_NWLOG("Mcast "); + status = ::recvfrom(_sockfdMcast, buf, length, flags, (struct sockaddr*) &sender, &addrlen); + } + else + { + return 0; + } - if (status < 0 && errno != EAGAIN) { - D_NWLOG("\033[0m\033[0;31merrno == %d in UdpPort::recvfrom \033[0m\033[0;37m\n", errno); - DISPLAY("\033[0m\033[0;31merrno == %d in UdpPort::recvfrom \033[0m\033[0;37m\n", errno); - }else if(status > 0){ - *ipAddressPtr = sender.sin_addr.s_addr; - *portPtr = sender.sin_port; - D_NWLOG("\nrecved %-15s:%-6u",inet_ntoa(sender.sin_addr), htons(*portPtr)); - for(uint16_t i = 0; i < status ; i++){ - D_NWLOG(" %02x", *(buf + i)); - } - D_NWLOG("\n"); + if (status < 0 && errno != EAGAIN) + { + D_NWLOG("\033[0m\033[0;31merrno == %d in UdpPort::recvfrom \033[0m\033[0;37m\n", errno); + } + else if (status > 0) + { + *ipAddressPtr = sender.sin_addr.s_addr; + *portPtr = sender.sin_port; + D_NWLOG("recved %-15s:%-6u",inet_ntoa(sender.sin_addr), htons(*portPtr)); + for (uint16_t i = 0; i < status; i++) + { + D_NWLOG(" %02x", *(buf + i)); + } D_NWLOG("\n"); - if ( !theClientMode ) - { - char sbuf[SCREEN_BUFF_SIZE]; - int pos = 0; - sprintf(sbuf, "\033[0;34mrecved %-15s:%-6u",inet_ntoa(sender.sin_addr), htons(*portPtr)); - pos = strlen(sbuf); - for(uint16_t i = 0; i < status ; i++){ - sprintf(sbuf + pos, " %02x", *(buf + i)); - if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20 ) - { - break; - } - pos += 3; - } - sprintf(sbuf + strlen(sbuf), "\033[0;37m\n"); - theScreen->display(sbuf); - } - return status; - }else{ - return 0; - } - return status; + if (!theClientMode) + { + char sbuf[SCREEN_BUFF_SIZE]; + int pos = 0; + sprintf(sbuf, "\033[0;34mrecved %-15s:%-6u", inet_ntoa(sender.sin_addr), htons(*portPtr)); + pos = strlen(sbuf); + for (uint16_t i = 0; i < status; i++) + { + sprintf(sbuf + pos, " %02x", *(buf + i)); + if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20) + { + break; + } + pos += 3; + } + sprintf(sbuf + strlen(sbuf), "\033[0;37m\n"); + theScreen->display(sbuf); + } + return status; + } + else + { + return 0; + } + return status; } #endif diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkUdp.h b/MQTTSNGateway/GatewayTester/src/LNetworkUdp.h index 6f7be33..31bfdf9 100644 --- a/MQTTSNGateway/GatewayTester/src/LNetworkUdp.h +++ b/MQTTSNGateway/GatewayTester/src/LNetworkUdp.h @@ -17,7 +17,6 @@ #ifndef NETWORKUDP_H_ #define NETWORKUDP_H_ -#include "LMqttsnClientApp.h" #ifdef UDP #include @@ -30,7 +29,6 @@ #include #include - #define SOCKET_MAXHOSTNAME 200 #define SOCKET_MAXCONNECTIONS 5 #define SOCKET_MAXRECV 500 diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkUdp6.cpp b/MQTTSNGateway/GatewayTester/src/LNetworkUdp6.cpp new file mode 100644 index 0000000..6277f8b --- /dev/null +++ b/MQTTSNGateway/GatewayTester/src/LNetworkUdp6.cpp @@ -0,0 +1,433 @@ +/************************************************************************************** + * Copyright (c) 2021, 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 + **************************************************************************************/ +#ifdef UDP6 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "LMqttsnClientApp.h" +#include "LNetworkUdp6.h" +#include "LTimer.h" +#include "LScreen.h" + +using namespace std; +using namespace linuxAsyncClient; + +extern uint16_t getUint16(const uint8_t *pos); +extern uint32_t getUint32(const uint8_t *pos); +extern LScreen *theScreen; +extern bool theClientMode; +/*========================================= + Class LNetwork + =========================================*/ +LNetwork::LNetwork() +{ + _sleepflg = false; + resetGwAddress(); +} + +LNetwork::~LNetwork() +{ + +} + +int LNetwork::broadcast(const uint8_t *xmitData, uint16_t dataLen) +{ + return LUdp6Port::multicast(xmitData, (uint32_t) dataLen); +} + +int LNetwork::unicast(const uint8_t *xmitData, uint16_t dataLen) +{ + return LUdp6Port::unicast(xmitData, dataLen, _gwIpAddress, _gwPortNo); +} + +uint8_t* LNetwork::getMessage(int *len) +{ + *len = 0; + if (checkRecvBuf()) + { + uint16_t recvLen = LUdp6Port::recv(_rxDataBuf, MQTTSN_MAX_PACKET_SIZE, false, &_ipAddress, &_portNo); + int diffAddr = memcmp(_ipAddress.s6_addr, _gwIpAddress.s6_addr, sizeof(_gwIpAddress.s6_addr)); + if (isUnicast() && diffAddr && (_portNo != _gwPortNo)) + { + return 0; + } + + if (recvLen < 0) + { + *len = recvLen; + return 0; + } + else + { + if (_rxDataBuf[0] == 0x01) + { + *len = getUint16(_rxDataBuf + 1); + } + else + { + *len = _rxDataBuf[0]; + } + return _rxDataBuf; + } + } + return 0; +} + +void LNetwork::setGwAddress(void) +{ + memcpy(_gwIpAddress.s6_addr, _ipAddress.s6_addr, sizeof(_gwIpAddress.s6_addr)); + _gwPortNo = _portNo; +} + +void LNetwork::resetGwAddress(void) +{ + memset(_gwIpAddress.s6_addr, 0, sizeof(_gwIpAddress.s6_addr)); + _gwPortNo = 0; +} + +bool LNetwork::initialize(LUdp6Config *config) +{ + return LUdp6Port::open(config); +} + +void LNetwork::setSleep() +{ + _sleepflg = true; +} + +bool LNetwork::isBroadcastable() +{ + return true; +} +/*========================================= + Class udp6Stack + =========================================*/ +LUdp6Port::LUdp6Port() +{ + _disconReq = false; + memset(_pollfds, 0, sizeof(_pollfds)); + _sock = 0; + _interface = NULL; + _gIpAddrStr = NULL; +} + +LUdp6Port::~LUdp6Port() +{ + close(); + if (_gIpAddrStr) + { + free(_gIpAddrStr); + } + if (_interface) + { + free(_interface); + } +} + +void LUdp6Port::close() +{ + for (int i = 0; i < 2; i++) + { + if (_pollfds[i].fd > 0) + { + ::close(_pollfds[i].fd); + _pollfds[i].fd = 0; + } + } +} + +bool LUdp6Port::open(LUdp6Config *config) +{ + int optval = 1; + int sock = 0; + uint32_t ifindex = 0; + sockaddr_in6 addr6; + + _gPortNo = htons(config->gPortNo); + _uPortNo = htons(config->uPortNo); + + if (_gPortNo == 0 || _uPortNo == 0) + { + return false; + } + + /* create a unicast socket */ + sock = socket(AF_INET6, SOCK_DGRAM, 0); + if (sock < 0) + { + return false; + } + + optval = 1; + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)); + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + + if (strlen(config->interface) > 0) + { + ifindex = if_nametoindex(config->interface); +#ifdef __APPLE__ + setsockopt(sock, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex)); +#else + setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, config->interface, strlen(config->interface)); +#endif + } + + memset(&addr6, 0, sizeof(addr6)); + addr6.sin6_family = AF_INET6; + addr6.sin6_port = _uPortNo; + addr6.sin6_addr = in6addr_any; + + if (::bind(sock, (sockaddr*) &addr6, sizeof(addr6)) < 0) + { + D_NWLOG("\033[0m\033[0;31merror %s ::bind() to unicast address\033[0m\033[0;37m\n", strerror(errno)); + return false; + } + _pollfds[0].fd = sock; + _pollfds[0].events = POLLIN; + + /* create a multicast socket */ + sock = socket(AF_INET6, SOCK_DGRAM, 0); + if (sock < 0) + { + return false; + } + + optval = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)); + + memset(&addr6, 0, sizeof(addr6)); + addr6.sin6_family = AF_INET6; + addr6.sin6_port = _gPortNo; + addr6.sin6_addr = in6addr_any; + + if (::bind(sock, (sockaddr*) &addr6, sizeof(addr6)) < 0) + { + D_NWLOG("\033[0m\033[0;31merror %s ::bind() in Udp6Port::open\033[0m\033[0;37m\n", strerror(errno)); + return false; + } + + + ipv6_mreq addrm; + addrm.ipv6mr_interface = ifindex; + inet_pton(AF_INET6, config->ipAddress, &addrm.ipv6mr_multiaddr); + if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &addrm, sizeof(addrm)) < 0) + { + D_NWLOG("\033[0m\033[0;31merror %s IPV6_ADD_MEMBERSHIP in Udp6Port::open\033[0m\033[0;37m\n", strerror(errno)); + close(); + return false; + } + optval = 1; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &optval, sizeof(optval)) < 0) + { + D_NWLOG("\033[0m\033[0;31merror %s IPV6_MULTICAST_LOOP in Udp6Port::open\033[0m\033[0;37m\n", strerror(errno)); + close(); + return false; + } + _pollfds[1].fd = sock; + _pollfds[1].events = POLLIN; + _gIpAddr.sin6_family = AF_INET6; + _gIpAddr.sin6_port = _gPortNo; + memcpy(&_gIpAddr.sin6_addr, (const void*) &addrm.ipv6mr_multiaddr, sizeof(addrm.ipv6mr_multiaddr)); + _gIpAddrStr = strdup(config->ipAddress); + return true; +} + +int LUdp6Port::unicast(const uint8_t *buf, uint32_t length, in6_addr ipAddress, uint16_t port) +{ + struct sockaddr_in6 dest; + dest.sin6_family = AF_INET6; + dest.sin6_port = port; + memcpy(dest.sin6_addr.s6_addr, (const void*) ipAddress.s6_addr, sizeof(ipAddress.s6_addr)); + + char addrBuf[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &dest.sin6_addr, addrBuf, INET6_ADDRSTRLEN); + D_NWLOG("unicast to [%s]:%-6u", addrBuf, htons(port)); + + int status = ::sendto(_pollfds[0].fd, buf, length, 0, (const sockaddr*) &dest, sizeof(dest)); + if (status < 0) + { + D_NWLOG(" errno = %d %s in Udp6Port::unicast\n", errno, strerror(errno)); + } + else + { + for (uint16_t i = 0; i < length; i++) + { + D_NWLOG(" %02x", *(buf + i)); + } + D_NWLOG("\n"); + + if (!theClientMode) + { + char sbuf[SCREEN_BUFF_SIZE]; + int pos = 0; + sprintf(sbuf, "\033[0;34municast to [%s[:%-6u", addrBuf, htons(port)); + pos = strlen(sbuf); + for (uint16_t i = 0; i < length; i++) + { + sprintf(sbuf + pos, " %02x", *(buf + i)); + if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20) // -20 for Escape sequence + { + break; + } + pos += 3; + } + sprintf(sbuf + strlen(sbuf), "\033[0;37m\n"); + theScreen->display(sbuf); + } + } + return status; +} + +int LUdp6Port::multicast(const uint8_t *buf, uint32_t length) +{ + char sbuf[SCREEN_BUFF_SIZE]; + char portStr[8]; + sprintf(portStr, "%d", ntohs(_gPortNo)); + + int status = ::sendto(_pollfds[1].fd, buf, length, 0, (sockaddr*) &_gIpAddr, sizeof(_gIpAddr)); + if (status < 0) + { + D_NWLOG("multicast to [%s]:%-6s ", _gIpAddrStr, portStr); + D_NWLOG("\033[0m\033[0;31merrno = %d %s in Udp6Port::multicast\033[0m\033[0;37m\n", errno, strerror(errno)); + return errno; + } + else + { + D_NWLOG("multicast to [%s]:%-6s", _gIpAddrStr, portStr); + for (uint16_t i = 0; i < length; i++) + { + D_NWLOG(" %02x", *(buf + i)); + } + D_NWLOG("\n"); + + if (!theClientMode) + { + memset(sbuf, 0, SCREEN_BUFF_SIZE); + int pos = 0; + sprintf(sbuf, "\033[0;34mmulticast to [%s]:%-6s", _gIpAddrStr, portStr); + pos = strlen(sbuf); + for (uint16_t i = 0; i < length; i++) + { + sprintf(sbuf + pos, " %02x", *(buf + i)); + if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20) + { + break; + } + pos += 3; + } + sprintf(sbuf + strlen(sbuf), "\033[0;37m\n"); + theScreen->display(sbuf); + } + return status; + } +} + +bool LUdp6Port::checkRecvBuf() +{ + uint8_t buf[2]; + + int cnt = poll(_pollfds, 2, 2000); // Timeout 2secs + if (cnt == 0) + { + return false; + } + + for (int i = 0; i < 2; i++) + { + if (_pollfds[i].revents & POLLIN) + { + if (::recv(_pollfds[i].fd, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0) + { + _sock = _pollfds[i].fd; + return true; + } + } + } + return false; + +} + +int LUdp6Port::recv(uint8_t *buf, uint16_t len, bool flg, in6_addr *ipAddressPtr, uint16_t *portPtr) +{ + int flags = flg ? MSG_DONTWAIT : 0; + return recvfrom(buf, len, flags, ipAddressPtr, portPtr); +} + +int LUdp6Port::recvfrom(uint8_t *buf, uint16_t length, int flags, in6_addr *ipAddressPtr, uint16_t *portPtr) +{ + struct sockaddr_in6 sender; + int status; + socklen_t addrlen = sizeof(sender); + memset(&sender, 0, addrlen); + char addrBuf[INET6_ADDRSTRLEN]; + + status = ::recvfrom(_sock, buf, length, flags, (struct sockaddr*) &sender, &addrlen); + + if (status < 0 && errno != EAGAIN) + { + D_NWLOG("\033[0m\033[0;31merrno == %d in Udp6Port::recvfrom \033[0m\033[0;37m\n", errno); + } + + if (status > 0) + { + inet_ntop(AF_INET6, &sender.sin6_addr, addrBuf, INET6_ADDRSTRLEN); + memcpy(ipAddressPtr->s6_addr, (const void*) sender.sin6_addr.s6_addr, sizeof(sender.sin6_addr.s6_addr)); + *portPtr = sender.sin6_port; + + if (!theClientMode) + { + char sbuf[SCREEN_BUFF_SIZE]; + int pos = 0; + sprintf(sbuf, "\033[0;34mrecv from [%s]:%-6u", addrBuf, htons(*portPtr)); + pos = strlen(sbuf); + for (uint16_t i = 0; i < status; i++) + { + sprintf(sbuf + pos, " %02x", *(buf + i)); + if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20) + { + break; + } + pos += 3; + } + sprintf(sbuf + strlen(sbuf), "\033[0;37m\n"); + theScreen->display(sbuf); + } + return status; + } + else + { + return 0; + } + return status; +} + +bool LUdp6Port::isUnicast(void) +{ + return (_sock == _pollfds[0].fd && _sock > 0); +} +#endif /* UDP6 */ + diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkUdp6.h b/MQTTSNGateway/GatewayTester/src/LNetworkUdp6.h new file mode 100644 index 0000000..3d6883a --- /dev/null +++ b/MQTTSNGateway/GatewayTester/src/LNetworkUdp6.h @@ -0,0 +1,113 @@ +/************************************************************************************** + * Copyright (c) 2021, 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 NETWORKUDP6_H_ +#define NETWORKUDP6_H_ + +#ifdef UDP6 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define SOCKET_MAXHOSTNAME 200 +#define SOCKET_MAXCONNECTIONS 5 +#define SOCKET_MAXRECV 500 +#define SOCKET_MAXBUFFER_LENGTH 500 // buffer size + +#define STAT_UNICAST 1 +#define STAT_MULTICAST 2 + +using namespace std; + +namespace linuxAsyncClient { +/*======================================== + Class LUpd6Port + =======================================*/ +class LUdp6Port +{ + friend class LNetwork; +public: + LUdp6Port(); + virtual ~LUdp6Port(); + + bool open(LUdp6Config *config); + + int unicast(const uint8_t *buf, uint32_t length, in6_addr ipaddress, uint16_t port); + int multicast( const uint8_t* buf, uint32_t length ); + int recv(uint8_t *buf, uint16_t len, bool nonblock, in6_addr *ipaddress, uint16_t *port); + int recv(uint8_t* buf, int flags); + bool checkRecvBuf(); + bool isUnicast(); + +private: + void close(); + int recvfrom(uint8_t *buf, uint16_t len, int flags, in6_addr *ipaddress, uint16_t *port); + + pollfd _pollfds[2]; + uint16_t _gPortNo; + uint16_t _uPortNo; + sockaddr_in6 _gIpAddr; + char *_gIpAddrStr; + char* _interface; + int _sock; + bool _disconReq; + +}; + +#define NO_ERROR 0 +#define PACKET_EXCEEDS_LENGTH 1 +/*=========================================== + Class Network + ============================================*/ +class LNetwork: public LUdp6Port +{ +public: + LNetwork(); + ~LNetwork(); + + int broadcast(const uint8_t* payload, uint16_t payloadLen); + int unicast(const uint8_t* payload, uint16_t payloadLen); + void setGwAddress(void); + void resetGwAddress(void); + bool initialize(LUdp6Config *config); + uint8_t* getMessage(int* len); + bool isBroadcastable(); +private: + void setSleep(); + int readApiFrame(void); + + in6_addr _gwIpAddress; + in6_addr _ipAddress; + uint16_t _gwPortNo; + uint16_t _portNo; + int _returnCode; + bool _sleepflg; + uint8_t _rxDataBuf[MQTTSN_MAX_PACKET_SIZE + 1]; // defined in MqttsnClientApp.h + +}; + +} /* end of namespace */ +#endif /* UDP6 */ +#endif /* NETWORKUDP_H_ */ diff --git a/MQTTSNGateway/Makefile.org b/MQTTSNGateway/Makefile.org deleted file mode 100644 index 7e096e9..0000000 --- a/MQTTSNGateway/Makefile.org +++ /dev/null @@ -1,164 +0,0 @@ -PROGNAME := MQTT-SNGateway -APPL := mainGateway - -LPROGNAME := MQTT-SNLogmonitor -LAPPL := mainLogmonitor - -TESTPROGNAME := testPFW -TESTAPPL := mainTestProcess - -CONFIG := gateway.conf -CLIENTS := clients.conf -PREDEFTOPIC := predefinedTopic.conf - -SRCDIR := src -SUBDIR := ../MQTTSNPacket/src - -OS := linux -SENSORNET := udp -TEST := tests - -INSTALL_DIR=../../ -CONFIG_DIR=../../ - -CPPSRCS := \ -$(SRCDIR)/MQTTGWConnectionHandler.cpp \ -$(SRCDIR)/MQTTGWPacket.cpp \ -$(SRCDIR)/MQTTGWPublishHandler.cpp \ -$(SRCDIR)/MQTTGWSubscribeHandler.cpp \ -$(SRCDIR)/MQTTSNGateway.cpp \ -$(SRCDIR)/MQTTSNGWBrokerRecvTask.cpp \ -$(SRCDIR)/MQTTSNGWBrokerSendTask.cpp \ -$(SRCDIR)/MQTTSNGWClient.cpp \ -$(SRCDIR)/MQTTSNGWClientRecvTask.cpp \ -$(SRCDIR)/MQTTSNGWClientSendTask.cpp \ -$(SRCDIR)/MQTTSNGWConnectionHandler.cpp \ -$(SRCDIR)/MQTTSNGWLogmonitor.cpp \ -$(SRCDIR)/MQTTSNGWPacket.cpp \ -$(SRCDIR)/MQTTSNGWPacketHandleTask.cpp \ -$(SRCDIR)/MQTTSNGWProcess.cpp \ -$(SRCDIR)/MQTTSNGWPublishHandler.cpp \ -$(SRCDIR)/MQTTSNGWSubscribeHandler.cpp \ -$(SRCDIR)/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 \ -$(SRCDIR)/$(OS)/Threading.cpp \ -$(SRCDIR)/$(TEST)/TestProcess.cpp \ -$(SRCDIR)/$(TEST)/TestQue.cpp \ -$(SRCDIR)/$(TEST)/TestTree23.cpp \ -$(SRCDIR)/$(TEST)/TestTopics.cpp \ -$(SRCDIR)/$(TEST)/TestTopicIdMap.cpp \ -$(SRCDIR)/$(TEST)/TestTask.cpp - - -CSRCS := $(SUBDIR)/MQTTSNConnectClient.c \ -$(SUBDIR)/MQTTSNConnectServer.c \ -$(SUBDIR)/MQTTSNDeserializePublish.c \ -$(SUBDIR)/MQTTSNPacket.c \ -$(SUBDIR)/MQTTSNSearchClient.c \ -$(SUBDIR)/MQTTSNSearchServer.c \ -$(SUBDIR)/MQTTSNSerializePublish.c \ -$(SUBDIR)/MQTTSNSubscribeClient.c \ -$(SUBDIR)/MQTTSNSubscribeServer.c \ -$(SUBDIR)/MQTTSNUnsubscribeClient.c \ -$(SUBDIR)/MQTTSNUnsubscribeServer.c - -CPPFLAGS += - -INCLUDE := -INCLUDES += $(INCLUDE) -I$(SRCDIR) \ --I$(SRCDIR)/$(OS) \ --I$(SRCDIR)/$(OS)/$(SENSORNET) \ --I$(SUBDIR) \ --I$(SRCDIR)/$(TEST) \ --I/usr/local/opt/openssl/include/ - -# preprocessor defines -DEFS := - -CXX := g++ - -LIB := -LIBS += $(LIB) -L/usr/local/lib -L/usr/local/opt/openssl/lib/ - -LDFLAGS := -CXXFLAGS := -Wall -O3 -std=c++11 -LDADD := -lpthread -lssl -lcrypto -OUTDIR := Build - -PROG := $(OUTDIR)/$(PROGNAME) -LPROG := $(OUTDIR)/$(LPROGNAME) -TPROG := $(OUTDIR)/$(TESTPROGNAME) - -OBJS := $(CPPSRCS:%.cpp=$(OUTDIR)/%.o) -OBJS += $(CSRCS:%.c=$(OUTDIR)/%.o) -DEPS := $(CPPSRCS:%.cpp=$(OUTDIR)/%.d) -DEPS += $(CSRCS:%.c=$(OUTDIR)/%.d) - -.PHONY: install clean exectest - -all: $(PROG) $(LPROG) $(TPROG) - -monitor: $(LPROG) - -test: $(TPROG) $(LPROG) exectest - - --include $(DEPS) - -$(PROG): $(OBJS) $(OUTDIR)/$(SRCDIR)/$(APPL).o - $(CXX) $(LDFLAGS) -o $@ $^ $(LIBS) $(LDADD) - -$(LPROG): $(OBJS) $(OUTDIR)/$(SRCDIR)/$(LAPPL).o - $(CXX) $(LDFLAGS) -o $@ $^ $(LIBS) $(LDADD) - -$(TPROG): $(OBJS) $(OUTDIR)/$(SRCDIR)/$(TEST)/$(TESTAPPL).o - $(CXX) $(LDFLAGS) -o $@ $^ $(LIBS) $(LDADD) - - -$(OUTDIR)/$(SRCDIR)/%.o:$(SRCDIR)/%.cpp - @if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi - $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) $(DEFS) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $< - -$(OUTDIR)/$(SRCDIR)/$(APPL).o:$(SRCDIR)/$(APPL).cpp - @if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi - $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) $(DEFS) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $< - -$(OUTDIR)/$(SRCDIR)/$(TEST)/$(TESTAPPL).o:$(SRCDIR)/$(TEST)/$(TESTAPPL).cpp - @if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi - $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) $(DEFS) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $< - -$(OUTDIR)/$(SRCDIR)/$(LAPPL).o:$(SRCDIR)/$(LAPPL).cpp - @if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi - $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) $(DEFS) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $< - -$(OUTDIR)/$(SUBDIR)/%.o:$(SUBDIR)/%.c - @if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi - $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) $(DEFS) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $< - -clean: - rm -rf $(OUTDIR) - -install: - cp -pf $(PROG) $(INSTALL_DIR) - cp -pf $(LPROG) $(INSTALL_DIR) - cp -pf $(CONFIG) $(CONFIG_DIR) - cp -pf $(CLIENTS) $(CONFIG_DIR) - cp -pf $(PREDEFTOPIC) $(CONFIG_DIR) - - -exectest: - ./$(OUTDIR)/$(TESTPROGNAME) -f ./gateway.conf - - \ No newline at end of file diff --git a/MQTTSNGateway/README.md b/MQTTSNGateway/README.md index 4bc5192..3826c7a 100644 --- a/MQTTSNGateway/README.md +++ b/MQTTSNGateway/README.md @@ -1,142 +1,211 @@ - MQTT-SN Transparent / Aggregating Gateway - -**MQTT-SN** requires a MQTT-SN Gateway which acts as a protocol converter to convert **MQTT-SN messages to MQTT messages**. MQTT-SN client over SensorNetwork can not communicate directly with MQTT broker(TCP/IP). -This Gateway can run as a transparent or aggregating Gateway by specifying the gateway.conf. - -### **step1. Build the gateway** -```` -$ git clone -b develop https://github.com/eclipse/paho.mqtt-sn.embedded-c -$ cd paho.mqtt-sn.embedded-c/MQTTSNGateway +# MQTT-SN Transparent / Aggregating Gateway +MQTT-SN requires a MQTT-SN Gateway which acts as a protocol converter to convert MQTT-SN messages to MQTT messages. +MQTT-SN client over SensorNetwork can not communicate directly with MQTT broker(TCP/IP). +This Gateway can run as a transparent or aggregating Gateway by specifying the gateway.conf. +### step1. Build the gateway +copy and expand source code then, +``` +$ cd paho.mqtt-sn.embedded-c/MQTTSNGateway +``` +In order to build a gateway, one sensor network argument is required. +``` $ ./build.sh [udp|udp6|xbee|loralink|rfcomm] - -```` -In order to build a gateway, an argument is required. - -MQTT-SNGateway and MQTT-SNLogmonitor (executable programs) are built in the Build directory. - -### **step2. Execute the Gateway.** +``` -```` +MQTT-SNGateway and MQTT-SNLogmonitor (executable programs) are built in ./bin directory. + +### step2. Execute the Gateway. + +``` $ cd bin -$ ./MQTT-SNGateway -```` +$ ./MQTT-SNGateway +``` If you get the error message as follows: -```` -RingBuffer can't create a shared memory. -ABORT Gateway!!! -```` + +RingBuffer can't create a shared memory. ABORT Gateway!!! You have to start using sudo command only once for the first time. -```` -$ sudo ./MQTT-SNGateway -```` +``` +$ sudo ./MQTT-SNGateway +``` +## Contents of the gateway configuration file +**gateway.conf** is in bin directory. It's contents are follows: -### **How to Change the configuration of the gateway** -**gateway.conf** Contents are follows: - -


+```
+#**************************************************************************
+# Copyright (c) 2016-2021, 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.
+#***************************************************************************
+#
 # config file of MQTT-SN Gateway
 #
 
+GatewayID=1
+GatewayName=PahoGateway-01
+MaxNumberOfClients=30
+KeepAlive=60
+#LoginID=your_ID
+#Password=your_Password
+
 BrokerName=mqtt.eclipseprojects.io
 BrokerPortNo=1883
 BrokerSecurePortNo=8883
+```
+**GatewayID** is a gateway ID which  used by GWINFO message.    
+**GatewayName** is a name of the gateway.    
+**MaxNumberOfClients** is a maxmum number of clients. Clients are dynamically allocated.    
+**KeepAlive** is KeepAlive time in seconds.   
+**LoginID** is used by CONNECT message.  
+**Password** is used by CONNECT message.    
+**BrokerName**is a domain name or IP address of a broker.    
+**BrokerPortNo** is a broker's port no.    
+**BrokerSecurePortNo** is a broker's port no of TLS connection.    
+```
+#
+# CertsKey for TLS connections to a broker
+#
 
+#RootCAfile=/etc/ssl/certs/ca-certificates.crt
+#RootCApath=/etc/ssl/certs/
+#CertsKey=/path/to/certKey.pem
+#PrivateKey=/path/to/privateKey.pem
+```
+**RootCAfile** is a CA file name.    
+**RootCApath** is a CA path. **SSL_CTX_load_verify_locations(ctx, CAfile, CApath)** function requires these parameters.        
+**CertsKey** is a certificate pem file.    
+**PrivateKey** is a private key pem file.   
+Clients can connect to the broker via TLS by setting '**Secure Connection**' for each client in the client conf file.   
+```
 #
 # When AggregatingGateway=YES or ClientAuthentication=YES,
 # All clients must be specified by the ClientList File  
 #
 
-ClientAuthentication=NO
 AggregatingGateway=NO
 QoS-1=NO
 Forwarder=NO
-MaxNumberOfClients=30;
-
-#ClientsList=/path/to/your_clients.conf
-
 PredefinedTopic=NO
-#PredefinedTopicList=/path/to/your_predefinedTopic.conf
+ClientAuthentication=NO
 
-#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
+ClientsList=/path/to/your_clients.conf
+PredefinedTopicList=/path/to/your_predefinedTopic.conf
+```
+The gateway runs as a aggregating gateway when **AggregatingGateway** is 'YES'.   
+If **QoS-1** is 'YES, the gateway prepares a proxy for the QoS-1 client. QoS-1 client has a 'QoS-1' parameter in a clients.conf file. For QoS-1 clients, set the QoS-1 parameters in the clients.conf file.
+If **Forwarder** is 'YES', the gateway prepare a forwarder agent.   
+If **ClientAuthentication** is 'YES', the client cannot connect unless it is registered in the clients.conf file.  
+**ClientsList** defines clients and those address so on.    
+**PredefinedTopicList** file defines Predefined Topic.    
 
 
-# UDP
+```
+#==============================
+#  SensorNetworks parameters
+#==============================
+#
+# UDP | DTLS 
+# 
+
 GatewayPortNo=10000
-MulticastIP=225.1.1.1
 MulticastPortNo=1883
-MulticastTTL=1  
+MulticastIP=225.1.1.1
+MulticastTTL=1
+```
+**GatewayPortNo** is a unicast port no of the gateway.  
+**MulticastIP** and **MulticastPortNo** are for GWSEARCH messages. Clients can get the gateway address (Gateway IP address and GatewayPortNo) from GWINFO message by means of std::recvfrom().   
+Client needs to know the MulticastIP and MulticastPortNo to send a SEARCHGW message. 
+**MulticastTTL** is a multicast TTL.    
+```
+#
+# UDP6 | DTLS6
+#
 
-# UDP6
-GatewayUDP6Bind=FFFF:FFFE::1 
-GatewayUDP6Port=10000
-GatewayUDP6Broadcast=FF02::1
-GatewayUDP6If=wpan0
-GatewayUDP6Hops=1
+GatewayIPv6PortNo=10000
+MulticastIPv6PortNo=1883
+MulticastIPv6=ff1e:feed:caca:dead::feed:caca:dead
+MulticastIPv6If=wlp4s0
+MulticastHops=1
+```
+**GatewayIPv6PortNo** is a unicast port no of the gateway.
+**MulticastIPv6PortNo** and **MulticastIPv6** are for GWSEARCH messages. Set the Global scope Multicast address so that the Global address is used for sending GWINFO.   
+Clients can get the gateway address (Gateway IPv6 address and GatewayPortNo) from GWINFO message by means of std::recvfrom(). 
+**MulticastIPv6If** is a  multicast interface name.    
+**MulticastHops** is a multicast hops.    
+```
+#
+# DTLS | DTLS6  DTLS CertsKey  
+#
 
+DtlsCertsKey=/etc/ssl/certs/gateway.pem
+DtlsPrivKey=/etc/ssl/private/privkey.pem
+```
+**DtlsCertsKey** is a certs Key pem file for DTLS connection.        
+**DtlsPrivKey** is a private key pem file for DTLS connection.    
+```
+#
 # XBee
+#
+
 Baudrate=38400
 SerialDevice=/dev/ttyUSB0
 ApiMode=2
+```
+**Baudrate** is a baudrate of xbee.    
+```
+#
+# LoRaLink
+#
 
-#LoRaLink
 BaudrateLoRaLink=115200
-DeviceRxLoRaLink=/dev/ttyLoRaLinkRx
-DeviceTxLoRaLink=/dev/ttyLoRaLinkTx
+DeviceRxLoRaLink=/dev/loralinkRx
+DeviceTxLoRaLink=/dev/loralinkTx
+```
+https://github.com/ty4tw/MQTT-SN-LoRa    
 
+```
+#
 # Bluetooth RFCOMM
+#
+
 RFCOMMAddress=60:57:18:06:8B:72.*
-
+```
+**RFCOMMAddress** is a bluetooth mac address and channel. channel should be * for the gateway.
+```
+#
 # LOG
-ShearedMemory=NO;
+#
 
-
+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 **AggregatingGateway** 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. -**MaxNumberOfClients** Maximum number of clients allocated. - -### ** How to monitor the gateway from remote. ** +### How to monitor the gateway from a remote terminal. Change gateway.conf as follows: ``` # LOG ShearedMemory=YES; -```` - -Restart the gateway with sudo only once to create shared memories. - +``` +Restart the gateway with sudo only once to create shared memories. open ssh terminal and execute LogMonitor. - ``` $ cd bin $ ./MQTT-SNLogmonitor -``` - +``` Now you can get the Log on your terminal. -## ** Tips ** -Uncomment the line 62, 63 in MQTTSNDefines.h then you can get more precise logs. +##### Tips +Use compiler definitions then you can get more precise logs. +**-DDEBUG_NW** is a flag for debug logs of Sensor network. +**-DDEBUG_MQTTSN** is a flag for debug logs of MQTT-SN message haandling. +One or both flags can be specified. + +``` +./build.sh udp -DDEBUG -DDEBUG_NW ``` -/*================================= - * Log controls - ==================================*/ -//#define DEBUG // print out log for debug -//#define DEBUG_NWSTACK // print out SensorNetwork log -``` \ No newline at end of file diff --git a/MQTTSNGateway/build.sh b/MQTTSNGateway/build.sh index b5ed316..6dc49c0 100755 --- a/MQTTSNGateway/build.sh +++ b/MQTTSNGateway/build.sh @@ -1,19 +1,42 @@ #!/bin/bash -if [ $# -eq 0 ]; then - echo "Usage: build.sh [ udp | udp6 | xbee | loralink | rfcomm ]" -else - echo "Start building MQTT-SN Gateway" +build () { + echo "Start building MQTT-SN Gateway $1" - SCRIPT_DIR=$(cd $(dirname $0); pwd) cd $SCRIPT_DIR/.. - rm -rf build.gateway - mkdir build.gateway - cd build.gateway - cmake .. -DSENSORNET=$1 + BDIR='build.gateway' + if [ ! -d ./$BDIR ]; then + mkdir $BDIR + fi + cd $BDIR + cmake .. -DSENSORNET=$1 -DDEFS="${2} ${3}" make MQTTSNPacket make MQTT-SNGateway make MQTT-SNLogmonitor cd ../MQTTSNGateway cp *.conf ./bin/ -fi \ No newline at end of file +} + +SCRIPT_DIR=$(cd $(dirname $0); pwd) + +if [ $1 == "udp" ] ; then + build $1 $2 $3 +elif [ $1 == "udp6" ] ; then + build $1 $2 $3 +elif [ $1 == "xbee" ] ; then + build $1 $2 $3 +elif [ $1 == "loralink" ]; then + build $1 $2 $3 +elif [ $1 == "rfcomm" ] ; then + build $1 $2 $3 +elif [ $1 == "dtls" ] ; then + build $1 $2 $3 +elif [ $1 == "dtls6" ] ; then + build dtls "${2} ${3} -DDTLS6" +elif [ $1 == "clean" ] ; then + rm -rf ../builg.gateway +else + echo "Usage: build.sh [ udp | udp6 | xbee | loralink | rfcomm | dtls | dtls6 | clean]" +fi + + diff --git a/MQTTSNGateway/gateway.conf b/MQTTSNGateway/gateway.conf index f6fb401..77efab6 100644 --- a/MQTTSNGateway/gateway.conf +++ b/MQTTSNGateway/gateway.conf @@ -1,5 +1,5 @@ #************************************************************************** -# Copyright (c) 2016-2019, Tomoaki Yamaguchi +# Copyright (c) 2016-2021, Tomoaki Yamaguchi # # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 @@ -14,64 +14,96 @@ # config file of MQTT-SN Gateway # +GatewayID=1 +GatewayName=PahoGateway-01 +MaxNumberOfClients=30 +KeepAlive=60 +#LoginID=your_ID +#Password=your_Password + BrokerName=mqtt.eclipseprojects.io BrokerPortNo=1883 BrokerSecurePortNo=8883 # -# When AggregatingGateway=YES or ClientAuthentication=YES, -# All clients must be specified by the ClientList File +# CertsKey for TLS connections to a broker # -ClientAuthentication=NO -AggregatingGateway=NO -QoS-1=NO -Forwarder=NO -MaxNumberOfClients=30; - -#ClientsList=/path/to/your_clients.conf - -PredefinedTopic=NO -PredefinedTopicList=/path/to/your_predefinedTopic.conf - #RootCAfile=/etc/ssl/certs/ca-certificates.crt #RootCApath=/etc/ssl/certs/ #CertsKey=/path/to/certKey.pem #PrivateKey=/path/to/privateKey.pem -GatewayID=1 -GatewayName=PahoGateway-01 -KeepAlive=900 -#LoginID=your_ID -#Password=your_Password +# +# When AggregatingGateway=YES or ClientAuthentication=YES, +# All clients must be specified by the ClientList File +# + +AggregatingGateway=NO +QoS-1=NO +Forwarder=NO +PredefinedTopic=NO +ClientAuthentication=NO + +ClientsList=/path/to/your_clients.conf +PredefinedTopicList=/path/to/your_predefinedTopic.conf -# UDP +#============================== +# SensorNetworks parameters +#============================== +# +# UDP | DTLS +# + GatewayPortNo=10000 -MulticastIP=225.1.1.1 MulticastPortNo=1883 +MulticastIP=225.1.1.1 MulticastTTL=1 -# UDP6 -GatewayUDP6Bind=FFFF:FFFE::1 -GatewayUDP6Port=10000 -GatewayUDP6Broadcast=FF02::1 -GatewayUDP6If=wpan0 -GatewayUDP6Hops=1 +# +# UDP6 | DTLS6 +# +GatewayIPv6PortNo=10000 +MulticastIPv6PortNo=1883 +MulticastIPv6=ff1e:feed:caca:dead::1 +MulticastIPv6If=wlp4s0 +MulticastHops=1 + +# +# DTLS | DTLS6 +# + +DtlsCertsKey=/etc/ssl/certs/gateway.pem +DtlsPrivKey=/etc/ssl/private/privkey.pem +DtlsSSLPortNo=10001 + +# # XBee +# + Baudrate=38400 SerialDevice=/dev/ttyUSB0 ApiMode=2 +# # LoRaLink +# + BaudrateLoRaLink=115200 DeviceRxLoRaLink=/dev/loralinkRx DeviceTxLoRaLink=/dev/loralinkTx +# # Bluetooth RFCOMM +# + RFCOMMAddress=60:57:18:06:8B:72.* +# # LOG -ShearedMemory=NO; +# + +ShearedMemory=NO diff --git a/MQTTSNGateway/src/CMakeLists.txt b/MQTTSNGateway/src/CMakeLists.txt index 0b1c9d7..9a16e28 100644 --- a/MQTTSNGateway/src/CMakeLists.txt +++ b/MQTTSNGateway/src/CMakeLists.txt @@ -35,6 +35,9 @@ IF(NOT DEFINED SENSORNET) ENDIF() MESSAGE(STATUS "SENSORNET: " ${SENSORNET}) +ADD_DEFINITIONS(${DEFS}) +MESSAGE(STATUS "Definitions: " ${DEFS}) + ADD_LIBRARY(mqtt-sngateway_common MQTTGWConnectionHandler.cpp MQTTGWPacket.cpp @@ -74,8 +77,11 @@ ADD_LIBRARY(mqtt-sngateway_common ${OS}/Threading.h ) +# linux link_directories("/usr/local/lib") -link_directories("/usr/local/opt/openssl/lib") + +# Mac +link_directories("/usr/local/opt/openssl") TARGET_INCLUDE_DIRECTORIES(mqtt-sngateway_common @@ -84,7 +90,7 @@ TARGET_INCLUDE_DIRECTORIES(mqtt-sngateway_common ${OS} ${OS}/${SENSORNET} ../../MQTTSNPacket/src - /usr/local/opt/openssl/include + /usr/local/include ) IF(SENSORNET MATCHES "rfcomm") diff --git a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp index 98f0eb6..b702ab5 100644 --- a/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp @@ -17,6 +17,7 @@ #include "MQTTSNGWBrokerRecvTask.h" #include "MQTTSNGWClient.h" #include "MQTTSNGWClientList.h" +#include "MQTTSNGateway.h" #include using namespace std; diff --git a/MQTTSNGateway/src/MQTTSNGWClientList.cpp b/MQTTSNGateway/src/MQTTSNGWClientList.cpp index 9f6b0ea..a4dd62f 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientList.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientList.cpp @@ -58,6 +58,7 @@ ClientList::~ClientList() void ClientList::initialize(bool aggregate) { + _maxClients = _gateway->getGWParams()->maxClients; _clientsPool->allocate(_gateway->getGWParams()->maxClients); if (_gateway->getGWParams()->clientAuthentication) @@ -380,6 +381,7 @@ Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, { client->setQoSm1(); } + client->getNetwork()->setSecure(secure); _mutex.lock(); @@ -402,16 +404,18 @@ Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, Client* ClientList::createPredefinedTopic(MQTTSNString* clientId, string topicName, uint16_t topicId, bool aggregate) { + Client *client = nullptr; + if (topicId == 0) { WRITELOG("Invalid TopicId. Predefined Topic %s, TopicId is 0. \n", topicName.c_str()); - return nullptr; + goto exit; } if (strcmp(clientId->cstring, common_topic) == 0) { _gateway->getTopics()->add((const char*) topicName.c_str(), topicId); - return nullptr; + goto exit; } else { @@ -419,47 +423,19 @@ Client* ClientList::createPredefinedTopic(MQTTSNString* clientId, string topicNa if (_authorize && client == nullptr) { - return nullptr; + goto exit; } - /* anonimous clients */ - if (_clientCnt > MAX_CLIENTS) + client = createClient(NULL, clientId, aggregate); + if (client) { - return nullptr; // full of clients + // create Topic & Add it + client->getTopics()->add((const char*) topicName.c_str(), topicId); + client->_hasPredefTopic = true; } - - 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; } +exit: + return client; } uint16_t ClientList::getClientCount() @@ -517,15 +493,17 @@ void ClientsPool::allocate(int maxClients) Client* ClientsPool::getClient(void) { + Client *cl = nullptr; + while (_firstClient != nullptr) { - Client* cl = _firstClient; + cl = _firstClient; _firstClient = cl->_nextClient; cl->_nextClient = nullptr; _clientCnt--; - return cl; + break; } - return nullptr; + return cl; } void ClientsPool::setClient(Client* client) diff --git a/MQTTSNGateway/src/MQTTSNGWClientList.h b/MQTTSNGateway/src/MQTTSNGWClientList.h index 33424be..4cb2ca3 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientList.h +++ b/MQTTSNGateway/src/MQTTSNGWClientList.h @@ -83,6 +83,7 @@ private: Client* _endClient; Mutex _mutex; uint16_t _clientCnt; + uint16_t _maxClients; bool _authorize { false }; }; diff --git a/MQTTSNGateway/src/MQTTSNGWDefines.h b/MQTTSNGateway/src/MQTTSNGWDefines.h index 7a10fcd..bf55b62 100644 --- a/MQTTSNGateway/src/MQTTSNGWDefines.h +++ b/MQTTSNGateway/src/MQTTSNGWDefines.h @@ -37,7 +37,7 @@ namespace MQTTSNGW /*================================= * MQTT-SN Parametrs ==================================*/ -#define MAX_CLIENTS (100) // Number of Clients can be handled. +#define MAX_CLIENTS (100) // Default 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 @@ -60,13 +60,19 @@ typedef unsigned int uint32_t; /*================================= * Log controls ==================================*/ -//#define DEBUG // print out log for debug -//#define DEBUG_NWSTACK // print out SensorNetwork log -#ifdef DEBUG +//#define DEBUG_MQTTSN // print out log for debug +//#define DEBUG_NW // print out SensorNetwork log +#ifdef DEBUG_MQTTSN #define DEBUGLOG(...) printf(__VA_ARGS__) #else #define DEBUGLOG(...) #endif +#ifdef DEBUG_NW +#define D_NWSTACK(...) printf(__VA_ARGS__) +#else +#define D_NWSTACK(...) +#endif + } #endif /* MQTTSNGWDEFINES_H_ */ diff --git a/MQTTSNGateway/src/MQTTSNGWPacket.cpp b/MQTTSNGateway/src/MQTTSNGWPacket.cpp index c82466b..72189db 100644 --- a/MQTTSNGateway/src/MQTTSNGWPacket.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPacket.cpp @@ -100,10 +100,6 @@ int MQTTSNPacket::recv(SensorNetwork* network) { len = desirialize(buf, len); } - else - { - len = 0; - } return len; } diff --git a/MQTTSNGateway/src/MQTTSNGWPacket.h b/MQTTSNGateway/src/MQTTSNGWPacket.h index c6fd4fc..4ac3007 100644 --- a/MQTTSNGateway/src/MQTTSNGWPacket.h +++ b/MQTTSNGateway/src/MQTTSNGWPacket.h @@ -22,6 +22,7 @@ namespace MQTTSNGW { +class SensorNetwork; class MQTTSNPacket { diff --git a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp index 5b09b14..08d1cfb 100644 --- a/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp @@ -38,6 +38,7 @@ using namespace MQTTSNGW; #define EVENT_QUE_TIME_OUT 2000 // 2000 msecs char* currentDateTime(void); + /*===================================== Class PacketHandleTask =====================================*/ diff --git a/MQTTSNGateway/src/MQTTSNGWProcess.cpp b/MQTTSNGateway/src/MQTTSNGWProcess.cpp index 55d1ae6..9473a36 100644 --- a/MQTTSNGateway/src/MQTTSNGWProcess.cpp +++ b/MQTTSNGateway/src/MQTTSNGWProcess.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -156,6 +157,8 @@ int Process::getParam(const char* parameter, char* value) { char str[MQTTSNGW_PARAM_MAX]; char param[MQTTSNGW_PARAM_MAX]; + memset(str, 0, sizeof(str)); + memset(param, 0, sizeof(param)); FILE *fp; int i = 0, j = 0; @@ -166,40 +169,55 @@ int Process::getParam(const char* parameter, char* value) throw Exception("Config file not found:\n\nUsage: Command -f path/config_file_name\n", 0); } + int paramlen = strlen(parameter); + while (true) { + int pos = 0; + int len = 0; if (fgets(str, MQTTSNGW_PARAM_MAX - 1, fp) == NULL) { fclose(fp); return -3; } - if (!strncmp(str, parameter, strlen(parameter))) + if (str[0] == '#' || str[0] == '\n') { - while (str[i++] != '=') - { - ; - } - while (str[i] != '\n') - { - param[j++] = str[i++]; - } - param[j] = '\0'; + continue; + } - for (i = strlen(param) - 1; i >= 0 && isspace(param[i]); i--) - ; - param[i + 1] = '\0'; - for (i = 0; isspace(param[i]); i++) - ; - if (i > 0) + len = strlen(str); + for (pos = 0; i < len; pos++) + { + if (str[pos] == '=') { - j = 0; - while (param[i]) - param[j++] = param[i++]; - param[j] = '\0'; + break; + } + } + + if (pos == paramlen) + { + if (strncmp(str, parameter, paramlen) == 0) + { + strcpy(param, str + pos + 1); + param[len - pos - 2] = '\0'; + + + for (i = strlen(param) - 1; i >= 0 && isspace(param[i]); i--) + ; + param[i + 1] = '\0'; + for (i = 0; isspace(param[i]); i++) + ; + if (i > 0) + { + j = 0; + while (param[i]) + param[j++] = param[i++]; + param[j] = '\0'; + } + strcpy(value, param); + fclose(fp); + return 0; } - strcpy(value, param); - fclose(fp); - return 0; } } fclose(fp); diff --git a/MQTTSNGateway/src/MQTTSNGateway.cpp b/MQTTSNGateway/src/MQTTSNGateway.cpp index 3ef0dab..d672268 100644 --- a/MQTTSNGateway/src/MQTTSNGateway.cpp +++ b/MQTTSNGateway/src/MQTTSNGateway.cpp @@ -32,9 +32,9 @@ MQTTSNGW::Gateway* theGateway = nullptr; Gateway::Gateway(void) { + theGateway = this; theMultiTaskProcess = this; theProcess = this; - _packetEventQue.setMaxSize(MAX_INFLIGHTMESSAGES * MAX_CLIENTS); _clientList = new ClientList(this); _adapterManager = new AdapterManager(this); _topics = new Topics(); @@ -95,15 +95,21 @@ Gateway::~Gateway() { free(_params.configName); } - if (_params.qosMinusClientListName) { free(_params.qosMinusClientListName); } - - if (_params.bleAddress) + if (_params.rfcommAddr) { - free(_params.bleAddress); + free(_params.rfcommAddr); + } + if (_params.gwCertskey) + { + free(_params.gwCertskey); + } + if (_params.gwPrivatekey) + { + free(_params.gwPrivatekey); } if (_adapterManager) @@ -114,7 +120,6 @@ Gateway::~Gateway() { delete _clientList; } - if (_topics) { delete _topics; @@ -178,6 +183,14 @@ void Gateway::initialize(int argc, char** argv) { _params.rootCAfile = strdup(param); } + if (getParam("DtlsCertsKey", param) == 0) + { + _params.gwCertskey = strdup(param); + } + if (getParam("DtlsPrivKey", param) == 0) + { + _params.gwPrivatekey = strdup(param); + } if (getParam("GatewayID", param) == 0) { @@ -282,11 +295,14 @@ void Gateway::initialize(int argc, char** argv) _params.maxClients = atoi(param); } - if (getParam("BleAddress", param) == 0) + if (getParam("RFCOMMAddress", param) == 0) { - _params.bleAddress = strdup(param); + _params.rfcommAddr = strdup(param); } + /* Setup max PacketEventQue size */ + _packetEventQue.setMaxSize(_params.maxInflightMsgs * _params.maxClients); + /* Initialize adapters */ _adapterManager->initialize(_params.gatewayName, _params.aggregatingGw, _params.forwarder, _params.qosMinus1); @@ -308,26 +324,30 @@ void Gateway::run(void) WRITELOG(" *\n%s\n", PAHO_COPYRIGHT3); WRITELOG(" * Version: %s\n", PAHO_GATEWAY_VERSION); WRITELOG("%s\n", PAHO_COPYRIGHT4); - WRITELOG("\n%s %s has been started.\n\n", currentDateTime(), _params.gatewayName); - WRITELOG(" ConfigFile: %s\n", _params.configName); + WRITELOG(" ConfigFile : %s\n", _params.configName); if (_params.clientListName) { - WRITELOG(" ClientList: %s\n", _params.clientListName); + WRITELOG(" ClientList : %s\n", _params.clientListName); } if (_params.predefinedTopicFileName) { - WRITELOG(" PreDefFile: %s\n", _params.predefinedTopicFileName); + WRITELOG(" PreDefFile : %s\n", _params.predefinedTopicFileName); } - WRITELOG(" SensorN/W: %s\n", _sensorNetwork.getDescription()); - WRITELOG(" Broker: %s : %s, %s\n", _params.brokerName, _params.port, _params.portSecure); - WRITELOG(" Max number of Clients: %d\n", _params.maxClients); - WRITELOG(" RootCApath: %s\n", _params.rootCApath); - WRITELOG(" RootCAfile: %s\n", _params.rootCAfile); - WRITELOG(" CertKey: %s\n", _params.certKey); - WRITELOG(" PrivateKey: %s\n\n\n", _params.privateKey); + 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(" SensorN/W : %s\n", _sensorNetwork.getDescription()); +#ifdef DTLS + WRITELOG(" DtlsCertsKey: %s\n", _params.gwCertskey); + WRITELOG(" DtlsPrivKey : %s\n", _params.gwPrivatekey); +#endif + WRITELOG(" Max Clients : %d\n\n", _params.maxClients); + WRITELOG("%s %s starts running.\n\n", currentDateTime(), _params.gatewayName); _stopFlg = false; @@ -408,12 +428,12 @@ bool Gateway::hasSecureConnection(void) { return (_params.certKey && _params.privateKey && _params.rootCApath && _params.rootCAfile); } + /*===================================== Class EventQue =====================================*/ EventQue::EventQue() { - } EventQue::~EventQue() diff --git a/MQTTSNGateway/src/MQTTSNGateway.h b/MQTTSNGateway/src/MQTTSNGateway.h index 9e13ddd..a2798ad 100644 --- a/MQTTSNGateway/src/MQTTSNGateway.h +++ b/MQTTSNGateway/src/MQTTSNGateway.h @@ -168,7 +168,9 @@ public: bool qosMinus1 { false }; bool forwarder { false }; int maxClients {0}; - char* bleAddress { nullptr }; + char* rfcommAddr { nullptr }; + char* gwCertskey { nullptr }; + char* gwPrivatekey { nullptr }; }; /*===================================== @@ -197,10 +199,10 @@ public: int getParam(const char* parameter, char* value); char* getClientListFileName(void); char* getPredefinedTopicFileName(void); - bool hasSecureConnection(void); Topics* getTopics(void); bool IsStopping(void); + void requestSensorNetSubTask(void); private: GatewayParams _params; @@ -214,7 +216,6 @@ private: Topics* _topics; bool _stopFlg; }; - } #endif /* MQTTSNGATEWAY_H_ */ diff --git a/MQTTSNGateway/src/linux/Network.cpp b/MQTTSNGateway/src/linux/Network.cpp index 4951f8d..bd5039a 100644 --- a/MQTTSNGateway/src/linux/Network.cpp +++ b/MQTTSNGateway/src/linux/Network.cpp @@ -656,3 +656,7 @@ bool Network::isSecure() return _secureFlg; } +void Network::setSecure(bool secureFlg) +{ + _secureFlg = secureFlg; +} diff --git a/MQTTSNGateway/src/linux/Network.h b/MQTTSNGateway/src/linux/Network.h index f5e15bd..57ed2ce 100644 --- a/MQTTSNGateway/src/linux/Network.h +++ b/MQTTSNGateway/src/linux/Network.h @@ -80,6 +80,7 @@ public: bool isValid(void); bool isSecure(void); int getSock(void); + void setSecure(bool secureFlg); private: static SSL_CTX* _ctx; diff --git a/MQTTSNGateway/src/linux/dtls/SensorNetwork.cpp b/MQTTSNGateway/src/linux/dtls/SensorNetwork.cpp new file mode 100644 index 0000000..407a0b7 --- /dev/null +++ b/MQTTSNGateway/src/linux/dtls/SensorNetwork.cpp @@ -0,0 +1,1437 @@ +/************************************************************************************** + * Copyright (c) 2021, Tomoaki Yamaguchi + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Tomoaki Yamaguchi - initial API and implementation and/or initial documentation + **************************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "SensorNetwork.h" +#include "MQTTSNGWProcess.h" +#include "MQTTSNGateway.h" + +using namespace std; +using namespace MQTTSNGW; + +extern Gateway *theGateway; + +#define COOKIE_SECRET_LENGTH 16 +int cookie_initialized = 0; +unsigned char cookie_secret[COOKIE_SECRET_LENGTH]; + +/*=========================================== + Class SensorNetAddreess + + These 4 methods are minimum requirements for the SensorNetAddress class. + isMatch(SensorNetAddress* ) + operator =(SensorNetAddress& ) + setAddress(string* ) + sprint(char* ) + + UDPPort class requires these 3 methods. + getIpAddress(void) + getPortNo(void) + setAddress(uint32_t IpAddr, uint16_t port) + + ============================================*/ +SensorNetAddress::SensorNetAddress() +{ + _portNo = 0; + memset(&_ipAddr, 0, sizeof(_ipAddr)); +} + +SensorNetAddress::~SensorNetAddress() +{ +} + +void SensorNetAddress::setFamily(int type) +{ + _ipAddr.af = type; +} + +int SensorNetAddress::getFamily(void) +{ + return _ipAddr.af; +} + +ipAddr_t* SensorNetAddress::getIpAddress(void) +{ + return &_ipAddr; +} + +in_port_t SensorNetAddress::getPort(void) +{ + return _portNo; +} + +void SensorNetAddress::setAddress(ipAddr_t *IpAddr, uint16_t port) +{ + + _ipAddr.addr.ad6 = IpAddr->addr.ad6; + _portNo = htons(port); + + _ipAddr.af = IpAddr->af; +} + +void SensorNetAddress::setPort(uint16_t port) +{ + _portNo = htons(port); +} + +/** + * Set Address data to SensorNetAddress + * + * @param *ip_port is "IP_Address:PortNo" format string + * @return success = 0, Invalid format = -1 + * + * This function is used in ClientList::authorize(const char* fileName) + * e.g. + * Authorized clients are defined by fileName = "clients.conf" + * + * Client02,172.16.1.7:12002 + * Client03,172.16.1.8:13003 + * Client01,172.16.1.6:12001 + * or + * Client01,[xxxx::xxxx]:11001 + * Client02,[xxxx::xxxx]:12001 + * + * This definition is necessary when using TLS/DTLS connection. + * Gateway rejects clients are not in the list for security reasons. + * + */ +int SensorNetAddress::setAddress(string *ipAddrPort) +{ + string port(""); + string ip(""); + size_t pos; + int portNo = 0; + _portNo = 0; + memset(&_ipAddr.addr, 0, sizeof(_ipAddr.addr.ad6)); + + if (*ipAddrPort->c_str() == '[') + { + // AF_INET6 + pos = ipAddrPort->find_last_of("]:"); + if (pos != string::npos) + { + ip = ipAddrPort->substr(1, pos - 2); + port = ipAddrPort->substr(pos + 1); + } + } + else + { + // AF_INET + pos = ipAddrPort->find_last_of(':'); + if (pos != string::npos) + { + ip = ipAddrPort->substr(0, pos); + port = ipAddrPort->substr(pos + 1); + } + } + + if (port == "" || ip == "") + { + return -1; + } + + if (setIpAddress(&ip) == 0) + { + if ((portNo = atoi(port.c_str())) != 0) + { + _portNo = htons(portNo); + return 0; + } + } + return -1; +} + +int SensorNetAddress::setIpAddress(string *ipAddress) +{ + if (inet_pton(AF_INET, (const char*) ipAddress->c_str(), (void*) &_ipAddr.addr) == 1) + { + _ipAddr.af = AF_INET; + } + else if (inet_pton(AF_INET6, (const char*) ipAddress->c_str(), (void*) &_ipAddr.addr) == 1) + { + _ipAddr.af = AF_INET6; + } + else + { + _ipAddr.af = 0; + return -1; + } + return 0; +} + +bool SensorNetAddress::isMatch(SensorNetAddress *addr) +{ + if (this->_portNo != addr->_portNo || this->_ipAddr.af != addr->_ipAddr.af) + { + return false; + } + + if (this->_ipAddr.af == AF_INET + && memcmp((const void*) &this->_ipAddr.addr.ad4, (const void*) &addr->_ipAddr.addr.ad4, sizeof(struct in_addr)) + == 0) + { + return true; + } + + if (this->_ipAddr.af == AF_INET6 + && memcmp((const void*) &this->_ipAddr.addr.ad6, (const void*) &addr->_ipAddr.addr.ad6, sizeof(struct in6_addr)) + == 0) + { + return true; + } + return false; +} + +SensorNetAddress& SensorNetAddress::operator =(SensorNetAddress &addr) +{ + this->_portNo = addr._portNo; + memcpy((void*) &this->_ipAddr, (const void*) &addr._ipAddr, sizeof(_ipAddr)); + this->_pfdsIndex = addr._pfdsIndex; + return *this; +} + +void SensorNetAddress::setSockaddr4(sockaddr_in *sockaddr) +{ + _ipAddr.af = sockaddr->sin_family; + _portNo = sockaddr->sin_port; + memcpy((void*) &_ipAddr.addr.ad4, (void*) &sockaddr->sin_addr, sizeof(_ipAddr.addr.ad4)); + this->_pfdsIndex = 0; +} + +void SensorNetAddress::setSockaddr6(sockaddr_in6 *sockaddr) +{ + _ipAddr.af = sockaddr->sin6_family; + _portNo = sockaddr->sin6_port; + memcpy((void*) &_ipAddr.addr.ad6, (void*) &sockaddr->sin6_addr, sizeof(_ipAddr.addr.ad6)); + this->_pfdsIndex = 0; +} + +void SensorNetAddress::cpyAddr4(sockaddr_in *sockaddr) +{ + sockaddr->sin_family = _ipAddr.af; + memcpy((void*) &sockaddr->sin_addr, (void*) &_ipAddr.addr.ad4, sizeof(_ipAddr.addr.ad4)); + sockaddr->sin_port = _portNo; +} + +void SensorNetAddress::cpyAddr6(sockaddr_in6 *sockaddr) +{ + sockaddr->sin6_family = _ipAddr.af; + memcpy((void*) &sockaddr->sin6_addr, (void*) &_ipAddr.addr.ad6, sizeof(_ipAddr.addr.ad6)); + sockaddr->sin6_port = _portNo; +} + +char* SensorNetAddress::sprint(char *buf) +{ + char senderstr[INET6_ADDRSTRLEN]; + char *ptr = senderstr; + + if (_ipAddr.af == AF_INET) + { + ptr = inet_ntoa(_ipAddr.addr.ad4); + sprintf(buf, "%s:", ptr); + } + else if (_ipAddr.af == AF_INET6) + { + inet_ntop(AF_INET6, (const void*) &_ipAddr.addr.ad6, ptr, INET6_ADDRSTRLEN); + sprintf(buf, "[%s]:", ptr); + } + else + { + *buf = 0; + return buf; + } + sprintf(buf + strlen(buf), "%d", ntohs(_portNo)); + return buf; +} + +void SensorNetAddress::setIndex(int index) +{ + _pfdsIndex = index; +} +int SensorNetAddress::getIndex(void) +{ + return _pfdsIndex; +} + +void SensorNetAddress::clear(void) +{ + memset(&_ipAddr, 0, sizeof(_ipAddr)); + _portNo = 0; +} + +Connections::Connections() +{ + _pollfds = nullptr; + _clientAddr = nullptr; + _ssls = nullptr; + _maxfds = 0; + _numfds = 2; +} + +Connections::~Connections() +{ + if (_ssls) + { + for (int i = 0; i < _numfds; i++) + { + if (_ssls[i] > 0) + { + SSL_shutdown(_ssls[i]); + SSL_free(_ssls[i]); + } + } + free(_ssls); + } + + if (_pollfds) + { + for (int i = 0; i < _numfds; i++) + { + if (_pollfds[i].fd > 0) + { + ::close(_pollfds[i].fd); + } + } + free(_pollfds); + } + + for (int i = 0; i < _maxfds; i++) + { + delete _clientAddr[i]; + } + free(_clientAddr); +} +void Connections::initialize(int maxClient) +{ + _maxfds = maxClient + POLL_SSL; + if ((_pollfds = (pollfd*) calloc(_maxfds, sizeof(pollfd))) == NULL) + { + throw EXCEPTION("Can't allocate pollfd.", 0); + } + if ((_ssls = (SSL**) calloc(_maxfds, sizeof(SSL*))) == NULL) + { + throw EXCEPTION("Can't allocate ssls.", 0); + } + + + _clientAddr = (SensorNetAddress**) malloc(_maxfds * sizeof(unsigned long int)); + for (int i = 0; i < _maxfds; i++) + { + _clientAddr[i] = new SensorNetAddress(); + } +} + +void Connections::closeSSL(int index) +{ + index += POLL_SSL; + SSL_shutdown(_ssls[index]); + SSL_free(_ssls[index]); + _ssls[index] = (SSL*) -1; +} + +int Connections::getEventUnicast(void) +{ + return _pollfds[POLL_UCAST].revents; +} + +int Connections::getEventMulticast(void) +{ + return _pollfds[POLL_MCAST].revents; +} + +int Connections::getEventClient(int index) +{ + return _pollfds[index + POLL_SSL].revents; +} + +int Connections::getSockMulticast(void) +{ + return _pollfds[POLL_MCAST].fd; +} + +void Connections::setSockMulticast(int sock) +{ + _mutex.lock(); + _pollfds[POLL_MCAST].fd = sock; + _pollfds[POLL_MCAST].events = POLLIN; + _mutex.unlock(); +} + +void Connections::setSockUnicast(int sock) +{ + _mutex.lock(); + _pollfds[POLL_UCAST].fd = sock; + _pollfds[POLL_UCAST].events = POLLIN; + _mutex.unlock(); +} + +int Connections::getSockUnicast(void) +{ + return _pollfds[POLL_UCAST].fd; +} + +int Connections::getSockClient(int index) +{ + return _pollfds[index + POLL_SSL].fd; +} + +void Connections::close(int index) +{ + _mutex.lock(); + + int idx = index + POLL_SSL; + _mutex.lock(); + int sock = _pollfds[idx].fd; + SSL *ssl = _ssls[idx]; + SensorNetAddress *addr = _clientAddr[idx]; + + for (; idx < _numfds; idx++) + { + _ssls[index] = _ssls[idx + 1]; + _pollfds[index] = _pollfds[idx + 1]; + _clientAddr[index] = _clientAddr[idx + 1]; + + if (_ssls[idx + 1] == 0) + { + _clientAddr[idx + 1] = new SensorNetAddress(); + break; + } + } + + if (ssl > 0) + { + _numfds--; + SSL_shutdown(ssl); + SSL_free(ssl); + } + if (sock > 0) + { + close(sock); + } + if (addr != nullptr) + { + delete addr; + } + _mutex.unlock(); +} + +int Connections::poll(int timeout) +{ + return ::poll(_pollfds, _numfds, timeout); +} + +int Connections::addClientSSL(SSL *ssl, int sock) +{ + _mutex.lock(); + _pollfds[_numfds].fd = sock; + _pollfds[_numfds].events = POLLIN; + _ssls[_numfds] = ssl; + int rc = _numfds - POLL_SSL; + _numfds++; + _mutex.unlock(); + return rc; +} + +int Connections::getNumOfConnections(void) +{ + return _numfds; +} + +int Connections::getNumOfClients(void) +{ + return _numfds - POLL_SSL > 0 ? _numfds - POLL_SSL : 0; +} + +SSL* Connections::getClientSSL(int index) +{ + return _ssls[index + POLL_SSL]; +} + +int Connections::searchClient(SensorNetAddress *addr) +{ + for (int i = POLL_SSL; i < _numfds; i++) + { + if (_clientAddr[i]->isMatch(addr) == true) + { + return i - POLL_SSL; + } + } + return -1; +} + +/*================================================================ + Class SensorNetwork + + getDescpription( ) is used by Gateway::initialize( ) + initialize( ) is used by Gateway::initialize( ) + getSenderAddress( ) is used by ClientRecvTask::run( ) + broadcast( ) is used by MQTTSNPacket::broadcast( ) + unicast( ) is used by MQTTSNPacket::unicast( ) + read( ) is used by MQTTSNPacket::recv( ) + + ================================================================*/ +#define PACKET_CLIENTHELLO 10000 +#define PACKET_APPL 10001 +#define PACKET_OTHERS 10002 + +/* Certificate verification. Returns 1 if trusted, else 0 */ +int verify_cert(int ok, X509_STORE_CTX *ctx); + +/* Generate cookie. Returns 1 on success, 0 otherwise */ +int generate_cookie(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len); + +/* Verify cookie. Returns 1 on success, 0 otherwise */ +int verify_cookie(SSL *ssl, const unsigned char *cookie, unsigned int cookie_len); + +SensorNetwork::SensorNetwork() +{ + _senderAddr = new SensorNetAddress(); + _multicastAddr = new SensorNetAddress(); + _unicastAddr = new SensorNetAddress(); + _conns = new Connections(); + _dtlsctx = nullptr; + _af = 0; +} + +SensorNetwork::~SensorNetwork() +{ + if (_conns != nullptr) + { + delete _conns; + } + if (_senderAddr != nullptr) + { + delete _senderAddr; + } + if (_multicastAddr != nullptr) + { + delete _multicastAddr; + } + if (_unicastAddr != nullptr) + { + delete _unicastAddr; + } +} + +int SensorNetwork::unicast(const uint8_t *payload, uint16_t payloadLength, SensorNetAddress *sendToAddr) +{ + _mutex.lock(); + + SSL *ssl = _conns->getClientSSL(sendToAddr->getIndex()); + int len = SSL_write(ssl, payload, payloadLength); + int rc = SSL_get_error(ssl, len); + if (rc < 0) + { + D_NWSTACK("error %d in SensorNetwork::unicast\n", rc); + len = -1; + } + _mutex.unlock(); + return len; +} + +int SensorNetwork::broadcast(const uint8_t *payload, uint16_t payloadLength) +{ + _mutex.lock(); + + int status; +#ifndef DTLS6 + sockaddr_in dest; + _multicastAddr->cpyAddr4(&dest); + + status = ::sendto(_conns->getSockUnicast(), payload, payloadLength, 0, (const sockaddr*) &dest, sizeof(dest)); + if (status < 0) + { + WRITELOG("AF_INET errno = %d in UDP4_6Port::sendto\n", errno); + } + + D_NWSTACK("sendto %s:%u length = %d\n", inet_ntoa(dest.sin_addr), ntohs(dest.sin_port), status); + +#else + sockaddr_in6 dest; + _multicastAddr->cpyAddr6(&dest); + + status = ::sendto(_conns->getSockUnicast(), payload, payloadLength, 0, (const sockaddr*) &dest, sizeof(dest)); + if (status < 0) + { + WRITELOG("AF_INET6 errno = %d in SensorNetwork::broadcast\n", errno); + } + +#ifdef DEBUG_NW + char buff[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &dest.sin6_addr, buff, INET6_ADDRSTRLEN); + D_NWSTACK("sendto [%s]:%u length = %d\n", buff, ntohs(dest.sin6_port), status); +#endif +#endif + _mutex.unlock(); + return status; +} + +int SensorNetwork::read(uint8_t *buf, uint16_t bufLen) +{ + int optval; + int clientIndex = -1; + int sockListen = 0; + SensorNetAddress client; + char errmsg[256]; + union + { + struct sockaddr_in s4; + struct sockaddr_in6 s6; + } client_addr; + + // Ccheck sockets + int cnt = _conns->poll(2000); // Timeout 2secs + if (cnt == 0) + { + return cnt; + } + + if (cnt < 0) + { + + /* ToDo: close socket */ + + return -1; + } + + int numfds = _conns->getNumOfConnections(); + + client.clear(); + client.setFamily(_af); + size_t recvlen = 0; + SSL *ssl = 0; + + _mutex.lock(); + + // Check Unicast Port + + if (_conns->getEventUnicast() & POLLIN) + { + D_NWSTACK("Connect RECV\n"); + // SSL connection request from a client + optval = 1; + + client.clear(); + client.setFamily(_af); + + getUnicastClient(&client); + sockListen = _conns->getSockUnicast(); + +ListenClient_hello: + // Listen Connection + SSL *ssl = SSL_new(_dtlsctx); + BIO *bio = BIO_new_dgram(sockListen, BIO_NOCLOSE); + SSL_set_bio(ssl, bio, bio); + + SSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE); + + int rc = 0; + + // SSL Listen + D_NWSTACK("Listen SSL\n"); + + rc = DTLSv1_listen(ssl, (BIO_ADDR*) &client_addr); + + if (rc <= 0) + { + ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg)); + WRITELOG("Listen rc=%d %s\n", rc, errmsg); + _mutex.unlock(); + return 0; + } + +// if (clientIndex != -1) +// { +// _conns->close(clientIndex); +// } + + // SSL Accept +#ifndef DTLS6 + int client_fd = socket(AF_INET, SOCK_DGRAM, 0); + setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &optval, sizeof(optval)); + // Bind to Dtls PortNo + bind(client_fd, (sockaddr*) &_serverAddr4, sizeof(sockaddr_in)); + connect(client_fd, (sockaddr*) &client_addr, sizeof(sockaddr_in)); + client.setSockaddr4((sockaddr_in*) &client_addr.s4); +#else + // DTLS over IPv6 + int client_fd = socket(AF_INET6, SOCK_DGRAM, 0); + setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &optval, sizeof(optval)); + // Bind to Dtls PortNo + bind(client_fd, (sockaddr*) &_serverAddr6, sizeof(sockaddr_in6)); + connect(client_fd, (sockaddr*) &client_addr, sizeof(sockaddr_in6)); + client.setSockaddr6((sockaddr_in6*) &client_addr.s6); +#endif + + BIO *cbio = SSL_get_rbio(ssl); + BIO_set_fd(cbio, client_fd, BIO_NOCLOSE); + BIO_ctrl(cbio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &client_addr); + + D_NWSTACK("Accept SSL\n"); + + int ret = SSL_accept(ssl); + if (ret <= 0) + { + ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg)); + WRITELOG("SSL_accept ret=%d %s\n", ret, errmsg); + SSL_shutdown(ssl); + SSL_free(ssl); + ::close(client_fd); + } + else + { + + // add ssl & socket to Connections instance + int index = _conns->addClientSSL(ssl, client_fd); + + // save SensorNetworkAddress of Client + client.setIndex(index); + _senderAddr = &client; + + char clientaddrBuf[128]; + client.sprint(clientaddrBuf); + WRITELOG("Client %s SSL Accepted. idx=%d\n", clientaddrBuf, index); + } + _mutex.unlock(); + } + + // check Multicast + else if (_conns->getEventMulticast() & POLLIN) + { + _mutex.unlock(); + return multicastRecv(buf, bufLen); + } + else + { + // Check SSL packet from clients + for (int i = 0; i < numfds - POLL_SSL; i++) + { + if (_conns->getEventClient(i) == POLLIN) + { + D_NWSTACK("SSL RECV\n"); + int dtls = getSendClient(i, &client); + + if (dtls > 0) + { + D_NWSTACK("DTLT type=%d\n", dtls); + if (dtls == PACKET_CLIENTHELLO) + { +#ifdef DEBUG_NW + char clientaddrBuf[128]; + client.sprint(clientaddrBuf); + D_NWSTACK("Client %s SSL reconnect. idx=%d\n", clientaddrBuf, i); +#endif + clientIndex = i; + sockListen = _conns->getSockClient(i); + goto ListenClient_hello; + } + + // Recv a MQTT-SN message from a client + ssl = _conns->getClientSSL(i); + int len = SSL_read_ex(ssl, (void*) buf, (size_t) bufLen, &recvlen); + if (SSL_get_error(ssl, len) >= 0) + { + _senderAddr = &client; + _senderAddr->setIndex(i); + + char clientaddrBuf[128]; + client.sprint(clientaddrBuf); + D_NWSTACK("Client %s SSL Accepted. idx=%d\n", clientaddrBuf, i); + } + else + { + D_NWSTACK("SSL RECV Error\n"); + _conns->close(i); + recvlen = -1; + } + _mutex.unlock(); + return recvlen; + } + } + } + } + return 0; +} + +void SensorNetwork::initialize(void) +{ + char param[MQTTSNGW_PARAM_MAX]; + char errmsg[256]; + uint16_t multicastPortNo = 0; + uint16_t unicastPortNo = 0; + uint16_t dtlsPortNo = 0; + + SensorNetAddress add; + sockaddr_in6 soadd; + add.setSockaddr6(&soadd); + +#ifndef DTLS6 + string ip; + uint32_t ttl = 1; + + if (theProcess->getParam("MulticastIP", param) == 0) + { + ip = param; + _description += "IPv4 DTLS Multicast "; + _description += param; + } + if (theProcess->getParam("MulticastPortNo", param) == 0) + { + multicastPortNo = atoi(param); + _description += ":"; + _description += param; + } + if (theProcess->getParam("GatewayPortNo", param) == 0) + { + unicastPortNo = atoi(param); + _description += ", Gateway PortNo:"; + _description += param; + } + if (theProcess->getParam("DtlsPortNo", param) == 0) + { + dtlsPortNo = atoi(param); + _description += ", SSL PortNo:"; + _description += param; + } + if (theProcess->getParam("MulticastTTL", param) == 0) + { + ttl = atoi(param); + _description += ", TTL:"; + _description += param; + } +#else + string ip6; + uint32_t hops = 1; + string interface; + + if (theProcess->getParam("MulticastIPv6", param) == 0) + { + ip6 = param; + _description += "IPv6 DTLS Multicast ["; + _description += param; + } + if (theProcess->getParam("MulticastIPv6PortNo", param) == 0) + { + multicastPortNo = atoi(param); + _description += "]:"; + _description += param; + } + if (theProcess->getParam("GatewayIPv6PortNo", param) == 0) + { + unicastPortNo = atoi(param); + _description += ", Gateway PortNo:"; + _description += param; + } + if (theProcess->getParam("DtlsPortNo", param) == 0) + { + dtlsPortNo = atoi(param); + _description += ", SSL PortNo:"; + _description += param; + } + if (theProcess->getParam("MulticastIPv6If", param) == 0) + { + interface = param; + _description += ", Interface:"; + _description += param; + } + if (theProcess->getParam("MulticastHops", param) == 0) + { + hops = atoi(param); + _description += ", Hops:"; + _description += param; + } +#endif + + if (theGateway->getGWParams()->gwCertskey == nullptr) + { + throw EXCEPTION("DtlsCertsKey is required.", 0); + } + if (theGateway->getGWParams()->gwPrivatekey == nullptr) + { + throw EXCEPTION("DtlsPrivateKey is required.", 0); + } + + /* allocate Connections */ + _conns->initialize(theGateway->getGWParams()->maxClients); + + SSL_load_error_strings(); + SSL_library_init(); + + _dtlsctx = SSL_CTX_new(DTLS_server_method()); + if (_dtlsctx == 0) + { + ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg)); + D_NWSTACK("SSL_CTX_new() %s\n", errmsg); + throw EXCEPTION("SSL_CTX_new()", 0); + } + SSL_CTX_set_min_proto_version(_dtlsctx, DTLS1_VERSION); + + if (SSL_CTX_use_certificate_file(_dtlsctx, theGateway->getGWParams()->gwCertskey, SSL_FILETYPE_PEM) != 1) + { + ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg)); + D_NWSTACK("SSL_CTX_use_certificate_file() %s %s\n", theGateway->getGWParams()->gwCertskey, errmsg); + throw EXCEPTION("SSL_CTX_use_certificate_file()", 0); + } + if (SSL_CTX_use_PrivateKey_file(_dtlsctx, theGateway->getGWParams()->gwPrivatekey, SSL_FILETYPE_PEM) != 1) + { + ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg)); + D_NWSTACK("SSL_CTX_use_PrivateKey_file() %s %s\n", theGateway->getGWParams()->gwPrivatekey, errmsg); + throw EXCEPTION("SSL_CTX_use_PrivateKey_file()", 0); + } + + /* Client certification and cookie are not required */ + SSL_CTX_set_verify(_dtlsctx, SSL_VERIFY_NONE, NULL); + SSL_CTX_set_cookie_generate_cb(_dtlsctx, generate_cookie); + SSL_CTX_set_cookie_verify_cb(_dtlsctx, verify_cookie); + + /* Prepare UDP and UDP6 sockets for Multicasting and unicasting */ +#ifndef DTLS6 + if (openV4(&ip, multicastPortNo, unicastPortNo, dtlsPortNo, ttl) < 0) + { + throw EXCEPTION("Can't open a UDP4", errno); + } +#else + if (openV6(&ip6, &interface, multicastPortNo, unicastPortNo, dtlsPortNo, hops) < 0) + { + throw EXCEPTION("Can't open a UDP6", errno); + } +#endif +} + +const char* SensorNetwork::getDescription(void) +{ + return _description.c_str(); +} + +SensorNetAddress* SensorNetwork::getSenderAddress(void) +{ + return _senderAddr; +} + +int SensorNetwork::openV4(string *ipAddress, uint16_t multiPortNo, uint16_t uniPortNo, uint16_t dtlsPortNo, uint32_t ttl) +{ + int optval = 0; + int rc = -1; + int sock = 0; + errno = 0; + _af = AF_INET; + + if (uniPortNo == 0 || multiPortNo == 0) + { + D_NWSTACK("error portNo undefined in UDP4_6Port::openV4\n"); + return rc; + } + + /*------ Create unicast socket --------*/ + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) + { + D_NWSTACK("can't create unicast socket in UDP4_6Port::openV4 error %d %s\n", errno, strerror(errno)); + return -1; + } + + optval = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(uniPortNo); + addr.sin_addr.s_addr = INADDR_ANY; + + if (::bind(sock, (sockaddr*) &addr, sizeof(addr)) < 0) + { + D_NWSTACK("can't bind unicast socket in UDP4_6Port::openV4 error %d %s\n", errno, strerror(errno)); + return -1; + } + _conns->setSockUnicast(sock); + + /*------ Set SSL socket address --------*/ + _serverAddr4.sin_family = AF_INET; + _serverAddr4.sin_port = htons(uniPortNo); + _serverAddr4.sin_addr.s_addr = INADDR_ANY; + + /*------ Create Multicast socket --------*/ + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) + { + D_NWSTACK("can't create multicast socket in UDP4_6Port::openV4 error %d %s\n", errno, strerror(errno)); + return -1; + } + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + + sockaddr_in addrm; + addrm.sin_family = AF_INET; + addrm.sin_port = htons(multiPortNo); + addrm.sin_addr.s_addr = INADDR_ANY; + + if (::bind(sock, (sockaddr*) &addrm, sizeof(addrm)) < 0) + { + D_NWSTACK("can't bind multicast socket in UDP4_6Port::openV4 error %d %s\n", errno, strerror(errno)); + return -1; + } + + ip_mreq mreq; + memset(&mreq, 0, sizeof(mreq)); + mreq.imr_interface.s_addr = INADDR_ANY; + mreq.imr_multiaddr.s_addr = inet_addr(ipAddress->c_str()); + + if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) + { + D_NWSTACK("Multicast IP_ADD_MEMBERSHIP in UDP4_6Port::openV4 error %d %s\n", errno, strerror(errno)); + return -1; + } + if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) + { + D_NWSTACK("Multicast IP_MULTICAST_TTL in UDP4_6Port::openV4 error %d %s\n", errno, strerror(errno)); + return -1; + } + +#ifdef DEBUG_NW + optval = 1; +#else + optval = 0; +#endif + + if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char*) &optval, sizeof(optval)) < 0) + { + D_NWSTACK("error %d IP_MULTICAST_LOOP in UDP4_6Port::openV4 %s\n", errno, strerror(errno)); + return -1; + } + _multicastAddr->setFamily(AF_INET); + _multicastAddr->setIpAddress(ipAddress); + _multicastAddr->setPort(multiPortNo); + _conns->setSockMulticast(sock); + return 0; +} + +int SensorNetwork::openV6(string *ipAddress, string *interface, uint16_t multiPortNo, uint16_t uniPortNo, uint16_t dtlsPortNo, + uint32_t hops) +{ + int optval = 0; + int sock = 0; + uint32_t ifindex = 0; + + errno = 0; + + if (uniPortNo == 0 || multiPortNo == 0) + { + WRITELOG("error portNo undefined in SensorNetwork::openV6\n"); + return -1; + } + + _multicastAddr->setPort(multiPortNo); + _unicastAddr->setPort(dtlsPortNo); + + if (_multicastAddr->setIpAddress(ipAddress) < 0) + { + D_NWSTACK("Incorrect IPV6 address in SensorNetwork::openV6 error %s\n", strerror(errno)); + return -1; + } + + /*------ Create unicast socket --------*/ + sock = socket(AF_INET6, SOCK_DGRAM, 0); + if (sock < 0) + { + D_NWSTACK("can't create unicast socket in SensorNetwork::openV6 error %s\n", strerror(errno)); + return -1; + } + _conns->setSockUnicast(sock); + + optval = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + + optval = 1; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)) < 0) + { + D_NWSTACK("IPV6_ONLY in SensorNetwork::openV6 error %s\n", strerror(errno)); + return -1; + } + + sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(uniPortNo); + addr.sin6_addr = in6addr_any; + + if (::bind(sock, (sockaddr*) &addr, sizeof(addr)) < 0) + { + D_NWSTACK("can't bind unicast socket in SensorNetwork::openV6 error %s\n", strerror(errno)); + return -1; + } + + if (interface->size() > 0) + { + ifindex = if_nametoindex(interface->c_str()); +#ifdef __APPLE__ + setsockopt(sock, IPPROTO_IP, IP_BOUND_IF, &ifindex, interface->size()); +#else + setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interface->c_str(), interface->size()); +#endif + } + + /*------ Set SSL socket address --------*/ + _serverAddr6.sin6_family = AF_INET6; + _serverAddr6.sin6_port = htons(uniPortNo); + _serverAddr6.sin6_addr = in6addr_any; + + if (::bind(sock, (sockaddr*) &_serverAddr6, sizeof(_serverAddr6)) < 0) + { + D_NWSTACK("can't bind listen socket in SensorNetwork::openV6 error %s\n", strerror(errno)); + return -1; + } + + if (interface->size() > 0) + { +#ifdef __APPLE__ + setsockopt(sock, IPPROTO_IP, IP_BOUND_IF, &ifindex, interface->size()); +#else + setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interface->c_str(), interface->size()); +#endif + } + + + // Create Multicast socket + sock = socket(AF_INET6, SOCK_DGRAM, 0); + if (sock < 0) + { + D_NWSTACK("can't create multicast socket in SensorNetwork::openV6 error %s\n", strerror(errno)); + return -1; + } + + _conns->setSockMulticast(sock); + + optval = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + + if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0) + { + D_NWSTACK("IPV6_MULTICAST_IF in SensorNetwork::openV6 error %s\n", strerror(errno)); + return -1; + } + + if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*) &optval, sizeof(optval)) < 0) + { + D_NWSTACK("IPV6_ONLY in SensorNetworkSensorNetwork::openV6 error %s\n", strerror(errno)); + return -1; + } + + sockaddr_in6 addrm; + addrm.sin6_family = AF_INET6; + addrm.sin6_port = htons(multiPortNo); + addrm.sin6_addr = in6addr_any; + + if (::bind(sock, (sockaddr*) &addrm, sizeof(addrm)) < 0) + { + D_NWSTACK("can't bind multicast socket in SensorNetwork::openV6 error %s\n", strerror(errno)); + return -1; + } + + struct ipv6_mreq mreq; + mreq.ipv6mr_multiaddr = _multicastAddr->getIpAddress()->addr.ad6; + mreq.ipv6mr_interface = ifindex; + + if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) + { + D_NWSTACK("Multicast IPV6_ADD_MEMBERSHIP in SensorNetwork::openV6 error %s\n", strerror(errno)); + return -1; + } + +#ifdef DEBUG_NW + optval = 1; +#else + optval = 0; +#endif + + if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &optval, sizeof(optval)) < 0) + { + D_NWSTACK("IPV6_MULTICAST_LOOP in SensorNetwork::openV6 error %s\n", strerror(errno)); + return -1; + } + + if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops)) < 0) + { + D_NWSTACK("Multicast IPV6_MULTICAST_HOPS in SensorNetwork::openV6 error %s\n", strerror(errno)); + return -1; + } + _multicastAddr->setFamily(AF_INET6); + _multicastAddr->setIpAddress(ipAddress); + _multicastAddr->setPort(multiPortNo); + return 0; +} + +int SensorNetwork::multicastRecv(uint8_t *buf, uint16_t len) +{ + int rc = -1; + +#ifndef DTLS6 + sockaddr_in sender; + socklen_t addrlen = sizeof(sender); + memset(&sender, 0, addrlen); + + rc = ::recvfrom(_conns->getSockMulticast(), buf, len, 0, (sockaddr*) &sender, &addrlen); + if (rc < 0 && errno != EAGAIN) + { + D_NWSTACK("errno %s IPv4 in SensorNetwork::multicastRecv\n", strerror(errno)); + return -1; + } + + D_NWSTACK("IPv4 multicast recved from %s:%d length = %d\n", inet_ntoa(sender.sin_addr), ntohs(sender.sin_port), rc); + +#else + sockaddr_in6 sender; + socklen_t addrlen = sizeof(sender); + memset(&sender, 0, addrlen); + + rc = ::recvfrom(_conns->getSockMulticast(), buf, len, 0, (sockaddr*) &sender, &addrlen); + if (rc < 0 && errno != EAGAIN) + { + D_NWSTACK("errno = %d IPv6 in SensorNetwork::multicastRecv\n", errno); + return -1; + } +#ifdef DEBUG_NW + char buff[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &sender.sin6_addr, buff, INET6_ADDRSTRLEN); + D_NWSTACK("IPv6 multicast recved from %s:%u length = %d\n", buff, ntohs(sender.sin6_port), rc); +#endif +#endif + + return rc; +} + +int SensorNetwork::getUnicastClient(SensorNetAddress *addr) +{ + return getSenderAddress(_conns->getSockUnicast(), addr); +} + +int SensorNetwork::getSendClient(int index, SensorNetAddress *addr) +{ + return getSenderAddress(_conns->getSockClient(index), addr); +} + +int SensorNetwork::getSenderAddress(int sock, SensorNetAddress *addr) +{ + int len = -1; + +#ifndef DTLS6 + // AF_INET + sockaddr_in sender4 = { 0 }; + socklen_t addrlen4 = sizeof(sender4); + char buf[16]; + int rc = PACKET_OTHERS; + + len = ::recvfrom(sock, buf, 15, MSG_PEEK, (sockaddr*) &sender4, &addrlen4); + + if (len < 0 && errno != EAGAIN) + { + D_NWSTACK("errno = %d in UDPPort::getSender\n", errno); + return -1; + } + addr->setFamily(AF_INET); + addr->getIpAddress()->addr.ad4 = sender4.sin_addr; + D_NWSTACK("SensorNetwork::getSenderAddress recved from %s:%d length = %d\n", inet_ntoa(sender4.sin_addr), + ntohs(sender4.sin_port), len); + +// if (len >= 13) + { + if (buf[0] == 22) + { + rc = PACKET_CLIENTHELLO; + } + else if (buf[0] == 23) + { + rc = PACKET_APPL; + } + D_NWSTACK("getSenderAddress len=%d Packet type=%d\n", len, buf[0]); + } + return rc; + +#else + //AF_INET6 + sockaddr_in6 sender6 = { 0 }; + socklen_t addrlen6 = sizeof(sender6); + unsigned long int buf = 0; + len = ::recvfrom(sock, &buf, 1, MSG_PEEK, (sockaddr*) &sender6, &addrlen6); + + if (len < 0 && errno != EAGAIN) + { + D_NWSTACK("errno = %d in SensorNetwork::getSender\n", errno); + return len; + } + + addr->setFamily(AF_INET6); + addr->setSockaddr6(&sender6); + +#ifdef DEBUG_NW + char senderstr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &sender6.sin6_addr,senderstr,INET6_ADDRSTRLEN); + D_NWSTACK("recved from %s:%d length = %d\n",senderstr ,ntohs(sender6.sin6_port), len); +#endif +#endif + + return len; +} + +void SensorNetwork::clearRecvData(int sock) +{ + uint8_t buf[MQTTSNGW_MAX_PACKET_SIZE]; + ::recv(sock, buf, MQTTSNGW_MAX_PACKET_SIZE, 0); +} + +int verify_cert(int ok, X509_STORE_CTX *ctx) +{ + return 1; +} + +int generate_cookie(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len) +{ + unsigned char *buf; + unsigned char result[EVP_MAX_MD_SIZE]; + unsigned int len = 0; + unsigned int rsltlen; + union + { + struct sockaddr_storage ss; + struct sockaddr_in6 s6; + struct sockaddr_in s4; + } peer; + + if (!cookie_initialized) + { + if (!RAND_bytes(cookie_secret, COOKIE_SECRET_LENGTH)) + { + return 0; + } + cookie_initialized = 1; + } + + (void) BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer); + + len = 0; + switch (peer.ss.ss_family) + { + case AF_INET: + len += sizeof(struct in_addr); + break; + case AF_INET6: + len += sizeof(struct in6_addr); + break; + default: + OPENSSL_assert(0); + break; + } + len += sizeof(in_port_t); + buf = (unsigned char*) OPENSSL_malloc(len); + + switch (peer.ss.ss_family) + { + case AF_INET: + memcpy(buf, &peer.s4.sin_port, sizeof(in_port_t)); + memcpy(buf + sizeof(peer.s4.sin_port), &peer.s4.sin_addr, sizeof(struct in_addr)); + break; + case AF_INET6: + memcpy(buf, &peer.s6.sin6_port, sizeof(in_port_t)); + memcpy(buf + sizeof(in_port_t), &peer.s6.sin6_addr, sizeof(struct in6_addr)); + break; + default: + OPENSSL_assert(0); + break; + } + + HMAC(EVP_sha1(), (const void*) cookie_secret, COOKIE_SECRET_LENGTH, (const unsigned char*) buf, len, result, &rsltlen); + OPENSSL_free(buf); + + memcpy(cookie, result, rsltlen); + *cookie_len = rsltlen; + + return 1; +} + +int verify_cookie(SSL *ssl, const unsigned char *cookie, unsigned int cookie_len) +{ + unsigned char *buf; + unsigned char result[EVP_MAX_MD_SIZE]; + unsigned int len = 0; + unsigned int rsltlen; + union + { + struct sockaddr_storage ss; + struct sockaddr_in6 s6; + struct sockaddr_in s4; + } peer; + + if (!cookie_initialized) + { + return 0; + } + + (void) BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer); + + len = 0; + switch (peer.ss.ss_family) + { + case AF_INET: + len += sizeof(struct in_addr); + break; + case AF_INET6: + len += sizeof(struct in6_addr); + break; + default: + OPENSSL_assert(0); + break; + } + len += sizeof(in_port_t); + buf = (unsigned char*) OPENSSL_malloc(len); + + switch (peer.ss.ss_family) + { + case AF_INET: + memcpy(buf, &peer.s4.sin_port, sizeof(in_port_t)); + memcpy(buf + sizeof(in_port_t), &peer.s4.sin_addr, sizeof(struct in_addr)); + break; + case AF_INET6: + memcpy(buf, &peer.s6.sin6_port, sizeof(in_port_t)); + memcpy(buf + sizeof(in_port_t), &peer.s6.sin6_addr, sizeof(struct in6_addr)); + break; + default: + OPENSSL_assert(0); + break; + } + + HMAC(EVP_sha1(), (const void*) cookie_secret, COOKIE_SECRET_LENGTH, (const unsigned char*) buf, len, result, &rsltlen); + OPENSSL_free(buf); + + if (cookie_len == rsltlen && memcmp(result, cookie, rsltlen) == 0) + { + return 1; + } + return 0; +} + diff --git a/MQTTSNGateway/src/linux/dtls/SensorNetwork.h b/MQTTSNGateway/src/linux/dtls/SensorNetwork.h new file mode 100644 index 0000000..8f8680c --- /dev/null +++ b/MQTTSNGateway/src/linux/dtls/SensorNetwork.h @@ -0,0 +1,163 @@ +/************************************************************************************** + * Copyright (c) 2021, Tomoaki Yamaguchi + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Tomoaki Yamaguchi - initial API and implementation and/or initial documentation + **************************************************************************************/ + +#ifndef SENSORNETWORK_H_ +#define SENSORNETWORK_H_ + +#include "MQTTSNGWDefines.h" +#include "Threading.h" +#include +#include +#include +#include +#include + +using namespace std; + +namespace MQTTSNGW +{ +/*=========================================== + Class SensorNetAddreess + ============================================*/ +typedef struct +{ + int af; + union + { + struct in_addr ad4; + struct in6_addr ad6; + } addr; +} ipAddr_t; + +class SensorNetAddress +{ +public: + SensorNetAddress(); + ~SensorNetAddress(); + void setAddress(ipAddr_t *Address, uint16_t port); + int setAddress(string *ipAddrPort); + int setIpAddress(string *IpAddress); + void setFamily(int type); + int getFamily(void); + void setPort(in_port_t port); + void setSockaddr4(sockaddr_in *sockaddr); + void setSockaddr6(sockaddr_in6 *sockaddr); + void cpyAddr4(sockaddr_in *sockaddr); + void cpyAddr6(sockaddr_in6 *sockaddr); + in_port_t getPort(void); + ipAddr_t* getIpAddress(void); + void setIndex(int index); + int getIndex(void); + + void clear(void); + + bool isMatch(SensorNetAddress *addr); + SensorNetAddress& operator =(SensorNetAddress &addr); + char* sprint(char *buf); +private: + int _pfdsIndex; + in_port_t _portNo; + ipAddr_t _ipAddr; +}; + +/*=========================================== + Class Connections + ============================================*/ +#define POLL_UCAST 0 +#define POLL_MCAST 1 +#define POLL_SSL 2 + +typedef struct +{ + int af; + SSL *ssl; +} afSSL_t; + +class Connections +{ +public: + Connections(); + ~Connections(); + void initialize(int maxClient); + void close(int index); + int poll(int timeout); + int addClientSock(int sock); + int addClientSSL(SSL *ssl, int sock); + void setSockMulticast(int sock); + void setSockUnicast(int sock); + int getNumOfConnections(void); + int getNumOfClients(void); + SSL* getClientSSL(int index); + int getEventClient(int index); + int getSockClient(int index); + int getSockMulticast(void); + int getSockUnicast(void); + int getEventMulticast(void); + int getEventUnicast(void); + int getEventListen(void); + void closeSSL(int index); + int searchClient(SensorNetAddress *addr); +private: + pollfd *_pollfds; + SSL **_ssls; + SensorNetAddress **_clientAddr; + int _maxfds; + int _numfds; + Mutex _mutex; +}; + +/*=========================================== + Class SensorNetwork + ============================================*/ +class SensorNetwork +{ + friend class SensorNetSubTask; +public: + SensorNetwork(); + ~SensorNetwork(); + + int unicast(const uint8_t *payload, uint16_t payloadLength, SensorNetAddress *sendto); + int broadcast(const uint8_t *payload, uint16_t payloadLength); + int read(uint8_t *buf, uint16_t bufLen); + void initialize(void); + const char* getDescription(void); + SensorNetAddress* getSenderAddress(void); + void close(); + +private: + int openV4(string *ipAddress, uint16_t multiPortNo, uint16_t uniPortNo, uint16_t listenPortNo, uint32_t ttl); + int openV6(string *ipAddress, string *interface, uint16_t multiPortNo, uint16_t uniPortNo, uint16_t listenPortNo, + uint32_t hops); + int multicastRecv(uint8_t *buf, uint16_t len); + int getSendClient(int index, SensorNetAddress *addr); + int getSenderAddress(int sock, SensorNetAddress *addr); + int getUnicastClient(SensorNetAddress *addr); + void clearRecvData(int sock); + + Mutex _mutex; + SensorNetAddress *_senderAddr; + SensorNetAddress *_multicastAddr; + SensorNetAddress *_unicastAddr; + string _description; + SSL_CTX *_dtlsctx; + Connections *_conns; + sockaddr_in _serverAddr4; + sockaddr_in6 _serverAddr6; + int _af; +}; + +} +#endif /* SENSORNETWORK_H_ */ diff --git a/MQTTSNGateway/src/linux/loralink/SensorNetwork.cpp b/MQTTSNGateway/src/linux/loralink/SensorNetwork.cpp index fc7f8e0..9d755db 100644 --- a/MQTTSNGateway/src/linux/loralink/SensorNetwork.cpp +++ b/MQTTSNGateway/src/linux/loralink/SensorNetwork.cpp @@ -383,7 +383,7 @@ bool LoRaLink::readApiFrame(LoRaLinkFrame_t* api, LoRaLinkReadParameters_t* para int LoRaLink::send(LoRaLinkPayloadType_t type, const uint8_t* payload, uint16_t pLen, SensorNetAddress* addr) { - D_NWSTACK("\r\n===> Send: "); + D_LRSTACK("\r\n===> Send: "); uint8_t buf[2] = { 0 }; uint8_t chks = 0; uint16_t len = pLen + 3; // 3 = DestAddr[1] + PayloadType[1] + Crc[1] @@ -404,7 +404,7 @@ int LoRaLink::send(LoRaLinkPayloadType_t type, const uint8_t* payload, uint16_t send(type); chks += type; - D_NWSTACK("\r\n Payload: "); + D_LRSTACK("\r\n Payload: "); for ( uint8_t i = 0; i < pLen; i++ ){ send(payload[i]); // Payload @@ -412,21 +412,21 @@ int LoRaLink::send(LoRaLinkPayloadType_t type, const uint8_t* payload, uint16_t } chks = 0xff - chks; - D_NWSTACK(" checksum "); + D_LRSTACK(" checksum "); send(chks); - D_NWSTACK("\r\n"); + D_LRSTACK("\r\n"); /* wait ACK */ _sem.timedwait(LORALINK_TIMEOUT_ACK); if ( _respCd == LORALINK_NO_FREE_CH ) { - D_NWSTACK(" Channel isn't free\r\n"); + D_LRSTACK(" Channel isn't free\r\n"); return -1; } else if ( _respCd != LORALINK_ACK ) { - D_NWSTACK(" Not Acknowleged\r\n"); + D_LRSTACK(" Not Acknowleged\r\n"); return -1; } return (int)pLen; @@ -479,7 +479,7 @@ int LoRaLink::recv(uint8_t* buf) /* if ( *buf == ESCAPE ) { - D_NWSTACK( " %02x",buf[0] ); + D_LRSTACK( " %02x",buf[0] ); if ( read(fd, buf, 1) == 1 ) { *buf = PAD ^ *buf; @@ -491,7 +491,7 @@ int LoRaLink::recv(uint8_t* buf) } */ - D_NWSTACK( " %02x",buf[0] ); + D_LRSTACK(" %02x", buf[0]); return 0; } } @@ -552,7 +552,7 @@ bool SerialPort::send(unsigned char b) } else { - D_NWSTACK( " %02x", b); + D_LRSTACK(" %02x", b); return true; } } diff --git a/MQTTSNGateway/src/linux/loralink/SensorNetwork.h b/MQTTSNGateway/src/linux/loralink/SensorNetwork.h index febfeda..212dc46 100644 --- a/MQTTSNGateway/src/linux/loralink/SensorNetwork.h +++ b/MQTTSNGateway/src/linux/loralink/SensorNetwork.h @@ -11,7 +11,7 @@ * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: - * Tomoaki Yamaguchi - initial API and implementation + * Tomoaki Yamaguchi - initial API and implementation **************************************************************************************/ #ifndef SENSORNETWORKX_H_ #define SENSORNETWORKX_H_ @@ -25,12 +25,11 @@ using namespace std; namespace MQTTSNGW { -//#define DEBUG_NWSTACK -#ifdef DEBUG_NWSTACK - #define D_NWSTACK(...) printf(__VA_ARGS__); fflush(stdout) +#ifdef DEBUG_NW +#define D_LRSTACK(...) printf(__VA_ARGS__); fflush(stdout) #else - #define D_NWSTACK(...) + #define D_LRSTACK(...) #endif diff --git a/MQTTSNGateway/src/linux/rfcomm/SensorNetwork.h b/MQTTSNGateway/src/linux/rfcomm/SensorNetwork.h index 1a90b42..2aef9f8 100644 --- a/MQTTSNGateway/src/linux/rfcomm/SensorNetwork.h +++ b/MQTTSNGateway/src/linux/rfcomm/SensorNetwork.h @@ -26,12 +26,6 @@ using namespace std; namespace MQTTSNGW { -#ifdef DEBUG_NWSTACK - #define D_NWSTACK(...) printf(__VA_ARGS__) -#else - #define D_NWSTACK(...) -#endif - #define MAX_RFCOMM_CH 30 /*=========================================== diff --git a/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp b/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp index 0828dd6..e855619 100644 --- a/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp +++ b/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp @@ -20,10 +20,13 @@ #include #include #include +#include +#include #include #include #include #include +#include #include "SensorNetwork.h" #include "MQTTSNGWProcess.h" @@ -196,33 +199,33 @@ void SensorNetwork::initialize(void) * MulticastIP=225.1.1.1 * MulticastPortNo=1883 * - */ - if (theProcess->getParam("MulticastIP", param) == 0) - { - ip = param; - _description = "UDP Multicast "; - _description += param; - } - if (theProcess->getParam("MulticastPortNo", param) == 0) - { - multicastPortNo = atoi(param); - _description += ":"; - _description += param; - } - if (theProcess->getParam("GatewayPortNo", param) == 0) - { - unicastPortNo = atoi(param); - _description += " Gateway Port "; - _description += param; - } - if (theProcess->getParam("MulticastTTL", param) == 0) - { - ttl = atoi(param); - _description += " TTL: "; - _description += param; - } + */ + if (theProcess->getParam("MulticastIP", param) == 0) + { + ip = param; + _description = "UDP Multicast "; + _description += param; + } + if (theProcess->getParam("MulticastPortNo", param) == 0) + { + multicastPortNo = atoi(param); + _description += ":"; + _description += param; + } + if (theProcess->getParam("GatewayPortNo", param) == 0) + { + unicastPortNo = atoi(param); + _description += ", Gateway Port:"; + _description += param; + } + if (theProcess->getParam("MulticastTTL", param) == 0) + { + ttl = atoi(param); + _description += ", TTL:"; + _description += param; + } - /* Prepare UDP sockets */ + /* setup UDP sockets */ errno = 0; if ( UDPPort::open(ip.c_str(), multicastPortNo, unicastPortNo, ttl) < 0 ) { @@ -247,9 +250,7 @@ SensorNetAddress* SensorNetwork::getSenderAddress(void) UDPPort::UDPPort() { _disconReq = false; - _sockfdUnicast = -1; - _sockfdMulticast = -1; - _ttl = 0; + memset(_pollFds, 0, sizeof(_pollFds)); } UDPPort::~UDPPort() @@ -259,130 +260,126 @@ UDPPort::~UDPPort() void UDPPort::close(void) { - if (_sockfdUnicast > 0) - { - ::close(_sockfdUnicast); - _sockfdUnicast = -1; - } - if (_sockfdMulticast > 0) - { - ::close(_sockfdMulticast); - _sockfdMulticast = -1; - } + for (int i = 0; i < 2; i++) + { + if (_pollFds[i].fd > 0) + { + ::close(_pollFds[i].fd); + _pollFds[i].fd = 0; + } + } } -int UDPPort::open(const char* ipAddress, uint16_t multiPortNo, uint16_t uniPortNo, unsigned int ttl) +int UDPPort::open(const char *multicastIP, uint16_t multiPortNo, uint16_t uniPortNo, unsigned int ttl) { - char loopch = 0; - const int reuse = 1; + int optval = 0; + int sock = 0; - if (uniPortNo == 0 || multiPortNo == 0) - { - D_NWSTACK("error portNo undefined in UDPPort::open\n"); - return -1; - } + if (uniPortNo == 0 || multiPortNo == 0) + { + D_NWSTACK("error portNo undefined in UDPPort::open\n"); + return -1; + } - uint32_t ip = inet_addr(ipAddress); - _multicastAddr.setAddress(ip, htons(multiPortNo)); - _unicastAddr.setAddress(ip, htons(uniPortNo)); - _ttl = ttl; + /*------ Create unicast socket --------*/ + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) + { + D_NWSTACK("error can't create unicast socket in UDPPort::open\n"); + return -1; + } - /*------ Create unicast socket --------*/ - _sockfdUnicast = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (_sockfdUnicast < 0) - { - D_NWSTACK("error can't create unicast socket in UDPPort::open\n"); - return -1; - } + sockaddr_in addru; + addru.sin_family = AF_INET; + addru.sin_port = htons(uniPortNo); + addru.sin_addr.s_addr = INADDR_ANY; - setsockopt(_sockfdUnicast, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); - - sockaddr_in addru; - addru.sin_family = AF_INET; - addru.sin_port = htons(uniPortNo); - addru.sin_addr.s_addr = INADDR_ANY; - - if (::bind(_sockfdUnicast, (sockaddr*) &addru, sizeof(addru)) < 0) + if (::bind(sock, (sockaddr*) &addru, sizeof(addru)) < 0) { D_NWSTACK("error can't bind unicast socket in UDPPort::open\n"); return -1; } - if (setsockopt(_sockfdUnicast, IPPROTO_IP, IP_MULTICAST_LOOP, (char*) &loopch, sizeof(loopch)) < 0) - { - D_NWSTACK("error IP_MULTICAST_LOOP in UDPPort::open\n"); - close(); - return -1; - } - /*------ Create Multicast socket --------*/ - _sockfdMulticast = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (_sockfdMulticast < 0) + _pollFds[0].fd = sock; + _pollFds[0].events = POLLIN; + + /*------ Create Multicast socket --------*/ + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { D_NWSTACK("error can't create multicast socket in UDPPort::open\n"); close(); return -1; } - setsockopt(_sockfdMulticast, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); + optval = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); - sockaddr_in addrm; - addrm.sin_family = AF_INET; - addrm.sin_port = _multicastAddr.getPortNo(); - addrm.sin_addr.s_addr = INADDR_ANY; + sockaddr_in addrm; + addrm.sin_family = AF_INET; + addrm.sin_port = htons(multiPortNo); + addrm.sin_addr.s_addr = INADDR_ANY; - if (::bind(_sockfdMulticast, (sockaddr*) &addrm, sizeof(addrm)) < 0) - { - D_NWSTACK("error can't bind multicast socket in UDPPort::open\n"); - return -1; - } - if (setsockopt(_sockfdMulticast, IPPROTO_IP, IP_MULTICAST_LOOP, (char*) &loopch, sizeof(loopch)) < 0) - { - D_NWSTACK("error IP_MULTICAST_LOOP in UDPPort::open\n"); - close(); - return -1; - } + if (::bind(sock, (sockaddr*) &addrm, sizeof(addrm)) < 0) + { + D_NWSTACK("error can't bind multicast socket in UDPPort::open\n"); + return -1; + } - ip_mreq mreq; - mreq.imr_interface.s_addr = INADDR_ANY; - mreq.imr_multiaddr.s_addr = _multicastAddr.getIpAddress(); + ip_mreq mreq; + memset(&mreq, 0, sizeof(mreq)); + mreq.imr_interface.s_addr = INADDR_ANY; + mreq.imr_multiaddr.s_addr = inet_addr(multicastIP); - if (setsockopt(_sockfdMulticast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) - { - D_NWSTACK("error Multicast IP_ADD_MEMBERSHIP in UDPPort::open\n"); - close(); - return -1; - } + if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) + { + D_NWSTACK("error Multicast IP_ADD_MEMBERSHIP in UDPPort::open\n"); + close(); + return -1; + } - if (setsockopt(_sockfdMulticast, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,sizeof(ttl)) < 0) - { - D_NWSTACK("error Multicast IP_ADD_MEMBERSHIP in UDPPort::open\n"); - close(); - return -1; - } + if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) + { + D_NWSTACK("error Multicast IP_MULTICAST_TTL in UDPPort::open\n"); + close(); + return -1; + } - if (setsockopt(_sockfdUnicast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) - { - D_NWSTACK("error Unicast IP_ADD_MEMBERSHIP in UDPPort::open\n"); - close(); - return -1; - } - return 0; +#ifdef DEBUG_NW + optval = 1; +#else + optval = 0; +#endif + + if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &optval, sizeof(optval)) < 0) + { + D_NWSTACK("error IP_MULTICAST_LOOP in UDPPort::open\n"); + close(); + return -1; + } + + _multicastAddr.setAddress(inet_addr(multicastIP), htons(multiPortNo)); + _pollFds[1].fd = sock; + _pollFds[1].events = POLLIN; + + return 0; } int UDPPort::unicast(const uint8_t* buf, uint32_t length, SensorNetAddress* addr) { - sockaddr_in dest; - dest.sin_family = AF_INET; - dest.sin_port = addr->getPortNo(); - dest.sin_addr.s_addr = addr->getIpAddress(); + sockaddr_in dest; + dest.sin_family = AF_INET; + dest.sin_port = addr->getPortNo(); + dest.sin_addr.s_addr = addr->getIpAddress(); - int status = ::sendto(_sockfdUnicast, buf, length, 0, (const sockaddr*) &dest, sizeof(dest)); - if (status < 0) - { - D_NWSTACK("errno == %d in UDPPort::sendto\n", errno); - } - D_NWSTACK("sendto %s:%u length = %d\n", inet_ntoa(dest.sin_addr), ntohs(dest.sin_port), status); - return status; + int status = ::sendto(_pollFds[0].fd, buf, length, 0, (const sockaddr*) &dest, sizeof(dest)); + if (status < 0) + { + D_NWSTACK("errno == %d in UDPPort::sendto\n", errno); + } + + D_NWSTACK("sendto %s:%u length = %d\n", inet_ntoa(dest.sin_addr), ntohs(dest.sin_port), status); + return status; } int UDPPort::broadcast(const uint8_t* buf, uint32_t length) @@ -392,55 +389,35 @@ int UDPPort::broadcast(const uint8_t* buf, uint32_t length) int UDPPort::recv(uint8_t* buf, uint16_t len, SensorNetAddress* addr) { - struct timeval timeout; - fd_set recvfds; - int maxSock = 0; + int rc = 0; + poll(_pollFds, 2, 2000); // Timeout 2 seconds - timeout.tv_sec = 1; - timeout.tv_usec = 0; // 1 sec - FD_ZERO(&recvfds); - FD_SET(_sockfdUnicast, &recvfds); - FD_SET(_sockfdMulticast, &recvfds); - - if (_sockfdMulticast > _sockfdUnicast) - { - maxSock = _sockfdMulticast; - } - else - { - maxSock = _sockfdUnicast; - } - - int rc = 0; - if ( select(maxSock + 1, &recvfds, 0, 0, &timeout) > 0 ) - { - if (FD_ISSET(_sockfdUnicast, &recvfds)) - { - rc = recvfrom(_sockfdUnicast, buf, len, 0, addr); - } - else if (FD_ISSET(_sockfdMulticast, &recvfds)) - { - rc = recvfrom(_sockfdMulticast, buf, len, 0, &_multicastAddr); - } - } - return rc; + if (_pollFds[0].revents == POLLIN) + { + rc = recvfrom(_pollFds[0].fd, buf, len, 0, addr); + } + else if (_pollFds[1].revents == POLLIN) + { + rc = recvfrom(_pollFds[1].fd, buf, len, 0, addr); + } + return rc; } int UDPPort::recvfrom(int sockfd, uint8_t* buf, uint16_t len, uint8_t flags, SensorNetAddress* addr) { - sockaddr_in sender; - socklen_t addrlen = sizeof(sender); - memset(&sender, 0, addrlen); + sockaddr_in sender; + socklen_t addrlen = sizeof(sender); + memset(&sender, 0, addrlen); - int status = ::recvfrom(sockfd, buf, len, flags, (sockaddr*) &sender, &addrlen); + int status = ::recvfrom(sockfd, buf, len, flags, (sockaddr*) &sender, &addrlen); - if (status < 0 && errno != EAGAIN) - { - D_NWSTACK("errno == %d in UDPPort::recvfrom\n", errno); - return -1; - } - addr->setAddress(sender.sin_addr.s_addr, sender.sin_port); - D_NWSTACK("recved from %s:%d length = %d\n", inet_ntoa(sender.sin_addr),ntohs(sender.sin_port), status); - return status; + if (status < 0 && errno != EAGAIN) + { + D_NWSTACK("errno == %d in UDPPort::recvfrom\n", errno); + return -1; + } + addr->setAddress(sender.sin_addr.s_addr, sender.sin_port); + D_NWSTACK("recved from %s:%d length = %d\n", inet_ntoa(sender.sin_addr),ntohs(sender.sin_port), status); + return status; } diff --git a/MQTTSNGateway/src/linux/udp/SensorNetwork.h b/MQTTSNGateway/src/linux/udp/SensorNetwork.h index 9d1aef8..2a3870a 100644 --- a/MQTTSNGateway/src/linux/udp/SensorNetwork.h +++ b/MQTTSNGateway/src/linux/udp/SensorNetwork.h @@ -19,18 +19,13 @@ #include "MQTTSNGWDefines.h" #include +#include using namespace std; namespace MQTTSNGW { -#ifdef DEBUG_NWSTACK - #define D_NWSTACK(...) printf(__VA_ARGS__) -#else - #define D_NWSTACK(...) -#endif - /*=========================================== Class SensorNetAddreess ============================================*/ @@ -70,13 +65,9 @@ private: void setNonBlocking(const bool); int recvfrom(int sockfd, uint8_t* buf, uint16_t len, uint8_t flags, SensorNetAddress* addr); - int _sockfdUnicast; - int _sockfdMulticast; - - SensorNetAddress _multicastAddr; - SensorNetAddress _unicastAddr; + pollfd _pollFds[2]; bool _disconReq; - unsigned int _ttl; + SensorNetAddress _multicastAddr; }; /*=========================================== diff --git a/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp b/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp index 0d78c06..cbcc4d5 100644 --- a/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp +++ b/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp @@ -1,6 +1,6 @@ /************************************************************************************** * Copyright (c) 2017, Benjamin Aigner - * Copyright (c) 2016, Tomoaki Yamaguchi (original UDPv4 implementation) + * Copyright (c) 2021, Tomoaki Yamaguchi * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -20,8 +20,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -40,61 +42,57 @@ using namespace MQTTSNGW; ============================================*/ SensorNetAddress::SensorNetAddress() { - _portNo = 0; - memset((void *)&_IpAddr,0,sizeof(_IpAddr)); + memset((void*) &_IpAddr, 0, sizeof(_IpAddr)); } SensorNetAddress::~SensorNetAddress() { } -struct sockaddr_in6 *SensorNetAddress::getIpAddress(void) +sockaddr_in6* SensorNetAddress::getIpAddress(void) { - return &_IpAddr; + return &_IpAddr; } uint16_t SensorNetAddress::getPortNo(void) { - return _portNo; + return _IpAddr.sin6_port; } -void SensorNetAddress::setAddress(struct sockaddr_in6 *IpAddr, uint16_t port) +void SensorNetAddress::setAddress(struct sockaddr_in6 *IpAddr) { - memcpy((void *)&_IpAddr,IpAddr,sizeof(_IpAddr)); - _portNo = port; + memcpy((void*) &_IpAddr, IpAddr, sizeof(_IpAddr)); } /** * convert Text data to SensorNetAddress - * @param data is a IPV6_Address:PortNo format string + * @param data is a string [IPV6_Address]:PortNo * @return success = 0, Invalid format = -1 */ int SensorNetAddress::setAddress(string* data) { + size_t pos = data->find_last_of("]:"); - size_t pos = data->find_last_of(":"); + if (pos != string::npos) + { + int portNo = 0; + string port = data->substr(pos + 1); - if ( pos != string::npos) - { - int portNo = 0; - string port = data->substr(pos + 1); + if ((portNo = atoi(port.c_str())) > 0) + { + _IpAddr.sin6_port = htons(portNo); + _IpAddr.sin6_family = AF_INET6; + string ip = data->substr(1, pos - 2); + const char *cstr = ip.c_str(); - if ( ( portNo = atoi(port.c_str()) ) > 0 ) - { - _portNo = htons(portNo); - - string ip = data->substr(1,pos - 1); - const char *cstr = ip.c_str(); - - if (inet_pton(AF_INET6, cstr, &(_IpAddr.sin6_addr)) == 1 ) - { - return 0; - } - } - } - _portNo = 0; - memset((void *)&_IpAddr,0,sizeof(_IpAddr)); - return -1; + if (inet_pton(AF_INET6, cstr, &(_IpAddr.sin6_addr)) == 1) + { + return 0; + } + } + } + memset((void*) &_IpAddr, 0, sizeof(_IpAddr)); + return -1; } /** @@ -104,43 +102,42 @@ int SensorNetAddress::setAddress(string* data) */ int SensorNetAddress::setAddress(const char* data) { - if ( inet_pton(AF_INET6, data, &(_IpAddr.sin6_addr)) == 1 ) - { - return 0; - } - else - { - return -1; - } + if (inet_pton(AF_INET6, data, &(_IpAddr.sin6_addr)) == 1) + { + _IpAddr.sin6_family = AF_INET6; + return 0; + } + else + { + return -1; + } } char* SensorNetAddress::getAddress(void) { - inet_ntop(AF_INET6, &(_IpAddr.sin6_addr), _addrString, INET6_ADDRSTRLEN); - return _addrString; + inet_ntop(AF_INET6, &(_IpAddr.sin6_addr), _addrString, INET6_ADDRSTRLEN); + return _addrString; } bool SensorNetAddress::isMatch(SensorNetAddress* addr) { - return (this->_portNo == addr->_portNo) && \ - (memcmp(this->_IpAddr.sin6_addr.s6_addr, addr->_IpAddr.sin6_addr.s6_addr, sizeof(this->_IpAddr.sin6_addr.s6_addr)) == 0); + return (this->_IpAddr.sin6_port == addr->_IpAddr.sin6_port) + && (memcmp(this->_IpAddr.sin6_addr.s6_addr, addr->_IpAddr.sin6_addr.s6_addr, + sizeof(this->_IpAddr.sin6_addr.s6_addr)) == 0); } SensorNetAddress& SensorNetAddress::operator =(SensorNetAddress& addr) { - this->_portNo = addr._portNo; - memcpy(&this->_IpAddr.sin6_addr, &addr._IpAddr.sin6_addr, sizeof(this->_IpAddr.sin6_addr)); - return *this; + memcpy(&this->_IpAddr, &addr._IpAddr, sizeof(this->_IpAddr)); + return *this; } char* SensorNetAddress::sprint(char* buf) { - char ip[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &(_IpAddr.sin6_addr), ip, INET6_ADDRSTRLEN); - sprintf( buf, "%s:", ip); - sprintf( buf + strlen(buf), "%d", ntohs(_portNo)); - return buf; + sprintf(buf, "[%s]:", getAddress()); + sprintf(buf + strlen(buf), "%d", ntohs(_IpAddr.sin6_port)); + return buf; } /*=========================================== @@ -156,75 +153,74 @@ SensorNetwork::~SensorNetwork() int SensorNetwork::unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendToAddr) { - return UDPPort6::unicast(payload, payloadLength, sendToAddr); + return UDPPort6::unicast(payload, payloadLength, sendToAddr); } int SensorNetwork::broadcast(const uint8_t* payload, uint16_t payloadLength) { - return UDPPort6::broadcast(payload, payloadLength); + return UDPPort6::broadcast(payload, payloadLength); } int SensorNetwork::read(uint8_t* buf, uint16_t bufLen) { - return UDPPort6::recv(buf, bufLen, &_clientAddr); + return UDPPort6::recv(buf, bufLen, &_clientAddr); } void SensorNetwork::initialize(void) { - char param[MQTTSNGW_PARAM_MAX]; - uint16_t unicastPortNo = 0; - string ip; - string broadcast; - string interface; - unsigned int hops = 1; + char param[MQTTSNGW_PARAM_MAX]; + uint16_t unicastPortNo = 0; + uint16_t multicastPortNo = 0; + string ip; + string multicast; + string interface; + uint32_t hops = 1; - if (theProcess->getParam("GatewayUDP6Bind", param) == 0) - { - ip = param; - _description = "GatewayUDP6Bind: "; - _description += param; - } - if (theProcess->getParam("GatewayUDP6Port", param) == 0) - { - unicastPortNo = atoi(param); - _description += " Gateway Port: "; - _description += param; - } - if (theProcess->getParam("GatewayUDP6Broadcast", param) == 0) - { - broadcast = param; - _description += " Broadcast Address: "; - _description += param; - } - if (theProcess->getParam("GatewayUDP6If", param) == 0) - { - interface = param; - _description += " Interface: "; - _description += param; - } - if (theProcess->getParam("GatewayUDP6Hops", param) == 0) - { - hops = atoi(param); - _description += " Hops: "; - _description += param; - } + if (theProcess->getParam("MulticastIPv6", param) == 0) + { + multicast = param; + _description += "Multicast Address: ["; + _description += param; + } + if (theProcess->getParam("MulticastIPv6PortNo", param) == 0) + { + multicastPortNo = atoi(param); + _description += "]:"; + _description += param; + } + if (theProcess->getParam("GatewayIPv6PortNo", param) == 0) + { + unicastPortNo = atoi(param); + _description += ", Gateway Port:"; + _description += param; + } + if (theProcess->getParam("MulticastIPv6If", param) == 0) + { + interface = param; + _description += ", Interface: "; + _description += param; + } + if (theProcess->getParam("MulticastHops", param) == 0) + { + hops = atoi(param); + _description += ", Hops:"; + _description += param; + } - errno = 0; - - if ( UDPPort6::open(ip.c_str(), unicastPortNo, broadcast.c_str(), interface.c_str(), hops) < 0 ) - { - throw EXCEPTION("Can't open a UDP6", errno); - } + if (UDPPort6::open(unicastPortNo, multicastPortNo, multicast.c_str(), interface.c_str(), hops) < 0) + { + throw EXCEPTION("Can't open a UDP6", errno); + } } const char* SensorNetwork::getDescription(void) { - return _description.c_str(); + return _description.c_str(); } SensorNetAddress* SensorNetwork::getSenderAddress(void) { - return &_clientAddr; + return &_clientAddr; } /*========================================= @@ -233,278 +229,241 @@ SensorNetAddress* SensorNetwork::getSenderAddress(void) UDPPort6::UDPPort6() { - _disconReq = false; - _sockfdUnicast = -1; - _sockfdMulticast = -1; + _disconReq = false; + _hops = 0; } UDPPort6::~UDPPort6() { - close(); + close(); } void UDPPort6::close(void) { - if (_sockfdUnicast > 0) - { - ::close(_sockfdUnicast); - _sockfdUnicast = -1; - } - if (_sockfdMulticast > 0) - { - ::close(_sockfdMulticast); - _sockfdMulticast = -1; - } + for (int i = 0; i < 2; i++) + { + if (_pollfds[i].fd > 0) + { + ::close(_pollfds[i].fd); + _pollfds[i].fd = 0; + } + } } -int UDPPort6::open(const char* ipAddress, uint16_t uniPortNo, const char* broadcastAddr, const char* interfaceName, unsigned int hops) +int UDPPort6::open(uint16_t uniPortNo, uint16_t multiPortNo, const char *multicastAddr, const char *interfaceName, + uint32_t hops) { - struct addrinfo hints, *res; - int errnu; - const int reuse = 1; + int optval = 0; + int sock = 0; + sockaddr_in6 addr6; + uint32_t ifindex = 0; - if (uniPortNo == 0) - { - WRITELOG("error portNo undefined in UDPPort::open\n"); - return -1; - } + errno = 0; + if (uniPortNo == 0 || multiPortNo == 0) + { + D_NWSTACK("error portNo undefined in UDPPort6::open\n"); + return -1; + } - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_INET6; // use IPv6 - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_PASSIVE; //use local IF address + // Create a unicast socket + sock = socket(AF_INET6, SOCK_DGRAM, 0); + if (sock < 0) + { + D_NWSTACK("UDP6::open - unicast socket: %s", strerror(errno)); + return -1; + } - getaddrinfo(NULL, std::to_string(uniPortNo).c_str(), &hints, &res); + _pollfds[0].fd = sock; + _pollfds[0].events = POLLIN; - _sockfdMulticast = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if(_sockfdMulticast <0) - { - WRITELOG("UDP6::open - multicast: %s",strerror(_sockfdMulticast)); - return errno; - } + optval = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &optval, sizeof(optval)); - //select the interface - unsigned int ifindex; - ifindex = if_nametoindex(interfaceName); - errnu = setsockopt(_sockfdMulticast, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex,sizeof(ifindex)); - if(errnu <0) - { - WRITELOG("UDP6::open - limit IF: %s",strerror(errnu)); - return errnu; - } + optval = 1; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*) &optval, sizeof(optval)) < 0) + { + D_NWSTACK("\033[0m\033[0;31m unicast socket error %s IPV6_V6ONLY\033[0m\033[0;37m\n", strerror(errno)); + close(); + return -1; + } - strcpy(_interfaceName,interfaceName); + if (setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, sizeof(hops)) < 0) + { + D_NWSTACK("\033[0m\033[0;31m error %s IPV6_UNICAST_HOPS\033[0m\033[0;37m\n", strerror(errno)); + close(); + return -1; + } - //restrict the socket to IPv6 only - int on = 1; - errnu = setsockopt(_sockfdMulticast, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)); - if(errnu <0) - { - WRITELOG("UDP6::open - limit IPv6: %s",strerror(errnu)); - return errnu; - } - errnu = setsockopt(_sockfdMulticast, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops,sizeof(hops)); - if(errnu <0) - { - WRITELOG("UDP6::open - limit HOPS: %s",strerror(errnu)); - return errnu; - } - - _uniPortNo = uniPortNo; - _hops = hops; - freeaddrinfo(res); - - //init the structs for getaddrinfo - //according to: https://beej.us/guide/bgnet/output/html/multipage/ - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_INET6; // use IPv6, whichever - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_PASSIVE; // fill in my IP for me - - //no specific address, bind to available ones... - getaddrinfo(NULL, std::to_string(uniPortNo).c_str(), &hints, &res); - - //create the socket - _sockfdUnicast = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (_sockfdUnicast < 0) - { - WRITELOG("UDP6::open - unicast socket: %s",strerror(_sockfdUnicast)); - return -1; - } - - //if given, set a given device name to bind to - if(strlen(interfaceName) > 0) - { + if (strlen(interfaceName) > 0) + { + ifindex = if_nametoindex(interfaceName); #ifdef __APPLE__ - int idx = if_nametoindex(interfaceName); - setsockopt(_sockfdUnicast, IPPROTO_IP, IP_BOUND_IF, &idx, sizeof(idx)); -#else - //socket option: bind to a given interface name - setsockopt(_sockfdUnicast, SOL_SOCKET, SO_BINDTODEVICE, interfaceName, strlen(interfaceName)); + setsockopt(sock, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex)); +#else + setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interfaceName, strlen(interfaceName)); #endif - } + } - //socket option: reuse address - setsockopt(_sockfdUnicast, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); + memset(&addr6, 0, sizeof(addr6)); + addr6.sin6_family = AF_INET6; + addr6.sin6_port = htons(uniPortNo); + addr6.sin6_addr = in6addr_any; - //finally: bind... - errnu = ::bind(_sockfdUnicast, res->ai_addr, res->ai_addrlen); - if (errnu < 0) - { - WRITELOG("error can't bind unicast socket in UDPPort::open: %s\n",strerror(errnu)); - return -1; - } + if (::bind(sock, (sockaddr*) &addr6, sizeof(addr6)) < 0) + { + D_NWSTACK("error can't bind unicast socket in UDPPort6::open: %s\n", strerror(errno)); + close(); + return -1; + } - //if given, set a broadcast address; otherwise it will be :: - if(strlen(broadcastAddr) > 0) - { - _grpAddr.setAddress(broadcastAddr); - } else { - _grpAddr.setAddress("::"); - } - //everything went fine... - freeaddrinfo(res); - return 0; + + // create a MULTICAST socket + + sock = socket(AF_INET6, SOCK_DGRAM, 0); + if (sock < 0) + { + D_NWSTACK("UDP6::open - multicast: %s", strerror(errno)); + close(); + return -1; + } + _pollfds[1].fd = sock; + _pollfds[1].events = POLLIN; + + optval = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*) &optval, sizeof(optval)) < 0) + { + D_NWSTACK("\033[0m\033[0;31m multicast socket error %s SO_REUSEADDR\033[0m\033[0;37m\n", strerror(errno)); + close(); + return -1; + } + optval = 1; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*) &optval, sizeof(optval)) < 0) + { + D_NWSTACK("\033[0m\033[0;31m multicast socket error %s IPV6_V6ONLY\033[0m\033[0;37m\n", strerror(errno)); + close(); + return -1; + } + + memset(&addr6, 0, sizeof(addr6)); + addr6.sin6_family = AF_INET6; + addr6.sin6_port = htons(multiPortNo); + addr6.sin6_addr = in6addr_any; + + if (::bind(sock, (sockaddr*) &addr6, sizeof(addr6)) < 0) + { + close(); + D_NWSTACK("error can't bind multicast socket in UDPPort6::open: %s\n", strerror(errno)); + return -1; + } + + ipv6_mreq addrm; + addrm.ipv6mr_interface = ifindex; + inet_pton(AF_INET6, multicastAddr, &addrm.ipv6mr_multiaddr); + if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &addrm, sizeof(addrm)) < 0) + { + D_NWSTACK("\033[0m\033[0;31m error %d IPV6_ADD_MEMBERSHIP in Udp6Port::open\033[0m\033[0;37m\n", errno); + close(); + return false; + } + +#ifdef DEBUG_NW + optval = 1; +#else + optval = 0; +#endif + + if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char*) &optval, sizeof(optval)) < 0) + { + D_NWSTACK("\033[0m\033[0;31m error %s IPV6_MULTICAST_LOOP\033[0m\033[0;37m\n", strerror(errno)); + close(); + return false; + } + if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops)) < 0) + { + D_NWSTACK("\033[0m\033[0;31m error %s IPV6_MULTICAST_HOPS\033[0m\033[0;37m\n", strerror(errno)); + close(); + return -1; + } + + memcpy(&addr6.sin6_addr, &addrm.ipv6mr_multiaddr, sizeof(addrm.ipv6mr_multiaddr)); + _grpAddr.setAddress(&addr6); + return 0; } int UDPPort6::unicast(const uint8_t* buf, uint32_t length, SensorNetAddress* addr) { - char destStr[INET6_ADDRSTRLEN+10]; - struct addrinfo hints, *res; - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_INET6; // use IPv6 - hints.ai_socktype = SOCK_DGRAM; + sockaddr_in6 dest; + memset(&dest, 0, sizeof(dest)); + dest.sin6_family = AF_INET6; + dest.sin6_port = addr->getPortNo(); + memcpy(dest.sin6_addr.s6_addr, (const void*) &addr->getIpAddress()->sin6_addr, sizeof(in6_addr)); - int err = 0; - int port = 0; - string portStr; - if(addr->getPortNo() != 0) - { - port = htons(addr->getPortNo()); - portStr = to_string(port); - } else { - port = _uniPortNo; - portStr = to_string(port); - } +#ifdef DEBUG_NW + char addrBuf[INET6_ADDRSTRLEN]; + addr->sprint(addrBuf); + D_NWSTACK("sendto %s\n", addrBuf); +#endif - errno = 0; + int status = ::sendto(_pollfds[0].fd, buf, length, 0, (const sockaddr*) &dest, sizeof(dest)); - if(strlen(_interfaceName) != 0) - { - strcpy(destStr, addr->getAddress()); - strcat(destStr,"%"); - strcat(destStr,_interfaceName); - if(IN6_IS_ADDR_LINKLOCAL(&addr->getIpAddress()->sin6_addr)) - { - err = getaddrinfo(destStr, portStr.c_str(), &hints, &res); - } - else - { - err = getaddrinfo(addr->getAddress(), portStr.c_str(), &hints, &res); - } - } else { - strcpy(destStr, addr->getAddress()); - err = getaddrinfo(addr->getAddress(), portStr.c_str(), &hints, &res); - } - - if ( err != 0) - { - WRITELOG("UDP6::broadcast - getaddrinfo: %s",strerror(errno)); - return err; - } - - int status = ::sendto(_sockfdUnicast, buf, length, 0, res->ai_addr, res->ai_addrlen); - - if (status < 0) - { - WRITELOG("errno in UDPPort::unicast(sendto): %d, %s\n",status,strerror(errno)); - } - - return status; + if (status < 0) + { + D_NWSTACK("%s in UDPPor6t::sendto\n", strerror(errno)); + } + return status; } int UDPPort6::broadcast(const uint8_t* buf, uint32_t length) { - struct addrinfo hint,*info; - int err; - memset( &hint, 0, sizeof( hint ) ); + int err = unicast(buf, length, &_grpAddr); - hint.ai_family = AF_INET6; - hint.ai_socktype = SOCK_DGRAM; - hint.ai_protocol = 0; + if (err < 0) + { + D_NWSTACK("UDP6::broadcast - sendto: %s", strerror(errno)); + return err; + } - errno = 0; - - if(strlen(_interfaceName) != 0) - { - char destStr[80]; - strcpy(destStr, _grpAddr.getAddress()); - strcat(destStr,"%"); - strcat(destStr,_interfaceName); - if(IN6_IS_ADDR_MC_NODELOCAL(&_grpAddr.getIpAddress()->sin6_addr) || - IN6_IS_ADDR_MC_LINKLOCAL(&_grpAddr.getIpAddress()->sin6_addr)) - { - err = getaddrinfo(destStr, std::to_string(_uniPortNo).c_str(), &hint, &info ); - } - else - { - err = getaddrinfo(_grpAddr.getAddress(), std::to_string(_uniPortNo).c_str(), &hint, &info ); - } - } else { - err = getaddrinfo(_grpAddr.getAddress(), std::to_string(_uniPortNo).c_str(), &hint, &info ); - } - - if( err != 0 ) { - WRITELOG("UDP6::broadcast - getaddrinfo: %s",strerror(errno)); - return err; - } - - err = sendto(_sockfdMulticast, buf, length, 0, info->ai_addr, info->ai_addrlen ); - - if(err < 0 ) { - WRITELOG("UDP6::broadcast - sendto: %s",strerror(errno)); - return err; - } - - return 0; + return 0; } int UDPPort6::recv(uint8_t* buf, uint16_t len, SensorNetAddress* addr) { - struct timeval timeout; - fd_set recvfds; + int rc = poll(_pollfds, 2, 2000); // Timeout 2secs + if (rc == 0) + { + return rc; + } - timeout.tv_sec = 1; - timeout.tv_usec = 0; // 1 sec - FD_ZERO(&recvfds); - FD_SET(_sockfdUnicast, &recvfds); - - int rc = 0; - if ( select(_sockfdUnicast + 1, &recvfds, 0, 0, &timeout) > 0 ) - { - if (FD_ISSET(_sockfdUnicast, &recvfds)) - { - rc = recvfrom(_sockfdUnicast, buf, len, 0, addr); - } - } - return rc; + for (int i = 0; i < 2; i++) + { + if (_pollfds[i].revents & POLLIN) + { + return recvfrom(_pollfds[i].fd, buf, len, 0, addr); + } + } + return 0; } int UDPPort6::recvfrom(int sockfd, uint8_t* buf, uint16_t len, uint8_t flags, SensorNetAddress* addr) { - sockaddr_in6 sender; - socklen_t addrlen = sizeof(sender); - memset(&sender, 0, addrlen); + sockaddr_in6 sender; + socklen_t addrlen = sizeof(sender); + memset(&sender, 0, addrlen); - int status = ::recvfrom(sockfd, buf, len, flags, (sockaddr*) &sender, &addrlen); + int status = ::recvfrom(sockfd, buf, len, flags, (sockaddr*) &sender, &addrlen); - if (status < 0 && errno != EAGAIN) - { - WRITELOG("errno == %d in UDPPort::recvfrom: %s\n",errno,strerror(errno)); - return -1; - } - addr->setAddress(&sender, (uint16_t)sender.sin6_port); - //D_NWSTACK("recved from %s:%d length = %d\n", inet_ntoa(sender.sin_addr),ntohs(sender.sin_port), status); - return status; + if (status < 0 && errno != EAGAIN) + { + D_NWSTACK("errno in UDPPort6::recvfrom: %s\n", strerror(errno)); + return -1; + } + addr->setAddress(&sender); + +#ifdef DEBUG_NW + char addrBuf[INET6_ADDRSTRLEN]; + addr->sprint(addrBuf); + D_NWSTACK("sendto %s length = %d\n", addrBuf, status); +#endif + return status; } diff --git a/MQTTSNGateway/src/linux/udp6/SensorNetwork.h b/MQTTSNGateway/src/linux/udp6/SensorNetwork.h index 59be5fa..68830b6 100644 --- a/MQTTSNGateway/src/linux/udp6/SensorNetwork.h +++ b/MQTTSNGateway/src/linux/udp6/SensorNetwork.h @@ -12,7 +12,7 @@ * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: - * Benjamin Aigner - port to UDPv6, used by RFC7668 (6lowpan over Bluetooth LE) + * Benjamin Aigner - port to UDPv6, used by RFC7668 (6lowpan over Bluetooth LE) * Tomoaki Yamaguchi - initial API and implementation and/or initial documentation **************************************************************************************/ @@ -22,69 +22,59 @@ #include "MQTTSNGWDefines.h" #include #include +#include using namespace std; namespace MQTTSNGW { -#ifdef DEBUG_NWSTACK - #define D_NWSTACK(...) printf(__VA_ARGS__) -#else - #define D_NWSTACK(...) -#endif - /*=========================================== Class SensorNetAddreess ============================================*/ class SensorNetAddress { public: - SensorNetAddress(); - ~SensorNetAddress(); - void setAddress(struct sockaddr_in6 *IpAddr, uint16_t port); - int setAddress(string* data); - int setAddress(const char* data); - uint16_t getPortNo(void); - struct sockaddr_in6 *getIpAddress(void); - char* getAddress(void); - bool isMatch(SensorNetAddress* addr); - SensorNetAddress& operator =(SensorNetAddress& addr); - char* sprint(char* buf); + SensorNetAddress(); + ~SensorNetAddress(); + void setAddress(sockaddr_in6 *IpAddr); + int setAddress(string* data); + int setAddress(const char* data); + uint16_t getPortNo(void); + sockaddr_in6* getIpAddress(void); + char* getAddress(void); + bool isMatch(SensorNetAddress* addr); + SensorNetAddress& operator =(SensorNetAddress& addr); + char* sprint(char* buf); private: - uint16_t _portNo; - char _addrString[INET6_ADDRSTRLEN+1]; - struct sockaddr_in6 _IpAddr; + char _addrString[INET6_ADDRSTRLEN + 1]; + sockaddr_in6 _IpAddr; }; /*======================================== - Class UpdPort + Class UpdPort6 =======================================*/ class UDPPort6 { public: - UDPPort6(); - virtual ~UDPPort6(); + UDPPort6(); + virtual ~UDPPort6(); - int open(const char* ipAddress, uint16_t uniPortNo, const char* broadcastAddr, const char* interfaceName, unsigned int hops); - void close(void); - int unicast(const uint8_t* buf, uint32_t length, SensorNetAddress* sendToAddr); - int broadcast(const uint8_t* buf, uint32_t length); - int recv(uint8_t* buf, uint16_t len, SensorNetAddress* addr); + int open(uint16_t uniPortNo, uint16_t multiPortNo, const char *broadcastAddr, const char *interfaceName, uint32_t hops); + void close(void); + int unicast(const uint8_t* buf, uint32_t length, SensorNetAddress* sendToAddr); + int broadcast(const uint8_t* buf, uint32_t length); + int recv(uint8_t* buf, uint16_t len, SensorNetAddress* addr); private: - void setNonBlocking(const bool); - int recvfrom(int sockfd, uint8_t* buf, uint16_t len, uint8_t flags, SensorNetAddress* addr); + void setNonBlocking(const bool); + int recvfrom(int sockfd, uint8_t* buf, uint16_t len, uint8_t flags, SensorNetAddress* addr); - int _sockfdUnicast; - int _sockfdMulticast; - char _interfaceName[10]; - - SensorNetAddress _grpAddr; - SensorNetAddress _clientAddr; - uint16_t _uniPortNo; - bool _disconReq; - unsigned int _hops; + pollfd _pollfds[2]; + SensorNetAddress _grpAddr; + SensorNetAddress _clientAddr; + bool _disconReq; + uint32_t _hops; }; /*=========================================== @@ -93,19 +83,19 @@ private: class SensorNetwork: public UDPPort6 { public: - SensorNetwork(); - ~SensorNetwork(); + SensorNetwork(); + ~SensorNetwork(); - int unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendto); - int broadcast(const uint8_t* payload, uint16_t payloadLength); - int read(uint8_t* buf, uint16_t bufLen); - void initialize(void); - const char* getDescription(void); - SensorNetAddress* getSenderAddress(void); + int unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendto); + int broadcast(const uint8_t* payload, uint16_t payloadLength); + int read(uint8_t* buf, uint16_t bufLen); + void initialize(void); + const char* getDescription(void); + SensorNetAddress* getSenderAddress(void); private: - SensorNetAddress _clientAddr; // Sender's address. not gateway's one. - string _description; + SensorNetAddress _clientAddr; // Sender's address. not gateway's one. + string _description; }; } diff --git a/MQTTSNGateway/src/linux/xbee/SensorNetwork.h b/MQTTSNGateway/src/linux/xbee/SensorNetwork.h index 52ad29e..c21ce91 100644 --- a/MQTTSNGateway/src/linux/xbee/SensorNetwork.h +++ b/MQTTSNGateway/src/linux/xbee/SensorNetwork.h @@ -25,13 +25,6 @@ using namespace std; namespace MQTTSNGW { -//#define DEBUG_NWSTACK - -#ifdef DEBUG_NWSTACK - #define D_NWSTACK(...) printf(__VA_ARGS__) -#else - #define D_NWSTACK(...) -#endif #define API_XMITREQUEST 0x10 #define API_RESPONSE 0x90 diff --git a/MQTTSNGateway/src/mainGateway.cpp b/MQTTSNGateway/src/mainGateway.cpp index a995fa7..986cacc 100644 --- a/MQTTSNGateway/src/mainGateway.cpp +++ b/MQTTSNGateway/src/mainGateway.cpp @@ -21,7 +21,6 @@ #include "MQTTSNGWPacketHandleTask.h" using namespace MQTTSNGW; - /* * Gateway Application */ diff --git a/travis-build.sh b/travis-build.sh index 1d0aa05..1050f92 100755 --- a/travis-build.sh +++ b/travis-build.sh @@ -15,10 +15,15 @@ cmake .. -DSENSORNET=xbee make MQTT-SNGateway cmake .. -DSENSORNET=udp6 make MQTT-SNGateway +cmake .. -DSENSORNET=dtls +make MQTT-SNGateway cmake .. -DSENSORNET=udp make MQTT-SNGateway cd ../MQTTSNGateway/GatewayTester -make - +make SENSORNET=UDP6 +make SENSORNET=DTLS +make SENSORNET=DTLS6 +make SENSORNET=RFCOMM +make SENSORNET=UDP From 4fc0e2f52b2b9a02d0a52b2af05d22a632b1445d Mon Sep 17 00:00:00 2001 From: tomoaki Date: Mon, 2 Aug 2021 07:25:28 +0900 Subject: [PATCH 63/67] Bugfix 0f #234 Signed-off-by: tomoaki --- MQTTSNGateway/src/MQTTSNGWClientList.cpp | 25 ++++++++++++------------ 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/MQTTSNGateway/src/MQTTSNGWClientList.cpp b/MQTTSNGateway/src/MQTTSNGWClientList.cpp index a4dd62f..b7919f2 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientList.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientList.cpp @@ -404,38 +404,37 @@ Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, Client* ClientList::createPredefinedTopic(MQTTSNString* clientId, string topicName, uint16_t topicId, bool aggregate) { - Client *client = nullptr; - if (topicId == 0) { WRITELOG("Invalid TopicId. Predefined Topic %s, TopicId is 0. \n", topicName.c_str()); - goto exit; + return nullptr; } if (strcmp(clientId->cstring, common_topic) == 0) { _gateway->getTopics()->add((const char*) topicName.c_str(), topicId); - goto exit; + return nullptr; } else { - Client* client = getClient(clientId); + Client *client = getClient(clientId); if (_authorize && client == nullptr) { - goto exit; + return nullptr; } - client = createClient(NULL, clientId, aggregate); - if (client) + client = createClient(NULL, clientId, aggregate); // <=== BUGFIX + if (client == nullptr) { - // create Topic & Add it - client->getTopics()->add((const char*) topicName.c_str(), topicId); - client->_hasPredefTopic = true; + return nullptr; } + + // create Topic & Add it + client->getTopics()->add((const char*) topicName.c_str(), topicId); + client->_hasPredefTopic = true; + return client; } -exit: - return client; } uint16_t ClientList::getClientCount() From b6a152a912c7e60ff600e1ceb1db46ba6b5ba62b Mon Sep 17 00:00:00 2001 From: tomoaki Date: Mon, 2 Aug 2021 17:05:17 +0900 Subject: [PATCH 64/67] Bugfix of #241 Signed-off-by: tomoaki --- MQTTSNGateway/GatewayTester/src/LGwProxy.cpp | 15 +- .../GatewayTester/src/LMqttsnClient.cpp | 12 +- .../GatewayTester/src/LNetworkDtls.cpp | 12 +- MQTTSNGateway/gateway.conf | 1 - MQTTSNGateway/src/MQTTSNGateway.h | 2 +- .../src/linux/dtls/SensorNetwork.cpp | 135 ++++++------------ MQTTSNGateway/src/linux/dtls/SensorNetwork.h | 5 +- 7 files changed, 74 insertions(+), 108 deletions(-) diff --git a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp index 4a8a283..728f896 100644 --- a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp +++ b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp @@ -202,14 +202,19 @@ int LGwProxy::getConnectResponce(void) _gwId = _mqttsnMsg[1]; #if defined(DTLS) || defined(DTLS6) - if (_network.sslConnect() < 0) + for (int i = 0; i < MQTTSN_RETRY_COUNT; i++) { - DISPLAY( - "\033[0m\033[0;32m\n\nLGwProxy::getConnectResponce Can't connect the Gateway via SSL.\033[0m\033[0;37m\n\n"); - return 0; + if (_network.sslConnect() > 0) + { + _status = GW_CONNECTING; + DISPLAY( + "\033[0m\033[0;32m\n\nLGwProxy::getConnectResponce Can't connect the Gateway via SSL.\033[0m\033[0;37m\n\n"); + break; + } } -#endif +#else _status = GW_CONNECTING; +#endif } else if (_mqttsnMsg[0] == MQTTSN_TYPE_WILLTOPICREQ && _status == GW_WAIT_WILLTOPICREQ) { diff --git a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp index 0126a3e..c27ee8a 100644 --- a/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp +++ b/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp @@ -52,15 +52,15 @@ int main(int argc, char** argv) printf("\n%s", PAHO_COPYRIGHT4); printf("\n%s", PAHO_COPYRIGHT0); #if defined(UDP) - printf(" UDP\n"); + printf("UDP ClientId:%s PortNo:%d\n", theNetcon.clientId, theNetcon.uPortNo); #elif defined(UDP6) - printf(" UDP6\n"); -#elif defined(RFCOMM) - printf(" RFCOMM\n"); + printf("UDP6 ClientId:%s PortNo:%d\n", theNetcon.clientId, theNetcon.uPortNo); #elif defined(DTLS) - printf(" DTLS\n"); + printf("DTLS ClientId:%s PortNo:%d\n", theNetcon.clientId, theNetcon.uPortNo); #elif defined(DTLS6) - printf(" DTLS6\n"); + printf("DTLS6 ClientId:%s PortNo:%d\n", theNetcon.clientId, theNetcon.uPortNo); +#elif defined(RFCOMM) + printf("RFCOMM ClientId:%s channel:%d\n", theNetcon.clientId, theNetcon.channel); #else printf("\n"); #endif diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkDtls.cpp b/MQTTSNGateway/GatewayTester/src/LNetworkDtls.cpp index d861814..2d6f3f2 100644 --- a/MQTTSNGateway/GatewayTester/src/LNetworkDtls.cpp +++ b/MQTTSNGateway/GatewayTester/src/LNetworkDtls.cpp @@ -471,6 +471,7 @@ int LDtlsPort::sslConnect(uint32_t ipAddress, in_port_t portNo) int reuse = 1; if (_ssl != 0) { + D_NWLOG("LDtlsPort::sslConnect SSL exists.\n"); SSL_shutdown(_ssl); SSL_free(_ssl); _sockfdSsl = 0; @@ -489,7 +490,7 @@ int LDtlsPort::sslConnect(uint32_t ipAddress, in_port_t portNo) D_NWLOG("LDtlsPort::sslConnect Can't create a socket\n"); return -1; } - setsockopt(_sockfdSsl, SOL_SOCKET, SO_REUSEADDR || SO_REUSEPORT, &reuse, sizeof(reuse)); + setsockopt(_sockfdSsl, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); struct sockaddr_in addr; addr.sin_family = AF_INET; @@ -497,6 +498,8 @@ int LDtlsPort::sslConnect(uint32_t ipAddress, in_port_t portNo) addr.sin_addr.s_addr = INADDR_ANY; if (::bind(_sockfdSsl, (struct sockaddr*) &addr, sizeof(addr)) < 0) { + ::close(_sockfdSsl); + _sockfdSsl = 0; D_NWLOG("LDtlsPort::sslConnect Can't bind a socket\n"); return -1; } @@ -514,6 +517,12 @@ int LDtlsPort::sslConnect(uint32_t ipAddress, in_port_t portNo) SSL_set_bio(_ssl, cbio, cbio); D_NWLOG("LDtlsPort::sslConnect connect to %-15s:%-6u\n", inet_ntoa(dest.sin_addr), htons(dest.sin_port)); + + timeval timeout; + timeout.tv_sec = 5; + timeout.tv_usec = 0; + BIO_ctrl(cbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout); + int stat = SSL_connect(_ssl); if (stat != 1) { @@ -522,6 +531,7 @@ int LDtlsPort::sslConnect(uint32_t ipAddress, in_port_t portNo) } else { + rc = 1; D_NWLOG("SSL connected\n"); } return rc; diff --git a/MQTTSNGateway/gateway.conf b/MQTTSNGateway/gateway.conf index 77efab6..b3ad2a4 100644 --- a/MQTTSNGateway/gateway.conf +++ b/MQTTSNGateway/gateway.conf @@ -77,7 +77,6 @@ MulticastHops=1 DtlsCertsKey=/etc/ssl/certs/gateway.pem DtlsPrivKey=/etc/ssl/private/privkey.pem -DtlsSSLPortNo=10001 # # XBee diff --git a/MQTTSNGateway/src/MQTTSNGateway.h b/MQTTSNGateway/src/MQTTSNGateway.h index a2798ad..3bd9b1f 100644 --- a/MQTTSNGateway/src/MQTTSNGateway.h +++ b/MQTTSNGateway/src/MQTTSNGateway.h @@ -27,7 +27,7 @@ namespace MQTTSNGW /*================================= * Starting prompt ==================================*/ -#define PAHO_COPYRIGHT0 " * MQTT-SN Gateway" +#define PAHO_COPYRIGHT0 " * " #define PAHO_COPYRIGHT1 " * Part of Project Paho in Eclipse" #define PAHO_COPYRIGHT2 " * (http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt-sn.embedded-c.git/)" #define PAHO_COPYRIGHT3 " * Author : Tomoaki YAMAGUCHI" diff --git a/MQTTSNGateway/src/linux/dtls/SensorNetwork.cpp b/MQTTSNGateway/src/linux/dtls/SensorNetwork.cpp index 407a0b7..77f23b5 100644 --- a/MQTTSNGateway/src/linux/dtls/SensorNetwork.cpp +++ b/MQTTSNGateway/src/linux/dtls/SensorNetwork.cpp @@ -405,8 +405,6 @@ int Connections::getSockClient(int index) void Connections::close(int index) { - _mutex.lock(); - int idx = index + POLL_SSL; _mutex.lock(); int sock = _pollfds[idx].fd; @@ -415,9 +413,9 @@ void Connections::close(int index) for (; idx < _numfds; idx++) { - _ssls[index] = _ssls[idx + 1]; - _pollfds[index] = _pollfds[idx + 1]; - _clientAddr[index] = _clientAddr[idx + 1]; + _ssls[idx] = _ssls[idx + 1]; + _pollfds[idx] = _pollfds[idx + 1]; + _clientAddr[idx] = _clientAddr[idx + 1]; if (_ssls[idx + 1] == 0) { @@ -434,7 +432,7 @@ void Connections::close(int index) } if (sock > 0) { - close(sock); + ::close(sock); } if (addr != nullptr) { @@ -498,9 +496,9 @@ int Connections::searchClient(SensorNetAddress *addr) read( ) is used by MQTTSNPacket::recv( ) ================================================================*/ -#define PACKET_CLIENTHELLO 10000 -#define PACKET_APPL 10001 -#define PACKET_OTHERS 10002 +#define DTLS_CLIENTHELLO 22 +#define DTLS_APPL 23 +#define DTLS_OTHERS 100 /* Certificate verification. Returns 1 if trusted, else 0 */ int verify_cert(int ok, X509_STORE_CTX *ctx); @@ -607,7 +605,7 @@ int SensorNetwork::read(uint8_t *buf, uint16_t bufLen) struct sockaddr_in6 s6; } client_addr; - // Ccheck sockets + // Check POLL_IN int cnt = _conns->poll(2000); // Timeout 2secs if (cnt == 0) { @@ -668,13 +666,9 @@ ListenClient_hello: return 0; } -// if (clientIndex != -1) -// { -// _conns->close(clientIndex); -// } - - // SSL Accept + // Handle client connection #ifndef DTLS6 + // DTLS over IPv4 int client_fd = socket(AF_INET, SOCK_DGRAM, 0); setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &optval, sizeof(optval)); // Bind to Dtls PortNo @@ -695,8 +689,7 @@ ListenClient_hello: BIO_set_fd(cbio, client_fd, BIO_NOCLOSE); BIO_ctrl(cbio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &client_addr); - D_NWSTACK("Accept SSL\n"); - + // Finish handshake int ret = SSL_accept(ssl); if (ret <= 0) { @@ -708,17 +701,17 @@ ListenClient_hello: } else { - // add ssl & socket to Connections instance int index = _conns->addClientSSL(ssl, client_fd); // save SensorNetworkAddress of Client client.setIndex(index); _senderAddr = &client; - +#ifdef DEBUG_NW char clientaddrBuf[128]; client.sprint(clientaddrBuf); - WRITELOG("Client %s SSL Accepted. idx=%d\n", clientaddrBuf, index); + D_NWSTACK("Client %s SSL Accepted. idx=%d\n", clientaddrBuf, index); +#endif } _mutex.unlock(); } @@ -741,15 +734,21 @@ ListenClient_hello: if (dtls > 0) { - D_NWSTACK("DTLT type=%d\n", dtls); - if (dtls == PACKET_CLIENTHELLO) + if (dtls == DTLS_CLIENTHELLO) { + // Received packet is ClientHello #ifdef DEBUG_NW char clientaddrBuf[128]; client.sprint(clientaddrBuf); D_NWSTACK("Client %s SSL reconnect. idx=%d\n", clientaddrBuf, i); #endif + // Delete current connection. clientIndex = i; + D_NWSTACK("Close current connections\n"); + _mutex.unlock(); + _conns->close(clientIndex); // DEBUG + return 0; + sockListen = _conns->getSockClient(i); goto ListenClient_hello; } @@ -759,12 +758,13 @@ ListenClient_hello: int len = SSL_read_ex(ssl, (void*) buf, (size_t) bufLen, &recvlen); if (SSL_get_error(ssl, len) >= 0) { - _senderAddr = &client; - _senderAddr->setIndex(i); - +#ifdef DEBUG_NW char clientaddrBuf[128]; client.sprint(clientaddrBuf); D_NWSTACK("Client %s SSL Accepted. idx=%d\n", clientaddrBuf, i); +#endif + _senderAddr = &client; + _senderAddr->setIndex(i); } else { @@ -787,7 +787,6 @@ void SensorNetwork::initialize(void) char errmsg[256]; uint16_t multicastPortNo = 0; uint16_t unicastPortNo = 0; - uint16_t dtlsPortNo = 0; SensorNetAddress add; sockaddr_in6 soadd; @@ -815,12 +814,6 @@ void SensorNetwork::initialize(void) _description += ", Gateway PortNo:"; _description += param; } - if (theProcess->getParam("DtlsPortNo", param) == 0) - { - dtlsPortNo = atoi(param); - _description += ", SSL PortNo:"; - _description += param; - } if (theProcess->getParam("MulticastTTL", param) == 0) { ttl = atoi(param); @@ -850,12 +843,6 @@ void SensorNetwork::initialize(void) _description += ", Gateway PortNo:"; _description += param; } - if (theProcess->getParam("DtlsPortNo", param) == 0) - { - dtlsPortNo = atoi(param); - _description += ", SSL PortNo:"; - _description += param; - } if (theProcess->getParam("MulticastIPv6If", param) == 0) { interface = param; @@ -914,12 +901,12 @@ void SensorNetwork::initialize(void) /* Prepare UDP and UDP6 sockets for Multicasting and unicasting */ #ifndef DTLS6 - if (openV4(&ip, multicastPortNo, unicastPortNo, dtlsPortNo, ttl) < 0) + if (openV4(&ip, multicastPortNo, unicastPortNo, ttl) < 0) { throw EXCEPTION("Can't open a UDP4", errno); } #else - if (openV6(&ip6, &interface, multicastPortNo, unicastPortNo, dtlsPortNo, hops) < 0) + if (openV6(&ip6, &interface, multicastPortNo, unicastPortNo, hops) < 0) { throw EXCEPTION("Can't open a UDP6", errno); } @@ -936,7 +923,7 @@ SensorNetAddress* SensorNetwork::getSenderAddress(void) return _senderAddr; } -int SensorNetwork::openV4(string *ipAddress, uint16_t multiPortNo, uint16_t uniPortNo, uint16_t dtlsPortNo, uint32_t ttl) +int SensorNetwork::openV4(string *ipAddress, uint16_t multiPortNo, uint16_t uniPortNo, uint32_t ttl) { int optval = 0; int rc = -1; @@ -961,23 +948,17 @@ int SensorNetwork::openV4(string *ipAddress, uint16_t multiPortNo, uint16_t uniP optval = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); - sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(uniPortNo); - addr.sin_addr.s_addr = INADDR_ANY; + _serverAddr4.sin_family = AF_INET; + _serverAddr4.sin_port = htons(uniPortNo); + _serverAddr4.sin_addr.s_addr = INADDR_ANY; - if (::bind(sock, (sockaddr*) &addr, sizeof(addr)) < 0) + if (::bind(sock, (sockaddr*) &_serverAddr4, sizeof(_serverAddr4)) < 0) { D_NWSTACK("can't bind unicast socket in UDP4_6Port::openV4 error %d %s\n", errno, strerror(errno)); return -1; } _conns->setSockUnicast(sock); - /*------ Set SSL socket address --------*/ - _serverAddr4.sin_family = AF_INET; - _serverAddr4.sin_port = htons(uniPortNo); - _serverAddr4.sin_addr.s_addr = INADDR_ANY; - /*------ Create Multicast socket --------*/ sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sock < 0) @@ -1032,8 +1013,7 @@ int SensorNetwork::openV4(string *ipAddress, uint16_t multiPortNo, uint16_t uniP return 0; } -int SensorNetwork::openV6(string *ipAddress, string *interface, uint16_t multiPortNo, uint16_t uniPortNo, uint16_t dtlsPortNo, - uint32_t hops) +int SensorNetwork::openV6(string *ipAddress, string *interface, uint16_t multiPortNo, uint16_t uniPortNo, uint32_t hops) { int optval = 0; int sock = 0; @@ -1048,7 +1028,7 @@ int SensorNetwork::openV6(string *ipAddress, string *interface, uint16_t multiPo } _multicastAddr->setPort(multiPortNo); - _unicastAddr->setPort(dtlsPortNo); + _unicastAddr->setPort(uniPortNo); if (_multicastAddr->setIpAddress(ipAddress) < 0) { @@ -1075,13 +1055,12 @@ int SensorNetwork::openV6(string *ipAddress, string *interface, uint16_t multiPo return -1; } - sockaddr_in6 addr; - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - addr.sin6_port = htons(uniPortNo); - addr.sin6_addr = in6addr_any; + memset(&_serverAddr6, 0, sizeof(_serverAddr6)); + _serverAddr6.sin6_family = AF_INET6; + _serverAddr6.sin6_port = htons(uniPortNo); + _serverAddr6.sin6_addr = in6addr_any; - if (::bind(sock, (sockaddr*) &addr, sizeof(addr)) < 0) + if (::bind(sock, (sockaddr*) &_serverAddr6, sizeof(_serverAddr6)) < 0) { D_NWSTACK("can't bind unicast socket in SensorNetwork::openV6 error %s\n", strerror(errno)); return -1; @@ -1097,27 +1076,6 @@ int SensorNetwork::openV6(string *ipAddress, string *interface, uint16_t multiPo #endif } - /*------ Set SSL socket address --------*/ - _serverAddr6.sin6_family = AF_INET6; - _serverAddr6.sin6_port = htons(uniPortNo); - _serverAddr6.sin6_addr = in6addr_any; - - if (::bind(sock, (sockaddr*) &_serverAddr6, sizeof(_serverAddr6)) < 0) - { - D_NWSTACK("can't bind listen socket in SensorNetwork::openV6 error %s\n", strerror(errno)); - return -1; - } - - if (interface->size() > 0) - { -#ifdef __APPLE__ - setsockopt(sock, IPPROTO_IP, IP_BOUND_IF, &ifindex, interface->size()); -#else - setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interface->c_str(), interface->size()); -#endif - } - - // Create Multicast socket sock = socket(AF_INET6, SOCK_DGRAM, 0); if (sock < 0) @@ -1245,7 +1203,7 @@ int SensorNetwork::getSenderAddress(int sock, SensorNetAddress *addr) sockaddr_in sender4 = { 0 }; socklen_t addrlen4 = sizeof(sender4); char buf[16]; - int rc = PACKET_OTHERS; + int rc = DTLS_OTHERS; len = ::recvfrom(sock, buf, 15, MSG_PEEK, (sockaddr*) &sender4, &addrlen4); @@ -1259,17 +1217,12 @@ int SensorNetwork::getSenderAddress(int sock, SensorNetAddress *addr) D_NWSTACK("SensorNetwork::getSenderAddress recved from %s:%d length = %d\n", inet_ntoa(sender4.sin_addr), ntohs(sender4.sin_port), len); -// if (len >= 13) + if (len >= 13) { - if (buf[0] == 22) + if (buf[0] == DTLS_CLIENTHELLO || buf[0] == DTLS_APPL) { - rc = PACKET_CLIENTHELLO; + rc = buf[0]; } - else if (buf[0] == 23) - { - rc = PACKET_APPL; - } - D_NWSTACK("getSenderAddress len=%d Packet type=%d\n", len, buf[0]); } return rc; diff --git a/MQTTSNGateway/src/linux/dtls/SensorNetwork.h b/MQTTSNGateway/src/linux/dtls/SensorNetwork.h index 8f8680c..d84d5a5 100644 --- a/MQTTSNGateway/src/linux/dtls/SensorNetwork.h +++ b/MQTTSNGateway/src/linux/dtls/SensorNetwork.h @@ -138,9 +138,8 @@ public: void close(); private: - int openV4(string *ipAddress, uint16_t multiPortNo, uint16_t uniPortNo, uint16_t listenPortNo, uint32_t ttl); - int openV6(string *ipAddress, string *interface, uint16_t multiPortNo, uint16_t uniPortNo, uint16_t listenPortNo, - uint32_t hops); + int openV4(string *ipAddress, uint16_t multiPortNo, uint16_t uniPortNo, uint32_t ttl); + int openV6(string *ipAddress, string *interface, uint16_t multiPortNo, uint16_t uniPortNo, uint32_t hops); int multicastRecv(uint8_t *buf, uint16_t len); int getSendClient(int index, SensorNetAddress *addr); int getSenderAddress(int sock, SensorNetAddress *addr); From a136f50c75a28563453f49687f96d4caa84b7106 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 3 Aug 2021 14:24:35 +0900 Subject: [PATCH 65/67] Bugfix of #241, #90 Two clients works fine. Signed-off-by: tomoaki --- MQTTSNGateway/GatewayTester/src/LGwProxy.cpp | 7 +- .../src/linux/dtls/SensorNetwork.cpp | 72 +++++-------------- MQTTSNGateway/src/linux/dtls/SensorNetwork.h | 2 - 3 files changed, 22 insertions(+), 59 deletions(-) diff --git a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp index 728f896..1b631b9 100644 --- a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp +++ b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp @@ -207,10 +207,13 @@ int LGwProxy::getConnectResponce(void) if (_network.sslConnect() > 0) { _status = GW_CONNECTING; - DISPLAY( - "\033[0m\033[0;32m\n\nLGwProxy::getConnectResponce Can't connect the Gateway via SSL.\033[0m\033[0;37m\n\n"); + DISPLAY("\033[0m\033[0;32m\n\nLGwProxy::getConnectResponce SSL connection established.\033[0m\033[0;37m\n\n"); break; } + else + { + DISPLAY("\033[0m\033[0;32m\n\nLGwProxy::getConnectResponce SSL connection failed.\033[0m\033[0;37m\n\n"); + } } #else _status = GW_CONNECTING; diff --git a/MQTTSNGateway/src/linux/dtls/SensorNetwork.cpp b/MQTTSNGateway/src/linux/dtls/SensorNetwork.cpp index 77f23b5..28ef868 100644 --- a/MQTTSNGateway/src/linux/dtls/SensorNetwork.cpp +++ b/MQTTSNGateway/src/linux/dtls/SensorNetwork.cpp @@ -290,7 +290,6 @@ void SensorNetAddress::clear(void) Connections::Connections() { _pollfds = nullptr; - _clientAddr = nullptr; _ssls = nullptr; _maxfds = 0; _numfds = 2; @@ -322,13 +321,8 @@ Connections::~Connections() } free(_pollfds); } - - for (int i = 0; i < _maxfds; i++) - { - delete _clientAddr[i]; - } - free(_clientAddr); } + void Connections::initialize(int maxClient) { _maxfds = maxClient + POLL_SSL; @@ -340,13 +334,6 @@ void Connections::initialize(int maxClient) { throw EXCEPTION("Can't allocate ssls.", 0); } - - - _clientAddr = (SensorNetAddress**) malloc(_maxfds * sizeof(unsigned long int)); - for (int i = 0; i < _maxfds; i++) - { - _clientAddr[i] = new SensorNetAddress(); - } } void Connections::closeSSL(int index) @@ -409,17 +396,14 @@ void Connections::close(int index) _mutex.lock(); int sock = _pollfds[idx].fd; SSL *ssl = _ssls[idx]; - SensorNetAddress *addr = _clientAddr[idx]; for (; idx < _numfds; idx++) { _ssls[idx] = _ssls[idx + 1]; _pollfds[idx] = _pollfds[idx + 1]; - _clientAddr[idx] = _clientAddr[idx + 1]; if (_ssls[idx + 1] == 0) { - _clientAddr[idx + 1] = new SensorNetAddress(); break; } } @@ -434,10 +418,6 @@ void Connections::close(int index) { ::close(sock); } - if (addr != nullptr) - { - delete addr; - } _mutex.unlock(); } @@ -473,18 +453,6 @@ SSL* Connections::getClientSSL(int index) return _ssls[index + POLL_SSL]; } -int Connections::searchClient(SensorNetAddress *addr) -{ - for (int i = POLL_SSL; i < _numfds; i++) - { - if (_clientAddr[i]->isMatch(addr) == true) - { - return i - POLL_SSL; - } - } - return -1; -} - /*================================================================ Class SensorNetwork @@ -597,7 +565,6 @@ int SensorNetwork::read(uint8_t *buf, uint16_t bufLen) int optval; int clientIndex = -1; int sockListen = 0; - SensorNetAddress client; char errmsg[256]; union { @@ -605,27 +572,22 @@ int SensorNetwork::read(uint8_t *buf, uint16_t bufLen) struct sockaddr_in6 s6; } client_addr; + SensorNetAddress client; + client.clear(); + client.setFamily(_af); + // Check POLL_IN int cnt = _conns->poll(2000); // Timeout 2secs if (cnt == 0) { + // Timeout return cnt; } - - if (cnt < 0) + else if (cnt < 0) { - - /* ToDo: close socket */ - return -1; } - int numfds = _conns->getNumOfConnections(); - - client.clear(); - client.setFamily(_af); - size_t recvlen = 0; - SSL *ssl = 0; _mutex.lock(); @@ -643,7 +605,6 @@ int SensorNetwork::read(uint8_t *buf, uint16_t bufLen) getUnicastClient(&client); sockListen = _conns->getSockUnicast(); -ListenClient_hello: // Listen Connection SSL *ssl = SSL_new(_dtlsctx); BIO *bio = BIO_new_dgram(sockListen, BIO_NOCLOSE); @@ -725,11 +686,15 @@ ListenClient_hello: else { // Check SSL packet from clients + size_t recvlen = 0; + SSL *ssl = 0; + int numfds = _conns->getNumOfConnections(); + for (int i = 0; i < numfds - POLL_SSL; i++) { if (_conns->getEventClient(i) == POLLIN) { - D_NWSTACK("SSL RECV\n"); + D_NWSTACK("SSL Packet RECV\n"); int dtls = getSendClient(i, &client); if (dtls > 0) @@ -740,20 +705,15 @@ ListenClient_hello: #ifdef DEBUG_NW char clientaddrBuf[128]; client.sprint(clientaddrBuf); - D_NWSTACK("Client %s SSL reconnect. idx=%d\n", clientaddrBuf, i); + D_NWSTACK("Client %s A packet is ClientHello. Client reconnected. Close connection. SSL_connection will timeout.\n", clientaddrBuf); #endif - // Delete current connection. clientIndex = i; - D_NWSTACK("Close current connections\n"); _mutex.unlock(); - _conns->close(clientIndex); // DEBUG + _conns->close(clientIndex); return 0; - - sockListen = _conns->getSockClient(i); - goto ListenClient_hello; } - // Recv a MQTT-SN message from a client + // The packet is a MQTT-SN message ssl = _conns->getClientSSL(i); int len = SSL_read_ex(ssl, (void*) buf, (size_t) bufLen, &recvlen); if (SSL_get_error(ssl, len) >= 0) @@ -1214,6 +1174,7 @@ int SensorNetwork::getSenderAddress(int sock, SensorNetAddress *addr) } addr->setFamily(AF_INET); addr->getIpAddress()->addr.ad4 = sender4.sin_addr; + addr->setPort(sender4.sin_port); D_NWSTACK("SensorNetwork::getSenderAddress recved from %s:%d length = %d\n", inet_ntoa(sender4.sin_addr), ntohs(sender4.sin_port), len); @@ -1241,6 +1202,7 @@ int SensorNetwork::getSenderAddress(int sock, SensorNetAddress *addr) addr->setFamily(AF_INET6); addr->setSockaddr6(&sender6); + addr->setPort(sender4.sin_port); #ifdef DEBUG_NW char senderstr[INET6_ADDRSTRLEN]; diff --git a/MQTTSNGateway/src/linux/dtls/SensorNetwork.h b/MQTTSNGateway/src/linux/dtls/SensorNetwork.h index d84d5a5..f7e8e34 100644 --- a/MQTTSNGateway/src/linux/dtls/SensorNetwork.h +++ b/MQTTSNGateway/src/linux/dtls/SensorNetwork.h @@ -109,11 +109,9 @@ public: int getEventUnicast(void); int getEventListen(void); void closeSSL(int index); - int searchClient(SensorNetAddress *addr); private: pollfd *_pollfds; SSL **_ssls; - SensorNetAddress **_clientAddr; int _maxfds; int _numfds; Mutex _mutex; From 4dcfa98303818ef9eb74d92e5db194d515b6c211 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Thu, 5 Aug 2021 13:18:01 +0900 Subject: [PATCH 66/67] Bugfix of DTLS6 #241 This fix doesn't work on OpenSSL version 1.1.1 11.sep 2018 Upgrade to version 1.1.1k 25 Mar. 2021 Signed-off-by: tomoaki --- .cproject | 7 +- MQTTSNGateway/GatewayTester/Makefile | 6 +- MQTTSNGateway/GatewayTester/build.sh | 3 +- .../GatewayTester/samples/mainTest.cpp | 2 +- MQTTSNGateway/GatewayTester/src/LGwProxy.cpp | 4 +- .../GatewayTester/src/LMqttsnClientApp.h | 6 +- .../GatewayTester/src/LNetworkDtls.cpp | 5 +- .../GatewayTester/src/LNetworkDtls.h | 7 +- .../GatewayTester/src/LNetworkDtls6.cpp | 179 ++++++++++++------ .../GatewayTester/src/LNetworkDtls6.h | 5 +- .../GatewayTester/src/LNetworkUdp.cpp | 2 + .../GatewayTester/src/LNetworkUdp6.cpp | 2 +- MQTTSNGateway/clients.conf | 19 +- MQTTSNGateway/src/CMakeLists.txt | 3 +- MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp | 20 +- MQTTSNGateway/src/MQTTSNGateway.h | 4 +- .../src/linux/dtls/SensorNetwork.cpp | 178 ++++++++++------- MQTTSNGateway/src/linux/dtls/SensorNetwork.h | 9 +- .../src/linux/udp6/SensorNetwork.cpp | 4 +- 19 files changed, 285 insertions(+), 180 deletions(-) diff --git a/.cproject b/.cproject index a252276..c21710c 100644 --- a/.cproject +++ b/.cproject @@ -38,7 +38,6 @@ @@ -81,7 +80,8 @@ - + + @@ -153,7 +153,8 @@ - + + diff --git a/MQTTSNGateway/GatewayTester/Makefile b/MQTTSNGateway/GatewayTester/Makefile index 5cc07df..a4ec071 100644 --- a/MQTTSNGateway/GatewayTester/Makefile +++ b/MQTTSNGateway/GatewayTester/Makefile @@ -40,14 +40,14 @@ $(SUBDIR)/Util.cpp \ CXX := g++ CPPFLAGS += -INCLUDES += -I$(SUBDIR) +INCLUDES += -I$(SUBDIR) -I/usr/local/opt/openssl/include DEF1 := DEF2 := DEFS := -D$(SN) $(DEF1) $(DEF2) -LIBS += -L/usr/local/lib -L/usr/local/opt/openssl +LIBS += -L/usr/local/lib -L/usr/local/opt/openssl/lib LDFLAGS := CXXFLAGS := -Wall -O3 -std=c++11 -LDADD := -lbluetooth -lssl -lcrypto +LDADD := -lssl -lcrypto $(LDADDBLT) OUTDIR := Build PROG := $(OUTDIR)/$(PROGTEST) diff --git a/MQTTSNGateway/GatewayTester/build.sh b/MQTTSNGateway/GatewayTester/build.sh index 290440b..538ba14 100755 --- a/MQTTSNGateway/GatewayTester/build.sh +++ b/MQTTSNGateway/GatewayTester/build.sh @@ -8,6 +8,7 @@ if [ $1 == "udp" ] ; then elif [ $1 == "udp6" ] ; then make SN=UDP6 $DEF1 $DEF2 elif [ $1 == "rfcomm" ] ; then + export LDADDBLT=-lbluetooth make SN=RFCOMM $DEF1 $DEF2 elif [ $1 == "dtls" ] ; then make SN=DTLS $DEF1 $DEF2 @@ -16,7 +17,7 @@ elif [ $1 == "dtls6" ] ; then elif [ $1 == "clean" ] ; then make clean else - echo "Usage: build.sh [ udp | udp6 | rfcomm | dtls | dtls6] | clean" + echo "Usage: build.sh [ udp | udp6 | rfcomm | dtls | dtls6 | clean]" fi diff --git a/MQTTSNGateway/GatewayTester/samples/mainTest.cpp b/MQTTSNGateway/GatewayTester/samples/mainTest.cpp index 2210222..0c39184 100644 --- a/MQTTSNGateway/GatewayTester/samples/mainTest.cpp +++ b/MQTTSNGateway/GatewayTester/samples/mainTest.cpp @@ -52,7 +52,7 @@ extern LScreen* theScreen; * UDP,DTLS Configuration (theNetcon) *------------------------------------------------------*/ UDPCONF = { "GatewayTestClient", // ClientId - { 225, 1, 1, 1 }, // Multicast group IP + { 225, 1, 1, 1 }, // Multicast group IP 1883, // Multicast group Port 20020, // Local PortNo }; diff --git a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp index 1b631b9..3e71f83 100644 --- a/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp +++ b/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp @@ -207,12 +207,12 @@ int LGwProxy::getConnectResponce(void) if (_network.sslConnect() > 0) { _status = GW_CONNECTING; - DISPLAY("\033[0m\033[0;32m\n\nLGwProxy::getConnectResponce SSL connection established.\033[0m\033[0;37m\n\n"); + DISPLAY("\033[0m\033[0;32m\n\nLGwProxy::getConnectResponce DTLS connection established.\033[0m\033[0;37m\n\n"); break; } else { - DISPLAY("\033[0m\033[0;32m\n\nLGwProxy::getConnectResponce SSL connection failed.\033[0m\033[0;37m\n\n"); + DISPLAY("\033[0m\033[0;32m\n\nLGwProxy::getConnectResponce DTLS connection failed.\033[0m\033[0;37m\n\n"); } } #else diff --git a/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h b/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h index 79e77b8..8182f3a 100644 --- a/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h +++ b/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h @@ -252,11 +252,11 @@ typedef enum /*================================= * Starting prompt ==================================*/ -#define TESTER_VERSION " * Version: 2.0.0" +#define TESTER_VERSION " * Version: 2.1.0" -#define PAHO_COPYRIGHT0 " * MQTT-SN Gateway Tester" +#define PAHO_COPYRIGHT0 " * " #define PAHO_COPYRIGHT1 " * Part of Project Paho in Eclipse" -#define PAHO_COPYRIGHT2 " * (http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt-sn.embedded-c.git/)" +#define PAHO_COPYRIGHT2 " * (https://github.com/eclipse/paho.mqtt-sn.embedded-c.git)" #define PAHO_COPYRIGHT3 " * Author : Tomoaki YAMAGUCHI" #define PAHO_COPYRIGHT4 " ***************************************************************************" diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkDtls.cpp b/MQTTSNGateway/GatewayTester/src/LNetworkDtls.cpp index 2d6f3f2..a0adbe6 100644 --- a/MQTTSNGateway/GatewayTester/src/LNetworkDtls.cpp +++ b/MQTTSNGateway/GatewayTester/src/LNetworkDtls.cpp @@ -224,7 +224,6 @@ bool LDtlsPort::open(LUdpConfig *config) if (setsockopt(_sockfdMcast, IPPROTO_IP, IP_MULTICAST_LOOP, &optval, sizeof(optval)) < 0) { D_NWLOG("\033[0m\033[0;31merror IP_MULTICAST_LOOP in LDtlsPort::open\033[0m\033[0;37m\n"); - DISPLAY("\033[0m\033[0;31m\nerror IP_MULTICAST_LOOP in LDtlsPort::open\033[0m\033[0;37m\n"); close(); return false; } @@ -236,7 +235,6 @@ bool LDtlsPort::open(LUdpConfig *config) if (setsockopt(_sockfdMcast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { D_NWLOG("\033[0m\033[0;31merror IP_ADD_MEMBERSHIP in LDtlsPort::open\033[0m\033[0;37m\n"); - DISPLAY("\033[0m\033[0;31m\nerror IP_ADD_MEMBERSHIP in LDtlsPort::open\033[0m\033[0;37m\n"); close(); return false; } @@ -256,7 +254,6 @@ int LDtlsPort::unicast(const uint8_t *buf, uint32_t length) { int rc = 0; SSL_get_error(_ssl, rc); - D_NWLOG("errno == %d in LDtlsPort::unicast\n", rc); DISPLAY("errno == %d in LDtlsPort::unicast\n", rc); } else @@ -386,7 +383,7 @@ bool LDtlsPort::checkRecvBuf() return true; } } - _castStat = 0; + _castStat = STAT_NONE; return false; } diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkDtls.h b/MQTTSNGateway/GatewayTester/src/LNetworkDtls.h index 11bee40..5fac0b0 100644 --- a/MQTTSNGateway/GatewayTester/src/LNetworkDtls.h +++ b/MQTTSNGateway/GatewayTester/src/LNetworkDtls.h @@ -36,13 +36,14 @@ #define SOCKET_MAXRECV 500 #define SOCKET_MAXBUFFER_LENGTH 500 // buffer size -#define STAT_UNICAST 1 -#define STAT_MULTICAST 2 -#define STAT_SSL 3 using namespace std; namespace linuxAsyncClient { +#define STAT_NONE 0 +#define STAT_UNICAST 1 +#define STAT_MULTICAST 2 +#define STAT_SSL 3 /*======================================== Class LDtlsPort =======================================*/ diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkDtls6.cpp b/MQTTSNGateway/GatewayTester/src/LNetworkDtls6.cpp index d748acf..83006f9 100644 --- a/MQTTSNGateway/GatewayTester/src/LNetworkDtls6.cpp +++ b/MQTTSNGateway/GatewayTester/src/LNetworkDtls6.cpp @@ -75,8 +75,8 @@ uint8_t* LNetwork::getMessage(int *len) if (checkRecvBuf()) { uint16_t recvLen = LDtls6Port::recv(_rxDataBuf, MQTTSN_MAX_PACKET_SIZE, false, &_ipAddress, &_portNo); - int diffAddr = memcmp(_ipAddress.s6_addr, _gwIpAddress.s6_addr, sizeof(_gwIpAddress.s6_addr)); - if (isUnicast() && diffAddr && (_portNo != _gwPortNo)) + int addrFlg = memcmp(_ipAddress.s6_addr, _gwIpAddress.s6_addr, sizeof(_gwIpAddress.s6_addr)); + if (isUnicast() && addrFlg && (_portNo != _gwPortNo)) { return 0; } @@ -141,11 +141,14 @@ int LNetwork::sslConnect(void) LDtls6Port::LDtls6Port() { _disconReq = false; - memset(_pollfds, 0, sizeof(_pollfds)); - _sock = 0; - _castStat = 0; + _castStat = STAT_NONE; _ifIndex = 0; - _gIpAddrStr = NULL; + _gIpAddrStr = nullptr; + _sockfdMcast = 0; + _sockfdSsl = 0; + _ctx = nullptr; + _ssl = nullptr; + _gPortNo = _uPortNo = 0; } LDtls6Port::~LDtls6Port() @@ -159,12 +162,14 @@ LDtls6Port::~LDtls6Port() void LDtls6Port::close() { - for (int i = 0; i < 2; i++) + if (_sockfdMcast > 0) { - if (_pollfds[i].fd > 0) + ::close(_sockfdMcast); + _sockfdMcast = 0; + if (_sockfdSsl > 0) { - ::close(_pollfds[i].fd); - _pollfds[i].fd = 0; + ::close(_sockfdSsl); + _sockfdSsl = 0; } } } @@ -172,7 +177,6 @@ void LDtls6Port::close() bool LDtls6Port::open(LUdp6Config *config) { int optval = 1; - int sock = 0; sockaddr_in6 addr6; char errmsg[256]; @@ -205,22 +209,22 @@ bool LDtls6Port::open(LUdp6Config *config) } /* create a multicast socket */ - sock = socket(AF_INET6, SOCK_DGRAM, 0); - if (sock < 0) + _sockfdMcast = socket(AF_INET6, SOCK_DGRAM, 0); + if (_sockfdMcast < 0) { return false; } optval = 1; - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); - setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)); + setsockopt(_sockfdMcast, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + setsockopt(_sockfdMcast, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)); memset(&addr6, 0, sizeof(addr6)); addr6.sin6_family = AF_INET6; addr6.sin6_port = _gPortNo; addr6.sin6_addr = in6addr_any; - if (::bind(sock, (sockaddr*) &addr6, sizeof(addr6)) < 0) + if (::bind(_sockfdMcast, (sockaddr*) &addr6, sizeof(addr6)) < 0) { D_NWLOG("\033[0m\033[0;31merror %s ::bind() in Udp6Port::open\033[0m\033[0;37m\n", strerror(errno)); return false; @@ -229,21 +233,21 @@ bool LDtls6Port::open(LUdp6Config *config) ipv6_mreq addrm; addrm.ipv6mr_interface = _ifIndex; inet_pton(AF_INET6, config->ipAddress, &addrm.ipv6mr_multiaddr); - if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &addrm, sizeof(addrm)) < 0) + if (setsockopt(_sockfdMcast, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &addrm, sizeof(addrm)) < 0) { D_NWLOG("\033[0m\033[0;31merror %s IPV6_ADD_MEMBERSHIP in Udp6Port::open\033[0m\033[0;37m\n", strerror(errno)); close(); return false; } - optval = 0; - if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &optval, sizeof(optval)) < 0) + + optval = 1; + if (setsockopt(_sockfdMcast, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &optval, sizeof(optval)) < 0) { D_NWLOG("\033[0m\033[0;31merror %s IPV6_MULTICAST_LOOP in Udp6Port::open\033[0m\033[0;37m\n", strerror(errno)); close(); return false; } - _pollfds[1].fd = sock; - _pollfds[1].events = POLLIN; + _gIpAddr.sin6_family = AF_INET6; _gIpAddr.sin6_port = _gPortNo; memcpy(&_gIpAddr.sin6_addr, (const void*) &addrm.ipv6mr_multiaddr, sizeof(addrm.ipv6mr_multiaddr)); @@ -253,7 +257,7 @@ bool LDtls6Port::open(LUdp6Config *config) bool LDtls6Port::isUnicast() { - return (_sock == _pollfds[0].fd && _sock > 0); + return (_castStat == STAT_UNICAST); } int LDtls6Port::unicast(const uint8_t *buf, uint32_t length) @@ -267,11 +271,13 @@ int LDtls6Port::unicast(const uint8_t *buf, uint32_t length) } else { - D_NWLOG("sendto gateway via DTLS "); + D_NWLOG("sendto gateway via DTLS6 "); for (uint16_t i = 0; i < length; i++) { D_NWLOG(" %02x", *(buf + i)); - }D_NWLOG("\n"); + } + + D_NWLOG("\n"); if (!theClientMode) { @@ -299,12 +305,12 @@ int LDtls6Port::multicast(const uint8_t *buf, uint32_t length) { char sbuf[SCREEN_BUFF_SIZE]; char portStr[8]; - sprintf(portStr, "%d", ntohs(_gPortNo)); + sprintf(portStr, "%d", ntohs(_gIpAddr.sin6_port)); - int status = ::sendto(_pollfds[1].fd, buf, length, 0, (sockaddr*) &_gIpAddr, sizeof(_gIpAddr)); + int status = ::sendto(_sockfdMcast, buf, length, 0, (sockaddr*) &_gIpAddr, sizeof(_gIpAddr)); if (status < 0) { - D_NWLOG("multicast to [%s]:%-6s ", _gIpAddrStr, portStr);D_NWLOG("\033[0m\033[0;31merrno = %d %s in Udp6Port::multicast\033[0m\033[0;37m\n", errno, strerror(errno)); + DISPLAY("\033[0m\033[0;31merrno == %d in LDtls6Port::multicast\033[0m\033[0;37m\n", errno); return errno; } else @@ -313,7 +319,9 @@ int LDtls6Port::multicast(const uint8_t *buf, uint32_t length) for (uint16_t i = 0; i < length; i++) { D_NWLOG(" %02x", *(buf + i)); - }D_NWLOG("\n"); + } + + D_NWLOG("\n"); if (!theClientMode) { @@ -339,32 +347,52 @@ int LDtls6Port::multicast(const uint8_t *buf, uint32_t length) bool LDtls6Port::checkRecvBuf() { + timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 50000; // 50 msec + uint8_t buf[2]; + fd_set recvfds; + int maxSock = 0; - int cnt = poll(_pollfds, 2, 2000); // Timeout 2secs - if (cnt == 0) + FD_ZERO(&recvfds); + if (_sockfdMcast) { - return false; + FD_SET(_sockfdMcast, &recvfds); + } + if (_sockfdSsl) + { + FD_SET(_sockfdSsl, &recvfds); } - if (_pollfds[0].revents & POLLIN) + if (_sockfdMcast > _sockfdSsl) { - if (::recv(_pollfds[0].fd, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0) - { - _castStat = STAT_SSL; - _sock = _pollfds[0].fd; - return true; - } + maxSock = _sockfdMcast; } - else if (_pollfds[1].revents & POLLIN) + else { - if (::recv(_pollfds[1].fd, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0) + maxSock = _sockfdSsl; + } + + select(maxSock + 1, &recvfds, 0, 0, &timeout); + + if (FD_ISSET(_sockfdMcast, &recvfds)) + { + if (::recv(_sockfdMcast, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0) { _castStat = STAT_MULTICAST; - _sock = _pollfds[1].fd; return true; } } + else if (FD_ISSET(_sockfdSsl, &recvfds)) + { + if (::recv(_sockfdSsl, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0) + { + _castStat = STAT_SSL; + return true; + } + } + _castStat = STAT_NONE; return false; } @@ -393,7 +421,7 @@ int LDtls6Port::recvfrom(uint8_t *buf, uint16_t length, int flags, in6_addr *ipA else if (_castStat == STAT_MULTICAST) { D_NWLOG("Mcast "); - status = ::recvfrom(_sock, buf, length, flags, (sockaddr*) &sender, &addrlen); + status = ::recvfrom(_sockfdMcast, buf, length, flags, (sockaddr*) &sender, &addrlen); } else { @@ -445,63 +473,82 @@ int LDtls6Port::recvfrom(uint8_t *buf, uint16_t length, int flags, in6_addr *ipA return status; } -int LDtls6Port::sslConnect(in6_addr ipAddress, uint16_t portNo) +int LDtls6Port::sslConnect(in6_addr ipAddress, in_port_t portNo) { int optval = 1; - int sock = _pollfds[0].fd; if (_ssl != 0) { + D_NWLOG("LDtls6Port::sslConnect SSL exists.\n"); + SSL_shutdown(_ssl); SSL_free(_ssl); + _sockfdSsl = 0; + _ssl = 0; } - if (sock > 0) + if (_sockfdSsl > 0) { - ::close(sock); + D_NWLOG("LDtls6Port::sslConnect socket exists.\n"); + ::close(_sockfdSsl); } - sock = socket(AF_INET6, SOCK_DGRAM, 0); - if (sock <= 0) + _sockfdSsl = socket(AF_INET6, SOCK_DGRAM, 0); + if (_sockfdSsl <= 0) { + D_NWLOG("LDtls6Port::sslConnect Can't create a socket\n"); return -1; } optval = 1; - setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)); - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR || SO_REUSEPORT, &optval, sizeof(optval)); + setsockopt(_sockfdSsl, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)); + setsockopt(_sockfdSsl, SOL_SOCKET, SO_REUSEADDR || SO_REUSEPORT, &optval, sizeof(optval)); if (_ifIndex > 0) { #ifdef __APPLE__ - setsockopt(sock, IPPROTO_IP, IP_BOUND_IF, &_ifIndex, sizeof(_ifIndex)); + setsockopt(_sockfdSsl, IPPROTO_IP, IP_BOUND_IF, &_ifIndex, sizeof(_ifIndex)); #else - setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, _interfaceName.c_str(), _interfaceName.size()); + setsockopt(_sockfdSsl, SOL_SOCKET, SO_BINDTODEVICE, _interfaceName.c_str(), _interfaceName.size()); #endif } - struct sockaddr_in6 addr; + sockaddr_in6 addr; addr.sin6_family = AF_INET6; addr.sin6_port = _uPortNo; addr.sin6_addr = in6addr_any; - if (::bind(sock, (struct sockaddr*) &addr, sizeof(addr)) < 0) + if (::bind(_sockfdSsl, (struct sockaddr*) &addr, sizeof(addr)) < 0) { + ::close(_sockfdSsl); + D_NWLOG("LDtlsPort::sslConnect Can't bind a socket\n"); return -1; } - _pollfds[0].fd = sock; - _pollfds[0].events = POLLIN; - uint16_t listenPort = htons(portNo); - struct sockaddr_in6 dest; + // Destination is a gateway address and portNo + int rc = 0; + sockaddr_in6 dest; dest.sin6_family = AF_INET6; - dest.sin6_port = htons(listenPort); + dest.sin6_port = portNo; memcpy(dest.sin6_addr.s6_addr, (const void*) ipAddress.s6_addr, sizeof(ipAddress.s6_addr)); - int rc = 0; + BIO *cbio = BIO_new_dgram(_sockfdSsl, BIO_NOCLOSE); + if (connect(_sockfdSsl, (sockaddr*) &dest, sizeof(sockaddr_in6)) < 0) + { + D_NWLOG("socket can't connect %s\n",strerror(errno)); + return -1; + } + + if (BIO_ctrl(cbio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &dest) <0) + { + D_NWLOG("BIO_ctrl %s\n",strerror(errno)); + return -1; + } - BIO *cbio = BIO_new_dgram(sock, BIO_NOCLOSE); - connect(sock, (sockaddr*) &dest, sizeof(sockaddr_in6)); - BIO_ctrl(cbio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &dest); _ssl = SSL_new(_ctx); + if (_ssl == nullptr) + { + D_NWLOG("SSL_new %s\n",strerror(errno)); + return -1; + } SSL_set_bio(_ssl, cbio, cbio); #ifdef DEBUG_NW @@ -510,7 +557,12 @@ int LDtls6Port::sslConnect(in6_addr ipAddress, uint16_t portNo) D_NWLOG("connect to %-15s:%-6u\n", addrBuf, ntohs(dest.sin6_port)); #endif + timeval timeout; + timeout.tv_sec = 5; + timeout.tv_usec = 0; + BIO_ctrl(cbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout); errno = 0; + int stat = SSL_connect(_ssl); if (stat != 1) { @@ -519,6 +571,7 @@ int LDtls6Port::sslConnect(in6_addr ipAddress, uint16_t portNo) } else { + rc = 1; D_NWLOG("SSL connected\n"); } return rc; diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkDtls6.h b/MQTTSNGateway/GatewayTester/src/LNetworkDtls6.h index 6177e4b..05c8cff 100644 --- a/MQTTSNGateway/GatewayTester/src/LNetworkDtls6.h +++ b/MQTTSNGateway/GatewayTester/src/LNetworkDtls6.h @@ -37,6 +37,7 @@ #define SOCKET_MAXRECV 500 #define SOCKET_MAXBUFFER_LENGTH 500 // buffer size +#define STAT_NONE 0 #define STAT_UNICAST 1 #define STAT_MULTICAST 2 #define STAT_SSL 3 @@ -68,9 +69,10 @@ private: void close(); int recvfrom ( uint8_t* buf, uint16_t len, int flags, in6_addr* ipaddress, in_port_t* port ); + int _sockfdMcast; + int _sockfdSsl; SSL_CTX *_ctx; SSL *_ssl; - pollfd _pollfds[2]; in_port_t _gPortNo; in_port_t _uPortNo; sockaddr_in6 _gIpAddr; @@ -78,7 +80,6 @@ private: uint32_t _ifIndex; string _interfaceName; uint8_t _castStat; - int _sock; bool _disconReq; }; diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp b/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp index 25020f7..c0ac9e9 100644 --- a/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp +++ b/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp @@ -197,6 +197,7 @@ bool LUdpPort::open(LUdpConfig *config) if (::bind(_sockfdUcast, (struct sockaddr*) &addr, sizeof(addr)) < 0) { + D_NWLOG("\033[0m\033[0;31merror %s ::bind() to unicast address\033[0m\033[0;37m\n", strerror(errno)); return false; } @@ -216,6 +217,7 @@ bool LUdpPort::open(LUdpConfig *config) if (::bind(_sockfdMcast, (struct sockaddr*) &addrm, sizeof(addrm)) < 0) { + D_NWLOG("\033[0m\033[0;31merror %s ::bind() in UdpPort::open\033[0m\033[0;37m\n", strerror(errno)); return false; } diff --git a/MQTTSNGateway/GatewayTester/src/LNetworkUdp6.cpp b/MQTTSNGateway/GatewayTester/src/LNetworkUdp6.cpp index 6277f8b..0d1167f 100644 --- a/MQTTSNGateway/GatewayTester/src/LNetworkUdp6.cpp +++ b/MQTTSNGateway/GatewayTester/src/LNetworkUdp6.cpp @@ -350,7 +350,7 @@ bool LUdp6Port::checkRecvBuf() { uint8_t buf[2]; - int cnt = poll(_pollfds, 2, 2000); // Timeout 2secs + int cnt = poll(_pollfds, 2, 50); // Timeout 50m secs if (cnt == 0) { return false; diff --git a/MQTTSNGateway/clients.conf b/MQTTSNGateway/clients.conf index a2c005c..d91d2a5 100644 --- a/MQTTSNGateway/clients.conf +++ b/MQTTSNGateway/clients.conf @@ -15,10 +15,10 @@ # Lines bigning with # are comment line. # ClientId, SensorNetAddress, "unstableLine", "secureConnection" # in case of UDP, SensorNetAddress format is IPAddress: port no. -# 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. +# if the SensorNetwork is not stable, specify "unstableLine". +# if Broker's Connection is TLS, specify "secureConnection". +# if the client is a forwarder,specify "forwarder". +# if the client send PUBLISH QoS-1, specify "QoS-1". # # Ex: # #Client List @@ -31,6 +31,17 @@ # # SensorNetwork address format is defined by SensorNetAddress::setAddress(string* data) function. # +# UDP6 (IPv6 UDP) [IPv6 address]:PortNo +# RFCOMM Device_address.channel (1-30) +# XBee FFFFFFFFFFFFFFFF 8bytes Hex +# LoRaLink 1-254 +# +# +# This is a sample of UDP. +# +# REWRITE ALL ACCORDING TO YOUR CLIENTS. +# + GatewayTester, 172.16.1.11:20020 ClientPUB,172.16.1.11:2010 Client01,172.16.1.11:12001 diff --git a/MQTTSNGateway/src/CMakeLists.txt b/MQTTSNGateway/src/CMakeLists.txt index 9a16e28..2e81bc1 100644 --- a/MQTTSNGateway/src/CMakeLists.txt +++ b/MQTTSNGateway/src/CMakeLists.txt @@ -81,7 +81,7 @@ ADD_LIBRARY(mqtt-sngateway_common link_directories("/usr/local/lib") # Mac -link_directories("/usr/local/opt/openssl") +link_directories("/usr/local/opt/openssl/lib") TARGET_INCLUDE_DIRECTORIES(mqtt-sngateway_common @@ -91,6 +91,7 @@ TARGET_INCLUDE_DIRECTORIES(mqtt-sngateway_common ${OS}/${SENSORNET} ../../MQTTSNPacket/src /usr/local/include + /usr/local/opt/openssl/include ) IF(SENSORNET MATCHES "rfcomm") diff --git a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp index bd7017c..d935c21 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp @@ -98,11 +98,11 @@ void ClientRecvTask::run() continue; } - SensorNetAddress* senderAddr = _gateway->getSensorNetwork()->getSenderAddress(); + SensorNetAddress senderAddr = *_gateway->getSensorNetwork()->getSenderAddress(); if (packet->getType() == MQTTSN_ENCAPSULATED) { - fwd = _gateway->getAdapterManager()->getForwarderList()->getForwarder(senderAddr); + fwd = _gateway->getAdapterManager()->getForwarderList()->getForwarder(&senderAddr); if (fwd != nullptr) { @@ -124,7 +124,7 @@ void ClientRecvTask::run() if (qosm1Proxy->isActive()) { - const char* clientName = qosm1Proxy->getClientId(senderAddr); + const char *clientName = qosm1Proxy->getClientId(&senderAddr); if (clientName != nullptr) { @@ -134,7 +134,7 @@ void ClientRecvTask::run() { log(clientName, packet); WRITELOG("%s %s %s can send only PUBLISH with QoS-1.%s\n", - ERRMSG_HEADER, clientName, senderAddr->sprint(buf), ERRMSG_FOOTER); + ERRMSG_HEADER, clientName, senderAddr.sprint(buf), ERRMSG_FOOTER); delete packet; continue; } @@ -143,7 +143,7 @@ void ClientRecvTask::run() if (client == nullptr) { - client = _gateway->getClientList()->getClient(senderAddr); + client = _gateway->getClientList()->getClient(&senderAddr); } } @@ -183,7 +183,7 @@ void ClientRecvTask::run() { log(0, packet, &data.clientID); WRITELOG("%s CONNECT message form %s is incorrect.%s\n", - ERRMSG_HEADER, senderAddr->sprint(buf), + ERRMSG_HEADER, senderAddr.sprint(buf), ERRMSG_FOOTER); delete packet; continue; @@ -208,13 +208,13 @@ void ClientRecvTask::run() /* Authentication is not required */ if (_gateway->getGWParams()->clientAuthentication == false) { - client->setClientAddress(senderAddr); + client->setClientAddress(&senderAddr); } } else { /* create a new client */ - client = clientList->createClient(senderAddr, &data.clientID, clientType); + client = clientList->createClient(&senderAddr, &data.clientID, clientType); } } @@ -223,7 +223,7 @@ void ClientRecvTask::run() if (client == nullptr) { WRITELOG("%s Client(%s) was rejected. CONNECT message has been discarded.%s\n", - ERRMSG_HEADER, senderAddr->sprint(buf), + ERRMSG_HEADER, senderAddr.sprint(buf), ERRMSG_FOOTER); delete packet; continue; @@ -247,7 +247,7 @@ void ClientRecvTask::run() else { WRITELOG("%s MQTTSNGWClientRecvTask Client(%s) is not connecting. message has been discarded.%s\n", - ERRMSG_HEADER, senderAddr->sprint(buf), + ERRMSG_HEADER, senderAddr.sprint(buf), ERRMSG_FOOTER); } delete packet; diff --git a/MQTTSNGateway/src/MQTTSNGateway.h b/MQTTSNGateway/src/MQTTSNGateway.h index 3bd9b1f..d4836ae 100644 --- a/MQTTSNGateway/src/MQTTSNGateway.h +++ b/MQTTSNGateway/src/MQTTSNGateway.h @@ -27,9 +27,9 @@ namespace MQTTSNGW /*================================= * Starting prompt ==================================*/ -#define PAHO_COPYRIGHT0 " * " +#define PAHO_COPYRIGHT0 " * MQTT-SN Gateway" #define PAHO_COPYRIGHT1 " * Part of Project Paho in Eclipse" -#define PAHO_COPYRIGHT2 " * (http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt-sn.embedded-c.git/)" +#define PAHO_COPYRIGHT2 " * (https://github.com/eclipse/paho.mqtt-sn.embedded-c.git)" #define PAHO_COPYRIGHT3 " * Author : Tomoaki YAMAGUCHI" #define PAHO_COPYRIGHT4 " ***************************************************************************" /*========================================================== diff --git a/MQTTSNGateway/src/linux/dtls/SensorNetwork.cpp b/MQTTSNGateway/src/linux/dtls/SensorNetwork.cpp index 28ef868..3f2dcf3 100644 --- a/MQTTSNGateway/src/linux/dtls/SensorNetwork.cpp +++ b/MQTTSNGateway/src/linux/dtls/SensorNetwork.cpp @@ -61,6 +61,7 @@ unsigned char cookie_secret[COOKIE_SECRET_LENGTH]; SensorNetAddress::SensorNetAddress() { _portNo = 0; + _pfdsIndex = 0; memset(&_ipAddr, 0, sizeof(_ipAddr)); } @@ -223,7 +224,6 @@ void SensorNetAddress::setSockaddr4(sockaddr_in *sockaddr) _ipAddr.af = sockaddr->sin_family; _portNo = sockaddr->sin_port; memcpy((void*) &_ipAddr.addr.ad4, (void*) &sockaddr->sin_addr, sizeof(_ipAddr.addr.ad4)); - this->_pfdsIndex = 0; } void SensorNetAddress::setSockaddr6(sockaddr_in6 *sockaddr) @@ -231,7 +231,6 @@ void SensorNetAddress::setSockaddr6(sockaddr_in6 *sockaddr) _ipAddr.af = sockaddr->sin6_family; _portNo = sockaddr->sin6_port; memcpy((void*) &_ipAddr.addr.ad6, (void*) &sockaddr->sin6_addr, sizeof(_ipAddr.addr.ad6)); - this->_pfdsIndex = 0; } void SensorNetAddress::cpyAddr4(sockaddr_in *sockaddr) @@ -244,8 +243,15 @@ void SensorNetAddress::cpyAddr4(sockaddr_in *sockaddr) void SensorNetAddress::cpyAddr6(sockaddr_in6 *sockaddr) { sockaddr->sin6_family = _ipAddr.af; - memcpy((void*) &sockaddr->sin6_addr, (void*) &_ipAddr.addr.ad6, sizeof(_ipAddr.addr.ad6)); sockaddr->sin6_port = _portNo; + memcpy((void*) &sockaddr->sin6_addr, (void*) &_ipAddr.addr.ad6, sizeof(_ipAddr.addr.ad6)); +} + +void SensorNetAddress::cpyAddr(SensorNetAddress *addr) +{ + addr->_portNo = _portNo; + memcpy((void*) &addr->_ipAddr, (const void*) &_ipAddr, sizeof(_ipAddr)); + addr->_pfdsIndex = _pfdsIndex; } char* SensorNetAddress::sprint(char *buf) @@ -269,6 +275,7 @@ char* SensorNetAddress::sprint(char *buf) return buf; } sprintf(buf + strlen(buf), "%d", ntohs(_portNo)); + sprintf(buf + strlen(buf), " index=%d", _pfdsIndex); return buf; } @@ -392,6 +399,7 @@ int Connections::getSockClient(int index) void Connections::close(int index) { + D_NWSTACK("Connection %d closed\n", index); int idx = index + POLL_SSL; _mutex.lock(); int sock = _pollfds[idx].fd; @@ -435,6 +443,7 @@ int Connections::addClientSSL(SSL *ssl, int sock) int rc = _numfds - POLL_SSL; _numfds++; _mutex.unlock(); + D_NWSTACK("Add client connection index=%d, ssl=%ld, sock=%d\n", rc, (long int )ssl, sock); return rc; } @@ -453,6 +462,14 @@ SSL* Connections::getClientSSL(int index) return _ssls[index + POLL_SSL]; } +void Connections::print(void) +{ + for (int i = 0; i < _numfds; i++) + { + printf("index=%d fd=%d ssl=%ld \n", i, _pollfds[i].fd, (long int) _ssls[i]); + } +} + /*================================================================ Class SensorNetwork @@ -468,6 +485,8 @@ SSL* Connections::getClientSSL(int index) #define DTLS_APPL 23 #define DTLS_OTHERS 100 +#define DTLS_TIMEOUT 4 + /* Certificate verification. Returns 1 if trusted, else 0 */ int verify_cert(int ok, X509_STORE_CTX *ctx); @@ -479,9 +498,6 @@ int verify_cookie(SSL *ssl, const unsigned char *cookie, unsigned int cookie_len SensorNetwork::SensorNetwork() { - _senderAddr = new SensorNetAddress(); - _multicastAddr = new SensorNetAddress(); - _unicastAddr = new SensorNetAddress(); _conns = new Connections(); _dtlsctx = nullptr; _af = 0; @@ -493,24 +509,18 @@ SensorNetwork::~SensorNetwork() { delete _conns; } - if (_senderAddr != nullptr) - { - delete _senderAddr; - } - if (_multicastAddr != nullptr) - { - delete _multicastAddr; - } - if (_unicastAddr != nullptr) - { - delete _unicastAddr; - } } int SensorNetwork::unicast(const uint8_t *payload, uint16_t payloadLength, SensorNetAddress *sendToAddr) { - _mutex.lock(); +#ifdef DEBUG_NW + char buf[256]; + _conns->print(); + sendToAddr->sprint(buf); + D_NWSTACK("sendto %s\n", buf); +#endif + _mutex.lock(); SSL *ssl = _conns->getClientSSL(sendToAddr->getIndex()); int len = SSL_write(ssl, payload, payloadLength); int rc = SSL_get_error(ssl, len); @@ -530,7 +540,7 @@ int SensorNetwork::broadcast(const uint8_t *payload, uint16_t payloadLength) int status; #ifndef DTLS6 sockaddr_in dest; - _multicastAddr->cpyAddr4(&dest); + _multicastAddr.cpyAddr4(&dest); status = ::sendto(_conns->getSockUnicast(), payload, payloadLength, 0, (const sockaddr*) &dest, sizeof(dest)); if (status < 0) @@ -542,7 +552,7 @@ int SensorNetwork::broadcast(const uint8_t *payload, uint16_t payloadLength) #else sockaddr_in6 dest; - _multicastAddr->cpyAddr6(&dest); + _multicastAddr.cpyAddr6(&dest); status = ::sendto(_conns->getSockUnicast(), payload, payloadLength, 0, (const sockaddr*) &dest, sizeof(dest)); if (status < 0) @@ -577,7 +587,7 @@ int SensorNetwork::read(uint8_t *buf, uint16_t bufLen) client.setFamily(_af); // Check POLL_IN - int cnt = _conns->poll(2000); // Timeout 2secs + int cnt = _conns->poll(6000); // Timeout 6secs if (cnt == 0) { // Timeout @@ -588,21 +598,21 @@ int SensorNetwork::read(uint8_t *buf, uint16_t bufLen) return -1; } - _mutex.lock(); // Check Unicast Port if (_conns->getEventUnicast() & POLLIN) { - D_NWSTACK("Connect RECV\n"); + D_NWSTACK("RECV Unicast SSL_connect\n"); + // SSL connection request from a client - optval = 1; - - client.clear(); - client.setFamily(_af); - +#ifdef DEBUG_NW + int dtls = getUnicastClient(&client); + D_NWSTACK("Packet type = %d\n", dtls); +#else getUnicastClient(&client); +#endif sockListen = _conns->getSockUnicast(); // Listen Connection @@ -615,7 +625,7 @@ int SensorNetwork::read(uint8_t *buf, uint16_t bufLen) int rc = 0; // SSL Listen - D_NWSTACK("Listen SSL\n"); + D_NWSTACK("DTLSv1_listen\n"); rc = DTLSv1_listen(ssl, (BIO_ADDR*) &client_addr); @@ -631,6 +641,7 @@ int SensorNetwork::read(uint8_t *buf, uint16_t bufLen) #ifndef DTLS6 // DTLS over IPv4 int client_fd = socket(AF_INET, SOCK_DGRAM, 0); + optval = 1; setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &optval, sizeof(optval)); // Bind to Dtls PortNo bind(client_fd, (sockaddr*) &_serverAddr4, sizeof(sockaddr_in)); @@ -639,6 +650,7 @@ int SensorNetwork::read(uint8_t *buf, uint16_t bufLen) #else // DTLS over IPv6 int client_fd = socket(AF_INET6, SOCK_DGRAM, 0); + optval = 1; setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &optval, sizeof(optval)); // Bind to Dtls PortNo bind(client_fd, (sockaddr*) &_serverAddr6, sizeof(sockaddr_in6)); @@ -650,12 +662,18 @@ int SensorNetwork::read(uint8_t *buf, uint16_t bufLen) BIO_set_fd(cbio, client_fd, BIO_NOCLOSE); BIO_ctrl(cbio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &client_addr); + // set timeout + timeval timeout; + timeout.tv_sec = DTLS_TIMEOUT; + timeout.tv_usec = 0; + BIO_ctrl(cbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout); + // Finish handshake int ret = SSL_accept(ssl); if (ret <= 0) { ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg)); - WRITELOG("SSL_accept ret=%d %s\n", ret, errmsg); + WRITELOG("SSL_accept %s\n", errmsg); SSL_shutdown(ssl); SSL_free(ssl); ::close(client_fd); @@ -667,11 +685,13 @@ int SensorNetwork::read(uint8_t *buf, uint16_t bufLen) // save SensorNetworkAddress of Client client.setIndex(index); - _senderAddr = &client; + client.cpyAddr(&_senderAddr); + #ifdef DEBUG_NW char clientaddrBuf[128]; - client.sprint(clientaddrBuf); - D_NWSTACK("Client %s SSL Accepted. idx=%d\n", clientaddrBuf, index); + _senderAddr.sprint(clientaddrBuf); + D_NWSTACK("DTLS accepted client is %s index=%d client_fd=%d\n", clientaddrBuf, _senderAddr.getIndex(), + client_fd); #endif } _mutex.unlock(); @@ -716,22 +736,23 @@ int SensorNetwork::read(uint8_t *buf, uint16_t bufLen) // The packet is a MQTT-SN message ssl = _conns->getClientSSL(i); int len = SSL_read_ex(ssl, (void*) buf, (size_t) bufLen, &recvlen); - if (SSL_get_error(ssl, len) >= 0) - { -#ifdef DEBUG_NW - char clientaddrBuf[128]; - client.sprint(clientaddrBuf); - D_NWSTACK("Client %s SSL Accepted. idx=%d\n", clientaddrBuf, i); -#endif - _senderAddr = &client; - _senderAddr->setIndex(i); - } - else + if (SSL_get_error(ssl, len) < 0) { D_NWSTACK("SSL RECV Error\n"); _conns->close(i); recvlen = -1; } + else + { + client.cpyAddr(&_senderAddr); + _senderAddr.setIndex(i); + +#ifdef DEBUG_NW + char clientaddrBuf[128]; + _senderAddr.sprint(clientaddrBuf); + D_NWSTACK("Client %s ssl=%ld Received. idx=%d\n", clientaddrBuf, (long int )ssl, i); +#endif + } _mutex.unlock(); return recvlen; } @@ -880,7 +901,7 @@ const char* SensorNetwork::getDescription(void) SensorNetAddress* SensorNetwork::getSenderAddress(void) { - return _senderAddr; + return &_senderAddr; } int SensorNetwork::openV4(string *ipAddress, uint16_t multiPortNo, uint16_t uniPortNo, uint32_t ttl) @@ -966,9 +987,9 @@ int SensorNetwork::openV4(string *ipAddress, uint16_t multiPortNo, uint16_t uniP D_NWSTACK("error %d IP_MULTICAST_LOOP in UDP4_6Port::openV4 %s\n", errno, strerror(errno)); return -1; } - _multicastAddr->setFamily(AF_INET); - _multicastAddr->setIpAddress(ipAddress); - _multicastAddr->setPort(multiPortNo); + _multicastAddr.setFamily(AF_INET); + _multicastAddr.setIpAddress(ipAddress); + _multicastAddr.setPort(multiPortNo); _conns->setSockMulticast(sock); return 0; } @@ -987,10 +1008,10 @@ int SensorNetwork::openV6(string *ipAddress, string *interface, uint16_t multiPo return -1; } - _multicastAddr->setPort(multiPortNo); - _unicastAddr->setPort(uniPortNo); + _multicastAddr.setPort(multiPortNo); + _unicastAddr.setPort(uniPortNo); - if (_multicastAddr->setIpAddress(ipAddress) < 0) + if (_multicastAddr.setIpAddress(ipAddress) < 0) { D_NWSTACK("Incorrect IPV6 address in SensorNetwork::openV6 error %s\n", strerror(errno)); return -1; @@ -1073,12 +1094,12 @@ int SensorNetwork::openV6(string *ipAddress, string *interface, uint16_t multiPo } struct ipv6_mreq mreq; - mreq.ipv6mr_multiaddr = _multicastAddr->getIpAddress()->addr.ad6; + mreq.ipv6mr_multiaddr = _multicastAddr.getIpAddress()->addr.ad6; mreq.ipv6mr_interface = ifindex; - if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) + if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) { - D_NWSTACK("Multicast IPV6_ADD_MEMBERSHIP in SensorNetwork::openV6 error %s\n", strerror(errno)); + D_NWSTACK("Multicast IPV6_JOIN_GROUP in SensorNetwork::openV6 error %s\n", strerror(errno)); return -1; } @@ -1099,9 +1120,9 @@ int SensorNetwork::openV6(string *ipAddress, string *interface, uint16_t multiPo D_NWSTACK("Multicast IPV6_MULTICAST_HOPS in SensorNetwork::openV6 error %s\n", strerror(errno)); return -1; } - _multicastAddr->setFamily(AF_INET6); - _multicastAddr->setIpAddress(ipAddress); - _multicastAddr->setPort(multiPortNo); + _multicastAddr.setFamily(AF_INET6); + _multicastAddr.setIpAddress(ipAddress); + _multicastAddr.setPort(multiPortNo); return 0; } @@ -1169,14 +1190,14 @@ int SensorNetwork::getSenderAddress(int sock, SensorNetAddress *addr) if (len < 0 && errno != EAGAIN) { - D_NWSTACK("errno = %d in UDPPort::getSender\n", errno); + D_NWSTACK("errno = %d in SensorNetwork::getSenderAddress\n", errno); return -1; } - addr->setFamily(AF_INET); - addr->getIpAddress()->addr.ad4 = sender4.sin_addr; - addr->setPort(sender4.sin_port); - D_NWSTACK("SensorNetwork::getSenderAddress recved from %s:%d length = %d\n", inet_ntoa(sender4.sin_addr), - ntohs(sender4.sin_port), len); + + addr->setSockaddr4(&sender4); + + D_NWSTACK("SensorNetwork::getSenderAddress recved from %s:%d length = %d fd=%d\n", inet_ntoa(sender4.sin_addr), + ntohs(addr->getPort()), len, sock); if (len >= 13) { @@ -1191,27 +1212,34 @@ int SensorNetwork::getSenderAddress(int sock, SensorNetAddress *addr) //AF_INET6 sockaddr_in6 sender6 = { 0 }; socklen_t addrlen6 = sizeof(sender6); - unsigned long int buf = 0; - len = ::recvfrom(sock, &buf, 1, MSG_PEEK, (sockaddr*) &sender6, &addrlen6); + char buf[16]; + int rc = DTLS_OTHERS; + + len = ::recvfrom(sock, &buf, 15, MSG_PEEK, (sockaddr*) &sender6, &addrlen6); if (len < 0 && errno != EAGAIN) { - D_NWSTACK("errno = %d in SensorNetwork::getSender\n", errno); - return len; + D_NWSTACK("errno = %d in SensorNetwork::getSenderAddress\n", errno); + return -1; } - addr->setFamily(AF_INET6); addr->setSockaddr6(&sender6); - addr->setPort(sender4.sin_port); #ifdef DEBUG_NW char senderstr[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &sender6.sin6_addr,senderstr,INET6_ADDRSTRLEN); - D_NWSTACK("recved from %s:%d length = %d\n",senderstr ,ntohs(sender6.sin6_port), len); + D_NWSTACK("recved from %s:%d length = %d fd=%d\n",senderstr ,ntohs(addr->getPort()), len, sock); #endif #endif - return len; + if (len >= 13) + { + if (buf[0] == DTLS_CLIENTHELLO || buf[0] == DTLS_APPL) + { + rc = buf[0]; + } + } + return rc; } void SensorNetwork::clearRecvData(int sock) @@ -1220,6 +1248,12 @@ void SensorNetwork::clearRecvData(int sock) ::recv(sock, buf, MQTTSNGW_MAX_PACKET_SIZE, 0); } +Connections* SensorNetwork::getConnections(void) +{ + return _conns; +} + + int verify_cert(int ok, X509_STORE_CTX *ctx) { return 1; diff --git a/MQTTSNGateway/src/linux/dtls/SensorNetwork.h b/MQTTSNGateway/src/linux/dtls/SensorNetwork.h index f7e8e34..0ef1753 100644 --- a/MQTTSNGateway/src/linux/dtls/SensorNetwork.h +++ b/MQTTSNGateway/src/linux/dtls/SensorNetwork.h @@ -57,6 +57,7 @@ public: void setSockaddr6(sockaddr_in6 *sockaddr); void cpyAddr4(sockaddr_in *sockaddr); void cpyAddr6(sockaddr_in6 *sockaddr); + void cpyAddr(SensorNetAddress *addr); in_port_t getPort(void); ipAddr_t* getIpAddress(void); void setIndex(int index); @@ -109,6 +110,7 @@ public: int getEventUnicast(void); int getEventListen(void); void closeSSL(int index); + void print(void); private: pollfd *_pollfds; SSL **_ssls; @@ -133,6 +135,7 @@ public: void initialize(void); const char* getDescription(void); SensorNetAddress* getSenderAddress(void); + Connections* getConnections(void); void close(); private: @@ -145,9 +148,9 @@ private: void clearRecvData(int sock); Mutex _mutex; - SensorNetAddress *_senderAddr; - SensorNetAddress *_multicastAddr; - SensorNetAddress *_unicastAddr; + SensorNetAddress _senderAddr; + SensorNetAddress _multicastAddr; + SensorNetAddress _unicastAddr; string _description; SSL_CTX *_dtlsctx; Connections *_conns; diff --git a/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp b/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp index cbcc4d5..193d1d7 100644 --- a/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp +++ b/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp @@ -360,9 +360,9 @@ int UDPPort6::open(uint16_t uniPortNo, uint16_t multiPortNo, const char *multica ipv6_mreq addrm; addrm.ipv6mr_interface = ifindex; inet_pton(AF_INET6, multicastAddr, &addrm.ipv6mr_multiaddr); - if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &addrm, sizeof(addrm)) < 0) + if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &addrm, sizeof(addrm)) < 0) { - D_NWSTACK("\033[0m\033[0;31m error %d IPV6_ADD_MEMBERSHIP in Udp6Port::open\033[0m\033[0;37m\n", errno); + D_NWSTACK("\033[0m\033[0;31m error %d IPV6_JOIN_GROUP in Udp6Port::open\033[0m\033[0;37m\n", errno); close(); return false; } From 52500a0c79220f50a8fb7e4257fd5522e5be8f52 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Thu, 16 Sep 2021 11:13:13 +0900 Subject: [PATCH 67/67] Update README delete unused include statement --- MQTTSNGateway/README.md | 2 +- MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/MQTTSNGateway/README.md b/MQTTSNGateway/README.md index 3826c7a..21f9d4e 100644 --- a/MQTTSNGateway/README.md +++ b/MQTTSNGateway/README.md @@ -9,7 +9,7 @@ $ cd paho.mqtt-sn.embedded-c/MQTTSNGateway ``` In order to build a gateway, one sensor network argument is required. ``` -$ ./build.sh [udp|udp6|xbee|loralink|rfcomm] +$ ./build.sh [udp|udp6|xbee|loralink|rfcomm|dtls|dtls6] ``` MQTT-SNGateway and MQTT-SNLogmonitor (executable programs) are built in ./bin directory. diff --git a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp index d935c21..f4c019b 100644 --- a/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp +++ b/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp @@ -20,8 +20,6 @@ #include "MQTTSNGWEncapsulatedPacket.h" #include -//#include "MQTTSNGWForwarder.h" - using namespace MQTTSNGW; char* currentDateTime(void); /*===================================== @@ -45,7 +43,7 @@ void ClientRecvTask::initialize(int argc, char** argv) /* * Receive a packet from clients via sensor netwwork - * and generate a event to execute the packet handling procedure + * and creats a event to execute the packet handling procedure * of MQTTSNPacketHandlingTask. */ void ClientRecvTask::run()