ESPHome 2026.2.1
Loading...
Searching...
No Matches
udp_component.cpp
Go to the documentation of this file.
2#ifdef USE_NETWORK
3#include "esphome/core/log.h"
6#include "udp_component.h"
7
8namespace esphome::udp {
9
10static const char *const TAG = "udp";
11
13#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
14 for (const auto &address : this->addresses_) {
15 struct sockaddr saddr {};
16 socket::set_sockaddr(&saddr, sizeof(saddr), address, this->broadcast_port_);
17 this->sockaddrs_.push_back(saddr);
18 }
19 // set up broadcast socket
20 if (this->should_broadcast_) {
21 this->broadcast_socket_ = socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
22 if (this->broadcast_socket_ == nullptr) {
23 this->status_set_error(LOG_STR("Could not create socket"));
24 this->mark_failed();
25 return;
26 }
27 int enable = 1;
28 auto err = this->broadcast_socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
29 if (err != 0) {
30 this->status_set_warning(LOG_STR("Socket unable to set reuseaddr"));
31 // we can still continue
32 }
33 err = this->broadcast_socket_->setsockopt(SOL_SOCKET, SO_BROADCAST, &enable, sizeof(int));
34 if (err != 0) {
35 this->status_set_warning(LOG_STR("Socket unable to set broadcast"));
36 }
37 }
38 // create listening socket if we either want to subscribe to providers, or need to listen
39 // for ping key broadcasts.
40 if (this->should_listen_) {
41 this->listen_socket_ = socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
42 if (this->listen_socket_ == nullptr) {
43 this->status_set_error(LOG_STR("Could not create socket"));
44 this->mark_failed();
45 return;
46 }
47 auto err = this->listen_socket_->setblocking(false);
48 if (err < 0) {
49 ESP_LOGE(TAG, "Unable to set nonblocking: errno %d", errno);
50 this->status_set_error(LOG_STR("Unable to set nonblocking"));
51 this->mark_failed();
52 return;
53 }
54 int enable = 1;
55 err = this->listen_socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
56 if (err != 0) {
57 this->status_set_warning(LOG_STR("Socket unable to set reuseaddr"));
58 // we can still continue
59 }
60 struct sockaddr_in server {};
61
62 server.sin_family = AF_INET;
63 server.sin_addr.s_addr = ESPHOME_INADDR_ANY;
64 server.sin_port = htons(this->listen_port_);
65
66 if (this->listen_address_.has_value()) {
67 // Only 16 bytes needed for IPv4, but use standard size for consistency
68 char addr_buf[network::IP_ADDRESS_BUFFER_SIZE];
69 this->listen_address_.value().str_to(addr_buf);
70 struct ip_mreq imreq = {};
71 imreq.imr_interface.s_addr = ESPHOME_INADDR_ANY;
72 inet_aton(addr_buf, &imreq.imr_multiaddr);
73 server.sin_addr.s_addr = imreq.imr_multiaddr.s_addr;
74 ESP_LOGD(TAG, "Join multicast %s", addr_buf);
75 err = this->listen_socket_->setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP, &imreq, sizeof(imreq));
76 if (err < 0) {
77 ESP_LOGE(TAG, "Failed to set IP_ADD_MEMBERSHIP. Error %d", errno);
78 this->status_set_error(LOG_STR("Failed to set IP_ADD_MEMBERSHIP"));
79 this->mark_failed();
80 return;
81 }
82 }
83
84 err = this->listen_socket_->bind((struct sockaddr *) &server, sizeof(server));
85 if (err != 0) {
86 ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
87 this->status_set_error(LOG_STR("Unable to bind socket"));
88 this->mark_failed();
89 return;
90 }
91 }
92#endif
93#ifdef USE_SOCKET_IMPL_LWIP_TCP
94 // 8266 and RP2040 `Duino
95 for (const auto &address : this->addresses_) {
96 auto ipaddr = IPAddress();
97 ipaddr.fromString(address);
98 this->ipaddrs_.push_back(ipaddr);
99 }
100 if (this->should_listen_)
101 this->udp_client_.begin(this->listen_port_);
102#endif
103}
104
106 if (this->should_listen_) {
107 std::array<uint8_t, MAX_PACKET_SIZE> buf;
108 for (;;) {
109#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
110 auto len = this->listen_socket_->read(buf.data(), buf.size());
111#endif
112#ifdef USE_SOCKET_IMPL_LWIP_TCP
113 auto len = this->udp_client_.parsePacket();
114 if (len > 0)
115 len = this->udp_client_.read(buf.data(), buf.size());
116#endif
117 if (len <= 0)
118 break;
119 size_t packet_len = static_cast<size_t>(len);
120 ESP_LOGV(TAG, "Received packet of length %zu", packet_len);
121 this->packet_listeners_.call(std::span<const uint8_t>(buf.data(), packet_len));
122 }
123 }
124}
125
127 ESP_LOGCONFIG(TAG,
128 "UDP:\n"
129 " Listen Port: %u\n"
130 " Broadcast Port: %u",
131 this->listen_port_, this->broadcast_port_);
132 for (const char *address : this->addresses_)
133 ESP_LOGCONFIG(TAG, " Address: %s", address);
134 if (this->listen_address_.has_value()) {
135 char addr_buf[network::IP_ADDRESS_BUFFER_SIZE];
136 ESP_LOGCONFIG(TAG, " Listen address: %s", this->listen_address_.value().str_to(addr_buf));
137 }
138 ESP_LOGCONFIG(TAG,
139 " Broadcasting: %s\n"
140 " Listening: %s",
141 YESNO(this->should_broadcast_), YESNO(this->should_listen_));
142}
143
144void UDPComponent::send_packet(const uint8_t *data, size_t size) {
145#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
146 for (const auto &saddr : this->sockaddrs_) {
147 auto result = this->broadcast_socket_->sendto(data, size, 0, &saddr, sizeof(saddr));
148 if (result < 0)
149 ESP_LOGW(TAG, "sendto() error %d", errno);
150 }
151#endif
152#ifdef USE_SOCKET_IMPL_LWIP_TCP
153 auto iface = IPAddress(0, 0, 0, 0);
154 for (const auto &saddr : this->ipaddrs_) {
155 if (this->udp_client_.beginPacketMulticast(saddr, this->broadcast_port_, iface, 128) != 0) {
156 this->udp_client_.write(data, size);
157 auto result = this->udp_client_.endPacket();
158 if (result == 0)
159 ESP_LOGW(TAG, "udp.write() error");
160 }
161 }
162#endif
163}
164} // namespace esphome::udp
165
166#endif
uint8_t address
Definition bl0906.h:4
virtual void mark_failed()
Mark this component as failed.
void status_set_warning(const char *message=nullptr)
std::unique_ptr< socket::Socket > listen_socket_
std::unique_ptr< socket::Socket > broadcast_socket_
void send_packet(const uint8_t *data, size_t size)
std::vector< IPAddress > ipaddrs_
CallbackManager< void(std::span< const uint8_t >)> packet_listeners_
optional< network::IPAddress > listen_address_
std::vector< struct sockaddr > sockaddrs_
FixedVector< const char * > addresses_
socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const char *ip_address, uint16_t port)
Set a sockaddr to the specified address and port for the IP version used by socket_ip().
Definition socket.cpp:120
std::unique_ptr< Socket > socket(int domain, int type, int protocol)
Create a socket of the given domain, type and protocol.
const char *const TAG
Definition spi.cpp:7
std::string size_t len
Definition helpers.h:692
size_t size
Definition helpers.h:729
struct in_addr sin_addr
Definition headers.h:65
sa_family_t sin_family
Definition headers.h:63
in_port_t sin_port
Definition headers.h:64