mirror of
https://github.com/espressif/arduino-esp32
synced 2024-09-21 10:28:04 +00:00
This is a continuation on the topic of adding IPv6 Support to ESP32 Arduino (#9016)
* IPv6 for Arduino 3.0.0 * Fix warning in WifiUdp * remove comment / formating * Add zone to IPAddress and update WiFiUDP and WiFiGeneric * Add from ip_addr_t conversion and better toString implementation * Use constant for IPAddress offset @sgryphon is this better? * Combine hostByName to support both IPv6 and IPv4 results * implement logic to use v6 dns only when global v6 address is assigned and remove IPv6Address * Rename softAPenableIPv6 * Rename mDNS methods * fix IPAddress method to work with const address * Some cleanup and do not print zone in IPAddress * rename WiFiMulti method * Fix AP DHCPS not properly working on recent IDF * Add option to print the zone at the end of IPv6 @TD-er * remove log prints from hostByName * Use correct array length for listing IPv6 addresses * Implement some Tasmota requirements Added constructor that takes `const ip_addr_t *`. Added `addr_type()` getter Organize header to highlight the Espressif additions to IPAddress * add 'const' to IPAddress::addr_type() * Fix WiFiUdp not updating mapped v4 address * Update WiFiServer.cpp --------- Co-authored-by: Jason2866 <24528715+Jason2866@users.noreply.github.com> Co-authored-by: s-hadinger <49731213+s-hadinger@users.noreply.github.com>
This commit is contained in:
parent
e4d6a8abf9
commit
768719c68f
@ -51,7 +51,6 @@ set(CORE_SRCS
|
||||
cores/esp32/FunctionalInterrupt.cpp
|
||||
cores/esp32/HardwareSerial.cpp
|
||||
cores/esp32/IPAddress.cpp
|
||||
cores/esp32/IPv6Address.cpp
|
||||
cores/esp32/libb64/cdecode.c
|
||||
cores/esp32/libb64/cencode.c
|
||||
cores/esp32/main.cpp
|
||||
|
@ -1,38 +1,40 @@
|
||||
/*
|
||||
IPAddress.cpp - Base class that provides IPAddress
|
||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||
IPAddress.cpp - Base class that provides IPAddress
|
||||
Copyright (c) 2011 Adrian McEwen. 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 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.
|
||||
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
|
||||
*/
|
||||
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 <Arduino.h>
|
||||
#include <IPAddress.h>
|
||||
#include <Print.h>
|
||||
#include <StreamString.h>
|
||||
#include "IPAddress.h"
|
||||
#include "Print.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "StreamString.h"
|
||||
|
||||
IPAddress::IPAddress() : IPAddress(IPv4) {}
|
||||
|
||||
IPAddress::IPAddress(IPType ip_type)
|
||||
{
|
||||
_type = ip_type;
|
||||
_zone = IP6_NO_ZONE;
|
||||
memset(_address.bytes, 0, sizeof(_address.bytes));
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet)
|
||||
{
|
||||
_type = IPv4;
|
||||
_zone = IP6_NO_ZONE;
|
||||
memset(_address.bytes, 0, sizeof(_address.bytes));
|
||||
_address.bytes[IPADDRESS_V4_BYTES_INDEX] = first_octet;
|
||||
_address.bytes[IPADDRESS_V4_BYTES_INDEX + 1] = second_octet;
|
||||
@ -40,7 +42,7 @@ IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_oc
|
||||
_address.bytes[IPADDRESS_V4_BYTES_INDEX + 3] = fourth_octet;
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(uint8_t o1, uint8_t o2, uint8_t o3, uint8_t o4, uint8_t o5, uint8_t o6, uint8_t o7, uint8_t o8, uint8_t o9, uint8_t o10, uint8_t o11, uint8_t o12, uint8_t o13, uint8_t o14, uint8_t o15, uint8_t o16) {
|
||||
IPAddress::IPAddress(uint8_t o1, uint8_t o2, uint8_t o3, uint8_t o4, uint8_t o5, uint8_t o6, uint8_t o7, uint8_t o8, uint8_t o9, uint8_t o10, uint8_t o11, uint8_t o12, uint8_t o13, uint8_t o14, uint8_t o15, uint8_t o16, uint8_t z) {
|
||||
_type = IPv6;
|
||||
_address.bytes[0] = o1;
|
||||
_address.bytes[1] = o2;
|
||||
@ -58,12 +60,14 @@ IPAddress::IPAddress(uint8_t o1, uint8_t o2, uint8_t o3, uint8_t o4, uint8_t o5,
|
||||
_address.bytes[13] = o14;
|
||||
_address.bytes[14] = o15;
|
||||
_address.bytes[15] = o16;
|
||||
_zone = z;
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(uint32_t address)
|
||||
{
|
||||
// IPv4 only
|
||||
_type = IPv4;
|
||||
_zone = IP6_NO_ZONE;
|
||||
memset(_address.bytes, 0, sizeof(_address.bytes));
|
||||
_address.dword[IPADDRESS_V4_DWORD_INDEX] = address;
|
||||
|
||||
@ -78,14 +82,16 @@ IPAddress::IPAddress(uint32_t address)
|
||||
|
||||
IPAddress::IPAddress(const uint8_t *address) : IPAddress(IPv4, address) {}
|
||||
|
||||
IPAddress::IPAddress(IPType ip_type, const uint8_t *address)
|
||||
IPAddress::IPAddress(IPType ip_type, const uint8_t *address, uint8_t z)
|
||||
{
|
||||
_type = ip_type;
|
||||
if (ip_type == IPv4) {
|
||||
memset(_address.bytes, 0, sizeof(_address.bytes));
|
||||
memcpy(&_address.bytes[IPADDRESS_V4_BYTES_INDEX], address, sizeof(uint32_t));
|
||||
_zone = 0;
|
||||
} else {
|
||||
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||
_zone = z;
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,151 +100,20 @@ IPAddress::IPAddress(const char *address)
|
||||
fromString(address);
|
||||
}
|
||||
|
||||
IPAddress& IPAddress::operator=(const uint8_t *address)
|
||||
IPAddress::IPAddress(const IPAddress& address)
|
||||
{
|
||||
// IPv4 only conversion from byte pointer
|
||||
_type = IPv4;
|
||||
memset(_address.bytes, 0, sizeof(_address.bytes));
|
||||
memcpy(&_address.bytes[IPADDRESS_V4_BYTES_INDEX], address, sizeof(uint32_t));
|
||||
return *this;
|
||||
*this = address;
|
||||
}
|
||||
|
||||
IPAddress& IPAddress::operator=(const char *address)
|
||||
{
|
||||
fromString(address);
|
||||
return *this;
|
||||
}
|
||||
|
||||
IPAddress& IPAddress::operator=(uint32_t address)
|
||||
{
|
||||
// IPv4 conversion
|
||||
// See note on conversion/comparison and uint32_t
|
||||
_type = IPv4;
|
||||
memset(_address.bytes, 0, sizeof(_address.bytes));
|
||||
_address.dword[IPADDRESS_V4_DWORD_INDEX] = address;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool IPAddress::operator==(const IPAddress& addr) const
|
||||
{
|
||||
return (addr._type == _type)
|
||||
&& (memcmp(addr._address.bytes, _address.bytes, sizeof(_address.bytes)) == 0);
|
||||
}
|
||||
|
||||
bool IPAddress::operator==(const uint8_t* addr) const
|
||||
{
|
||||
// IPv4 only comparison to byte pointer
|
||||
// Can't support IPv6 as we know our type, but not the length of the pointer
|
||||
return _type == IPv4 && memcmp(addr, &_address.bytes[IPADDRESS_V4_BYTES_INDEX], sizeof(uint32_t)) == 0;
|
||||
}
|
||||
|
||||
uint8_t IPAddress::operator[](int index) const {
|
||||
if (_type == IPv4) {
|
||||
return _address.bytes[IPADDRESS_V4_BYTES_INDEX + index];
|
||||
}
|
||||
return _address.bytes[index];
|
||||
}
|
||||
|
||||
uint8_t& IPAddress::operator[](int index) {
|
||||
if (_type == IPv4) {
|
||||
return _address.bytes[IPADDRESS_V4_BYTES_INDEX + index];
|
||||
}
|
||||
return _address.bytes[index];
|
||||
}
|
||||
|
||||
size_t IPAddress::printTo(Print& p) const
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
if (_type == IPv6) {
|
||||
// IPv6 IETF canonical format: compress left-most longest run of two or more zero fields, lower case
|
||||
int8_t longest_start = -1;
|
||||
int8_t longest_length = 1;
|
||||
int8_t current_start = -1;
|
||||
int8_t current_length = 0;
|
||||
for (int8_t f = 0; f < 8; f++) {
|
||||
if (_address.bytes[f * 2] == 0 && _address.bytes[f * 2 + 1] == 0) {
|
||||
if (current_start == -1) {
|
||||
current_start = f;
|
||||
current_length = 1;
|
||||
} else {
|
||||
current_length++;
|
||||
}
|
||||
if (current_length > longest_length) {
|
||||
longest_start = current_start;
|
||||
longest_length = current_length;
|
||||
}
|
||||
} else {
|
||||
current_start = -1;
|
||||
}
|
||||
}
|
||||
for (int f = 0; f < 8; f++) {
|
||||
if (f < longest_start || f >= longest_start + longest_length) {
|
||||
uint8_t c1 = _address.bytes[f * 2] >> 4;
|
||||
uint8_t c2 = _address.bytes[f * 2] & 0xf;
|
||||
uint8_t c3 = _address.bytes[f * 2 + 1] >> 4;
|
||||
uint8_t c4 = _address.bytes[f * 2 + 1] & 0xf;
|
||||
if (c1 > 0) {
|
||||
n += p.print((char)(c1 < 10 ? '0' + c1 : 'a' + c1 - 10));
|
||||
}
|
||||
if (c1 > 0 || c2 > 0) {
|
||||
n += p.print((char)(c2 < 10 ? '0' + c2 : 'a' + c2 - 10));
|
||||
}
|
||||
if (c1 > 0 || c2 > 0 || c3 > 0) {
|
||||
n += p.print((char)(c3 < 10 ? '0' + c3 : 'a' + c3 - 10));
|
||||
}
|
||||
n += p.print((char)(c4 < 10 ? '0' + c4 : 'a' + c4 - 10));
|
||||
if (f < 7) {
|
||||
n += p.print(':');
|
||||
}
|
||||
} else if (f == longest_start) {
|
||||
if (longest_start == 0) {
|
||||
n += p.print(':');
|
||||
}
|
||||
n += p.print(':');
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// IPv4
|
||||
for (int i =0; i < 3; i++)
|
||||
{
|
||||
n += p.print(_address.bytes[IPADDRESS_V4_BYTES_INDEX + i], DEC);
|
||||
n += p.print('.');
|
||||
}
|
||||
n += p.print(_address.bytes[IPADDRESS_V4_BYTES_INDEX + 3], DEC);
|
||||
return n;
|
||||
}
|
||||
|
||||
String IPAddress::toString4() const
|
||||
{
|
||||
char szRet[16];
|
||||
snprintf(szRet, sizeof(szRet), "%u.%u.%u.%u", _address.bytes[IPADDRESS_V4_BYTES_INDEX], _address.bytes[IPADDRESS_V4_BYTES_INDEX + 1], _address.bytes[IPADDRESS_V4_BYTES_INDEX + 2], _address.bytes[IPADDRESS_V4_BYTES_INDEX + 3]);
|
||||
return String(szRet);
|
||||
}
|
||||
|
||||
String IPAddress::toString6() const
|
||||
String IPAddress::toString(bool includeZone) const
|
||||
{
|
||||
StreamString s;
|
||||
s.reserve(40);
|
||||
printTo(s);
|
||||
return s;
|
||||
printTo(s, includeZone);
|
||||
return String(s);
|
||||
}
|
||||
|
||||
String IPAddress::toString() const
|
||||
{
|
||||
if (_type == IPv4) {
|
||||
return toString4();
|
||||
} else {
|
||||
return toString6();
|
||||
}
|
||||
}
|
||||
|
||||
bool IPAddress::fromString(const char *address)
|
||||
{
|
||||
if (!fromString4(address))
|
||||
{
|
||||
bool IPAddress::fromString(const char *address) {
|
||||
if (!fromString4(address)) {
|
||||
return fromString6(address);
|
||||
}
|
||||
return true;
|
||||
@ -336,6 +211,12 @@ bool IPAddress::fromString6(const char *address) {
|
||||
colons++;
|
||||
acc = 0;
|
||||
}
|
||||
else if (c == '%') {
|
||||
_zone = netif_name_to_index(address);
|
||||
while(*address != '\0'){
|
||||
address++;
|
||||
}
|
||||
}
|
||||
else
|
||||
// Invalid char
|
||||
return false;
|
||||
@ -364,5 +245,186 @@ bool IPAddress::fromString6(const char *address) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// declared one time - as external in IPAddress.h
|
||||
IPAddress INADDR_NONE(0, 0, 0, 0);
|
||||
IPAddress& IPAddress::operator=(const uint8_t *address)
|
||||
{
|
||||
// IPv4 only conversion from byte pointer
|
||||
_type = IPv4;
|
||||
memset(_address.bytes, 0, sizeof(_address.bytes));
|
||||
memcpy(&_address.bytes[IPADDRESS_V4_BYTES_INDEX], address, sizeof(uint32_t));
|
||||
return *this;
|
||||
}
|
||||
|
||||
IPAddress& IPAddress::operator=(const char *address)
|
||||
{
|
||||
fromString(address);
|
||||
return *this;
|
||||
}
|
||||
|
||||
IPAddress& IPAddress::operator=(uint32_t address)
|
||||
{
|
||||
// IPv4 conversion
|
||||
// See note on conversion/comparison and uint32_t
|
||||
_type = IPv4;
|
||||
memset(_address.bytes, 0, sizeof(_address.bytes));
|
||||
_address.dword[IPADDRESS_V4_DWORD_INDEX] = address;
|
||||
return *this;
|
||||
}
|
||||
|
||||
IPAddress& IPAddress::operator=(const IPAddress& address){
|
||||
_type = address.type();
|
||||
_zone = address.zone();
|
||||
memcpy(_address.bytes, address._address.bytes, sizeof(_address.bytes));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool IPAddress::operator==(const IPAddress& addr) const {
|
||||
return (addr._type == _type)
|
||||
&& (memcmp(addr._address.bytes, _address.bytes, sizeof(_address.bytes)) == 0);
|
||||
}
|
||||
|
||||
bool IPAddress::operator==(const uint8_t* addr) const
|
||||
{
|
||||
// IPv4 only comparison to byte pointer
|
||||
// Can't support IPv6 as we know our type, but not the length of the pointer
|
||||
return _type == IPv4 && memcmp(addr, &_address.bytes[IPADDRESS_V4_BYTES_INDEX], sizeof(uint32_t)) == 0;
|
||||
}
|
||||
|
||||
uint8_t IPAddress::operator[](int index) const {
|
||||
if (_type == IPv4) {
|
||||
return _address.bytes[IPADDRESS_V4_BYTES_INDEX + index];
|
||||
}
|
||||
return _address.bytes[index];
|
||||
}
|
||||
|
||||
uint8_t& IPAddress::operator[](int index) {
|
||||
if (_type == IPv4) {
|
||||
return _address.bytes[IPADDRESS_V4_BYTES_INDEX + index];
|
||||
}
|
||||
return _address.bytes[index];
|
||||
}
|
||||
|
||||
size_t IPAddress::printTo(Print& p) const
|
||||
{
|
||||
return printTo(p, false);
|
||||
}
|
||||
|
||||
size_t IPAddress::printTo(Print& p, bool includeZone) const
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
if (_type == IPv6) {
|
||||
// IPv6 IETF canonical format: compress left-most longest run of two or more zero fields, lower case
|
||||
int8_t longest_start = -1;
|
||||
int8_t longest_length = 1;
|
||||
int8_t current_start = -1;
|
||||
int8_t current_length = 0;
|
||||
for (int8_t f = 0; f < 8; f++) {
|
||||
if (_address.bytes[f * 2] == 0 && _address.bytes[f * 2 + 1] == 0) {
|
||||
if (current_start == -1) {
|
||||
current_start = f;
|
||||
current_length = 1;
|
||||
} else {
|
||||
current_length++;
|
||||
}
|
||||
if (current_length > longest_length) {
|
||||
longest_start = current_start;
|
||||
longest_length = current_length;
|
||||
}
|
||||
} else {
|
||||
current_start = -1;
|
||||
}
|
||||
}
|
||||
for (int f = 0; f < 8; f++) {
|
||||
if (f < longest_start || f >= longest_start + longest_length) {
|
||||
uint8_t c1 = _address.bytes[f * 2] >> 4;
|
||||
uint8_t c2 = _address.bytes[f * 2] & 0xf;
|
||||
uint8_t c3 = _address.bytes[f * 2 + 1] >> 4;
|
||||
uint8_t c4 = _address.bytes[f * 2 + 1] & 0xf;
|
||||
if (c1 > 0) {
|
||||
n += p.print((char)(c1 < 10 ? '0' + c1 : 'a' + c1 - 10));
|
||||
}
|
||||
if (c1 > 0 || c2 > 0) {
|
||||
n += p.print((char)(c2 < 10 ? '0' + c2 : 'a' + c2 - 10));
|
||||
}
|
||||
if (c1 > 0 || c2 > 0 || c3 > 0) {
|
||||
n += p.print((char)(c3 < 10 ? '0' + c3 : 'a' + c3 - 10));
|
||||
}
|
||||
n += p.print((char)(c4 < 10 ? '0' + c4 : 'a' + c4 - 10));
|
||||
if (f < 7) {
|
||||
n += p.print(':');
|
||||
}
|
||||
} else if (f == longest_start) {
|
||||
if (longest_start == 0) {
|
||||
n += p.print(':');
|
||||
}
|
||||
n += p.print(':');
|
||||
}
|
||||
}
|
||||
// add a zone if zone-id is non-zero
|
||||
if(_zone > 0 && includeZone){
|
||||
n += p.print('%');
|
||||
char if_name[NETIF_NAMESIZE];
|
||||
netif_index_to_name(_zone, if_name);
|
||||
n += p.print(if_name);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// IPv4
|
||||
for (int i =0; i < 3; i++)
|
||||
{
|
||||
n += p.print(_address.bytes[IPADDRESS_V4_BYTES_INDEX + i], DEC);
|
||||
n += p.print('.');
|
||||
}
|
||||
n += p.print(_address.bytes[IPADDRESS_V4_BYTES_INDEX + 3], DEC);
|
||||
return n;
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(const ip_addr_t *addr){
|
||||
from_ip_addr_t(addr);
|
||||
}
|
||||
|
||||
void IPAddress::to_ip_addr_t(ip_addr_t* addr) const {
|
||||
if(_type == IPv6){
|
||||
addr->type = IPADDR_TYPE_V6;
|
||||
addr->u_addr.ip6.addr[0] = _address.dword[0];
|
||||
addr->u_addr.ip6.addr[1] = _address.dword[1];
|
||||
addr->u_addr.ip6.addr[2] = _address.dword[2];
|
||||
addr->u_addr.ip6.addr[3] = _address.dword[3];
|
||||
#if LWIP_IPV6_SCOPES
|
||||
addr->u_addr.ip6.zone = _zone;
|
||||
#endif /* LWIP_IPV6_SCOPES */
|
||||
} else {
|
||||
addr->type = IPADDR_TYPE_V4;
|
||||
addr->u_addr.ip4.addr = _address.dword[IPADDRESS_V4_DWORD_INDEX];
|
||||
}
|
||||
}
|
||||
|
||||
IPAddress& IPAddress::from_ip_addr_t(const ip_addr_t* addr){
|
||||
if(addr->type == IPADDR_TYPE_V6){
|
||||
_type = IPv6;
|
||||
_address.dword[0] = addr->u_addr.ip6.addr[0];
|
||||
_address.dword[1] = addr->u_addr.ip6.addr[1];
|
||||
_address.dword[2] = addr->u_addr.ip6.addr[2];
|
||||
_address.dword[3] = addr->u_addr.ip6.addr[3];
|
||||
#if LWIP_IPV6_SCOPES
|
||||
_zone = addr->u_addr.ip6.zone;
|
||||
#endif /* LWIP_IPV6_SCOPES */
|
||||
} else {
|
||||
_type = IPv4;
|
||||
_address.dword[IPADDRESS_V4_DWORD_INDEX] = addr->u_addr.ip4.addr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
esp_ip6_addr_type_t IPAddress::addr_type() const {
|
||||
if(_type != IPv6){
|
||||
return ESP_IP6_ADDR_IS_UNKNOWN;
|
||||
}
|
||||
ip_addr_t addr;
|
||||
to_ip_addr_t(&addr);
|
||||
return esp_netif_ip6_get_addr_type((esp_ip6_addr_t*)(&(addr.u_addr.ip6)));
|
||||
}
|
||||
|
||||
const IPAddress IN6ADDR_ANY(IPv6);
|
||||
const IPAddress INADDR_NONE(0,0,0,0);
|
||||
|
@ -1,82 +1,83 @@
|
||||
/*
|
||||
IPAddress.h - Base class that provides IPAddress
|
||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||
IPAddress.h - Base class that provides IPAddress
|
||||
Copyright (c) 2011 Adrian McEwen. 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 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.
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
|
||||
#ifndef IPAddress_h
|
||||
#define IPAddress_h
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <WString.h>
|
||||
#include <Printable.h>
|
||||
|
||||
// A class to make it easier to handle and pass around IP addresses
|
||||
#include "Printable.h"
|
||||
#include "WString.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "esp_netif_ip_addr.h"
|
||||
|
||||
#define IPADDRESS_V4_BYTES_INDEX 12
|
||||
#define IPADDRESS_V4_DWORD_INDEX 3
|
||||
|
||||
enum IPType
|
||||
{
|
||||
// A class to make it easier to handle and pass around IP addresses
|
||||
|
||||
enum IPType {
|
||||
IPv4,
|
||||
IPv6
|
||||
};
|
||||
|
||||
class IPAddress: public Printable
|
||||
{
|
||||
class IPAddress : public Printable {
|
||||
private:
|
||||
union {
|
||||
uint8_t bytes[16];
|
||||
uint32_t dword[4];
|
||||
} _address;
|
||||
IPType _type;
|
||||
uint8_t _zone;
|
||||
|
||||
// Access the raw byte array containing the address. Because this returns a pointer
|
||||
// to the internal structure rather than a copy of the address this function should only
|
||||
// be used when you know that the usage of the returned uint8_t* will be transient and not
|
||||
// stored.
|
||||
uint8_t* raw_address()
|
||||
{
|
||||
return _type == IPv4 ? &_address.bytes[IPADDRESS_V4_BYTES_INDEX] : _address.bytes;
|
||||
}
|
||||
uint8_t* raw_address() { return _type == IPv4 ? &_address.bytes[IPADDRESS_V4_BYTES_INDEX] : _address.bytes; }
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
|
||||
// Default IPv4
|
||||
IPAddress();
|
||||
IPAddress(IPType ip_type);
|
||||
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
|
||||
IPAddress(uint8_t o1, uint8_t o2, uint8_t o3, uint8_t o4, uint8_t o5, uint8_t o6, uint8_t o7, uint8_t o8, uint8_t o9, uint8_t o10, uint8_t o11, uint8_t o12, uint8_t o13, uint8_t o14, uint8_t o15, uint8_t o16);
|
||||
IPAddress(uint8_t o1, uint8_t o2, uint8_t o3, uint8_t o4, uint8_t o5, uint8_t o6, uint8_t o7, uint8_t o8, uint8_t o9, uint8_t o10, uint8_t o11, uint8_t o12, uint8_t o13, uint8_t o14, uint8_t o15, uint8_t o16, uint8_t z=0);
|
||||
// IPv4; see implementation note
|
||||
IPAddress(uint32_t address);
|
||||
// Default IPv4
|
||||
IPAddress(const uint8_t *address);
|
||||
IPAddress(IPType ip_type, const uint8_t *address);
|
||||
IPAddress(IPType ip_type, const uint8_t *address, uint8_t z=0);
|
||||
// If IPv4 fails tries IPv6 see fromString function
|
||||
IPAddress(const char *address);
|
||||
virtual ~IPAddress() {}
|
||||
IPAddress(const IPAddress& address);
|
||||
|
||||
bool fromString(const char *address);
|
||||
bool fromString(const String &address) { return fromString(address.c_str()); }
|
||||
|
||||
// Overloaded cast operator to allow IPAddress objects to be used where a
|
||||
// uint32_t is expected
|
||||
operator uint32_t() const
|
||||
{
|
||||
return _type == IPv4 ? _address.dword[IPADDRESS_V4_DWORD_INDEX] : 0;
|
||||
}
|
||||
// Overloaded cast operator to allow IPAddress objects to be used where a uint32_t is expected
|
||||
// NOTE: IPv4 only; see implementation note
|
||||
operator uint32_t() const { return _type == IPv4 ? _address.dword[IPADDRESS_V4_DWORD_INDEX] : 0; };
|
||||
|
||||
bool operator==(const IPAddress& addr) const;
|
||||
bool operator!=(const IPAddress& addr) const { return !(*this == addr); };
|
||||
|
||||
// NOTE: IPv4 only; we don't know the length of the pointer
|
||||
bool operator==(const uint8_t* addr) const;
|
||||
|
||||
// Overloaded index operator to allow getting and setting individual octets of the address
|
||||
@ -84,31 +85,35 @@ public:
|
||||
uint8_t& operator[](int index);
|
||||
|
||||
// Overloaded copy operators to allow initialisation of IPAddress objects from other types
|
||||
// NOTE: IPv4 only
|
||||
IPAddress& operator=(const uint8_t *address);
|
||||
// NOTE: IPv4 only; see implementation note
|
||||
IPAddress& operator=(uint32_t address);
|
||||
// If IPv4 fails tries IPv6 see fromString function
|
||||
IPAddress& operator=(const char *address);
|
||||
IPAddress& operator=(const IPAddress& address);
|
||||
|
||||
virtual size_t printTo(Print& p) const;
|
||||
String toString() const;
|
||||
String toString(bool includeZone = false) const;
|
||||
|
||||
IPType type() const { return _type; }
|
||||
|
||||
friend class EthernetClass;
|
||||
// Espresif LwIP conversions
|
||||
IPAddress(const ip_addr_t *addr);
|
||||
void to_ip_addr_t(ip_addr_t* addr) const;
|
||||
IPAddress& from_ip_addr_t(const ip_addr_t* addr);
|
||||
esp_ip6_addr_type_t addr_type() const;
|
||||
uint8_t zone() const { return (type() == IPv6)?_zone:0; }
|
||||
size_t printTo(Print& p, bool includeZone) const;
|
||||
|
||||
friend class UDP;
|
||||
friend class Client;
|
||||
friend class Server;
|
||||
friend class DhcpClass;
|
||||
friend class DNSClient;
|
||||
|
||||
protected:
|
||||
bool fromString4(const char *address);
|
||||
bool fromString6(const char *address);
|
||||
String toString4() const;
|
||||
String toString6() const;
|
||||
};
|
||||
|
||||
// changed to extern because const declaration creates copies in BSS of INADDR_NONE for each CPP unit that includes it
|
||||
extern IPAddress INADDR_NONE;
|
||||
extern IPAddress IN6ADDR_ANY;
|
||||
#endif
|
||||
extern const IPAddress IN6ADDR_ANY;
|
||||
extern const IPAddress INADDR_NONE;
|
||||
|
@ -1,90 +0,0 @@
|
||||
/*
|
||||
IPv6Address.cpp - Base class that provides IPv6Address
|
||||
Copyright (c) 2011 Adrian McEwen. 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 <Arduino.h>
|
||||
#include <IPv6Address.h>
|
||||
#include <Print.h>
|
||||
|
||||
IPv6Address::IPv6Address()
|
||||
{
|
||||
memset(_address.bytes, 0, sizeof(_address.bytes));
|
||||
}
|
||||
|
||||
IPv6Address::IPv6Address(const uint8_t *address)
|
||||
{
|
||||
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||
}
|
||||
|
||||
IPv6Address::IPv6Address(const uint32_t *address)
|
||||
{
|
||||
memcpy(_address.bytes, (const uint8_t *)address, sizeof(_address.bytes));
|
||||
}
|
||||
|
||||
IPv6Address& IPv6Address::operator=(const uint8_t *address)
|
||||
{
|
||||
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool IPv6Address::operator==(const uint8_t* addr) const
|
||||
{
|
||||
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
|
||||
}
|
||||
|
||||
size_t IPv6Address::printTo(Print& p) const
|
||||
{
|
||||
size_t n = 0;
|
||||
for(int i = 0; i < 16; i+=2) {
|
||||
if(i){
|
||||
n += p.print(':');
|
||||
}
|
||||
n += p.printf("%02x", _address.bytes[i]);
|
||||
n += p.printf("%02x", _address.bytes[i+1]);
|
||||
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
String IPv6Address::toString() const
|
||||
{
|
||||
char szRet[40];
|
||||
sprintf(szRet,"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
|
||||
_address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3],
|
||||
_address.bytes[4], _address.bytes[5], _address.bytes[6], _address.bytes[7],
|
||||
_address.bytes[8], _address.bytes[9], _address.bytes[10], _address.bytes[11],
|
||||
_address.bytes[12], _address.bytes[13], _address.bytes[14], _address.bytes[15]);
|
||||
return String(szRet);
|
||||
}
|
||||
|
||||
bool IPv6Address::fromString(const char *address)
|
||||
{
|
||||
//format 0011:2233:4455:6677:8899:aabb:ccdd:eeff
|
||||
if(strlen(address) != 39){
|
||||
return false;
|
||||
}
|
||||
char * pos = (char *)address;
|
||||
size_t i = 0;
|
||||
for(i = 0; i < 16; i+=2) {
|
||||
if(!sscanf(pos, "%2hhx", &_address.bytes[i]) || !sscanf(pos+2, "%2hhx", &_address.bytes[i+1])){
|
||||
return false;
|
||||
}
|
||||
pos += 5;
|
||||
}
|
||||
return true;
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
/*
|
||||
IPv6Address.h - Base class that provides IPv6Address
|
||||
Copyright (c) 2011 Adrian McEwen. 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
|
||||
*/
|
||||
|
||||
#ifndef IPv6Address_h
|
||||
#define IPv6Address_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <WString.h>
|
||||
#include <Printable.h>
|
||||
|
||||
// A class to make it easier to handle and pass around IP addresses
|
||||
|
||||
class IPv6Address: public Printable
|
||||
{
|
||||
private:
|
||||
union {
|
||||
uint8_t bytes[16]; // IPv4 address
|
||||
uint32_t dword[4];
|
||||
} _address;
|
||||
|
||||
// Access the raw byte array containing the address. Because this returns a pointer
|
||||
// to the internal structure rather than a copy of the address this function should only
|
||||
// be used when you know that the usage of the returned uint8_t* will be transient and not
|
||||
// stored.
|
||||
uint8_t* raw_address()
|
||||
{
|
||||
return _address.bytes;
|
||||
}
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
IPv6Address();
|
||||
IPv6Address(const uint8_t *address);
|
||||
IPv6Address(const uint32_t *address);
|
||||
virtual ~IPv6Address() {}
|
||||
|
||||
bool fromString(const char *address);
|
||||
bool fromString(const String &address) { return fromString(address.c_str()); }
|
||||
|
||||
operator const uint8_t*() const
|
||||
{
|
||||
return _address.bytes;
|
||||
}
|
||||
operator const uint32_t*() const
|
||||
{
|
||||
return _address.dword;
|
||||
}
|
||||
bool operator==(const IPv6Address& addr) const
|
||||
{
|
||||
return (_address.dword[0] == addr._address.dword[0])
|
||||
&& (_address.dword[1] == addr._address.dword[1])
|
||||
&& (_address.dword[2] == addr._address.dword[2])
|
||||
&& (_address.dword[3] == addr._address.dword[3]);
|
||||
}
|
||||
bool operator==(const uint8_t* addr) const;
|
||||
|
||||
// Overloaded index operator to allow getting and setting individual octets of the address
|
||||
uint8_t operator[](int index) const
|
||||
{
|
||||
return _address.bytes[index];
|
||||
}
|
||||
uint8_t& operator[](int index)
|
||||
{
|
||||
return _address.bytes[index];
|
||||
}
|
||||
|
||||
// Overloaded copy operators to allow initialisation of IPv6Address objects from other types
|
||||
IPv6Address& operator=(const uint8_t *address);
|
||||
|
||||
virtual size_t printTo(Print& p) const;
|
||||
String toString() const;
|
||||
|
||||
friend class UDP;
|
||||
friend class Client;
|
||||
friend class Server;
|
||||
};
|
||||
|
||||
#endif
|
@ -21,7 +21,8 @@
|
||||
|
||||
#ifndef STREAMSTRING_H_
|
||||
#define STREAMSTRING_H_
|
||||
|
||||
#include "Stream.h"
|
||||
#include "WString.h"
|
||||
|
||||
class StreamString: public Stream, public String
|
||||
{
|
||||
|
@ -327,14 +327,14 @@ Get the softAP subnet mask.
|
||||
|
||||
IPAddress softAPSubnetMask();
|
||||
|
||||
softAPenableIpV6
|
||||
softAPenableIPv6
|
||||
****************
|
||||
|
||||
Function used to enable the IPv6 support.
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
bool softAPenableIpV6();
|
||||
bool softAPenableIPv6(bool enable=true);
|
||||
|
||||
The function will return ``true`` if the configuration is successful.
|
||||
|
||||
@ -345,9 +345,9 @@ Function to get the IPv6 address.
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
IPv6Address softAPIPv6();
|
||||
IPAddress softAPIPv6();
|
||||
|
||||
The function will return the AP IPv6 address in ``IPv6Address`` format.
|
||||
The function will return the AP IPv6 address in ``IPAddress`` format.
|
||||
|
||||
softAPgetHostname
|
||||
*****************
|
||||
|
@ -424,12 +424,12 @@ IPAddress AsyncUDPPacket::localIP()
|
||||
return IPAddress(_localIp.u_addr.ip4.addr);
|
||||
}
|
||||
|
||||
IPv6Address AsyncUDPPacket::localIPv6()
|
||||
IPAddress AsyncUDPPacket::localIPv6()
|
||||
{
|
||||
if(_localIp.type != IPADDR_TYPE_V6){
|
||||
return IPv6Address();
|
||||
return IPAddress(IPv6);
|
||||
}
|
||||
return IPv6Address(_localIp.u_addr.ip6.addr);
|
||||
return IPAddress(IPv6, (const uint8_t *)_localIp.u_addr.ip6.addr, _localIp.u_addr.ip6.zone);
|
||||
}
|
||||
|
||||
uint16_t AsyncUDPPacket::localPort()
|
||||
@ -445,12 +445,12 @@ IPAddress AsyncUDPPacket::remoteIP()
|
||||
return IPAddress(_remoteIp.u_addr.ip4.addr);
|
||||
}
|
||||
|
||||
IPv6Address AsyncUDPPacket::remoteIPv6()
|
||||
IPAddress AsyncUDPPacket::remoteIPv6()
|
||||
{
|
||||
if(_remoteIp.type != IPADDR_TYPE_V6){
|
||||
return IPv6Address();
|
||||
return IPAddress(IPv6);
|
||||
}
|
||||
return IPv6Address(_remoteIp.u_addr.ip6.addr);
|
||||
return IPAddress(IPv6, (const uint8_t *)_remoteIp.u_addr.ip6.addr, _remoteIp.u_addr.ip6.zone);
|
||||
}
|
||||
|
||||
uint16_t AsyncUDPPacket::remotePort()
|
||||
@ -739,32 +739,28 @@ bool AsyncUDP::listen(uint16_t port)
|
||||
bool AsyncUDP::listen(const IPAddress addr, uint16_t port)
|
||||
{
|
||||
ip_addr_t laddr;
|
||||
laddr.type = IPADDR_TYPE_V4;
|
||||
laddr.u_addr.ip4.addr = addr;
|
||||
addr.to_ip_addr_t(&laddr);
|
||||
return listen(&laddr, port);
|
||||
}
|
||||
|
||||
bool AsyncUDP::listenMulticast(const IPAddress addr, uint16_t port, uint8_t ttl, tcpip_adapter_if_t tcpip_if)
|
||||
{
|
||||
ip_addr_t laddr;
|
||||
laddr.type = IPADDR_TYPE_V4;
|
||||
laddr.u_addr.ip4.addr = addr;
|
||||
addr.to_ip_addr_t(&laddr);
|
||||
return listenMulticast(&laddr, port, ttl, tcpip_if);
|
||||
}
|
||||
|
||||
bool AsyncUDP::connect(const IPAddress addr, uint16_t port)
|
||||
{
|
||||
ip_addr_t daddr;
|
||||
daddr.type = IPADDR_TYPE_V4;
|
||||
daddr.u_addr.ip4.addr = addr;
|
||||
addr.to_ip_addr_t(&daddr);
|
||||
return connect(&daddr, port);
|
||||
}
|
||||
|
||||
size_t AsyncUDP::writeTo(const uint8_t *data, size_t len, const IPAddress addr, uint16_t port, tcpip_adapter_if_t tcpip_if)
|
||||
{
|
||||
ip_addr_t daddr;
|
||||
daddr.type = IPADDR_TYPE_V4;
|
||||
daddr.u_addr.ip4.addr = addr;
|
||||
addr.to_ip_addr_t(&daddr);
|
||||
return writeTo(data, len, &daddr, port, tcpip_if);
|
||||
}
|
||||
|
||||
@ -776,44 +772,12 @@ IPAddress AsyncUDP::listenIP()
|
||||
return IPAddress(_pcb->remote_ip.u_addr.ip4.addr);
|
||||
}
|
||||
|
||||
bool AsyncUDP::listen(const IPv6Address addr, uint16_t port)
|
||||
{
|
||||
ip_addr_t laddr;
|
||||
laddr.type = IPADDR_TYPE_V6;
|
||||
memcpy((uint8_t*)(laddr.u_addr.ip6.addr), (const uint8_t*)addr, 16);
|
||||
return listen(&laddr, port);
|
||||
}
|
||||
|
||||
bool AsyncUDP::listenMulticast(const IPv6Address addr, uint16_t port, uint8_t ttl, tcpip_adapter_if_t tcpip_if)
|
||||
{
|
||||
ip_addr_t laddr;
|
||||
laddr.type = IPADDR_TYPE_V6;
|
||||
memcpy((uint8_t*)(laddr.u_addr.ip6.addr), (const uint8_t*)addr, 16);
|
||||
return listenMulticast(&laddr, port, ttl, tcpip_if);
|
||||
}
|
||||
|
||||
bool AsyncUDP::connect(const IPv6Address addr, uint16_t port)
|
||||
{
|
||||
ip_addr_t daddr;
|
||||
daddr.type = IPADDR_TYPE_V6;
|
||||
memcpy((uint8_t*)(daddr.u_addr.ip6.addr), (const uint8_t*)addr, 16);
|
||||
return connect(&daddr, port);
|
||||
}
|
||||
|
||||
size_t AsyncUDP::writeTo(const uint8_t *data, size_t len, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if)
|
||||
{
|
||||
ip_addr_t daddr;
|
||||
daddr.type = IPADDR_TYPE_V6;
|
||||
memcpy((uint8_t*)(daddr.u_addr.ip6.addr), (const uint8_t*)addr, 16);
|
||||
return writeTo(data, len, &daddr, port, tcpip_if);
|
||||
}
|
||||
|
||||
IPv6Address AsyncUDP::listenIPv6()
|
||||
IPAddress AsyncUDP::listenIPv6()
|
||||
{
|
||||
if(!_pcb || _pcb->remote_ip.type != IPADDR_TYPE_V6){
|
||||
return IPv6Address();
|
||||
return IPAddress(IPv6);
|
||||
}
|
||||
return IPv6Address(_pcb->remote_ip.u_addr.ip6.addr);
|
||||
return IPAddress(IPv6, (const uint8_t *)_pcb->remote_ip.u_addr.ip6.addr, _pcb->remote_ip.u_addr.ip6.zone);
|
||||
}
|
||||
|
||||
size_t AsyncUDP::write(const uint8_t *data, size_t len)
|
||||
@ -866,14 +830,6 @@ size_t AsyncUDP::sendTo(AsyncUDPMessage &message, const IPAddress addr, uint16_t
|
||||
return writeTo(message.data(), message.length(), addr, port, tcpip_if);
|
||||
}
|
||||
|
||||
size_t AsyncUDP::sendTo(AsyncUDPMessage &message, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if)
|
||||
{
|
||||
if(!message) {
|
||||
return 0;
|
||||
}
|
||||
return writeTo(message.data(), message.length(), addr, port, tcpip_if);
|
||||
}
|
||||
|
||||
size_t AsyncUDP::send(AsyncUDPMessage &message)
|
||||
{
|
||||
if(!message) {
|
||||
|
@ -2,7 +2,6 @@
|
||||
#define ESPASYNCUDP_H
|
||||
|
||||
#include "IPAddress.h"
|
||||
#include "IPv6Address.h"
|
||||
#include "Print.h"
|
||||
#include "Stream.h"
|
||||
#include <functional>
|
||||
@ -81,10 +80,10 @@ public:
|
||||
tcpip_adapter_if_t interface();
|
||||
|
||||
IPAddress localIP();
|
||||
IPv6Address localIPv6();
|
||||
IPAddress localIPv6();
|
||||
uint16_t localPort();
|
||||
IPAddress remoteIP();
|
||||
IPv6Address remoteIPv6();
|
||||
IPAddress remoteIPv6();
|
||||
uint16_t remotePort();
|
||||
void remoteMac(uint8_t * mac);
|
||||
|
||||
@ -121,22 +120,18 @@ public:
|
||||
|
||||
bool listen(const ip_addr_t *addr, uint16_t port);
|
||||
bool listen(const IPAddress addr, uint16_t port);
|
||||
bool listen(const IPv6Address addr, uint16_t port);
|
||||
bool listen(uint16_t port);
|
||||
|
||||
bool listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
|
||||
bool listenMulticast(const IPAddress addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
|
||||
bool listenMulticast(const IPv6Address addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
|
||||
|
||||
bool connect(const ip_addr_t *addr, uint16_t port);
|
||||
bool connect(const IPAddress addr, uint16_t port);
|
||||
bool connect(const IPv6Address addr, uint16_t port);
|
||||
|
||||
void close();
|
||||
|
||||
size_t writeTo(const uint8_t *data, size_t len, const ip_addr_t *addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
|
||||
size_t writeTo(const uint8_t *data, size_t len, const IPAddress addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
|
||||
size_t writeTo(const uint8_t *data, size_t len, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
|
||||
size_t write(const uint8_t *data, size_t len);
|
||||
size_t write(uint8_t data);
|
||||
|
||||
@ -147,14 +142,13 @@ public:
|
||||
|
||||
size_t sendTo(AsyncUDPMessage &message, const ip_addr_t *addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
|
||||
size_t sendTo(AsyncUDPMessage &message, const IPAddress addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
|
||||
size_t sendTo(AsyncUDPMessage &message, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
|
||||
size_t send(AsyncUDPMessage &message);
|
||||
|
||||
size_t broadcastTo(AsyncUDPMessage &message, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
|
||||
size_t broadcast(AsyncUDPMessage &message);
|
||||
|
||||
IPAddress listenIP();
|
||||
IPv6Address listenIPv6();
|
||||
IPAddress listenIPv6();
|
||||
bool connected();
|
||||
esp_err_t lastErr();
|
||||
operator bool();
|
||||
|
@ -70,7 +70,7 @@ void browseService(const char * service, const char * proto){
|
||||
Serial.print(": ");
|
||||
Serial.print(MDNS.hostname(i));
|
||||
Serial.print(" (");
|
||||
Serial.print(MDNS.IP(i));
|
||||
Serial.print(MDNS.address(i));
|
||||
Serial.print(":");
|
||||
Serial.print(MDNS.port(i));
|
||||
Serial.println(")");
|
||||
|
@ -265,7 +265,7 @@ String MDNSResponder::hostname(int idx) {
|
||||
return String(result->hostname);
|
||||
}
|
||||
|
||||
IPAddress MDNSResponder::IP(int idx) {
|
||||
IPAddress MDNSResponder::address(int idx) {
|
||||
mdns_result_t * result = _getResult(idx);
|
||||
if(!result){
|
||||
log_e("Result %d not found", idx);
|
||||
@ -281,20 +281,20 @@ IPAddress MDNSResponder::IP(int idx) {
|
||||
return IPAddress();
|
||||
}
|
||||
|
||||
IPv6Address MDNSResponder::IPv6(int idx) {
|
||||
IPAddress MDNSResponder::addressV6(int idx) {
|
||||
mdns_result_t * result = _getResult(idx);
|
||||
if(!result){
|
||||
log_e("Result %d not found", idx);
|
||||
return IPv6Address();
|
||||
return IPAddress(IPv6);
|
||||
}
|
||||
mdns_ip_addr_t * addr = result->addr;
|
||||
while(addr){
|
||||
if(addr->addr.type == MDNS_IP_PROTOCOL_V6){
|
||||
return IPv6Address(addr->addr.u_addr.ip6.addr);
|
||||
return IPAddress(IPv6, (const uint8_t *)addr->addr.u_addr.ip6.addr, addr->addr.u_addr.ip6.zone);
|
||||
}
|
||||
addr = addr->next;
|
||||
}
|
||||
return IPv6Address();
|
||||
return IPAddress(IPv6);
|
||||
}
|
||||
|
||||
uint16_t MDNSResponder::port(int idx) {
|
||||
|
@ -42,7 +42,6 @@ License (MIT license):
|
||||
#define ESP32MDNS_H
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "IPv6Address.h"
|
||||
#include "mdns.h"
|
||||
#include "esp_interface.h"
|
||||
|
||||
@ -108,8 +107,8 @@ public:
|
||||
}
|
||||
|
||||
String hostname(int idx);
|
||||
IPAddress IP(int idx);
|
||||
IPv6Address IPv6(int idx);
|
||||
IPAddress address(int idx);
|
||||
IPAddress addressV6(int idx);
|
||||
uint16_t port(int idx);
|
||||
int numTxt(int idx);
|
||||
bool hasTxt(int idx, const char * key);
|
||||
|
@ -401,13 +401,13 @@ bool ETHClass::beginSPI(eth_phy_type_t type, uint8_t phy_addr, int cs, int irq,
|
||||
|
||||
// Init SPI bus
|
||||
if(_pin_sck >= 0 && _pin_miso >= 0 && _pin_mosi >= 0){
|
||||
spi_bus_config_t buscfg = {
|
||||
.mosi_io_num = _pin_mosi,
|
||||
.miso_io_num = _pin_miso,
|
||||
.sclk_io_num = _pin_sck,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
};
|
||||
spi_bus_config_t buscfg;
|
||||
memset(&buscfg, 0, sizeof(spi_bus_config_t));
|
||||
buscfg.mosi_io_num = _pin_mosi;
|
||||
buscfg.miso_io_num = _pin_miso;
|
||||
buscfg.sclk_io_num = _pin_sck;
|
||||
buscfg.quadwp_io_num = -1;
|
||||
buscfg.quadhd_io_num = -1;
|
||||
ret = spi_bus_initialize(spi_host, &buscfg, SPI_DMA_CH_AUTO);
|
||||
if(ret != ESP_OK){
|
||||
log_e("SPI bus initialize failed: %d", ret);
|
||||
@ -433,13 +433,13 @@ bool ETHClass::beginSPI(eth_phy_type_t type, uint8_t phy_addr, int cs, int irq,
|
||||
phy_config.reset_gpio_num = _pin_rst;
|
||||
|
||||
// Configure SPI interface for specific SPI module
|
||||
spi_device_interface_config_t spi_devcfg = {
|
||||
.mode = 0,
|
||||
.clock_speed_hz = _spi_freq_mhz * 1000 * 1000,
|
||||
.input_delay_ns = 20,
|
||||
.spics_io_num = _pin_cs,
|
||||
.queue_size = 20,
|
||||
};
|
||||
spi_device_interface_config_t spi_devcfg;
|
||||
memset(&spi_devcfg, 0, sizeof(spi_device_interface_config_t));
|
||||
spi_devcfg.mode = 0;
|
||||
spi_devcfg.clock_speed_hz = _spi_freq_mhz * 1000 * 1000;
|
||||
spi_devcfg.input_delay_ns = 20;
|
||||
spi_devcfg.spics_io_num = _pin_cs;
|
||||
spi_devcfg.queue_size = 20;
|
||||
|
||||
esp_eth_mac_t *mac = NULL;
|
||||
esp_eth_phy_t *phy = NULL;
|
||||
@ -861,24 +861,42 @@ bool ETHClass::setHostname(const char * hostname)
|
||||
return esp_netif_set_hostname(_esp_netif, hostname) == 0;
|
||||
}
|
||||
|
||||
bool ETHClass::enableIpV6()
|
||||
bool ETHClass::enableIPv6(bool en)
|
||||
{
|
||||
if(_esp_netif == NULL){
|
||||
return false;
|
||||
// if(_esp_netif == NULL){
|
||||
// return false;
|
||||
// }
|
||||
// return esp_netif_create_ip6_linklocal(_esp_netif) == 0;
|
||||
if (en) {
|
||||
WiFiGenericClass::setStatusBits(ETH_WANT_IP6_BIT);
|
||||
} else {
|
||||
WiFiGenericClass::clearStatusBits(ETH_WANT_IP6_BIT);
|
||||
}
|
||||
return esp_netif_create_ip6_linklocal(_esp_netif) == 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
IPv6Address ETHClass::localIPv6()
|
||||
IPAddress ETHClass::localIPv6()
|
||||
{
|
||||
if(_esp_netif == NULL){
|
||||
return IPv6Address();
|
||||
return IPAddress(IPv6);
|
||||
}
|
||||
static esp_ip6_addr_t addr;
|
||||
if(esp_netif_get_ip6_linklocal(_esp_netif, &addr)){
|
||||
return IPv6Address();
|
||||
return IPAddress(IPv6);
|
||||
}
|
||||
return IPv6Address(addr.addr);
|
||||
return IPAddress(IPv6, (const uint8_t *)addr.addr, addr.zone);
|
||||
}
|
||||
|
||||
IPAddress ETHClass::globalIPv6()
|
||||
{
|
||||
if(_esp_netif == NULL){
|
||||
return IPAddress(IPv6);
|
||||
}
|
||||
static esp_ip6_addr_t addr;
|
||||
if(esp_netif_get_ip6_global(_esp_netif, &addr)){
|
||||
return IPAddress(IPv6);
|
||||
}
|
||||
return IPAddress(IPv6, (const uint8_t *)addr.addr, addr.zone);
|
||||
}
|
||||
|
||||
const char * ETHClass::ifkey(void)
|
||||
@ -1031,6 +1049,28 @@ void ETHClass::printInfo(Print & out){
|
||||
out.print(dnsIP());
|
||||
out.println();
|
||||
|
||||
static const char * types[] = { "UNKNOWN", "GLOBAL", "LINK_LOCAL", "SITE_LOCAL", "UNIQUE_LOCAL", "IPV4_MAPPED_IPV6" };
|
||||
esp_ip6_addr_t if_ip6[CONFIG_LWIP_IPV6_NUM_ADDRESSES];
|
||||
int v6addrs = esp_netif_get_all_ip6(_esp_netif, if_ip6);
|
||||
for (int i = 0; i < v6addrs; ++i){
|
||||
out.print(" ");
|
||||
out.print("inet6 ");
|
||||
IPAddress(IPv6, (const uint8_t *)if_ip6[i].addr, if_ip6[i].zone).printTo(out, true);
|
||||
out.print(" type ");
|
||||
out.print(types[esp_netif_ip6_get_addr_type(&if_ip6[i])]);
|
||||
out.println();
|
||||
}
|
||||
|
||||
// out.print(" ");
|
||||
// out.print("inet6 ");
|
||||
// localIPv6().printTo(out);
|
||||
// out.println();
|
||||
|
||||
// out.print(" ");
|
||||
// out.print("inet6 ");
|
||||
// globalIPv6().printTo(out);
|
||||
// out.println();
|
||||
|
||||
out.println();
|
||||
}
|
||||
|
||||
|
@ -145,8 +145,9 @@ class ETHClass {
|
||||
IPAddress broadcastIP();
|
||||
IPAddress networkID();
|
||||
uint8_t subnetCIDR();
|
||||
bool enableIpV6();
|
||||
IPv6Address localIPv6();
|
||||
bool enableIPv6(bool en=true);
|
||||
IPAddress localIPv6();
|
||||
IPAddress globalIPv6();
|
||||
const char * ifkey(void);
|
||||
const char * desc(void);
|
||||
String impl_name(void);
|
||||
|
@ -89,7 +89,6 @@ void WiFiEvent(WiFiEvent_t event){
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
|
||||
Serial.println("STA Connected");
|
||||
WiFi.enableIpV6();
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
|
||||
Serial.print("STA IPv6: ");
|
||||
@ -114,6 +113,7 @@ void setup() {
|
||||
Serial.begin(115200);
|
||||
pinMode(0, INPUT_PULLUP);
|
||||
WiFi.onEvent(WiFiEvent); // Will call WiFiEvent() from another thread.
|
||||
WiFi.enableIPv6();
|
||||
Serial.print("ESP32 SDK: ");
|
||||
Serial.println(ESP.getSdkVersion());
|
||||
Serial.println("Press the button to select the next mode");
|
||||
|
@ -70,16 +70,12 @@ void WiFiEvent(WiFiEvent_t event){
|
||||
case ARDUINO_EVENT_WIFI_AP_START:
|
||||
//can set ap hostname here
|
||||
WiFi.softAPsetHostname(AP_SSID);
|
||||
//enable ap ipv6 here
|
||||
WiFi.softAPenableIpV6();
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_START:
|
||||
//set sta hostname here
|
||||
WiFi.setHostname(AP_SSID);
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
|
||||
//enable sta ipv6 here
|
||||
WiFi.enableIpV6();
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
|
||||
Serial.print("STA IPv6: ");
|
||||
@ -107,7 +103,11 @@ void setup(){
|
||||
WiFi.disconnect(true);
|
||||
WiFi.onEvent(WiFiEvent); // Will call WiFiEvent() from another thread.
|
||||
WiFi.mode(WIFI_MODE_APSTA);
|
||||
//enable ap ipv6 here
|
||||
WiFi.softAPenableIPv6();
|
||||
WiFi.softAP(AP_SSID);
|
||||
//enable sta ipv6 here
|
||||
WiFi.enableIPv6();
|
||||
WiFi.begin(STA_SSID, STA_PASS);
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,6 @@
|
||||
|
||||
#include "Print.h"
|
||||
#include "IPAddress.h"
|
||||
#include "IPv6Address.h"
|
||||
|
||||
#include "WiFiType.h"
|
||||
#include "WiFiSTA.h"
|
||||
|
@ -411,26 +411,35 @@ bool WiFiAPClass::softAPsetHostname(const char * hostname)
|
||||
* Enable IPv6 on the softAP interface.
|
||||
* @return true on success
|
||||
*/
|
||||
bool WiFiAPClass::softAPenableIpV6()
|
||||
bool WiFiAPClass::softAPenableIPv6(bool enable)
|
||||
{
|
||||
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
|
||||
return false;
|
||||
if (enable) {
|
||||
WiFiGenericClass::setStatusBits(AP_WANT_IP6_BIT);
|
||||
} else {
|
||||
WiFiGenericClass::clearStatusBits(AP_WANT_IP6_BIT);
|
||||
}
|
||||
return esp_netif_create_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_AP)) == ESP_OK;
|
||||
return true;
|
||||
// if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
|
||||
// return false;
|
||||
// }
|
||||
// return esp_netif_create_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_AP)) == ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the softAP interface IPv6 address.
|
||||
* @return IPv6Address softAP IPv6
|
||||
* @return IPAddress softAP IPv6
|
||||
*/
|
||||
IPv6Address WiFiAPClass::softAPIPv6()
|
||||
|
||||
IPAddress WiFiAPClass::softAPIPv6()
|
||||
{
|
||||
esp_ip6_addr_t addr;
|
||||
static esp_ip6_addr_t addr;
|
||||
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
|
||||
return IPv6Address();
|
||||
return IPAddress(IPv6);
|
||||
}
|
||||
if(esp_netif_get_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_AP), &addr)) {
|
||||
return IPv6Address();
|
||||
|
||||
if(esp_netif_get_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_STA), &addr)){
|
||||
return IPAddress(IPv6);
|
||||
}
|
||||
return IPv6Address(addr.addr);
|
||||
return IPAddress(IPv6, (const uint8_t *)addr.addr, addr.zone);
|
||||
}
|
||||
|
||||
|
@ -56,8 +56,8 @@ public:
|
||||
IPAddress softAPSubnetMask();
|
||||
uint8_t softAPSubnetCIDR();
|
||||
|
||||
bool softAPenableIpV6();
|
||||
IPv6Address softAPIPv6();
|
||||
bool softAPenableIPv6(bool enable=true);
|
||||
IPAddress softAPIPv6();
|
||||
|
||||
const char * softAPgetHostname();
|
||||
bool softAPsetHostname(const char * hostname);
|
||||
|
@ -23,6 +23,11 @@
|
||||
#include <lwip/netdb.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define IN6_IS_ADDR_V4MAPPED(a) \
|
||||
((((__const uint32_t *) (a))[0] == 0) \
|
||||
&& (((__const uint32_t *) (a))[1] == 0) \
|
||||
&& (((__const uint32_t *) (a))[2] == htonl (0xffff)))
|
||||
|
||||
#define WIFI_CLIENT_DEF_CONN_TIMEOUT_MS (3000)
|
||||
#define WIFI_CLIENT_MAX_WRITE_RETRY (10)
|
||||
#define WIFI_CLIENT_SELECT_TIMEOUT_US (1000000)
|
||||
@ -219,22 +224,33 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
|
||||
{
|
||||
return connect(ip,port,_timeout);
|
||||
}
|
||||
|
||||
int WiFiClient::connect(IPAddress ip, uint16_t port, int32_t timeout_ms)
|
||||
{
|
||||
struct sockaddr_storage serveraddr = {};
|
||||
_timeout = timeout_ms;
|
||||
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
int sockfd = -1;
|
||||
|
||||
if (ip.type() == IPv6) {
|
||||
struct sockaddr_in6 *tmpaddr = (struct sockaddr_in6 *)&serveraddr;
|
||||
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
tmpaddr->sin6_family = AF_INET6;
|
||||
memcpy(tmpaddr->sin6_addr.un.u8_addr, &ip[0], 16);
|
||||
tmpaddr->sin6_port = htons(port);
|
||||
tmpaddr->sin6_scope_id = ip.zone();
|
||||
} else {
|
||||
struct sockaddr_in *tmpaddr = (struct sockaddr_in *)&serveraddr;
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
tmpaddr->sin_family = AF_INET;
|
||||
tmpaddr->sin_addr.s_addr = ip;
|
||||
tmpaddr->sin_port = htons(port);
|
||||
}
|
||||
if (sockfd < 0) {
|
||||
log_e("socket: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
fcntl( sockfd, F_SETFL, fcntl( sockfd, F_GETFL, 0 ) | O_NONBLOCK );
|
||||
|
||||
uint32_t ip_addr = ip;
|
||||
struct sockaddr_in serveraddr;
|
||||
memset((char *) &serveraddr, 0, sizeof(serveraddr));
|
||||
serveraddr.sin_family = AF_INET;
|
||||
memcpy((void *)&serveraddr.sin_addr.s_addr, (const void *)(&ip_addr), 4);
|
||||
serveraddr.sin_port = htons(port);
|
||||
fd_set fdset;
|
||||
struct timeval tv;
|
||||
FD_ZERO(&fdset);
|
||||
@ -574,8 +590,24 @@ IPAddress WiFiClient::remoteIP(int fd) const
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t len = sizeof addr;
|
||||
getpeername(fd, (struct sockaddr*)&addr, &len);
|
||||
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
|
||||
return IPAddress((uint32_t)(s->sin_addr.s_addr));
|
||||
|
||||
// IPv4 socket, old way
|
||||
if (((struct sockaddr*)&addr)->sa_family == AF_INET) {
|
||||
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
|
||||
return IPAddress((uint32_t)(s->sin_addr.s_addr));
|
||||
}
|
||||
|
||||
// IPv6, but it might be IPv4 mapped address
|
||||
if (((struct sockaddr*)&addr)->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&addr;
|
||||
if (IN6_IS_ADDR_V4MAPPED(saddr6->sin6_addr.un.u32_addr)) {
|
||||
return IPAddress(IPv4, (uint8_t*)saddr6->sin6_addr.s6_addr+IPADDRESS_V4_BYTES_INDEX);
|
||||
} else {
|
||||
return IPAddress(IPv6, (uint8_t*)(saddr6->sin6_addr.s6_addr), saddr6->sin6_scope_id);
|
||||
}
|
||||
}
|
||||
log_e("WiFiClient::remoteIP Not AF_INET or AF_INET6?");
|
||||
return (IPAddress(0,0,0,0));
|
||||
}
|
||||
|
||||
uint16_t WiFiClient::remotePort(int fd) const
|
||||
@ -638,4 +670,3 @@ int WiFiClient::fd() const
|
||||
return clientSocketHandle->fd();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,7 @@ extern "C" {
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "dhcpserver/dhcpserver.h"
|
||||
#include "dhcpserver/dhcpserver_options.h"
|
||||
|
||||
@ -191,16 +192,17 @@ esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=IPA
|
||||
lease.start_ip.addr = _byte_swap32(lease.start_ip.addr);
|
||||
lease.end_ip.addr = _byte_swap32(lease.end_ip.addr);
|
||||
log_v("DHCP Server Range: %s to %s", IPAddress(lease.start_ip.addr).toString().c_str(), IPAddress(lease.end_ip.addr).toString().c_str());
|
||||
err = esp_netif_dhcps_option(
|
||||
esp_netif,
|
||||
ESP_NETIF_OP_SET,
|
||||
ESP_NETIF_SUBNET_MASK,
|
||||
(void*)&info.netmask.addr, sizeof(info.netmask.addr)
|
||||
);
|
||||
if(err){
|
||||
log_e("DHCPS Set Netmask Failed! 0x%04x", err);
|
||||
return err;
|
||||
}
|
||||
// Following block is commented because it breaks AP DHCPS on recent ESP-IDF
|
||||
// err = esp_netif_dhcps_option(
|
||||
// esp_netif,
|
||||
// ESP_NETIF_OP_SET,
|
||||
// ESP_NETIF_SUBNET_MASK,
|
||||
// (void*)&info.netmask.addr, sizeof(info.netmask.addr)
|
||||
// );
|
||||
// if(err){
|
||||
// log_e("DHCPS Set Netmask Failed! 0x%04x", err);
|
||||
// return err;
|
||||
// }
|
||||
err = esp_netif_dhcps_option(
|
||||
esp_netif,
|
||||
ESP_NETIF_OP_SET,
|
||||
@ -459,7 +461,13 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_GOT_IP6) {
|
||||
ip_event_got_ip6_t * event = (ip_event_got_ip6_t*)event_data;
|
||||
esp_interface_t iface = get_esp_netif_interface(event->esp_netif);
|
||||
log_v("IF[%d] Got IPv6: IP Index: %d, Zone: %d, " IPV6STR, iface, event->ip_index, event->ip6_info.ip.zone, IPV62STR(event->ip6_info.ip));
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
char if_name[NETIF_NAMESIZE] = {0,};
|
||||
netif_index_to_name(event->ip6_info.ip.zone, if_name);
|
||||
esp_ip6_addr_type_t addr_type = esp_netif_ip6_get_addr_type(&event->ip6_info.ip);
|
||||
static const char * addr_types[] = { "UNKNOWN", "GLOBAL", "LINK_LOCAL", "SITE_LOCAL", "UNIQUE_LOCAL", "IPV4_MAPPED_IPV6" };
|
||||
log_v("IF %s Got IPv6: Interface: %d, IP Index: %d, Type: %s, Zone: %d (%s), Address: " IPV6STR, esp_netif_get_desc(event->esp_netif), iface, event->ip_index, addr_types[addr_type], event->ip6_info.ip.zone, if_name, IPV62STR(event->ip6_info.ip));
|
||||
#endif
|
||||
memcpy(&arduino_event.event_info.got_ip6, event_data, sizeof(ip_event_got_ip6_t));
|
||||
if(iface == ESP_IF_WIFI_STA){
|
||||
arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_GOT_IP6;
|
||||
@ -554,6 +562,8 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t _initial_bits = NET_DNS_IDLE_BIT;
|
||||
|
||||
static bool _start_network_event_task(){
|
||||
if(!_arduino_event_group){
|
||||
_arduino_event_group = xEventGroupCreate();
|
||||
@ -561,7 +571,7 @@ static bool _start_network_event_task(){
|
||||
log_e("Network Event Group Create Failed!");
|
||||
return false;
|
||||
}
|
||||
xEventGroupSetBits(_arduino_event_group, WIFI_DNS_IDLE_BIT);
|
||||
xEventGroupSetBits(_arduino_event_group, _initial_bits);
|
||||
}
|
||||
if(!_arduino_event_queue){
|
||||
_arduino_event_queue = xQueueCreate(32, sizeof(arduino_event_t*));
|
||||
@ -909,21 +919,23 @@ bool WiFiGenericClass::setHostname(const char * hostname)
|
||||
|
||||
int WiFiGenericClass::setStatusBits(int bits){
|
||||
if(!_arduino_event_group){
|
||||
return 0;
|
||||
_initial_bits |= bits;
|
||||
return _initial_bits;
|
||||
}
|
||||
return xEventGroupSetBits(_arduino_event_group, bits);
|
||||
}
|
||||
|
||||
int WiFiGenericClass::clearStatusBits(int bits){
|
||||
if(!_arduino_event_group){
|
||||
return 0;
|
||||
_initial_bits &= ~bits;
|
||||
return _initial_bits;
|
||||
}
|
||||
return xEventGroupClearBits(_arduino_event_group, bits);
|
||||
}
|
||||
|
||||
int WiFiGenericClass::getStatusBits(){
|
||||
if(!_arduino_event_group){
|
||||
return 0;
|
||||
return _initial_bits;
|
||||
}
|
||||
return xEventGroupGetBits(_arduino_event_group);
|
||||
}
|
||||
@ -1051,12 +1063,16 @@ esp_err_t WiFiGenericClass::_eventCallback(arduino_event_t *event)
|
||||
}
|
||||
} else if(event->event_id == ARDUINO_EVENT_WIFI_STA_STOP) {
|
||||
WiFiSTAClass::_setStatus(WL_STOPPED);
|
||||
clearStatusBits(STA_STARTED_BIT | STA_CONNECTED_BIT | STA_HAS_IP_BIT | STA_HAS_IP6_BIT);
|
||||
clearStatusBits(STA_STARTED_BIT | STA_CONNECTED_BIT | STA_HAS_IP_BIT | STA_HAS_IP6_BIT | STA_HAS_IP6_GLOBAL_BIT);
|
||||
} else if(event->event_id == ARDUINO_EVENT_WIFI_STA_CONNECTED) {
|
||||
if (getStatusBits() & STA_WANT_IP6_BIT){
|
||||
esp_err_t err = esp_netif_create_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_STA));
|
||||
if(err != ESP_OK){
|
||||
log_e("Failed to enable IPv6 Link Local on STA: [%d] %s", err, esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
WiFiSTAClass::_setStatus(WL_IDLE_STATUS);
|
||||
setStatusBits(STA_CONNECTED_BIT);
|
||||
|
||||
//esp_netif_create_ip6_linklocal(esp_netifs[ESP_IF_WIFI_STA]);
|
||||
} else if(event->event_id == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) {
|
||||
uint8_t reason = event->event_info.wifi_sta_disconnected.reason;
|
||||
// Reason 0 causes crash, use reason 1 (UNSPECIFIED) instead
|
||||
@ -1074,7 +1090,7 @@ esp_err_t WiFiGenericClass::_eventCallback(arduino_event_t *event)
|
||||
} else {
|
||||
WiFiSTAClass::_setStatus(WL_DISCONNECTED);
|
||||
}
|
||||
clearStatusBits(STA_CONNECTED_BIT | STA_HAS_IP_BIT | STA_HAS_IP6_BIT);
|
||||
clearStatusBits(STA_CONNECTED_BIT | STA_HAS_IP_BIT | STA_HAS_IP6_BIT | STA_HAS_IP6_GLOBAL_BIT);
|
||||
|
||||
bool DoReconnect = false;
|
||||
if(reason == WIFI_REASON_ASSOC_LEAVE) { //Voluntarily disconnected. Don't reconnect!
|
||||
@ -1113,6 +1129,12 @@ esp_err_t WiFiGenericClass::_eventCallback(arduino_event_t *event)
|
||||
|
||||
} else if(event->event_id == ARDUINO_EVENT_WIFI_AP_START) {
|
||||
setStatusBits(AP_STARTED_BIT);
|
||||
if (getStatusBits() & AP_WANT_IP6_BIT){
|
||||
esp_err_t err = esp_netif_create_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_AP));
|
||||
if(err != ESP_OK){
|
||||
log_e("Failed to enable IPv6 Link Local on AP: [%d] %s", err, esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
} else if(event->event_id == ARDUINO_EVENT_WIFI_AP_STOP) {
|
||||
clearStatusBits(AP_STARTED_BIT | AP_HAS_CLIENT_BIT);
|
||||
} else if(event->event_id == ARDUINO_EVENT_WIFI_AP_STACONNECTED) {
|
||||
@ -1126,11 +1148,17 @@ esp_err_t WiFiGenericClass::_eventCallback(arduino_event_t *event)
|
||||
} else if(event->event_id == ARDUINO_EVENT_ETH_START) {
|
||||
setStatusBits(ETH_STARTED_BIT);
|
||||
} else if(event->event_id == ARDUINO_EVENT_ETH_STOP) {
|
||||
clearStatusBits(ETH_STARTED_BIT | ETH_CONNECTED_BIT | ETH_HAS_IP_BIT | ETH_HAS_IP6_BIT);
|
||||
clearStatusBits(ETH_STARTED_BIT | ETH_CONNECTED_BIT | ETH_HAS_IP_BIT | ETH_HAS_IP6_BIT | ETH_HAS_IP6_GLOBAL_BIT);
|
||||
} else if(event->event_id == ARDUINO_EVENT_ETH_CONNECTED) {
|
||||
if (getStatusBits() & ETH_WANT_IP6_BIT){
|
||||
esp_err_t err = esp_netif_create_ip6_linklocal(get_esp_interface_netif(ESP_IF_ETH));
|
||||
if(err != ESP_OK){
|
||||
log_e("Failed to enable IPv6 Link Local on ETH: [%d] %s", err, esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
setStatusBits(ETH_CONNECTED_BIT);
|
||||
} else if(event->event_id == ARDUINO_EVENT_ETH_DISCONNECTED) {
|
||||
clearStatusBits(ETH_CONNECTED_BIT | ETH_HAS_IP_BIT | ETH_HAS_IP6_BIT);
|
||||
clearStatusBits(ETH_CONNECTED_BIT | ETH_HAS_IP_BIT | ETH_HAS_IP6_BIT | ETH_HAS_IP6_GLOBAL_BIT);
|
||||
} else if(event->event_id == ARDUINO_EVENT_ETH_GOT_IP) {
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
|
||||
uint8_t * ip = (uint8_t *)&(event->event_info.got_ip.ip_info.ip.addr);
|
||||
@ -1146,11 +1174,26 @@ esp_err_t WiFiGenericClass::_eventCallback(arduino_event_t *event)
|
||||
clearStatusBits(ETH_HAS_IP_BIT);
|
||||
|
||||
} else if(event->event_id == ARDUINO_EVENT_WIFI_STA_GOT_IP6) {
|
||||
setStatusBits(STA_CONNECTED_BIT | STA_HAS_IP6_BIT);
|
||||
setStatusBits(STA_CONNECTED_BIT);
|
||||
esp_ip6_addr_type_t addr_type = esp_netif_ip6_get_addr_type((esp_ip6_addr_t*)&(event->event_info.got_ip6.ip6_info.ip));
|
||||
if(addr_type == ESP_IP6_ADDR_IS_GLOBAL){
|
||||
setStatusBits(STA_HAS_IP6_GLOBAL_BIT);
|
||||
} else if(addr_type == ESP_IP6_ADDR_IS_LINK_LOCAL){
|
||||
setStatusBits(STA_HAS_IP6_BIT);
|
||||
}
|
||||
} else if(event->event_id == ARDUINO_EVENT_WIFI_AP_GOT_IP6) {
|
||||
setStatusBits(AP_HAS_IP6_BIT);
|
||||
esp_ip6_addr_type_t addr_type = esp_netif_ip6_get_addr_type((esp_ip6_addr_t*)&(event->event_info.got_ip6.ip6_info.ip));
|
||||
if(addr_type == ESP_IP6_ADDR_IS_LINK_LOCAL){
|
||||
setStatusBits(AP_HAS_IP6_BIT);
|
||||
}
|
||||
} else if(event->event_id == ARDUINO_EVENT_ETH_GOT_IP6) {
|
||||
setStatusBits(ETH_CONNECTED_BIT | ETH_HAS_IP6_BIT);
|
||||
setStatusBits(ETH_CONNECTED_BIT);
|
||||
esp_ip6_addr_type_t addr_type = esp_netif_ip6_get_addr_type((esp_ip6_addr_t*)&(event->event_info.got_ip6.ip6_info.ip));
|
||||
if(addr_type == ESP_IP6_ADDR_IS_GLOBAL){
|
||||
setStatusBits(ETH_HAS_IP6_GLOBAL_BIT);
|
||||
} else if(addr_type == ESP_IP6_ADDR_IS_LINK_LOCAL){
|
||||
setStatusBits(ETH_HAS_IP6_BIT);
|
||||
}
|
||||
} else if(event->event_id == ARDUINO_EVENT_SC_GOT_SSID_PSWD) {
|
||||
WiFi.begin(
|
||||
(const char *)event->event_info.sc_got_ssid_pswd.ssid,
|
||||
@ -1546,6 +1589,13 @@ set_ant:
|
||||
// ------------------------------------------------ Generic Network function ---------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
typedef struct gethostbynameParameters {
|
||||
const char *hostname;
|
||||
ip_addr_t addr;
|
||||
uint8_t addr_type;
|
||||
int result;
|
||||
} gethostbynameParameters_t;
|
||||
|
||||
/**
|
||||
* DNS callback
|
||||
* @param name
|
||||
@ -1554,18 +1604,18 @@ set_ant:
|
||||
*/
|
||||
static void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg)
|
||||
{
|
||||
gethostbynameParameters_t *parameters = static_cast<gethostbynameParameters_t *>(callback_arg);
|
||||
if(ipaddr) {
|
||||
(*reinterpret_cast<IPAddress*>(callback_arg)) = ipaddr->u_addr.ip4.addr;
|
||||
if(parameters->result == 0){
|
||||
memcpy(&(parameters->addr), ipaddr, sizeof(ip_addr_t));
|
||||
parameters->result = 1;
|
||||
}
|
||||
} else {
|
||||
parameters->result = -1;
|
||||
}
|
||||
xEventGroupSetBits(_arduino_event_group, WIFI_DNS_DONE_BIT);
|
||||
xEventGroupSetBits(_arduino_event_group, NET_DNS_DONE_BIT);
|
||||
}
|
||||
|
||||
typedef struct gethostbynameParameters {
|
||||
const char *hostname;
|
||||
ip_addr_t addr;
|
||||
void *callback_arg;
|
||||
} gethostbynameParameters_t;
|
||||
|
||||
/**
|
||||
* Callback to execute dns_gethostbyname in lwIP's TCP/IP context
|
||||
* @param param Parameters for dns_gethostbyname call
|
||||
@ -1573,39 +1623,60 @@ typedef struct gethostbynameParameters {
|
||||
static esp_err_t wifi_gethostbyname_tcpip_ctx(void *param)
|
||||
{
|
||||
gethostbynameParameters_t *parameters = static_cast<gethostbynameParameters_t *>(param);
|
||||
return dns_gethostbyname(parameters->hostname, ¶meters->addr, &wifi_dns_found_callback, parameters->callback_arg);
|
||||
return dns_gethostbyname_addrtype(parameters->hostname, ¶meters->addr, &wifi_dns_found_callback, parameters, parameters->addr_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the given hostname to an IP address. If passed hostname is an IP address, it will be parsed into IPAddress structure.
|
||||
* @param aHostname Name to be resolved or string containing IP address
|
||||
* Resolve the given hostname to an IP address.
|
||||
* @param aHostname Name to be resolved
|
||||
* @param aResult IPAddress structure to store the returned IP address
|
||||
* @return 1 if aIPAddrString was successfully converted to an IP address,
|
||||
* else error code
|
||||
*/
|
||||
int WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult)
|
||||
int WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult, bool preferV6)
|
||||
{
|
||||
if (!aResult.fromString(aHostname))
|
||||
{
|
||||
gethostbynameParameters_t params;
|
||||
params.hostname = aHostname;
|
||||
params.callback_arg = &aResult;
|
||||
aResult = static_cast<uint32_t>(0);
|
||||
waitStatusBits(WIFI_DNS_IDLE_BIT, 16000);
|
||||
clearStatusBits(WIFI_DNS_IDLE_BIT | WIFI_DNS_DONE_BIT);
|
||||
err_t err = esp_netif_tcpip_exec(wifi_gethostbyname_tcpip_ctx, ¶ms);
|
||||
if(err == ERR_OK && params.addr.u_addr.ip4.addr) {
|
||||
aResult = params.addr.u_addr.ip4.addr;
|
||||
} 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((uint32_t)aResult == 0){
|
||||
log_e("DNS Failed for %s", aHostname);
|
||||
}
|
||||
err_t err = ERR_OK;
|
||||
gethostbynameParameters_t params;
|
||||
|
||||
// This should generally check if we have a global address assigned to one of the interfaces.
|
||||
// If such address is not assigned, there is no point in trying to get V6 from DNS as we will not be able to reach it.
|
||||
// That is of course, if 'preferV6' is not set to true
|
||||
static bool hasGlobalV6 = false;
|
||||
bool hasGlobalV6Now = (getStatusBits() & NET_HAS_IP6_GLOBAL_BIT) != 0;
|
||||
if(hasGlobalV6 != hasGlobalV6Now){
|
||||
hasGlobalV6 = hasGlobalV6Now;
|
||||
dns_clear_cache();
|
||||
log_d("Clearing DNS cache");
|
||||
}
|
||||
return (uint32_t)aResult != 0;
|
||||
|
||||
aResult = static_cast<uint32_t>(0);
|
||||
params.hostname = aHostname;
|
||||
params.addr_type = (preferV6 || hasGlobalV6)?LWIP_DNS_ADDRTYPE_IPV6_IPV4:LWIP_DNS_ADDRTYPE_IPV4;
|
||||
params.result = 0;
|
||||
aResult.to_ip_addr_t(&(params.addr));
|
||||
|
||||
if (!aResult.fromString(aHostname)) {
|
||||
waitStatusBits(NET_DNS_IDLE_BIT, 16000);
|
||||
clearStatusBits(NET_DNS_IDLE_BIT | NET_DNS_DONE_BIT);
|
||||
|
||||
err = esp_netif_tcpip_exec(wifi_gethostbyname_tcpip_ctx, ¶ms);
|
||||
if (err == ERR_OK) {
|
||||
aResult.from_ip_addr_t(&(params.addr));
|
||||
} else if (err == ERR_INPROGRESS) {
|
||||
waitStatusBits(NET_DNS_DONE_BIT, 15000); //real internal timeout in lwip library is 14[s]
|
||||
clearStatusBits(NET_DNS_DONE_BIT);
|
||||
if (params.result == 1) {
|
||||
aResult.from_ip_addr_t(&(params.addr));
|
||||
err = ERR_OK;
|
||||
}
|
||||
}
|
||||
setStatusBits(NET_DNS_IDLE_BIT);
|
||||
}
|
||||
if (err == ERR_OK) {
|
||||
return 1;
|
||||
}
|
||||
log_e("DNS Failed for '%s' with error '%d' and result '%d'", aHostname, err, params.result);
|
||||
return err;
|
||||
}
|
||||
|
||||
IPAddress WiFiGenericClass::calculateNetworkID(IPAddress ip, IPAddress subnet) {
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "esp_netif_types.h"
|
||||
#include "esp_eth_driver.h"
|
||||
#include "wifi_provisioning/manager.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
ESP_EVENT_DECLARE_BASE(ARDUINO_EVENTS);
|
||||
|
||||
@ -111,6 +112,34 @@ typedef void (*WiFiEventSysCb)(arduino_event_t *event);
|
||||
|
||||
typedef size_t wifi_event_id_t;
|
||||
|
||||
// General Flags
|
||||
static const int NET_DNS_IDLE_BIT = BIT0;
|
||||
static const int NET_DNS_DONE_BIT = BIT1;
|
||||
// WiFi Scan Flags
|
||||
static const int WIFI_SCANNING_BIT = BIT2;
|
||||
static const int WIFI_SCAN_DONE_BIT = BIT3;
|
||||
// AP Flags
|
||||
static const int AP_STARTED_BIT = BIT4;
|
||||
static const int AP_HAS_IP6_BIT = BIT5;
|
||||
static const int AP_HAS_CLIENT_BIT = BIT6;
|
||||
static const int AP_WANT_IP6_BIT = BIT7;
|
||||
// STA Flags
|
||||
static const int STA_STARTED_BIT = BIT8;
|
||||
static const int STA_CONNECTED_BIT = BIT9;
|
||||
static const int STA_HAS_IP_BIT = BIT10;
|
||||
static const int STA_HAS_IP6_BIT = BIT11;
|
||||
static const int STA_HAS_IP6_GLOBAL_BIT = BIT12;
|
||||
static const int STA_WANT_IP6_BIT = BIT13;
|
||||
// ETH Flags
|
||||
static const int ETH_STARTED_BIT = BIT14;
|
||||
static const int ETH_CONNECTED_BIT = BIT15;
|
||||
static const int ETH_HAS_IP_BIT = BIT16;
|
||||
static const int ETH_HAS_IP6_BIT = BIT17;
|
||||
static const int ETH_HAS_IP6_GLOBAL_BIT = BIT18;
|
||||
static const int ETH_WANT_IP6_BIT = BIT19;
|
||||
// Masks
|
||||
static const int NET_HAS_IP6_GLOBAL_BIT = STA_HAS_IP6_GLOBAL_BIT | ETH_HAS_IP6_GLOBAL_BIT;
|
||||
|
||||
typedef enum {
|
||||
WIFI_POWER_19_5dBm = 78,// 19.5dBm
|
||||
WIFI_POWER_19dBm = 76,// 19dBm
|
||||
@ -126,22 +155,6 @@ typedef enum {
|
||||
WIFI_POWER_MINUS_1dBm = -4// -1dBm
|
||||
} wifi_power_t;
|
||||
|
||||
static const int AP_STARTED_BIT = BIT0;
|
||||
static const int AP_HAS_IP6_BIT = BIT1;
|
||||
static const int AP_HAS_CLIENT_BIT = BIT2;
|
||||
static const int STA_STARTED_BIT = BIT3;
|
||||
static const int STA_CONNECTED_BIT = BIT4;
|
||||
static const int STA_HAS_IP_BIT = BIT5;
|
||||
static const int STA_HAS_IP6_BIT = BIT6;
|
||||
static const int ETH_STARTED_BIT = BIT7;
|
||||
static const int ETH_CONNECTED_BIT = BIT8;
|
||||
static const int ETH_HAS_IP_BIT = BIT9;
|
||||
static const int ETH_HAS_IP6_BIT = BIT10;
|
||||
static const int WIFI_SCANNING_BIT = BIT11;
|
||||
static const int WIFI_SCAN_DONE_BIT= BIT12;
|
||||
static const int WIFI_DNS_IDLE_BIT = BIT13;
|
||||
static const int WIFI_DNS_DONE_BIT = BIT14;
|
||||
|
||||
typedef enum {
|
||||
WIFI_RX_ANT0 = 0,
|
||||
WIFI_RX_ANT1,
|
||||
@ -216,7 +229,7 @@ class WiFiGenericClass
|
||||
static bool _isReconnectableReason(uint8_t reason);
|
||||
|
||||
public:
|
||||
static int hostByName(const char *aHostname, IPAddress &aResult);
|
||||
static int hostByName(const char *aHostname, IPAddress &aResult, bool preferV6=false);
|
||||
|
||||
static IPAddress calculateNetworkID(IPAddress ip, IPAddress subnet);
|
||||
static IPAddress calculateBroadcast(IPAddress ip, IPAddress subnet);
|
||||
@ -226,6 +239,7 @@ class WiFiGenericClass
|
||||
friend class WiFiSTAClass;
|
||||
friend class WiFiScanClass;
|
||||
friend class WiFiAPClass;
|
||||
friend class ETHClass;
|
||||
};
|
||||
|
||||
#endif /* ESP32WIFIGENERIC_H_ */
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
WiFiMulti::WiFiMulti()
|
||||
{
|
||||
ipv6_support = false;
|
||||
}
|
||||
|
||||
WiFiMulti::~WiFiMulti()
|
||||
@ -159,6 +160,9 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout)
|
||||
if(bestNetwork.ssid) {
|
||||
log_i("[WIFI] Connecting BSSID: %02X:%02X:%02X:%02X:%02X:%02X SSID: %s Channel: %d (%d)", bestBSSID[0], bestBSSID[1], bestBSSID[2], bestBSSID[3], bestBSSID[4], bestBSSID[5], bestNetwork.ssid, bestChannel, bestNetworkDb);
|
||||
|
||||
if (ipv6_support == true) {
|
||||
WiFi.enableIPv6();
|
||||
}
|
||||
WiFi.begin(bestNetwork.ssid, bestNetwork.passphrase, bestChannel, bestBSSID);
|
||||
status = WiFi.status();
|
||||
|
||||
@ -202,3 +206,7 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout)
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void WiFiMulti::enableIPv6(bool state) {
|
||||
ipv6_support = state;
|
||||
}
|
||||
|
@ -42,10 +42,12 @@ public:
|
||||
|
||||
bool addAP(const char* ssid, const char *passphrase = NULL);
|
||||
|
||||
void enableIPv6(bool state);
|
||||
uint8_t run(uint32_t connectTimeout=5000);
|
||||
|
||||
private:
|
||||
std::vector<WifiAPlist_t> APlist;
|
||||
bool ipv6_support;
|
||||
};
|
||||
|
||||
#endif /* WIFICLIENTMULTI_H_ */
|
||||
|
@ -805,30 +805,50 @@ int8_t WiFiSTAClass::RSSI(void)
|
||||
|
||||
/**
|
||||
* Enable IPv6 on the station interface.
|
||||
* Should be called before WiFi.begin()
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
bool WiFiSTAClass::enableIpV6()
|
||||
bool WiFiSTAClass::enableIPv6(bool en)
|
||||
{
|
||||
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
|
||||
return false;
|
||||
if (en) {
|
||||
WiFiGenericClass::setStatusBits(STA_WANT_IP6_BIT);
|
||||
} else {
|
||||
WiFiGenericClass::clearStatusBits(STA_WANT_IP6_BIT);
|
||||
}
|
||||
return esp_netif_create_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_STA)) == ESP_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the station interface IPv6 address.
|
||||
* @return IPv6Address
|
||||
* Get the station interface link-local IPv6 address.
|
||||
* @return IPAddress
|
||||
*/
|
||||
IPv6Address WiFiSTAClass::localIPv6()
|
||||
IPAddress WiFiSTAClass::localIPv6()
|
||||
{
|
||||
esp_ip6_addr_t addr;
|
||||
static esp_ip6_addr_t addr;
|
||||
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
|
||||
return IPv6Address();
|
||||
return IPAddress(IPv6);
|
||||
}
|
||||
if(esp_netif_get_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_STA), &addr)) {
|
||||
return IPv6Address();
|
||||
if(esp_netif_get_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_STA), &addr)){
|
||||
return IPAddress(IPv6);
|
||||
}
|
||||
return IPv6Address(addr.addr);
|
||||
return IPAddress(IPv6, (const uint8_t *)addr.addr, addr.zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the station interface global IPv6 address.
|
||||
* @return IPAddress
|
||||
*/
|
||||
IPAddress WiFiSTAClass::globalIPv6()
|
||||
{
|
||||
static esp_ip6_addr_t addr;
|
||||
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
|
||||
return IPAddress(IPv6);
|
||||
}
|
||||
if(esp_netif_get_ip6_global(get_esp_interface_netif(ESP_IF_WIFI_STA), &addr)){
|
||||
return IPAddress(IPv6);
|
||||
}
|
||||
return IPAddress(IPv6, (const uint8_t *)addr.addr, addr.zone);
|
||||
}
|
||||
|
||||
|
||||
|
@ -93,8 +93,9 @@ public:
|
||||
IPAddress networkID();
|
||||
uint8_t subnetCIDR();
|
||||
|
||||
bool enableIpV6();
|
||||
IPv6Address localIPv6();
|
||||
bool enableIPv6(bool en=true);
|
||||
IPAddress localIPv6();
|
||||
IPAddress globalIPv6();
|
||||
|
||||
// STA WiFi info
|
||||
static wl_status_t status();
|
||||
|
@ -51,8 +51,8 @@ WiFiClient WiFiServer::accept(){
|
||||
_accepted_sockfd = -1;
|
||||
}
|
||||
else {
|
||||
struct sockaddr_in _client;
|
||||
int cs = sizeof(struct sockaddr_in);
|
||||
struct sockaddr_in6 _client;
|
||||
int cs = sizeof(struct sockaddr_in6);
|
||||
#ifdef ESP_IDF_VERSION_MAJOR
|
||||
client_sock = lwip_accept(sockfd, (struct sockaddr *)&_client, (socklen_t*)&cs);
|
||||
#else
|
||||
@ -80,14 +80,21 @@ void WiFiServer::begin(uint16_t port, int enable){
|
||||
if(port){
|
||||
_port = port;
|
||||
}
|
||||
struct sockaddr_in server;
|
||||
sockfd = socket(AF_INET , SOCK_STREAM, 0);
|
||||
struct sockaddr_in6 server;
|
||||
sockfd = socket(AF_INET6 , SOCK_STREAM, 0);
|
||||
if (sockfd < 0)
|
||||
return;
|
||||
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_addr.s_addr = _addr;
|
||||
server.sin_port = htons(_port);
|
||||
server.sin6_family = AF_INET6;
|
||||
if (_addr.type() == IPv4) {
|
||||
memcpy(server.sin6_addr.s6_addr+11, (uint8_t*)&_addr[0], 4);
|
||||
server.sin6_addr.s6_addr[10] = 0xFF;
|
||||
server.sin6_addr.s6_addr[11] = 0xFF;
|
||||
} else {
|
||||
memcpy(server.sin6_addr.s6_addr, (uint8_t*)&_addr[0], 16);
|
||||
}
|
||||
memset(server.sin6_addr.s6_addr, 0x0, 16);
|
||||
server.sin6_port = htons(_port);
|
||||
if(bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
|
||||
return;
|
||||
if(listen(sockfd , _max_clients) < 0)
|
||||
@ -110,8 +117,8 @@ bool WiFiServer::hasClient() {
|
||||
if (_accepted_sockfd >= 0) {
|
||||
return true;
|
||||
}
|
||||
struct sockaddr_in _client;
|
||||
int cs = sizeof(struct sockaddr_in);
|
||||
struct sockaddr_in6 _client;
|
||||
int cs = sizeof(struct sockaddr_in6);
|
||||
#ifdef ESP_IDF_VERSION_MAJOR
|
||||
_accepted_sockfd = lwip_accept(sockfd, (struct sockaddr *)&_client, (socklen_t*)&cs);
|
||||
#else
|
||||
@ -140,4 +147,3 @@ void WiFiServer::close(){
|
||||
void WiFiServer::stop(){
|
||||
end();
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,6 @@ class WiFiServer : public Server {
|
||||
public:
|
||||
void listenOnLocalhost(){}
|
||||
|
||||
// _addr(INADDR_ANY) is the same as _addr() ==> 0.0.0.0
|
||||
WiFiServer(uint16_t port=80, uint8_t max_clients=4):sockfd(-1),_accepted_sockfd(-1),_addr(),_port(port),_max_clients(max_clients),_listening(false),_noDelay(false) {
|
||||
log_v("WiFiServer::WiFiServer(port=%d, ...)", port);
|
||||
}
|
||||
|
@ -51,7 +51,11 @@ uint8_t WiFiUDP::begin(IPAddress address, uint16_t port){
|
||||
}
|
||||
tx_buffer_len = 0;
|
||||
|
||||
#if LWIP_IPV6
|
||||
if ((udp_server=socket((address.type() == IPv6) ? AF_INET6 : AF_INET, 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;
|
||||
}
|
||||
@ -63,12 +67,31 @@ uint8_t WiFiUDP::begin(IPAddress address, uint16_t port){
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset((char *) &addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(server_port);
|
||||
addr.sin_addr.s_addr = (in_addr_t)address;
|
||||
if(bind(udp_server , (struct sockaddr*)&addr, sizeof(addr)) == -1){
|
||||
struct sockaddr_storage serveraddr = {};
|
||||
size_t sock_size = 0;
|
||||
#if LWIP_IPV6
|
||||
if (address.type() == IPv6) {
|
||||
struct sockaddr_in6 *tmpaddr = (struct sockaddr_in6 *)&serveraddr;
|
||||
ip_addr_t addr;
|
||||
address.to_ip_addr_t(&addr);
|
||||
memset((char *) tmpaddr, 0, sizeof(struct sockaddr_in));
|
||||
tmpaddr->sin6_family = AF_INET6;
|
||||
tmpaddr->sin6_port = htons(server_port);
|
||||
tmpaddr->sin6_scope_id = addr.u_addr.ip6.zone;
|
||||
inet6_addr_from_ip6addr(&tmpaddr->sin6_addr, ip_2_ip6(&addr));
|
||||
tmpaddr->sin6_flowinfo = 0;
|
||||
sock_size = sizeof(sockaddr_in6);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
struct sockaddr_in *tmpaddr = (struct sockaddr_in *)&serveraddr;
|
||||
memset((char *) tmpaddr, 0, sizeof(struct sockaddr_in));
|
||||
tmpaddr->sin_family = AF_INET;
|
||||
tmpaddr->sin_port = htons(server_port);
|
||||
tmpaddr->sin_addr.s_addr = (in_addr_t)address;
|
||||
sock_size = sizeof(sockaddr_in);
|
||||
}
|
||||
if(bind(udp_server , (sockaddr*)&serveraddr, sock_size) == -1){
|
||||
log_e("could not bind socket: %d", errno);
|
||||
stop();
|
||||
return 0;
|
||||
@ -78,23 +101,48 @@ uint8_t WiFiUDP::begin(IPAddress address, uint16_t port){
|
||||
}
|
||||
|
||||
uint8_t WiFiUDP::begin(uint16_t p){
|
||||
return begin(IPAddress(INADDR_ANY), p);
|
||||
return begin(IPAddress(), p);
|
||||
}
|
||||
|
||||
uint8_t WiFiUDP::beginMulticast(IPAddress a, uint16_t p){
|
||||
if(begin(IPAddress(INADDR_ANY), p)){
|
||||
if((uint32_t)a != 0){
|
||||
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) {
|
||||
uint8_t WiFiUDP::beginMulticast(IPAddress address, uint16_t p){
|
||||
if(begin(IPAddress(), p)){
|
||||
ip_addr_t addr;
|
||||
address.to_ip_addr_t(&addr);
|
||||
if (ip_addr_ismulticast(&addr)) {
|
||||
#if LWIP_IPV6
|
||||
if (address.type() == IPv6) {
|
||||
struct ipv6_mreq mreq;
|
||||
bool joined = false;
|
||||
inet6_addr_from_ip6addr(&mreq.ipv6mr_multiaddr, ip_2_ip6(&addr));
|
||||
|
||||
// iterate on each interface
|
||||
for (netif* intf = netif_list; intf != nullptr; intf = intf->next) {
|
||||
mreq.ipv6mr_interface = intf->num + 1;
|
||||
if (intf->name[0] != 'l' || intf->name[1] != 'o') { // skip 'lo' local interface
|
||||
int ret = setsockopt(udp_server, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
|
||||
if (ret >= 0) { joined = true; }
|
||||
}
|
||||
}
|
||||
if (!joined) {
|
||||
log_e("could not join igmp: %d", errno);
|
||||
stop();
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
struct ip_mreq mreq;
|
||||
mreq.imr_multiaddr.s_addr = (in_addr_t)address;
|
||||
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;
|
||||
multicast_ip = address;
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -112,19 +160,38 @@ void WiFiUDP::stop(){
|
||||
}
|
||||
if(udp_server == -1)
|
||||
return;
|
||||
if((uint32_t)multicast_ip != 0){
|
||||
struct ip_mreq mreq;
|
||||
mreq.imr_multiaddr.s_addr = (in_addr_t)multicast_ip;
|
||||
mreq.imr_interface.s_addr = (in_addr_t)0;
|
||||
setsockopt(udp_server, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
|
||||
multicast_ip = IPAddress(INADDR_ANY);
|
||||
ip_addr_t addr;
|
||||
multicast_ip.to_ip_addr_t(&addr);
|
||||
if (!ip_addr_isany(&addr)) {
|
||||
#if LWIP_IPV6
|
||||
if (multicast_ip.type() == IPv6) {
|
||||
struct ipv6_mreq mreq;
|
||||
inet6_addr_from_ip6addr(&mreq.ipv6mr_multiaddr, ip_2_ip6(&addr));
|
||||
|
||||
// iterate on each interface
|
||||
for (netif* intf = netif_list; intf != nullptr; intf = intf->next) {
|
||||
mreq.ipv6mr_interface = intf->num + 1;
|
||||
if (intf->name[0] != 'l' || intf->name[1] != 'o') { // skip 'lo' local interface
|
||||
setsockopt(udp_server, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, sizeof(mreq));
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
struct ip_mreq mreq;
|
||||
mreq.imr_multiaddr.s_addr = (in_addr_t)multicast_ip;
|
||||
mreq.imr_interface.s_addr = (in_addr_t)0;
|
||||
setsockopt(udp_server, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
|
||||
}
|
||||
// now common code for v4/v6
|
||||
multicast_ip = IPAddress();
|
||||
}
|
||||
close(udp_server);
|
||||
udp_server = -1;
|
||||
}
|
||||
|
||||
int WiFiUDP::beginMulticastPacket(){
|
||||
if(!server_port || multicast_ip == IPAddress(INADDR_ANY))
|
||||
if(!server_port || multicast_ip == IPAddress())
|
||||
return 0;
|
||||
remote_ip = multicast_ip;
|
||||
remote_port = server_port;
|
||||
@ -176,14 +243,31 @@ int WiFiUDP::beginPacket(const char *host, uint16_t port){
|
||||
}
|
||||
|
||||
int WiFiUDP::endPacket(){
|
||||
struct sockaddr_in recipient;
|
||||
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;
|
||||
ip_addr_t addr;
|
||||
remote_ip.to_ip_addr_t(&addr);
|
||||
|
||||
if (remote_ip.type() == IPv4) {
|
||||
struct sockaddr_in recipient;
|
||||
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_flowinfo = 0;
|
||||
recipient.sin6_addr = *(in6_addr*)(ip_addr_t*)(&addr);
|
||||
recipient.sin6_family = AF_INET6;
|
||||
recipient.sin6_port = htons(remote_port);
|
||||
recipient.sin6_scope_id = remote_ip.zone();
|
||||
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;
|
||||
}
|
||||
@ -207,13 +291,14 @@ size_t WiFiUDP::write(const uint8_t *buffer, size_t size){
|
||||
int WiFiUDP::parsePacket(){
|
||||
if(rx_buffer)
|
||||
return 0;
|
||||
struct sockaddr_in si_other;
|
||||
int slen = sizeof(si_other) , len;
|
||||
struct sockaddr_storage si_other_storage; // enough storage for v4 and v6
|
||||
socklen_t slen = sizeof(sockaddr_storage);
|
||||
int len;
|
||||
char *buf = (char *)malloc(1460);
|
||||
if(!buf) {
|
||||
return 0;
|
||||
}
|
||||
if ((len = recvfrom(udp_server, buf, 1460, MSG_DONTWAIT, (struct sockaddr *) &si_other, (socklen_t *)&slen)) == -1){
|
||||
if ((len = recvfrom(udp_server, buf, 1460, MSG_DONTWAIT, (struct sockaddr *) &si_other_storage, (socklen_t *)&slen)) == -1){
|
||||
free(buf);
|
||||
if(errno == EWOULDBLOCK){
|
||||
return 0;
|
||||
@ -221,8 +306,30 @@ int WiFiUDP::parsePacket(){
|
||||
log_e("could not receive data: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
remote_ip = IPAddress(si_other.sin_addr.s_addr);
|
||||
remote_port = ntohs(si_other.sin_port);
|
||||
if (si_other_storage.ss_family == AF_INET) {
|
||||
struct sockaddr_in &si_other = (sockaddr_in&) si_other_storage;
|
||||
remote_ip = IPAddress(si_other.sin_addr.s_addr);
|
||||
remote_port = ntohs(si_other.sin_port);
|
||||
}
|
||||
#if LWIP_IPV6
|
||||
else if (si_other_storage.ss_family == AF_INET6) {
|
||||
struct sockaddr_in6 &si_other = (sockaddr_in6&) si_other_storage;
|
||||
remote_ip = IPAddress(IPv6, (uint8_t*)&si_other.sin6_addr, si_other.sin6_scope_id); // force IPv6
|
||||
ip_addr_t addr;
|
||||
remote_ip.to_ip_addr_t(&addr);
|
||||
/* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
|
||||
if (remote_ip.type() == IPv6 && ip6_addr_isipv4mappedipv6(ip_2_ip6(&addr))) {
|
||||
unmap_ipv4_mapped_ipv6(ip_2_ip4(&addr), ip_2_ip6(&addr));
|
||||
IP_SET_TYPE_VAL(addr, IPADDR_TYPE_V4);
|
||||
remote_ip.from_ip_addr_t(&addr);
|
||||
}
|
||||
remote_port = ntohs(si_other.sin6_port);
|
||||
}
|
||||
#endif // LWIP_IPV6=1
|
||||
else {
|
||||
remote_ip = ip_addr_any.u_addr.ip4.addr;
|
||||
remote_port = 0;
|
||||
}
|
||||
if (len > 0) {
|
||||
rx_buffer = new(std::nothrow) cbuf(len);
|
||||
rx_buffer->write(buf, len);
|
||||
|
Loading…
Reference in New Issue
Block a user