mdns_networking_socket.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. // Copyright 2021 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. /**
  14. * @brief MDNS Server Networking module implemented using BSD sockets
  15. */
  16. #include <string.h>
  17. #include "esp_event.h"
  18. #include "mdns_networking.h"
  19. #include <sys/types.h>
  20. #include <sys/socket.h>
  21. #include <arpa/inet.h>
  22. #include <netdb.h>
  23. #include <errno.h>
  24. #include <stdbool.h>
  25. #include <stdlib.h>
  26. #include <unistd.h>
  27. #include <sys/param.h>
  28. #include "esp_log.h"
  29. #if defined(CONFIG_IDF_TARGET_LINUX)
  30. #include <sys/ioctl.h>
  31. #include <net/if.h>
  32. #endif
  33. extern mdns_server_t * _mdns_server;
  34. static const char *TAG = "MDNS_Networking";
  35. static bool s_run_sock_recv_task = false;
  36. static int create_socket(esp_netif_t *netif);
  37. static int join_mdns_multicast_group(int sock, esp_netif_t *netif, mdns_ip_protocol_t ip_protocol);
  38. #if defined(CONFIG_IDF_TARGET_LINUX)
  39. // Need to define packet buffer struct on linux
  40. struct pbuf {
  41. struct pbuf * next;
  42. void * payload;
  43. size_t tot_len;
  44. size_t len;
  45. };
  46. #else
  47. // Compatibility define to access sock-addr struct the same way for lwip and linux
  48. #define s6_addr32 un.u32_addr
  49. #endif // CONFIG_IDF_TARGET_LINUX
  50. static void delete_socket(int sock)
  51. {
  52. close(sock);
  53. }
  54. static struct udp_pcb* sock_to_pcb(int sock)
  55. {
  56. if (sock < 0) {
  57. return NULL;
  58. }
  59. // Note: sock=0 is a valid descriptor, so save it as +1 ("1" is a valid pointer)
  60. intptr_t sock_plus_one = sock + 1;
  61. return (struct udp_pcb*)sock_plus_one;
  62. }
  63. static int pcb_to_sock(struct udp_pcb* pcb)
  64. {
  65. if (pcb == NULL) {
  66. return -1;
  67. }
  68. intptr_t sock_plus_one = (intptr_t)pcb;
  69. return sock_plus_one - 1;
  70. }
  71. void* _mdns_get_packet_data(mdns_rx_packet_t *packet)
  72. {
  73. return packet->pb->payload;
  74. }
  75. size_t _mdns_get_packet_len(mdns_rx_packet_t *packet)
  76. {
  77. return packet->pb->len;
  78. }
  79. void _mdns_packet_free(mdns_rx_packet_t *packet)
  80. {
  81. free(packet->pb->payload);
  82. free(packet->pb);
  83. free(packet);
  84. }
  85. esp_err_t _mdns_pcb_deinit(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
  86. {
  87. struct udp_pcb * pcb = _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb;
  88. _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb = NULL;
  89. if (_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb == NULL &&
  90. _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb == NULL) {
  91. // if the interface for both protocol uninitialized, close the interface socket
  92. int sock = pcb_to_sock(pcb);
  93. if (sock >= 0) {
  94. delete_socket(sock);
  95. }
  96. }
  97. for (int i=0; i<MDNS_IF_MAX; i++) {
  98. for (int j=0; j<MDNS_IP_PROTOCOL_MAX; j++) {
  99. if (_mdns_server->interfaces[i].pcbs[j].pcb)
  100. // If any of the interfaces/protocol initialized
  101. return ESP_OK;
  102. }
  103. }
  104. // no interface alive, stop the rx task
  105. s_run_sock_recv_task = false;
  106. vTaskDelay(pdMS_TO_TICKS(500));
  107. return ESP_OK;
  108. }
  109. #if defined(CONFIG_IDF_TARGET_LINUX)
  110. #ifdef CONFIG_LWIP_IPV6
  111. static char* inet6_ntoa_r(struct in6_addr addr, char* ptr, size_t size)
  112. {
  113. inet_ntop(AF_INET6, &(addr.s6_addr32[0]), ptr, size);
  114. return ptr;
  115. }
  116. #endif // CONFIG_LWIP_IPV6
  117. static char* inet_ntoa_r(struct in_addr addr, char* ptr, size_t size)
  118. {
  119. char * res = inet_ntoa(addr);
  120. if (res && strlen(res) < size) {
  121. strcpy(ptr, res);
  122. }
  123. return res;
  124. }
  125. #endif // CONFIG_IDF_TARGET_LINUX
  126. static inline char* get_string_address(struct sockaddr_storage *source_addr)
  127. {
  128. static char address_str[40]; // 40=(8*4+7+term) is the max size of ascii IPv6 addr "XXXX:XX...XX:XXXX"
  129. char *res = NULL;
  130. // Convert ip address to string
  131. if (source_addr->ss_family == PF_INET) {
  132. res = inet_ntoa_r(((struct sockaddr_in *)source_addr)->sin_addr, address_str, sizeof(address_str));
  133. }
  134. #ifdef CONFIG_LWIP_IPV6
  135. else if (source_addr->ss_family == PF_INET6) {
  136. res = inet6_ntoa_r(((struct sockaddr_in6 *)source_addr)->sin6_addr, address_str, sizeof(address_str));
  137. }
  138. #endif
  139. if (!res) {
  140. address_str[0] = '\0'; // Returns empty string if conversion didn't succeed
  141. }
  142. return address_str;
  143. }
  144. static inline size_t espaddr_to_inet(const esp_ip_addr_t *addr, const uint16_t port, const mdns_ip_protocol_t ip_protocol, struct sockaddr_storage *in_addr)
  145. {
  146. size_t ss_addr_len = 0;
  147. memset(in_addr, 0, sizeof(struct sockaddr_storage));
  148. if (ip_protocol == MDNS_IP_PROTOCOL_V4 && addr->type == ESP_IPADDR_TYPE_V4) {
  149. in_addr->ss_family = PF_INET;
  150. #if !defined(CONFIG_IDF_TARGET_LINUX)
  151. in_addr->s2_len = sizeof(struct sockaddr_in);
  152. #endif
  153. ss_addr_len = sizeof(struct sockaddr_in);
  154. struct sockaddr_in *in_addr_ip4 = (struct sockaddr_in *) in_addr;
  155. in_addr_ip4->sin_port = port;
  156. in_addr_ip4->sin_addr.s_addr = addr->u_addr.ip4.addr;
  157. }
  158. #if CONFIG_LWIP_IPV6
  159. else if (ip_protocol == MDNS_IP_PROTOCOL_V6 && addr->type == ESP_IPADDR_TYPE_V6) {
  160. memset(in_addr, 0, sizeof(struct sockaddr_storage));
  161. in_addr->ss_family = PF_INET6;
  162. #if !defined(CONFIG_IDF_TARGET_LINUX)
  163. in_addr->s2_len = sizeof(struct sockaddr_in6);
  164. #endif
  165. ss_addr_len = sizeof(struct sockaddr_in6);
  166. struct sockaddr_in6 * in_addr_ip6 = (struct sockaddr_in6 *)in_addr;
  167. uint32_t *u32_addr = in_addr_ip6->sin6_addr.s6_addr32;
  168. in_addr_ip6->sin6_port = port;
  169. u32_addr[0] = addr->u_addr.ip6.addr[0];
  170. u32_addr[1] = addr->u_addr.ip6.addr[1];
  171. u32_addr[2] = addr->u_addr.ip6.addr[2];
  172. u32_addr[3] = addr->u_addr.ip6.addr[3];
  173. }
  174. #endif // CONFIG_LWIP_IPV6
  175. return ss_addr_len;
  176. }
  177. size_t _mdns_udp_pcb_write(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, const esp_ip_addr_t *ip, uint16_t port, uint8_t * data, size_t len)
  178. {
  179. int sock = pcb_to_sock(_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb);
  180. if (sock < 0) {
  181. return 0;
  182. }
  183. struct sockaddr_storage in_addr;
  184. size_t ss_size = espaddr_to_inet(ip, htons(port), ip_protocol, &in_addr);
  185. if (!ss_size) {
  186. ESP_LOGE(TAG, "espaddr_to_inet() failed: Mismatch of IP protocols");
  187. return 0;
  188. }
  189. ESP_LOGD(TAG, "[sock=%d]: Sending to IP %s port %d", sock, get_string_address(&in_addr), port);
  190. ssize_t actual_len = sendto(sock, data, len, 0, (struct sockaddr *)&in_addr, ss_size);
  191. if (actual_len < 0) {
  192. ESP_LOGE(TAG, "[sock=%d]: _mdns_udp_pcb_write sendto() has failed\n error=%d: %s", sock, errno, strerror(errno));
  193. }
  194. return actual_len;
  195. }
  196. static inline void inet_to_espaddr(const struct sockaddr_storage *in_addr, esp_ip_addr_t *addr, uint16_t *port)
  197. {
  198. if (in_addr->ss_family == PF_INET) {
  199. struct sockaddr_in * in_addr_ip4 = (struct sockaddr_in *)in_addr;
  200. memset(addr, 0, sizeof(esp_ip_addr_t));
  201. *port = in_addr_ip4->sin_port;
  202. addr->u_addr.ip4.addr = in_addr_ip4->sin_addr.s_addr;
  203. addr->type = ESP_IPADDR_TYPE_V4;
  204. }
  205. #if CONFIG_LWIP_IPV6
  206. else if (in_addr->ss_family == PF_INET6) {
  207. struct sockaddr_in6 * in_addr_ip6 = (struct sockaddr_in6 *)in_addr;
  208. memset(addr, 0, sizeof(esp_ip_addr_t));
  209. *port = in_addr_ip6->sin6_port;
  210. uint32_t *u32_addr = in_addr_ip6->sin6_addr.s6_addr32;
  211. if (u32_addr[0] == 0 && u32_addr[1] == 0 && u32_addr[2] == esp_netif_htonl(0x0000FFFFUL)) {
  212. // Mapped IPv4 address, convert directly to IPv4
  213. addr->type = ESP_IPADDR_TYPE_V4;
  214. addr->u_addr.ip4.addr = u32_addr[3];
  215. } else {
  216. addr->type = ESP_IPADDR_TYPE_V6;
  217. addr->u_addr.ip6.addr[0] = u32_addr[0];
  218. addr->u_addr.ip6.addr[1] = u32_addr[1];
  219. addr->u_addr.ip6.addr[2] = u32_addr[2];
  220. addr->u_addr.ip6.addr[3] = u32_addr[3];
  221. }
  222. }
  223. #endif // CONFIG_LWIP_IPV6
  224. }
  225. void sock_recv_task(void* arg)
  226. {
  227. while (s_run_sock_recv_task) {
  228. struct timeval tv = {
  229. .tv_sec = 1,
  230. .tv_usec = 0,
  231. };
  232. fd_set rfds;
  233. FD_ZERO(&rfds);
  234. int max_sock = -1;
  235. for (int i=0; i<MDNS_IF_MAX; i++) {
  236. for (int j=0; j<MDNS_IP_PROTOCOL_MAX; j++) {
  237. int sock = pcb_to_sock(_mdns_server->interfaces[i].pcbs[j].pcb);
  238. if (sock >= 0) {
  239. FD_SET(sock, &rfds);
  240. max_sock = MAX(max_sock, sock);
  241. }
  242. }
  243. }
  244. if (max_sock < 0) {
  245. vTaskDelay(pdMS_TO_TICKS(1000));
  246. ESP_LOGI(TAG, "No sock!");
  247. continue;
  248. }
  249. int s = select(max_sock + 1, &rfds, NULL, NULL, &tv);
  250. if (s < 0) {
  251. ESP_LOGE(TAG, "Select failed: errno %d", errno);
  252. break;
  253. } else if (s > 0) {
  254. for (int tcpip_if=0; tcpip_if<MDNS_IF_MAX; tcpip_if++) {
  255. // Both protocols share once socket
  256. int sock = pcb_to_sock(_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb);
  257. if (sock < 0) {
  258. sock = pcb_to_sock(_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb);
  259. }
  260. if (sock < 0) {
  261. continue;
  262. }
  263. if (FD_ISSET(sock, &rfds)) {
  264. static char recvbuf[MDNS_MAX_PACKET_SIZE];
  265. uint16_t port = 0;
  266. struct sockaddr_storage raddr; // Large enough for both IPv4 or IPv6
  267. socklen_t socklen = sizeof(struct sockaddr_storage);
  268. esp_ip_addr_t addr = {0};
  269. int len = recvfrom(sock, recvbuf, sizeof(recvbuf), 0,
  270. (struct sockaddr *) &raddr, &socklen);
  271. if (len < 0) {
  272. ESP_LOGE(TAG, "multicast recvfrom failed: errno %d", errno);
  273. break;
  274. }
  275. ESP_LOGD(TAG, "[sock=%d]: Received from IP:%s", sock, get_string_address(&raddr));
  276. ESP_LOG_BUFFER_HEXDUMP(TAG, recvbuf, len, ESP_LOG_VERBOSE);
  277. inet_to_espaddr(&raddr, &addr, &port);
  278. // Allocate the packet structure and pass it to the mdns main engine
  279. mdns_rx_packet_t *packet = (mdns_rx_packet_t *) calloc(1, sizeof(mdns_rx_packet_t));
  280. struct pbuf *packet_pbuf = calloc(1, sizeof(struct pbuf));
  281. uint8_t *buf = malloc(len);
  282. if (packet == NULL || packet_pbuf == NULL || buf == NULL ) {
  283. free(buf);
  284. free(packet_pbuf);
  285. free(packet);
  286. HOOK_MALLOC_FAILED;
  287. ESP_LOGE(TAG, "Failed to allocate the mdns packet");
  288. continue;
  289. }
  290. memcpy(buf, recvbuf, len);
  291. packet_pbuf->next = NULL;
  292. packet_pbuf->payload = buf;
  293. packet_pbuf->tot_len = len;
  294. packet_pbuf->len = len;
  295. packet->tcpip_if = tcpip_if;
  296. packet->pb = packet_pbuf;
  297. packet->src_port = ntohs(port);
  298. memcpy(&packet->src, &addr, sizeof(esp_ip_addr_t));
  299. // TODO(IDF-3651): Add the correct dest addr -- for mdns to decide multicast/unicast
  300. // Currently it's enough to assume the packet is multicast and mdns to check the source port of the packet
  301. memset(&packet->dest, 0, sizeof(esp_ip_addr_t));
  302. packet->multicast = 1;
  303. packet->dest.type = packet->src.type;
  304. packet->ip_protocol =
  305. packet->src.type == ESP_IPADDR_TYPE_V4 ? MDNS_IP_PROTOCOL_V4 : MDNS_IP_PROTOCOL_V6;
  306. if (!_mdns_server || !_mdns_server->action_queue || _mdns_send_rx_action(packet) != ESP_OK) {
  307. ESP_LOGE(TAG, "_mdns_send_rx_action failed!");
  308. free(packet->pb->payload);
  309. free(packet->pb);
  310. free(packet);
  311. }
  312. }
  313. }
  314. }
  315. }
  316. vTaskDelete(NULL);
  317. }
  318. static void mdns_networking_init(void)
  319. {
  320. if (s_run_sock_recv_task == false) {
  321. s_run_sock_recv_task = true;
  322. xTaskCreate( sock_recv_task, "mdns recv task", 3*1024, NULL, 5, NULL );
  323. }
  324. }
  325. static struct udp_pcb* create_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
  326. {
  327. if (_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb) {
  328. return _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb;
  329. }
  330. mdns_ip_protocol_t other_ip_proto = ip_protocol==MDNS_IP_PROTOCOL_V4?MDNS_IP_PROTOCOL_V6:MDNS_IP_PROTOCOL_V4;
  331. esp_netif_t *netif = _mdns_get_esp_netif(tcpip_if);
  332. if (_mdns_server->interfaces[tcpip_if].pcbs[other_ip_proto].pcb) {
  333. struct udp_pcb* other_pcb = _mdns_server->interfaces[tcpip_if].pcbs[other_ip_proto].pcb;
  334. int err = join_mdns_multicast_group(pcb_to_sock(other_pcb), netif, ip_protocol);
  335. if (err < 0) {
  336. ESP_LOGE(TAG, "Failed to add ipv6 multicast group for protocol %d", ip_protocol);
  337. return NULL;
  338. }
  339. return other_pcb;
  340. }
  341. int sock = create_socket(netif);
  342. if (sock < 0) {
  343. ESP_LOGE(TAG, "Failed to create the socket!");
  344. return NULL;
  345. }
  346. int err = join_mdns_multicast_group(sock, netif, ip_protocol);
  347. if (err < 0) {
  348. ESP_LOGE(TAG, "Failed to add ipv6 multicast group for protocol %d", ip_protocol);
  349. }
  350. return sock_to_pcb(sock);
  351. }
  352. esp_err_t _mdns_pcb_init(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
  353. {
  354. ESP_LOGI(TAG, "_mdns_pcb_init(tcpip_if=%d, ip_protocol=%d)", tcpip_if, ip_protocol);
  355. _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb = create_pcb(tcpip_if, ip_protocol);
  356. _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].failed_probes = 0;
  357. mdns_networking_init();
  358. return ESP_OK;
  359. }
  360. static int create_socket(esp_netif_t *netif)
  361. {
  362. #if CONFIG_LWIP_IPV6
  363. int sock = socket(PF_INET6, SOCK_DGRAM, 0);
  364. #else
  365. int sock = socket(PF_INET, SOCK_DGRAM, 0);
  366. #endif
  367. if (sock < 0) {
  368. ESP_LOGE(TAG, "Failed to create socket. Error %d", errno);
  369. return -1;
  370. }
  371. int on = 1;
  372. if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) {
  373. ESP_LOGE(TAG, "setsockopt SO_REUSEADDR: %s\n", strerror(errno));
  374. }
  375. // Bind the socket to any address
  376. #if CONFIG_LWIP_IPV6
  377. struct sockaddr_in6 saddr = { INADDR_ANY };
  378. saddr.sin6_family = AF_INET6;
  379. saddr.sin6_port = htons(5353);
  380. bzero(&saddr.sin6_addr.s6_addr, sizeof(saddr.sin6_addr.s6_addr));
  381. int err = bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in6));
  382. if (err < 0) {
  383. ESP_LOGE(TAG, "Failed to bind socket. Error %d", errno);
  384. goto err;
  385. }
  386. #else
  387. struct sockaddr_in saddr = { 0 };
  388. saddr.sin_family = AF_INET;
  389. saddr.sin_port = htons(5353);
  390. bzero(&saddr.sin_addr.s_addr, sizeof(saddr.sin_addr.s_addr));
  391. int err = bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
  392. if (err < 0) {
  393. ESP_LOGE(TAG, "Failed to bind socket. Error %d", errno);
  394. goto err;
  395. }
  396. #endif // CONFIG_LWIP_IPV6
  397. struct ifreq ifr;
  398. esp_netif_get_netif_impl_name(netif, ifr.ifr_name);
  399. int ret = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void*)&ifr, sizeof(struct ifreq));
  400. if (ret < 0) {
  401. ESP_LOGE(TAG, "\"%s\" Unable to bind socket to specified interface: errno %d", esp_netif_get_desc(netif), errno);
  402. goto err;
  403. }
  404. return sock;
  405. err:
  406. close(sock);
  407. return -1;
  408. }
  409. #if CONFIG_LWIP_IPV6
  410. static int socket_add_ipv6_multicast_group(int sock, esp_netif_t *netif)
  411. {
  412. int ifindex = esp_netif_get_netif_impl_index(netif);
  413. int err = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex));
  414. if (err < 0) {
  415. ESP_LOGE(TAG, "Failed to set IPV6_MULTICAST_IF. Error %d", errno);
  416. return err;
  417. }
  418. struct ipv6_mreq v6imreq = { 0 };
  419. esp_ip_addr_t multi_addr = ESP_IP6ADDR_INIT(0x000002ff, 0, 0, 0xfb000000);
  420. memcpy(&v6imreq.ipv6mr_multiaddr, &multi_addr.u_addr.ip6.addr, sizeof(v6imreq.ipv6mr_multiaddr));
  421. v6imreq.ipv6mr_interface = ifindex;
  422. err = setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &v6imreq, sizeof(struct ipv6_mreq));
  423. if (err < 0) {
  424. ESP_LOGE(TAG, "Failed to set IPV6_ADD_MEMBERSHIP. Error %d", errno);
  425. return err;
  426. }
  427. return err;
  428. }
  429. #endif // CONFIG_LWIP_IPV6
  430. static int socket_add_ipv4_multicast_group(int sock, esp_netif_t *netif)
  431. {
  432. struct ip_mreq imreq = { 0 };
  433. int err = 0;
  434. esp_netif_ip_info_t ip_info = { 0 };
  435. if (esp_netif_get_ip_info(netif, &ip_info) != ESP_OK) {
  436. ESP_LOGE(TAG, "Failed to esp_netif_get_ip_info()");
  437. goto err;
  438. }
  439. imreq.imr_interface.s_addr = ip_info.ip.addr;
  440. esp_ip_addr_t multicast_addr = ESP_IP4ADDR_INIT(224, 0, 0, 251);
  441. imreq.imr_multiaddr.s_addr = multicast_addr.u_addr.ip4.addr;
  442. err = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imreq, sizeof(struct ip_mreq));
  443. if (err < 0) {
  444. ESP_LOGE(TAG, "%d %s", sock, strerror(errno));
  445. ESP_LOGE(TAG, "Failed to set IP_ADD_MEMBERSHIP. Error %d", errno);
  446. goto err;
  447. }
  448. err:
  449. return err;
  450. }
  451. static int join_mdns_multicast_group(int sock, esp_netif_t *netif, mdns_ip_protocol_t ip_protocol)
  452. {
  453. if (ip_protocol == MDNS_IP_PROTOCOL_V4) {
  454. return socket_add_ipv4_multicast_group(sock, netif);
  455. }
  456. #if CONFIG_LWIP_IPV6
  457. if (ip_protocol == MDNS_IP_PROTOCOL_V6) {
  458. return socket_add_ipv6_multicast_group(sock, netif);
  459. }
  460. #endif // CONFIG_LWIP_IPV6
  461. return -1;
  462. }