Files
esphome/esphome/components/network/ip_address.h

189 lines
5.6 KiB
C++

#pragma once
#include "esphome/core/defines.h"
#ifdef USE_NETWORK
#include <cstdint>
#include <string>
#include <cstdio>
#include <array>
#include "esphome/core/helpers.h"
#include "esphome/core/macros.h"
#if defined(USE_ESP32) || defined(USE_LIBRETINY) || USE_ARDUINO_VERSION_CODE > VERSION_CODE(3, 0, 0)
#include <lwip/ip_addr.h>
#endif
#if USE_ARDUINO
#include <Arduino.h>
#include <IPAddress.h>
#endif /* USE_ADRDUINO */
#ifdef USE_HOST
#include <arpa/inet.h>
using ip_addr_t = in_addr;
using ip4_addr_t = in_addr;
#define ipaddr_aton(x, y) inet_aton((x), (y))
#endif
#if USE_ESP32_FRAMEWORK_ARDUINO
#define arduino_ns Arduino_h
#elif USE_LIBRETINY
#define arduino_ns arduino
#elif USE_ARDUINO
#define arduino_ns
#endif
#ifdef USE_ESP32
#include <cstring>
#include <esp_netif.h>
#endif
namespace esphome {
namespace network {
/// Buffer size for IP address string (IPv6 max: 39 chars + null)
static constexpr size_t IP_ADDRESS_BUFFER_SIZE = 40;
/// Lowercase hex digits in IP address string (A-F -> a-f for IPv6 per RFC 5952)
inline void lowercase_ip_str(char *buf) {
for (char *p = buf; *p; ++p) {
if (*p >= 'A' && *p <= 'F')
*p += 32;
}
}
struct IPAddress {
public:
#ifdef USE_HOST
IPAddress() { ip_addr_.s_addr = 0; }
IPAddress(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth) {
this->ip_addr_.s_addr = htonl((first << 24) | (second << 16) | (third << 8) | fourth);
}
IPAddress(const std::string &in_address) { inet_aton(in_address.c_str(), &ip_addr_); }
IPAddress(const ip_addr_t *other_ip) { ip_addr_ = *other_ip; }
// Remove before 2026.8.0
ESPDEPRECATED("Use str_to() instead. Removed in 2026.8.0", "2026.2.0")
std::string str() const {
char buf[IP_ADDRESS_BUFFER_SIZE];
this->str_to(buf);
return buf;
}
/// Write IP address to buffer. Buffer must be at least IP_ADDRESS_BUFFER_SIZE bytes.
char *str_to(char *buf) const {
inet_ntop(AF_INET, &ip_addr_, buf, IP_ADDRESS_BUFFER_SIZE);
return buf; // IPv4 only, no hex letters to lowercase
}
#else
IPAddress() { ip_addr_set_zero(&ip_addr_); }
IPAddress(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth) {
IP_ADDR4(&ip_addr_, first, second, third, fourth);
}
IPAddress(const ip_addr_t *other_ip) { ip_addr_copy(ip_addr_, *other_ip); }
IPAddress(const char *in_address) { ipaddr_aton(in_address, &ip_addr_); }
IPAddress(const std::string &in_address) { ipaddr_aton(in_address.c_str(), &ip_addr_); }
IPAddress(ip4_addr_t *other_ip) {
memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip4_addr_t));
#if USE_ESP32 && LWIP_IPV6
ip_addr_.type = IPADDR_TYPE_V4;
#endif
}
#if USE_ARDUINO
IPAddress(const arduino_ns::IPAddress &other_ip) { ip_addr_set_ip4_u32(&ip_addr_, other_ip); }
#endif
#if LWIP_IPV6
IPAddress(ip6_addr_t *other_ip) {
memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip6_addr_t));
ip_addr_.type = IPADDR_TYPE_V6;
}
#endif /* LWIP_IPV6 */
#ifdef USE_ESP32
#if LWIP_IPV6
IPAddress(esp_ip6_addr_t *other_ip) {
memcpy((void *) &ip_addr_.u_addr.ip6, (void *) other_ip, sizeof(esp_ip6_addr_t));
ip_addr_.type = IPADDR_TYPE_V6;
}
#endif /* LWIP_IPV6 */
IPAddress(esp_ip4_addr_t *other_ip) {
memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(esp_ip4_addr_t));
#if LWIP_IPV6
ip_addr_.type = IPADDR_TYPE_V4;
#endif
}
IPAddress(esp_ip_addr_t *other_ip) {
#if LWIP_IPV6
memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip_addr_));
#else
memcpy((void *) &ip_addr_, (void *) &other_ip->u_addr.ip4, sizeof(ip_addr_));
#endif
}
operator esp_ip_addr_t() const {
esp_ip_addr_t tmp;
#if LWIP_IPV6
memcpy((void *) &tmp, (void *) &ip_addr_, sizeof(ip_addr_));
#else
memcpy((void *) &tmp.u_addr.ip4, (void *) &ip_addr_, sizeof(ip_addr_));
#endif /* LWIP_IPV6 */
return tmp;
}
operator esp_ip4_addr_t() const {
esp_ip4_addr_t tmp;
#if LWIP_IPV6
memcpy((void *) &tmp, (void *) &ip_addr_.u_addr.ip4, sizeof(esp_ip4_addr_t));
#else
memcpy((void *) &tmp, (void *) &ip_addr_, sizeof(ip_addr_));
#endif /* LWIP_IPV6 */
return tmp;
}
#endif /* USE_ESP32 */
operator ip_addr_t() const { return ip_addr_; }
#if LWIP_IPV6
operator ip4_addr_t() const { return *ip_2_ip4(&ip_addr_); }
#endif /* LWIP_IPV6 */
#if USE_ARDUINO
operator arduino_ns::IPAddress() const { return ip_addr_get_ip4_u32(&ip_addr_); }
#endif
bool is_set() const { return !ip_addr_isany(&ip_addr_); } // NOLINT(readability-simplify-boolean-expr)
bool is_ip4() const { return IP_IS_V4(&ip_addr_); }
bool is_ip6() const { return IP_IS_V6(&ip_addr_); }
bool is_multicast() const { return ip_addr_ismulticast(&ip_addr_); }
// Remove before 2026.8.0
ESPDEPRECATED("Use str_to() instead. Removed in 2026.8.0", "2026.2.0")
std::string str() const {
char buf[IP_ADDRESS_BUFFER_SIZE];
this->str_to(buf);
return buf;
}
/// Write IP address to buffer. Buffer must be at least IP_ADDRESS_BUFFER_SIZE bytes.
/// Output is lowercased per RFC 5952 (IPv6 hex digits a-f).
char *str_to(char *buf) const {
ipaddr_ntoa_r(&ip_addr_, buf, IP_ADDRESS_BUFFER_SIZE);
lowercase_ip_str(buf);
return buf;
}
bool operator==(const IPAddress &other) const { return ip_addr_cmp(&ip_addr_, &other.ip_addr_); }
bool operator!=(const IPAddress &other) const { return !ip_addr_cmp(&ip_addr_, &other.ip_addr_); }
IPAddress &operator+=(uint8_t increase) {
if (IP_IS_V4(&ip_addr_)) {
#if LWIP_IPV6
(((u8_t *) (&ip_addr_.u_addr.ip4))[3]) += increase;
#else
(((u8_t *) (&ip_addr_.addr))[3]) += increase;
#endif /* LWIP_IPV6 */
}
return *this;
}
#endif
protected:
ip_addr_t ip_addr_;
};
using IPAddresses = std::array<IPAddress, 5>;
} // namespace network
} // namespace esphome
#endif