From 02cf7c142be2a5702bc8296d7cda904848609198 Mon Sep 17 00:00:00 2001
From: 1e1 <1e1@users.noreply.github.com>
Date: Sun, 27 Oct 2024 23:10:41 +0100
Subject: [PATCH] sync IPAddress.h with ESP8266

---
 cores/arduino/IPAddress.h | 268 +++++++++++++++++++++++++++++---------
 1 file changed, 206 insertions(+), 62 deletions(-)

diff --git a/cores/arduino/IPAddress.h b/cores/arduino/IPAddress.h
index d762f2c02..99419b92a 100644
--- a/cores/arduino/IPAddress.h
+++ b/cores/arduino/IPAddress.h
@@ -1,78 +1,222 @@
 /*
-  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
 
 #include <stdint.h>
-#include "Printable.h"
-#include "WString.h"
+#include <WString.h>
+#include <Printable.h>
+
+#include <lwip/init.h>
+#include <lwip/ip_addr.h>
+#include <lwip/ip4_addr.h>
+
+#if !LWIP_IPV6
+struct ip_addr: ipv4_addr { };
+#endif // !LWIP_IPV6
+
+// to display a netif id with printf:
+#define NETIFID_STR        "%c%c%u"
+#define NETIFID_VAL(netif) \
+        ((netif)? (netif)->name[0]: '-'),     \
+        ((netif)? (netif)->name[1]: '-'),     \
+        ((netif)? netif_get_index(netif): 42)
 
 // A class to make it easier to handle and pass around IP addresses
+// IPv6 update:
+// IPAddress is now a decorator class for lwIP's ip_addr_t
+// fully backward compatible with legacy IPv4-only Arduino's
+// with unchanged footprint when IPv6 is disabled
+
+class IPAddress: public Printable {
+    private:
+
+        ip_addr_t _ip;
+
+        // 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 reinterpret_cast<uint8_t*>(&v4());
+        }
+        const uint8_t* raw_address() const {
+            return reinterpret_cast<const uint8_t*>(&v4());
+        }
+
+    public:
+        IPAddress();
+        IPAddress(const IPAddress&);
+        IPAddress(IPAddress&&);
+
+        IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
+        IPAddress(uint32_t address) { *this = address; }
+        IPAddress(unsigned long address) { *this = address; }
+        IPAddress(int address) { *this = address; }
+        IPAddress(const uint8_t *address) { *this = 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 pointer
+        // to a four-byte uint8_t array is expected
+        operator uint32_t() const { return isV4()? v4(): (uint32_t)0; }
+        operator uint32_t()       { return isV4()? v4(): (uint32_t)0; }
+
+        bool isSet () const;
+        operator bool () const { return isSet(); } // <-
+        operator bool ()       { return isSet(); } // <- both are needed
+
+        // generic IPv4 wrapper to uint32-view like arduino loves to see it
+        const uint32_t& v4() const { return ip_2_ip4(&_ip)->addr; }
+              uint32_t& v4()       { return ip_2_ip4(&_ip)->addr; }
+
+        bool operator==(const IPAddress& addr) const {
+            return ip_addr_cmp(&_ip, &addr._ip);
+        }
+        bool operator!=(const IPAddress& addr) const {
+            return !ip_addr_cmp(&_ip, &addr._ip);
+        }
+        bool operator==(uint32_t addr) const {
+            return isV4() && v4() == addr;
+        }
+        bool operator==(unsigned long addr) const {
+            return isV4() && v4() == (uint32_t)addr;
+        }
+        bool operator!=(uint32_t addr) const {
+            return !(isV4() && v4() == addr);
+        }
+        bool operator!=(unsigned long addr) const {
+            return isV4() && v4() != (uint32_t)addr;
+        }
+        bool operator==(const uint8_t* addr) const;
+
+        int operator>>(int n) const {
+            return isV4()? v4() >> n: 0;
+        }
+
+        // Overloaded index operator to allow getting and setting individual octets of the address
+        uint8_t operator[](int index) const {
+            if (!isV4()) {
+                return 0;
+            }
+
+            return ip4_addr_get_byte_val(*ip_2_ip4(&_ip), index);
+        }
+
+        uint8_t& operator[](int index) {
+            setV4();
+
+            uint8_t* ptr = reinterpret_cast<uint8_t*>(&v4());
+            return *(ptr + index);
+        }
+
+        // Overloaded copy operators to allow initialisation of IPAddress objects from other types
+        IPAddress& operator=(const uint8_t *address);
+        IPAddress& operator=(uint32_t address);
+        IPAddress& operator=(const IPAddress&) = default;
+
+        virtual size_t printTo(Print& p) const;
+        String toString() const;
+
+        void clear();
+
+        /*
+                check if input string(arg) is a valid IPV4 address or not.
+                return true on valid.
+                return false on invalid.
+        */
+        static bool isValid(const String& arg);
+        static bool isValid(const char* arg);
+
+        friend class EthernetClass;
+        friend class UDP;
+        friend class Client;
+        friend class Server;
+        friend class DhcpClass;
+        friend class DNSClient;
+
+        /*
+               lwIP address compatibility
+        */
+        IPAddress(const ipv4_addr& fw_addr)   { setV4(); v4() = fw_addr.addr; }
+        IPAddress(const ipv4_addr* fw_addr)   { setV4(); v4() = fw_addr->addr; }
+
+        IPAddress& operator=(const ipv4_addr& fw_addr)   { setV4(); v4() = fw_addr.addr;  return *this; }
+        IPAddress& operator=(const ipv4_addr* fw_addr)   { setV4(); v4() = fw_addr->addr; return *this; }
+
+        operator       ip_addr_t () const { return  _ip; }
+        operator const ip_addr_t*() const { return &_ip; }
+        operator       ip_addr_t*()       { return &_ip; }
+
+        bool isV4() const { return IP_IS_V4_VAL(_ip); }
+        void setV4() { IP_SET_TYPE_VAL(_ip, IPADDR_TYPE_V4); }
+
+        bool isLocal () const { return ip_addr_islinklocal(&_ip); }
+
+#if LWIP_IPV6
+
+        IPAddress(const ip_addr_t& lwip_addr) { ip_addr_copy(_ip, lwip_addr); }
+        IPAddress(const ip_addr_t* lwip_addr) { ip_addr_copy(_ip, *lwip_addr); }
+
+        IPAddress& operator=(const ip_addr_t& lwip_addr) { ip_addr_copy(_ip, lwip_addr); return *this; }
+        IPAddress& operator=(const ip_addr_t* lwip_addr) { ip_addr_copy(_ip, *lwip_addr); return *this; }
+
+        uint16_t* raw6()
+        {
+            setV6();
+            return reinterpret_cast<uint16_t*>(ip_2_ip6(&_ip));
+        }
+
+        const uint16_t* raw6() const
+        {
+            return isV6()? reinterpret_cast<const uint16_t*>(ip_2_ip6(&_ip)): nullptr;
+        }
+
+        // when not IPv6, ip_addr_t == ip4_addr_t so this one would be ambiguous
+        // required otherwise
+        operator const ip4_addr_t*() const { return isV4()? ip_2_ip4(&_ip): nullptr; }
+
+        bool isV6() const { return IP_IS_V6_VAL(_ip); }
+        void setV6() { IP_SET_TYPE_VAL(_ip, IPADDR_TYPE_V6); }
+
+    protected:
+        bool fromString6(const char *address);
+
+#else
+
+        // allow portable code when IPv6 is not enabled
+
+        uint16_t* raw6() { return nullptr; }
+        const uint16_t* raw6() const { return nullptr; }
+        bool isV6() const { return false; }
+        void setV6() { }
+
+#endif
+
+    protected:
+        bool fromString4(const char *address);
 
-class IPAddress : public Printable {
-private:
-    union {
-	uint8_t bytes[4];  // IPv4 address
-	uint32_t dword;
-    } _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
-    IPAddress();
-    IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
-    IPAddress(uint32_t address);
-    IPAddress(const uint8_t *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 pointer
-    // to a four-byte uint8_t array is expected
-    operator uint32_t() const { return _address.dword; };
-    bool operator==(const IPAddress& addr) const { return _address.dword == addr._address.dword; };
-    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 IPAddress objects from other types
-    IPAddress& operator=(const uint8_t *address);
-    IPAddress& operator=(uint32_t address);
-
-    virtual size_t printTo(Print& p) const;
-
-    friend class EthernetClass;
-    friend class UDP;
-    friend class Client;
-    friend class Server;
-    friend class DhcpClass;
-    friend class DNSClient;
 };
 
-const IPAddress INADDR_NONE(0,0,0,0);
+extern const IPAddress INADDR_ANY;
+extern const IPAddress INADDR_NONE;
 
 #endif