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