+
+
+#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