mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-23 10:46:31 +00:00
IPv6 improvements (#17268)
* IPv6 improvements * Fix esp8266 compilation * grrr * Fix compilation issue * Fix declaration * Fix esp32c3
This commit is contained in:
parent
a7eaca59e6
commit
2a1b900775
@ -91,6 +91,16 @@ bool WiFiClass32::getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int3
|
||||
return WiFi.getNetworkInfo(i, ssid, encType, rssi, bssid, channel);
|
||||
}
|
||||
|
||||
// from https://github.com/espressif/arduino-esp32/pull/7520
|
||||
static const int WIFI_WANT_IP6_BIT_ALT = BIT15;
|
||||
bool WiFiClass32::IPv6(bool state) {
|
||||
if (state)
|
||||
WiFiGenericClass::setStatusBits(WIFI_WANT_IP6_BIT_ALT);
|
||||
else
|
||||
WiFiGenericClass::clearStatusBits(WIFI_WANT_IP6_BIT_ALT);
|
||||
return true;
|
||||
}
|
||||
|
||||
void wifi_station_disconnect() {
|
||||
// erase ap: empty ssid, ...
|
||||
WiFi.disconnect(true, true);
|
||||
|
@ -50,6 +50,8 @@ public:
|
||||
static void forceSleepBegin();
|
||||
static void forceSleepWake();
|
||||
static bool getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int32_t &rssi, uint8_t* &bssid, int32_t &channel, bool &hidden_scan);
|
||||
|
||||
bool IPv6(bool state); // make sure it always exists even with older Arduino framework
|
||||
};
|
||||
|
||||
void wifi_station_disconnect();
|
||||
|
@ -45,17 +45,27 @@
|
||||
#include <Print.h>
|
||||
#include <StreamString.h>
|
||||
|
||||
// Tasmota Logging
|
||||
extern void AddLog(uint32_t loglevel, PGM_P formatP, ...);
|
||||
enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE};
|
||||
|
||||
IPAddress46::IPAddress46(const IPAddress46& from)
|
||||
{
|
||||
ip_addr_copy(_ip, from._ip);
|
||||
}
|
||||
|
||||
IPAddress46::IPAddress46() {
|
||||
_ip = *IP_ANY_TYPE; // lwIP's v4-or-v6 generic address
|
||||
#if LWIP_IPV6
|
||||
_ip = *IP6_ADDR_ANY;
|
||||
#else
|
||||
_ip = *IP_ADDR_ANY;
|
||||
#endif
|
||||
// _ip = *IP_ANY_TYPE; // lwIP's v4-or-v6 generic address
|
||||
}
|
||||
|
||||
bool IPAddress46::isSet () const {
|
||||
return !ip_addr_isany(&_ip) && ((*this) != IPADDR_NONE);
|
||||
return !IP_IS_ANY_TYPE_VAL(_ip);
|
||||
// return !ip_addr_isany(&_ip) && ((*this) != IPADDR_NONE);
|
||||
}
|
||||
|
||||
IPAddress46::IPAddress46(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) {
|
||||
@ -152,8 +162,8 @@ bool IPAddress46::operator==(const uint8_t* addr) const {
|
||||
size_t IPAddress46::printTo(Print& p) const {
|
||||
size_t n = 0;
|
||||
|
||||
if (!isSet())
|
||||
return p.print(F("(IP unset)"));
|
||||
// if (!isSet())
|
||||
// return p.print(F("(IP unset)"));
|
||||
|
||||
#if LWIP_IPV6
|
||||
if (isV6()) {
|
||||
@ -267,4 +277,55 @@ bool IPAddress46::fromString6(const char *address) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Get host by name working for IPv6
|
||||
// --------------------------------------------------
|
||||
#include "lwip/dns.h"
|
||||
|
||||
/**
|
||||
* DNS callback
|
||||
* @param name
|
||||
* @param ipaddr
|
||||
* @param callback_arg
|
||||
*/
|
||||
static void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg)
|
||||
{
|
||||
if(ipaddr) {
|
||||
(*reinterpret_cast<IPAddress46*>(callback_arg)) = IPAddress46(ipaddr);
|
||||
}
|
||||
WiFiGeneric46::DnsDone();
|
||||
// xEventGroupSetBits(_arduino_event_group, WIFI_DNS_DONE_BIT);
|
||||
}
|
||||
|
||||
int WiFiGeneric46::hostByName(const char* aHostname, IPAddress46& aResult) {
|
||||
ip_addr_t addr;
|
||||
aResult = static_cast<uint32_t>(INADDR_NONE);
|
||||
waitStatusBits(WIFI_DNS_IDLE_BIT, 16000);
|
||||
clearStatusBits(WIFI_DNS_IDLE_BIT | WIFI_DNS_DONE_BIT);
|
||||
err_t err = dns_gethostbyname_addrtype(aHostname, &addr, &wifi_dns_found_callback, &aResult, LWIP_DNS_ADDRTYPE_DEFAULT);
|
||||
AddLog(LOG_LEVEL_DEBUG, "WIF: WiFiGeneric46::hostByName err=%i", err);
|
||||
|
||||
if(err == ERR_OK) {
|
||||
aResult = IPAddress46(&addr);
|
||||
|
||||
if (!aResult.isSet()) {
|
||||
#if LWIP_IPV6
|
||||
aResult.setV6();
|
||||
#else
|
||||
aResult.setV4();
|
||||
#endif
|
||||
}
|
||||
} else if(err == ERR_INPROGRESS) {
|
||||
waitStatusBits(WIFI_DNS_DONE_BIT, 15000); //real internal timeout in lwip library is 14[s]
|
||||
clearStatusBits(WIFI_DNS_DONE_BIT);
|
||||
}
|
||||
setStatusBits(WIFI_DNS_IDLE_BIT);
|
||||
|
||||
if(err == ERR_OK) {
|
||||
AddLog(LOG_LEVEL_DEBUG, "WIF: WiFiGeneric46::hostByName Host: %s IP: %s", aHostname ? aHostname : "<null>", aResult.toString().c_str());
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -123,7 +123,7 @@ class IPAddress46: public Printable {
|
||||
static bool isValid(const char* arg);
|
||||
|
||||
friend class EthernetClass;
|
||||
friend class UDP;
|
||||
friend class UDP46;
|
||||
friend class Client;
|
||||
friend class Server;
|
||||
friend class DhcpClass;
|
||||
@ -181,4 +181,18 @@ class IPAddress46: public Printable {
|
||||
bool fromString4(const char *address);
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// We need to create a subclass of WiFiGenericClass to access protected methods
|
||||
// --------------------------------------------------------------------------------
|
||||
#include "WiFiGeneric.h"
|
||||
|
||||
class WiFiGeneric46 : public WiFiGenericClass
|
||||
{
|
||||
public:
|
||||
WiFiGeneric46() {};
|
||||
|
||||
static int hostByName(const char *aHostname, IPAddress46 &aResult);
|
||||
static void DnsDone(void) { setStatusBits(WIFI_DNS_DONE_BIT); };
|
||||
};
|
||||
|
||||
#endif // __IPADDRESS46_H
|
||||
|
93
lib/libesp32/ESP32-to-ESP8266-compat/src/Udp46.h
Normal file
93
lib/libesp32/ESP32-to-ESP8266-compat/src/Udp46.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Udp.cpp: Library to send/receive UDP packets.
|
||||
*
|
||||
* NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these)
|
||||
* 1) UDP does not guarantee the order in which assembled UDP packets are received. This
|
||||
* might not happen often in practice, but in larger network topologies, a UDP
|
||||
* packet can be received out of sequence.
|
||||
* 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being
|
||||
* aware of it. Again, this may not be a concern in practice on small local networks.
|
||||
* For more information, see http://www.cafeaulait.org/course/week12/35.html
|
||||
*
|
||||
* MIT License:
|
||||
* Copyright (c) 2008 Bjoern Hartmann
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* bjoern@cs.stanford.edu 12/30/2008
|
||||
*/
|
||||
|
||||
#ifndef udp46_h
|
||||
#define udp46_h
|
||||
|
||||
#include <Stream.h>
|
||||
#include <IPAddress46.h>
|
||||
|
||||
class UDP46: public Stream
|
||||
{
|
||||
|
||||
public:
|
||||
virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
|
||||
virtual uint8_t beginMulticast(IPAddress46, uint16_t) { return 0; } // initialize, start listening on specified multicast IP address and port. Returns 1 if successful, 0 on failure
|
||||
virtual void stop() =0; // Finish with the UDP socket
|
||||
|
||||
// Sending UDP packets
|
||||
|
||||
// Start building up a packet to send to the remote host specific in ip and port
|
||||
// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
|
||||
virtual int beginPacket(IPAddress46 ip, uint16_t port) =0;
|
||||
// Start building up a packet to send to the remote host specific in host and port
|
||||
// Returns 1 if successful, 0 if there was a problem resolving the hostname or port
|
||||
virtual int beginPacket(const char *host, uint16_t port) =0;
|
||||
// Finish off this packet and send it
|
||||
// Returns 1 if the packet was sent successfully, 0 if there was an error
|
||||
virtual int endPacket() =0;
|
||||
// Write a single byte into the packet
|
||||
virtual size_t write(uint8_t) =0;
|
||||
// Write size bytes from buffer into the packet
|
||||
virtual size_t write(const uint8_t *buffer, size_t size) =0;
|
||||
|
||||
// Start processing the next available incoming packet
|
||||
// Returns the size of the packet in bytes, or 0 if no packets are available
|
||||
virtual int parsePacket() =0;
|
||||
// Number of bytes remaining in the current packet
|
||||
virtual int available() =0;
|
||||
// Read a single byte from the current packet
|
||||
virtual int read() =0;
|
||||
// Read up to len bytes from the current packet and place them into buffer
|
||||
// Returns the number of bytes read, or 0 if none are available
|
||||
virtual int read(unsigned char* buffer, size_t len) =0;
|
||||
// Read up to len characters from the current packet and place them into buffer
|
||||
// Returns the number of characters read, or 0 if none are available
|
||||
virtual int read(char* buffer, size_t len) =0;
|
||||
// Return the next byte from the current packet without moving on to the next byte
|
||||
virtual int peek() =0;
|
||||
virtual void flush() =0; // Finish reading the current packet
|
||||
|
||||
// Return the IP address of the host who sent the current incoming packet
|
||||
virtual IPAddress46 remoteIP() =0;
|
||||
// Return the port of the host who sent the current incoming packet
|
||||
virtual uint16_t remotePort() =0;
|
||||
protected:
|
||||
uint8_t* rawIPAddress(IPAddress46& addr)
|
||||
{
|
||||
return addr.raw_address();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
335
lib/libesp32/ESP32-to-ESP8266-compat/src/WiFiUdp46.cpp
Normal file
335
lib/libesp32/ESP32-to-ESP8266-compat/src/WiFiUdp46.cpp
Normal file
@ -0,0 +1,335 @@
|
||||
/*
|
||||
Udp.cpp - UDP class for Raspberry Pi
|
||||
Copyright (c) 2016 Hristo Gochkov All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "WiFiUdp46.h"
|
||||
#include <lwip/sockets.h>
|
||||
#include <lwip/netdb.h>
|
||||
#include <errno.h>
|
||||
|
||||
#undef write
|
||||
#undef read
|
||||
|
||||
// Tasmota Logging
|
||||
extern void AddLog(uint32_t loglevel, PGM_P formatP, ...);
|
||||
enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE};
|
||||
|
||||
WiFiUDP46::WiFiUDP46()
|
||||
: udp_server(-1)
|
||||
, server_port(0)
|
||||
, remote_port(0)
|
||||
, tx_buffer(0)
|
||||
, tx_buffer_len(0)
|
||||
, rx_buffer(0)
|
||||
{}
|
||||
|
||||
WiFiUDP46::~WiFiUDP46(){
|
||||
stop();
|
||||
}
|
||||
|
||||
uint8_t WiFiUDP46::begin(IPAddress46 address, uint16_t port){
|
||||
stop();
|
||||
server_port = port;
|
||||
|
||||
tx_buffer = new char[1460];
|
||||
if(!tx_buffer){
|
||||
log_e("could not create tx buffer: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LWIP_IPV6
|
||||
if ((udp_server=socket(AF_INET6, SOCK_DGRAM, 0)) == -1){
|
||||
#else
|
||||
if ((udp_server=socket(AF_INET, SOCK_DGRAM, 0)) == -1){
|
||||
#endif
|
||||
log_e("could not create socket: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// AddLog(LOG_LEVEL_DEBUG, "WiFiUDP46::begin socket called");
|
||||
int yes = 1;
|
||||
if (setsockopt(udp_server,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)) < 0) {
|
||||
log_e("could not set socket option: %d", errno);
|
||||
stop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//AddLog(LOG_LEVEL_DEBUG, "WiFiUDP46::begin setsockopt called");
|
||||
|
||||
struct sockaddr* sock_addr = NULL;
|
||||
size_t sock_size = 0;
|
||||
struct sockaddr_in addr;
|
||||
#if LWIP_IPV6
|
||||
struct sockaddr_in6 addr6;
|
||||
if (address.isV6()) {
|
||||
// AddLog(LOG_LEVEL_DEBUG, "WiFiUDP46::begin set IPv6");
|
||||
memset((char *) &addr6, 0, sizeof(sockaddr_in6));
|
||||
addr6.sin6_len = sizeof(sockaddr_in6);
|
||||
addr6.sin6_family = AF_INET6;
|
||||
addr6.sin6_port = htons(server_port);
|
||||
addr6.sin6_addr = *(in6_addr*)(ip_addr_t*)address;
|
||||
addr6.sin6_addr = in6addr_any;
|
||||
addr6.sin6_flowinfo = 0;
|
||||
sock_addr = (struct sockaddr*)&addr6;
|
||||
sock_size = sizeof(sockaddr_in6);
|
||||
|
||||
// AddLog(LOG_LEVEL_DEBUG, "SOCK_ADDR_TYPE_MATCH(name, sock)=%i", SOCK_ADDR_TYPE_MATCH(sock_addr, sock_size));
|
||||
} else
|
||||
#endif
|
||||
if (1) {
|
||||
memset((char *) &addr, 0, sizeof(sockaddr_in));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(server_port);
|
||||
addr.sin_addr.s_addr = (in_addr_t)address;
|
||||
sock_addr = (struct sockaddr*)&addr;
|
||||
sock_size = sizeof(sockaddr_in);
|
||||
}
|
||||
//AddLog(LOG_LEVEL_DEBUG, "WiFiUDP46::begin udp_server=%p sock_addr=%p sock_size=%i", udp_server, sock_addr, sock_size);
|
||||
if(bind(udp_server , sock_addr, sock_size) == -1){
|
||||
AddLog(LOG_LEVEL_DEBUG, "WIF: WiFiUDP46::begin bind error=%o", errno);
|
||||
log_e("could not bind socket: %d", errno);
|
||||
stop();
|
||||
return 0;
|
||||
}
|
||||
fcntl(udp_server, F_SETFL, O_NONBLOCK);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t WiFiUDP46::begin(uint16_t p){
|
||||
return begin(IPAddress46(), p);
|
||||
}
|
||||
|
||||
uint8_t WiFiUDP46::beginMulticast(IPAddress46 a, uint16_t p){
|
||||
if(begin(IPAddress46(), p)){
|
||||
if(!ip_addr_isany((ip_addr_t*)a)){
|
||||
struct ip_mreq mreq;
|
||||
mreq.imr_multiaddr.s_addr = (in_addr_t)a;
|
||||
mreq.imr_interface.s_addr = INADDR_ANY;
|
||||
if (setsockopt(udp_server, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
|
||||
log_e("could not join igmp: %d", errno);
|
||||
stop();
|
||||
return 0;
|
||||
}
|
||||
multicast_ip = a;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WiFiUDP46::stop(){
|
||||
if(tx_buffer){
|
||||
delete[] tx_buffer;
|
||||
tx_buffer = NULL;
|
||||
}
|
||||
tx_buffer_len = 0;
|
||||
if(rx_buffer){
|
||||
cbuf *b = rx_buffer;
|
||||
rx_buffer = NULL;
|
||||
delete b;
|
||||
}
|
||||
if(udp_server == -1)
|
||||
return;
|
||||
if(!ip_addr_isany((ip_addr_t*)multicast_ip)){
|
||||
struct ip_mreq mreq;
|
||||
mreq.imr_multiaddr.s_addr = (in_addr_t)multicast_ip;
|
||||
mreq.imr_interface.s_addr = (in_addr_t)0;
|
||||
#if LWIP_IPV6
|
||||
setsockopt(udp_server, IPPROTO_IPV6, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
|
||||
#else
|
||||
setsockopt(udp_server, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
|
||||
#endif
|
||||
multicast_ip = IPAddress46(INADDR_ANY);
|
||||
}
|
||||
close(udp_server);
|
||||
udp_server = -1;
|
||||
}
|
||||
|
||||
int WiFiUDP46::beginMulticastPacket(){
|
||||
if(!server_port || multicast_ip == IPAddress46(INADDR_ANY))
|
||||
return 0;
|
||||
remote_ip = multicast_ip;
|
||||
remote_port = server_port;
|
||||
return beginPacket();
|
||||
}
|
||||
|
||||
int WiFiUDP46::beginPacket(){
|
||||
if(!remote_port)
|
||||
return 0;
|
||||
|
||||
// allocate tx_buffer if is necessary
|
||||
if(!tx_buffer){
|
||||
tx_buffer = new char[1460];
|
||||
if(!tx_buffer){
|
||||
log_e("could not create tx buffer: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
tx_buffer_len = 0;
|
||||
|
||||
// check whereas socket is already open
|
||||
if (udp_server != -1)
|
||||
return 1;
|
||||
|
||||
if ((udp_server=socket(AF_INET, SOCK_DGRAM, 0)) == -1){
|
||||
log_e("could not create socket: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fcntl(udp_server, F_SETFL, O_NONBLOCK);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int WiFiUDP46::beginPacket(IPAddress46 ip, uint16_t port){
|
||||
remote_ip = ip;
|
||||
remote_port = port;
|
||||
return beginPacket();
|
||||
}
|
||||
|
||||
int WiFiUDP46::beginPacket(const char *host, uint16_t port){
|
||||
struct hostent *server;
|
||||
server = gethostbyname(host);
|
||||
if (server == NULL){
|
||||
log_e("could not get host from dns: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
return beginPacket(IPAddress46((const uint8_t *)(server->h_addr_list[0])), port);
|
||||
}
|
||||
|
||||
int WiFiUDP46::endPacket(){
|
||||
if (remote_ip.isV4()) {
|
||||
struct sockaddr_in recipient;
|
||||
recipient.sin_len = sizeof(sockaddr_in);
|
||||
recipient.sin_addr.s_addr = (uint32_t)remote_ip;
|
||||
recipient.sin_family = AF_INET;
|
||||
recipient.sin_port = htons(remote_port);
|
||||
int sent = sendto(udp_server, tx_buffer, tx_buffer_len, 0, (struct sockaddr*) &recipient, sizeof(recipient));
|
||||
if(sent < 0){
|
||||
log_e("could not send data: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
struct sockaddr_in6 recipient;
|
||||
recipient.sin6_len = sizeof(sockaddr_in6);
|
||||
recipient.sin6_flowinfo = 0;
|
||||
recipient.sin6_addr = *(in6_addr*)(ip_addr_t*)remote_ip;
|
||||
// recipient.sin6_family = AF_INET6;
|
||||
recipient.sin6_port = htons(remote_port);
|
||||
int sent = sendto(udp_server, tx_buffer, tx_buffer_len, 0, (struct sockaddr*) &recipient, sizeof(recipient));
|
||||
if(sent < 0){
|
||||
log_e("could not send data: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t WiFiUDP46::write(uint8_t data){
|
||||
if(tx_buffer_len == 1460){
|
||||
endPacket();
|
||||
tx_buffer_len = 0;
|
||||
}
|
||||
tx_buffer[tx_buffer_len++] = data;
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t WiFiUDP46::write(const uint8_t *buffer, size_t size){
|
||||
size_t i;
|
||||
for(i=0;i<size;i++)
|
||||
write(buffer[i]);
|
||||
return i;
|
||||
}
|
||||
|
||||
int WiFiUDP46::parsePacket(){
|
||||
if(rx_buffer)
|
||||
return 0;
|
||||
struct sockaddr_in si_other;
|
||||
int slen = sizeof(si_other) , len;
|
||||
char * buf = new char[1460];
|
||||
if(!buf){
|
||||
return 0;
|
||||
}
|
||||
if ((len = recvfrom(udp_server, buf, 1460, MSG_DONTWAIT, (struct sockaddr *) &si_other, (socklen_t *)&slen)) == -1){
|
||||
delete[] buf;
|
||||
if(errno == EWOULDBLOCK){
|
||||
return 0;
|
||||
}
|
||||
log_e("could not receive data: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
remote_ip = IPAddress46(si_other.sin_addr.s_addr);
|
||||
remote_port = ntohs(si_other.sin_port);
|
||||
if (len > 0) {
|
||||
rx_buffer = new cbuf(len);
|
||||
rx_buffer->write(buf, len);
|
||||
}
|
||||
delete[] buf;
|
||||
return len;
|
||||
}
|
||||
|
||||
int WiFiUDP46::available(){
|
||||
if(!rx_buffer) return 0;
|
||||
return rx_buffer->available();
|
||||
}
|
||||
|
||||
int WiFiUDP46::read(){
|
||||
if(!rx_buffer) return -1;
|
||||
int out = rx_buffer->read();
|
||||
if(!rx_buffer->available()){
|
||||
cbuf *b = rx_buffer;
|
||||
rx_buffer = 0;
|
||||
delete b;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
int WiFiUDP46::read(unsigned char* buffer, size_t len){
|
||||
return read((char *)buffer, len);
|
||||
}
|
||||
|
||||
int WiFiUDP46::read(char* buffer, size_t len){
|
||||
if(!rx_buffer) return 0;
|
||||
int out = rx_buffer->read(buffer, len);
|
||||
if(!rx_buffer->available()){
|
||||
cbuf *b = rx_buffer;
|
||||
rx_buffer = 0;
|
||||
delete b;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
int WiFiUDP46::peek(){
|
||||
if(!rx_buffer) return -1;
|
||||
return rx_buffer->peek();
|
||||
}
|
||||
|
||||
void WiFiUDP46::flush(){
|
||||
if(!rx_buffer) return;
|
||||
cbuf *b = rx_buffer;
|
||||
rx_buffer = 0;
|
||||
delete b;
|
||||
}
|
||||
|
||||
IPAddress46 WiFiUDP46::remoteIP(){
|
||||
return remote_ip;
|
||||
}
|
||||
|
||||
uint16_t WiFiUDP46::remotePort(){
|
||||
return remote_port;
|
||||
}
|
77
lib/libesp32/ESP32-to-ESP8266-compat/src/WiFiUdp46.h
Normal file
77
lib/libesp32/ESP32-to-ESP8266-compat/src/WiFiUdp46.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Udp.cpp: Library to send/receive UDP packets.
|
||||
*
|
||||
* NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these)
|
||||
* 1) UDP does not guarantee the order in which assembled UDP packets are received. This
|
||||
* might not happen often in practice, but in larger network topologies, a UDP
|
||||
* packet can be received out of sequence.
|
||||
* 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being
|
||||
* aware of it. Again, this may not be a concern in practice on small local networks.
|
||||
* For more information, see http://www.cafeaulait.org/course/week12/35.html
|
||||
*
|
||||
* MIT License:
|
||||
* Copyright (c) 2008 Bjoern Hartmann
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* bjoern@cs.stanford.edu 12/30/2008
|
||||
*/
|
||||
|
||||
#ifndef _WIFIUDP46_H_
|
||||
#define _WIFIUDP46_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Udp46.h>
|
||||
#include <cbuf.h>
|
||||
|
||||
class WiFiUDP46 : public UDP46 {
|
||||
private:
|
||||
int udp_server;
|
||||
IPAddress46 multicast_ip;
|
||||
IPAddress46 remote_ip;
|
||||
uint16_t server_port;
|
||||
uint16_t remote_port;
|
||||
char * tx_buffer;
|
||||
size_t tx_buffer_len;
|
||||
cbuf * rx_buffer;
|
||||
public:
|
||||
WiFiUDP46();
|
||||
~WiFiUDP46();
|
||||
uint8_t begin(IPAddress46 a, uint16_t p);
|
||||
uint8_t begin(uint16_t p);
|
||||
uint8_t beginMulticast(IPAddress46 a, uint16_t p);
|
||||
void stop();
|
||||
int beginMulticastPacket();
|
||||
int beginPacket();
|
||||
int beginPacket(IPAddress46 ip, uint16_t port);
|
||||
int beginPacket(const char *host, uint16_t port);
|
||||
int endPacket();
|
||||
size_t write(uint8_t);
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
int parsePacket();
|
||||
int available();
|
||||
int read();
|
||||
int read(unsigned char* buffer, size_t len);
|
||||
int read(char* buffer, size_t len);
|
||||
int peek();
|
||||
void flush();
|
||||
IPAddress46 remoteIP();
|
||||
uint16_t remotePort();
|
||||
};
|
||||
|
||||
#endif /* _WIFIUDP46_H_ */
|
@ -15,21 +15,25 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFiGeneric.h>
|
||||
#include <WiFiUdp.h>
|
||||
#include <WiFiUdp46.h>
|
||||
#include "be_mapping.h"
|
||||
|
||||
// Tasmota Logging
|
||||
extern void AddLog(uint32_t loglevel, PGM_P formatP, ...);
|
||||
enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE};
|
||||
|
||||
extern "C" {
|
||||
|
||||
// init()
|
||||
WiFiUDP *be_udp_init_ntv(void) {
|
||||
return new WiFiUDP();
|
||||
WiFiUDP46 *be_udp_init_ntv(void) {
|
||||
return new WiFiUDP46();
|
||||
}
|
||||
int32_t be_udp_init(struct bvm *vm) {
|
||||
return be_call_c_func(vm, (void*) &be_udp_init_ntv, "+.p", "");
|
||||
}
|
||||
|
||||
// deinit()
|
||||
void *be_udp_deinit_ntv(WiFiUDP *udp) {
|
||||
void *be_udp_deinit_ntv(WiFiUDP46 *udp) {
|
||||
if (udp != nullptr) { delete udp; }
|
||||
return nullptr;
|
||||
}
|
||||
@ -38,20 +42,22 @@ extern "C" {
|
||||
}
|
||||
|
||||
// udp.begin(address:string, port:int) -> bool
|
||||
int32_t be_udp_begin_ntv(WiFiUDP *udp, const char *host, int32_t port) {
|
||||
IPAddress addr((uint32_t)0);
|
||||
// if no host or host is "" then we defult to INADDR_ANY (0.0.0.0)
|
||||
if(host && (*host != 0) && !WiFiGenericClass::hostByName(host, addr)){
|
||||
return 0;
|
||||
}
|
||||
int32_t be_udp_begin_ntv(WiFiUDP46 *udp, int32_t port) {
|
||||
IPAddress46 addr;
|
||||
// AddLog(LOG_LEVEL_DEBUG, "BRY: udp.begin listening to '%s'", addr.toString().c_str());
|
||||
return udp->begin(addr, port);
|
||||
}
|
||||
int32_t be_udp_begin(struct bvm *vm) {
|
||||
return be_call_c_func(vm, (void*) &be_udp_begin_ntv, "b", ".si");
|
||||
if (be_top(vm) >= 3 && be_isstring(vm, 2)) {
|
||||
// legacy string parameter, now ignored
|
||||
return be_call_c_func(vm, (void*) &be_udp_begin_ntv, "b", ".-i");
|
||||
} else {
|
||||
return be_call_c_func(vm, (void*) &be_udp_begin_ntv, "b", ".i");
|
||||
}
|
||||
}
|
||||
|
||||
// udp.stop() -> nil
|
||||
void be_udp_stop_ntv(WiFiUDP *udp) {
|
||||
void be_udp_stop_ntv(WiFiUDP46 *udp) {
|
||||
udp->stop();
|
||||
}
|
||||
int32_t be_udp_stop(struct bvm *vm) {
|
||||
@ -59,23 +65,24 @@ extern "C" {
|
||||
}
|
||||
|
||||
// udp.begin_multicast(address:string, port:int) -> nil
|
||||
int32_t be_udp_begin_mcast_ntv(WiFiUDP *udp, const char *host, int32_t port) {
|
||||
IPAddress addr((uint32_t)0);
|
||||
if(!WiFiGenericClass::hostByName(host, addr)){
|
||||
int32_t be_udp_begin_mcast_ntv(WiFiUDP46 *udp, const char *host, int32_t port) {
|
||||
IPAddress46 addr;
|
||||
if(!WiFiGeneric46::hostByName(host, addr)){
|
||||
return 0;
|
||||
}
|
||||
return udp->WiFiUDP::beginMulticast(addr, port);
|
||||
return udp->WiFiUDP46::beginMulticast(addr, port);
|
||||
}
|
||||
int32_t be_udp_begin_mcast(struct bvm *vm) {
|
||||
return be_call_c_func(vm, (void*) &be_udp_begin_mcast_ntv, "b", ".si");
|
||||
}
|
||||
|
||||
// udp.send(address:string, port:int, payload:bytes) -> bool
|
||||
int32_t be_udp_send_ntv(WiFiUDP *udp, const char *host, int32_t port, const uint8_t* buf, int32_t len) {
|
||||
IPAddress addr((uint32_t)0);
|
||||
if (!WiFiGenericClass::hostByName(host, addr)){
|
||||
int32_t be_udp_send_ntv(WiFiUDP46 *udp, const char *host, int32_t port, const uint8_t* buf, int32_t len) {
|
||||
IPAddress46 addr;
|
||||
if (!WiFiGeneric46::hostByName(host, addr)){
|
||||
return 0;
|
||||
}
|
||||
// AddLog(LOG_LEVEL_DEBUG, "BRY: udp.begin got host '%s'", addr.toString().c_str());
|
||||
if (!udp->beginPacket(addr, port)) { return 0; }
|
||||
int bw = udp->write(buf, len);
|
||||
if (!bw) { return 0; }
|
||||
@ -87,7 +94,7 @@ extern "C" {
|
||||
}
|
||||
|
||||
// udp.send_multicast(payload:bytes) -> bool
|
||||
int32_t be_udp_send_mcast_ntv(WiFiUDP *udp, const uint8_t* buf, int32_t len) {
|
||||
int32_t be_udp_send_mcast_ntv(WiFiUDP46 *udp, const uint8_t* buf, int32_t len) {
|
||||
if (!udp->beginMulticastPacket()) { return 0; }
|
||||
int bw = udp->write(buf, len);
|
||||
if (!bw) { return 0; }
|
||||
@ -100,7 +107,7 @@ extern "C" {
|
||||
|
||||
// udp.read() -> bytes or nil
|
||||
int32_t be_udp_read(struct bvm *vm) {
|
||||
WiFiUDP *udp = (WiFiUDP*) be_convert_single_elt(vm, 1, NULL, NULL);
|
||||
WiFiUDP46 *udp = (WiFiUDP46*) be_convert_single_elt(vm, 1, NULL, NULL);
|
||||
if (udp->parsePacket()) {
|
||||
int btr = udp->available(); // btr contains the size of bytes_to_read
|
||||
|
||||
@ -128,7 +135,7 @@ extern "C" {
|
||||
int32_t btr2 = udp->read(buf, btr);
|
||||
|
||||
// set remotet ip
|
||||
IPAddress remote_ip = udp->remoteIP();
|
||||
IPAddress46 remote_ip = udp->remoteIP();
|
||||
be_pushstring(vm, remote_ip.toString().c_str());
|
||||
be_setmember(vm, 1, "remote_ip");
|
||||
be_pop(vm, 1);
|
||||
|
@ -118,6 +118,8 @@ struct WIFI {
|
||||
bool wifi_test_AP_TIMEOUT = false;
|
||||
bool wifi_Test_Restart = false;
|
||||
bool wifi_Test_Save_SSID2 = false;
|
||||
// IPv6 support, not guarded with #if LWIP_IPV6 to avoid bloating code with ifdefs
|
||||
bool ipv6_local_link_called = false; // did we already enable IPv6 Local-Link address, needs to be redone at each reconnect
|
||||
} Wifi;
|
||||
|
||||
typedef struct {
|
||||
|
@ -802,7 +802,9 @@ void CmndStatus(void)
|
||||
}
|
||||
|
||||
if ((0 == payload) || (5 == payload)) {
|
||||
// WifiDumpAddressesIPv6();
|
||||
#if LWIP_IPV6
|
||||
if (5 == payload) { WifiDumpAddressesIPv6(); }
|
||||
#endif // LWIP_IPV6
|
||||
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS5_NETWORK "\":{\"" D_CMND_HOSTNAME "\":\"%s\",\""
|
||||
D_CMND_IPADDRESS "\":\"%_I\",\"" D_JSON_GATEWAY "\":\"%_I\",\"" D_JSON_SUBNETMASK "\":\"%_I\",\""
|
||||
D_JSON_DNSSERVER "1\":\"%_I\",\"" D_JSON_DNSSERVER "2\":\"%_I\",\""
|
||||
|
@ -213,6 +213,9 @@ void WifiBegin(uint8_t flag, uint8_t channel) {
|
||||
#endif // USE_EMULATION
|
||||
|
||||
WiFi.persistent(false); // Solve possible wifi init errors (re-add at 6.2.1.16 #4044, #4083)
|
||||
#if LWIP_IPV6 && defined(ESP32)
|
||||
WiFi.IPv6(true);
|
||||
#endif
|
||||
|
||||
#ifdef USE_WIFI_RANGE_EXTENDER
|
||||
if (WiFi.getMode() != WIFI_AP_STA || !RgxApUp()) { // Preserve range extender connections (#17103)
|
||||
@ -518,6 +521,17 @@ bool WifiHasIP(void) {
|
||||
}
|
||||
|
||||
void WifiCheckIp(void) {
|
||||
#if LWIP_IPV6
|
||||
if (WL_CONNECTED == WiFi.status()) {
|
||||
if (!Wifi.ipv6_local_link_called) {
|
||||
WiFi.enableIpV6();
|
||||
Wifi.ipv6_local_link_called = true;
|
||||
// AddLog(LOG_LEVEL_DEBUG, PSTR("WIF: calling enableIpV6"));
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((WL_CONNECTED == WiFi.status()) && WifiHasIP()) {
|
||||
WifiSetState(1);
|
||||
Wifi.counter = WIFI_CHECK_SEC;
|
||||
@ -530,11 +544,6 @@ void WifiCheckIp(void) {
|
||||
Settings->ipv4_address[2] = (uint32_t)WiFi.subnetMask();
|
||||
Settings->ipv4_address[3] = (uint32_t)WiFi.dnsIP();
|
||||
Settings->ipv4_address[4] = (uint32_t)WiFi.dnsIP(1);
|
||||
#if LWIP_IPV6
|
||||
// create Link-local address
|
||||
CreateLinkLocalIPv6();
|
||||
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI "IPv6 Link-Local %s"), WifiGetIPv6LinkLocal().c_str());
|
||||
#endif // LWIP_IPV6
|
||||
|
||||
// Save current AP parameters for quick reconnect
|
||||
Settings->wifi_channel = WiFi.channel();
|
||||
@ -721,10 +730,21 @@ void WifiEnable(void) {
|
||||
//#include <sntp.h> // sntp_servermode_dhcp()
|
||||
//#endif // ESP8266
|
||||
|
||||
#ifdef ESP32
|
||||
void WifiEvents(arduino_event_t *event);
|
||||
#endif
|
||||
|
||||
void WifiConnect(void)
|
||||
{
|
||||
if (!Settings->flag4.network_wifi) { return; }
|
||||
|
||||
#ifdef ESP32
|
||||
static bool wifi_event_registered = false;
|
||||
if (!wifi_event_registered) {
|
||||
WiFi.onEvent(WifiEvents); // register event listener only once
|
||||
wifi_event_registered = true;
|
||||
}
|
||||
#endif // ESP32
|
||||
WifiSetState(0);
|
||||
WifiSetOutputPower();
|
||||
|
||||
@ -1039,3 +1059,51 @@ uint64_t WifiGetNtp(void) {
|
||||
ntp_server_id++; // Next server next time
|
||||
return 0;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Respond to some Arduino/esp-idf events for better IPv6 support
|
||||
// --------------------------------------------------------------------------------
|
||||
#ifdef ESP32
|
||||
#include "IPAddress46.h"
|
||||
// typedef void (*WiFiEventSysCb)(arduino_event_t *event);
|
||||
void WifiEvents(arduino_event_t *event) {
|
||||
switch (event->event_id) {
|
||||
|
||||
#if LWIP_IPV6
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
|
||||
case ARDUINO_EVENT_ETH_GOT_IP6:
|
||||
{
|
||||
ip_addr_t ip_addr6;
|
||||
ip_addr_copy_from_ip6(ip_addr6, event->event_info.got_ip6.ip6_info.ip);
|
||||
IPAddress46 addr(ip_addr6);
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("WIF: IPv6 %s %s"), addr.isLocal() ? PSTR("Link-Local") : PSTR("Global"), addr.toString().c_str());
|
||||
}
|
||||
break;
|
||||
#endif // LWIP_IPV6
|
||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
{
|
||||
ip_addr_t ip_addr4;
|
||||
ip_addr_copy_from_ip4(ip_addr4, event->event_info.got_ip.ip_info.ip);
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("WIF: IPv4 %_I, mask %_I, gateway %_I"),
|
||||
event->event_info.got_ip.ip_info.ip.addr,
|
||||
event->event_info.got_ip.ip_info.netmask.addr,
|
||||
event->event_info.got_ip.ip_info.gw.addr);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
|
||||
// AddLog(LOG_LEVEL_DEBUG, PSTR("WIF: Received ARDUINO_EVENT_WIFI_STA_CONNECTED"));
|
||||
Wifi.ipv6_local_link_called = false; // not sure if this is needed, make sure link-local is restored at each reconnect
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||
case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE:
|
||||
Wifi.ipv6_local_link_called = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // ESP32
|
||||
|
Loading…
x
Reference in New Issue
Block a user