From fb3d936d4c19cb2cefaf5faabca1662e828d71b8 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Sun, 21 May 2017 09:27:22 -0300 Subject: [PATCH] Linux: Binds to MY_IP_ADDRESS in client mode (#849) --- core/MyGatewayTransportEthernet.cpp | 3 +++ core/MyGatewayTransportMQTTClient.cpp | 2 +- drivers/Linux/EthernetClient.cpp | 38 +++++++++++++++++++++------ drivers/Linux/EthernetClient.h | 7 ++++- drivers/Linux/EthernetServer.cpp | 5 ++++ 5 files changed, 45 insertions(+), 10 deletions(-) diff --git a/core/MyGatewayTransportEthernet.cpp b/core/MyGatewayTransportEthernet.cpp index 141800b..ad46456 100644 --- a/core/MyGatewayTransportEthernet.cpp +++ b/core/MyGatewayTransportEthernet.cpp @@ -138,6 +138,9 @@ bool gatewayTransportInit(void) #endif /* MY_GATEWAY_ESP8266 */ #if defined(MY_GATEWAY_CLIENT_MODE) +#if defined(MY_GATEWAY_LINUX) && defined(MY_IP_ADDRESS) + client.bind(_ethernetGatewayIP); +#endif #if defined(MY_CONTROLLER_URL_ADDRESS) if (client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) { #else diff --git a/core/MyGatewayTransportMQTTClient.cpp b/core/MyGatewayTransportMQTTClient.cpp index b879780..a9d1564 100644 --- a/core/MyGatewayTransportMQTTClient.cpp +++ b/core/MyGatewayTransportMQTTClient.cpp @@ -105,7 +105,7 @@ bool gatewayTransportConnect(void) MY_SERIALDEVICE.println(WiFi.localIP()); #elif defined(MY_GATEWAY_LINUX) #if defined(MY_IP_ADDRESS) - //TODO + _MQTT_ethClient.bind(_MQTT_clientIp); #endif #else #ifdef MY_IP_ADDRESS diff --git a/drivers/Linux/EthernetClient.cpp b/drivers/Linux/EthernetClient.cpp index 8540a62..c5686e8 100644 --- a/drivers/Linux/EthernetClient.cpp +++ b/drivers/Linux/EthernetClient.cpp @@ -43,11 +43,13 @@ EthernetClient::EthernetClient(int sock) : _sock(sock) int EthernetClient::connect(const char* host, uint16_t port) { - int sockfd; - struct addrinfo hints, *servinfo, *p; + struct addrinfo hints, *servinfo, *localinfo, *p; int rv; char s[INET6_ADDRSTRLEN]; char port_str[6]; + bool use_bind = (_srcip != 0); + + close(); memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; @@ -58,17 +60,31 @@ int EthernetClient::connect(const char* host, uint16_t port) logError("getaddrinfo: %s\n", gai_strerror(rv)); return -1; } + if (use_bind) { + if ((rv = getaddrinfo(_srcip.toString().c_str(), port_str, &hints, &localinfo)) != 0) { + logError("getaddrinfo: %s\n", gai_strerror(rv)); + return -1; + } + } // loop through all the results and connect to the first we can for (p = servinfo; p != NULL; p = p->ai_next) { - if ((sockfd = socket(p->ai_family, p->ai_socktype, - p->ai_protocol)) == -1) { + if ((_sock = socket(p->ai_family, p->ai_socktype, + p->ai_protocol)) == -1) { logError("socket: %s\n", strerror(errno)); continue; } - if (::connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { - ::close(sockfd); + if (use_bind) { + if (::bind(_sock, localinfo->ai_addr, localinfo->ai_addrlen) == -1) { + close(); + logError("bind: %s\n", strerror(errno)); + return -1; + } + } + + if (::connect(_sock, p->ai_addr, p->ai_addrlen) == -1) { + close(); logError("connect: %s\n", strerror(errno)); continue; } @@ -81,13 +97,14 @@ int EthernetClient::connect(const char* host, uint16_t port) return -1; } - _sock = sockfd; - void *addr = &(((struct sockaddr_in*)p->ai_addr)->sin_addr); inet_ntop(p->ai_family, addr, s, sizeof s); logDebug("connected to %s\n", s); freeaddrinfo(servinfo); // all done with this structure + if (use_bind) { + freeaddrinfo(localinfo); // all done with this structure + } return 1; } @@ -273,6 +290,11 @@ void EthernetClient::close() } } +void EthernetClient::bind(IPAddress ip) +{ + _srcip = ip; +} + int EthernetClient::getSocketNumber() { return _sock; diff --git a/drivers/Linux/EthernetClient.h b/drivers/Linux/EthernetClient.h index 8562700..710f8dd 100644 --- a/drivers/Linux/EthernetClient.h +++ b/drivers/Linux/EthernetClient.h @@ -155,6 +155,10 @@ public: * @brief Close the connection. */ void close(); + /** + * @brief Bind the conection to the specified local ip. + */ + void bind(IPAddress ip); /** * @brief Get the internal socket file descriptor. * @@ -200,7 +204,8 @@ public: friend class EthernetServer; private: - int _sock; //!< @brief Network socket. + int _sock; //!< @brief Network socket file descriptor. + IPAddress _srcip; //!< @brief Local ip to bind to. }; #endif diff --git a/drivers/Linux/EthernetServer.cpp b/drivers/Linux/EthernetServer.cpp index d327834..9bbeb0e 100644 --- a/drivers/Linux/EthernetServer.cpp +++ b/drivers/Linux/EthernetServer.cpp @@ -51,6 +51,11 @@ void EthernetServer::begin(IPAddress address) char ipstr[INET_ADDRSTRLEN]; char portstr[6]; + if (sockfd != -1) { + close(sockfd); + sockfd = -1; + } + memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM;