3 #include <catta/core.h>
4 #include <catta/lookup.h>
5 #include <catta/publish.h>
7 #include <catta/simple-watch.h>
8 #include <catta/malloc.h>
9 #include <catta/alternative.h>
10 #include <catta/error.h>
12 #if defined(__APPLE__) || defined(__unix) && !defined(__linux)
13 #include <net/route.h>
14 #elif defined(__linux)
15 #include <asm/types.h>
17 #include <linux/if_link.h>
18 #include <linux/netlink.h>
19 #include <linux/rtnetlink.h>
22 #include "meshlink_internal.h"
24 #include "discovery.h"
29 #include "connection.h"
32 #define MESHLINK_MDNS_SERVICE_TYPE "_%s._tcp"
33 #define MESHLINK_MDNS_NAME_KEY "name"
34 #define MESHLINK_MDNS_FINGERPRINT_KEY "fingerprint"
36 static void generate_rand_string(meshlink_handle_t *mesh, char *buffer, size_t size) {
39 for(size_t i = 0; i < (size - 1); ++i) {
40 buffer[i] = 'a' + prng(mesh, 'z' - 'a' + 1);
43 buffer[size - 1] = '\0';
46 static void discovery_entry_group_callback(CattaServer *server, CattaSEntryGroup *group, CattaEntryGroupState state, void *userdata) {
49 meshlink_handle_t *mesh = userdata;
52 assert(mesh->catta_server);
53 assert(mesh->catta_poll);
55 /* Called whenever the entry group state changes */
57 case CATTA_ENTRY_GROUP_ESTABLISHED:
58 /* The entry group has been established successfully */
59 logger(mesh, MESHLINK_DEBUG, "Catta Service successfully established.\n");
62 case CATTA_ENTRY_GROUP_COLLISION:
63 logger(mesh, MESHLINK_WARNING, "Catta Service collision.\n");
64 // @TODO can we just set a new name and retry?
67 case CATTA_ENTRY_GROUP_FAILURE :
68 /* Some kind of failure happened while we were registering our services */
69 logger(mesh, MESHLINK_ERROR, "Catta Entry group failure: %s\n", catta_strerror(catta_server_errno(mesh->catta_server)));
70 catta_simple_poll_quit(mesh->catta_poll);
73 case CATTA_ENTRY_GROUP_UNCOMMITED:
74 case CATTA_ENTRY_GROUP_REGISTERING:
80 static void discovery_create_services(meshlink_handle_t *mesh) {
81 char *fingerprint = NULL;
82 char *txt_name = NULL;
83 char *txt_fingerprint = NULL;
88 assert(mesh->catta_server);
89 assert(mesh->catta_poll);
90 assert(mesh->catta_servicetype);
93 logger(mesh, MESHLINK_DEBUG, "Adding service\n");
95 /* If this is the first time we're called, let's create a new entry group */
96 if(!(mesh->catta_group = catta_s_entry_group_new(mesh->catta_server, discovery_entry_group_callback, mesh))) {
97 logger(mesh, MESHLINK_ERROR, "catta_entry_group_new() failed: %s\n", catta_strerror(catta_server_errno(mesh->catta_server)));
101 /* Create txt records */
102 fingerprint = meshlink_get_fingerprint(mesh, (meshlink_node_t *)mesh->self);
103 xasprintf(&txt_name, "%s=%s", MESHLINK_MDNS_NAME_KEY, mesh->name);
104 xasprintf(&txt_fingerprint, "%s=%s", MESHLINK_MDNS_FINGERPRINT_KEY, fingerprint);
106 /* Add the service */
109 if((ret = catta_server_add_service(mesh->catta_server, mesh->catta_group, CATTA_IF_UNSPEC, CATTA_PROTO_UNSPEC, 0, fingerprint, mesh->catta_servicetype, NULL, NULL, atoi(mesh->myport), txt_name, txt_fingerprint, NULL)) < 0) {
110 logger(mesh, MESHLINK_ERROR, "Failed to add service: %s\n", catta_strerror(ret));
114 /* Tell the server to register the service */
115 if((ret = catta_s_entry_group_commit(mesh->catta_group)) < 0) {
116 logger(mesh, MESHLINK_ERROR, "Failed to commit entry_group: %s\n", catta_strerror(ret));
123 catta_simple_poll_quit(mesh->catta_poll);
128 free(txt_fingerprint);
131 static void discovery_server_callback(CattaServer *server, CattaServerState state, void *userdata) {
133 meshlink_handle_t *mesh = userdata;
138 case CATTA_SERVER_RUNNING:
140 /* The serve has startup successfully and registered its host
141 * name on the network, so it's time to create our services */
142 if(pthread_mutex_lock(&mesh->mutex) != 0) {
146 if(!mesh->catta_group) {
147 discovery_create_services(mesh);
150 pthread_mutex_unlock(&mesh->mutex);
154 case CATTA_SERVER_COLLISION: {
155 /* A host name collision happened. Let's pick a new name for the server */
157 generate_rand_string(mesh, hostname, sizeof(hostname));
159 if(pthread_mutex_lock(&mesh->mutex) != 0) {
163 assert(mesh->catta_server);
164 assert(mesh->catta_poll);
166 int result = catta_server_set_host_name(mesh->catta_server, hostname);
169 catta_simple_poll_quit(mesh->catta_poll);
172 pthread_mutex_unlock(&mesh->mutex);
176 case CATTA_SERVER_REGISTERING:
177 if(pthread_mutex_lock(&mesh->mutex) != 0) {
181 /* Let's drop our registered services. When the server is back
182 * in CATTA_SERVER_RUNNING state we will register them
183 * again with the new host name. */
184 if(mesh->catta_group) {
185 catta_s_entry_group_reset(mesh->catta_group);
186 mesh->catta_group = NULL;
189 pthread_mutex_unlock(&mesh->mutex);
193 case CATTA_SERVER_FAILURE:
194 if(pthread_mutex_lock(&mesh->mutex) != 0) {
198 assert(mesh->catta_server);
199 assert(mesh->catta_poll);
201 /* Terminate on failure */
202 catta_simple_poll_quit(mesh->catta_poll);
204 pthread_mutex_unlock(&mesh->mutex);
207 case CATTA_SERVER_INVALID:
212 static void discovery_resolve_callback(CattaSServiceResolver *resolver, CattaIfIndex interface_, CattaProtocol protocol, CattaResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const CattaAddress *address, uint16_t port, CattaStringList *txt, CattaLookupResultFlags flags, void *userdata) {
221 meshlink_handle_t *mesh = userdata;
225 if(event != CATTA_RESOLVER_FOUND) {
226 catta_s_service_resolver_free(resolver);
230 // retrieve fingerprint
231 CattaStringList *node_name_li = catta_string_list_find(txt, MESHLINK_MDNS_NAME_KEY);
232 CattaStringList *node_fp_li = catta_string_list_find(txt, MESHLINK_MDNS_FINGERPRINT_KEY);
234 if(node_name_li && node_fp_li) {
235 char *node_name = (char *)catta_string_list_get_text(node_name_li) + strlen(MESHLINK_MDNS_NAME_KEY);
236 char *node_fp = (char *)catta_string_list_get_text(node_fp_li) + strlen(MESHLINK_MDNS_FINGERPRINT_KEY);
238 if(node_name[0] == '=' && node_fp[0] == '=') {
239 if(pthread_mutex_lock(&mesh->mutex) != 0) {
245 meshlink_node_t *node = meshlink_get_node(mesh, node_name);
248 logger(mesh, MESHLINK_INFO, "Node %s is part of the mesh network.\n", node->name);
251 memset(&naddress, 0, sizeof(naddress));
253 switch(address->proto) {
254 case CATTA_PROTO_INET: {
255 naddress.in.sin_family = AF_INET;
256 naddress.in.sin_port = htons(port);
257 naddress.in.sin_addr.s_addr = address->data.ipv4.address;
261 case CATTA_PROTO_INET6: {
262 naddress.in6.sin6_family = AF_INET6;
263 naddress.in6.sin6_port = htons(port);
264 memcpy(naddress.in6.sin6_addr.s6_addr, address->data.ipv6.address, sizeof(naddress.in6.sin6_addr.s6_addr));
269 naddress.unknown.family = AF_UNKNOWN;
273 if(naddress.unknown.family != AF_UNKNOWN) {
274 node_t *n = (node_t *)node;
275 connection_t *c = n->connection;
277 n->catta_address = naddress;
278 node_add_recent_address(mesh, n, &naddress);
280 if(c && c->outgoing && !c->status.active) {
281 c->outgoing->timeout = 0;
283 if(c->outgoing->ev.cb) {
284 timeout_set(&mesh->loop, &c->outgoing->ev, &(struct timespec) {
289 c->last_ping_time = -3600;
293 logger(mesh, MESHLINK_WARNING, "Could not resolve node %s to a known address family type.\n", node->name);
296 logger(mesh, MESHLINK_WARNING, "Node %s is not part of the mesh network.\n", node_name);
299 pthread_mutex_unlock(&mesh->mutex);
303 catta_s_service_resolver_free(resolver);
306 static void discovery_browse_callback(CattaSServiceBrowser *browser, CattaIfIndex interface_, CattaProtocol protocol, CattaBrowserEvent event, const char *name, const char *type, const char *domain, CattaLookupResultFlags flags, void *userdata) {
309 meshlink_handle_t *mesh = userdata;
311 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
313 case CATTA_BROWSER_FAILURE:
314 if(pthread_mutex_lock(&mesh->mutex) != 0) {
318 catta_simple_poll_quit(mesh->catta_poll);
319 pthread_mutex_unlock(&mesh->mutex);
322 case CATTA_BROWSER_NEW:
323 if(pthread_mutex_lock(&mesh->mutex) != 0) {
327 catta_s_service_resolver_new(mesh->catta_server, interface_, protocol, name, type, domain, CATTA_PROTO_UNSPEC, 0, discovery_resolve_callback, mesh);
328 handle_network_change(mesh, ++mesh->catta_interfaces);
329 pthread_mutex_unlock(&mesh->mutex);
332 case CATTA_BROWSER_REMOVE:
333 if(pthread_mutex_lock(&mesh->mutex) != 0) {
337 handle_network_change(mesh, --mesh->catta_interfaces);
338 pthread_mutex_unlock(&mesh->mutex);
341 case CATTA_BROWSER_ALL_FOR_NOW:
342 case CATTA_BROWSER_CACHE_EXHAUSTED:
347 static void discovery_log_cb(CattaLogLevel level, const char *txt) {
348 meshlink_log_level_t mlevel = MESHLINK_CRITICAL;
351 case CATTA_LOG_ERROR:
352 mlevel = MESHLINK_ERROR;
356 mlevel = MESHLINK_WARNING;
359 case CATTA_LOG_NOTICE:
361 mlevel = MESHLINK_INFO;
364 case CATTA_LOG_DEBUG:
366 mlevel = MESHLINK_DEBUG;
370 logger(NULL, mlevel, "%s\n", txt);
373 static void *discovery_loop(void *userdata) {
375 meshlink_handle_t *mesh = userdata;
378 if(pthread_mutex_lock(&mesh->discovery_mutex) != 0) {
383 catta_set_log_function(discovery_log_cb);
385 // create service type string
386 char appname[strlen(mesh->appname) + 2];
387 strcpy(appname, mesh->appname);
389 for(char *p = appname; *p; p++) {
390 if(!isalnum(*p) && *p != '_' && *p != '-') {
400 size_t servicetype_strlen = sizeof(MESHLINK_MDNS_SERVICE_TYPE) + strlen(appname) + 1;
401 mesh->catta_servicetype = malloc(servicetype_strlen);
403 if(mesh->catta_servicetype == NULL) {
404 logger(mesh, MESHLINK_ERROR, "Failed to allocate memory for service type string.\n");
408 snprintf(mesh->catta_servicetype, servicetype_strlen, MESHLINK_MDNS_SERVICE_TYPE, appname);
410 // Allocate discovery loop object
411 if(!(mesh->catta_poll = catta_simple_poll_new())) {
412 logger(mesh, MESHLINK_ERROR, "Failed to create discovery poll object.\n");
416 // generate some unique host name (we actually do not care about it)
418 generate_rand_string(mesh, hostname, sizeof(hostname));
420 // Let's set the host name for this server.
421 CattaServerConfig config;
422 catta_server_config_init(&config);
423 config.host_name = catta_strdup(hostname);
424 config.publish_workstation = 0;
425 config.disallow_other_stacks = 0;
426 config.publish_hinfo = 0;
427 config.publish_addresses = 1;
428 config.publish_no_reverse = 1;
429 config.allow_point_to_point = 1;
431 /* Allocate a new server */
433 const CattaPoll *poller = catta_simple_poll_get(mesh->catta_poll);
436 logger(mesh, MESHLINK_ERROR, "Failed to create discovery server: %s\n", catta_strerror(error));
440 mesh->catta_server = catta_server_new(poller, &config, discovery_server_callback, mesh, &error);
442 /* Free the configuration data */
443 catta_server_config_free(&config);
445 /* Check whether creating the server object succeeded */
446 if(!mesh->catta_server) {
447 logger(mesh, MESHLINK_ERROR, "Failed to create discovery server: %s\n", catta_strerror(error));
451 // Create the service browser
452 if(!(mesh->catta_browser = catta_s_service_browser_new(mesh->catta_server, CATTA_IF_UNSPEC, CATTA_PROTO_UNSPEC, mesh->catta_servicetype, NULL, 0, discovery_browse_callback, mesh))) {
453 logger(mesh, MESHLINK_ERROR, "Failed to create discovery service browser: %s\n", catta_strerror(catta_server_errno(mesh->catta_server)));
461 pthread_cond_broadcast(&mesh->discovery_cond);
462 pthread_mutex_unlock(&mesh->discovery_mutex);
465 catta_simple_poll_loop(mesh->catta_poll);
468 if(mesh->catta_browser) {
469 catta_s_service_browser_free(mesh->catta_browser);
470 mesh->catta_browser = NULL;
473 if(mesh->catta_group) {
474 catta_s_entry_group_reset(mesh->catta_group);
475 catta_s_entry_group_free(mesh->catta_group);
476 mesh->catta_group = NULL;
479 if(mesh->catta_server) {
480 catta_server_free(mesh->catta_server);
481 mesh->catta_server = NULL;
484 if(mesh->catta_poll) {
485 catta_simple_poll_free(mesh->catta_poll);
486 mesh->catta_poll = NULL;
489 if(mesh->catta_servicetype) {
490 free(mesh->catta_servicetype);
491 mesh->catta_servicetype = NULL;
497 typedef struct discovery_address {
501 } discovery_address_t;
503 static int iface_compare(const void *va, const void *vb) {
509 static int address_compare(const void *va, const void *vb) {
510 const discovery_address_t *a = va;
511 const discovery_address_t *b = vb;
513 if(a->index != b->index) {
514 return a->index - b->index;
517 return sockaddrcmp_noport(&a->address, &b->address);
520 static void send_mdns_packet(meshlink_handle_t *mesh, const discovery_address_t *addr) {
521 char *host = NULL, *port = NULL;
522 sockaddr2str(&addr->address, &host, &port);
523 fprintf(stderr, "Sending on iface %d %s port %s\n", addr->index, host, port);
528 static void iface_up(meshlink_handle_t *mesh, int index) {
529 int *p = bsearch(&index, mesh->discovery_ifaces, mesh->discovery_iface_count, sizeof(*p), iface_compare);
535 fprintf(stderr, "iface %d up\n", index);
536 mesh->discovery_ifaces = xrealloc(mesh->discovery_ifaces, ++mesh->discovery_iface_count * sizeof(*p));
537 mesh->discovery_ifaces[mesh->discovery_iface_count - 1] = index;
538 qsort(mesh->discovery_ifaces, mesh->discovery_iface_count, sizeof(*p), iface_compare);
540 for(int i = 0; i < mesh->discovery_iface_count; i++) {
541 fprintf(stderr, "%d", mesh->discovery_ifaces[i]);
544 // Send an announcement for all addresses associated with this interface
545 for(int i = 0; i < mesh->discovery_address_count; i++) {
546 if(mesh->discovery_addresses[i].index == index) {
547 send_mdns_packet(mesh, &mesh->discovery_addresses[i]);
552 static void iface_down(meshlink_handle_t *const mesh, int index) {
553 int *p = bsearch(&index, mesh->discovery_ifaces, mesh->discovery_iface_count, sizeof(int), iface_compare);
559 fprintf(stderr, "iface %d down\n", index);
560 memmove(p, p + 1, --mesh->discovery_iface_count * sizeof(*p));
563 static void addr_add(meshlink_handle_t *mesh, const discovery_address_t *addr) {
564 discovery_address_t *p = bsearch(addr, mesh->discovery_addresses, mesh->discovery_address_count, sizeof(int), address_compare);
570 bool up = bsearch(&addr->index, mesh->discovery_ifaces, mesh->discovery_iface_count, sizeof(*p), iface_compare);
571 char *host = NULL, *port = NULL;
572 sockaddr2str(&addr->address, &host, &port);
573 fprintf(stderr, "address %d %s port %s up %d\n", addr->index, host, port, up);
577 mesh->discovery_addresses = xrealloc(mesh->discovery_addresses, ++mesh->discovery_address_count * sizeof(*p));
578 mesh->discovery_addresses[mesh->discovery_address_count - 1] = *addr;
579 qsort(mesh->discovery_addresses, mesh->discovery_address_count, sizeof(*p), address_compare);
581 mesh->discovery_addresses[mesh->discovery_address_count - 1].up = up;
584 send_mdns_packet(mesh, &mesh->discovery_addresses[mesh->discovery_address_count - 1]);
588 static void addr_del(meshlink_handle_t *mesh, const discovery_address_t *addr) {
589 discovery_address_t *p = bsearch(addr, mesh->discovery_addresses, mesh->discovery_address_count, sizeof(*p), address_compare);
595 char *host = NULL, *port = NULL;
596 sockaddr2str(&addr->address, &host, &port);
597 fprintf(stderr, "address %d %s port %s down\n", addr->index, host, port);
601 memmove(p, p + 1, --mesh->discovery_address_count * sizeof(*p));
605 static void netlink_getlink(int fd) {
606 static const struct {
608 struct ifinfomsg ifi;
610 .nlm.nlmsg_len = NLMSG_LENGTH(sizeof(msg.ifi)),
611 .nlm.nlmsg_type = RTM_GETLINK,
612 .nlm.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
614 .ifi.ifi_family = AF_UNSPEC,
616 send(fd, &msg, msg.nlm.nlmsg_len, 0);
619 static void netlink_getaddr(int fd) {
620 static const struct {
622 struct ifaddrmsg ifa;
624 .nlm.nlmsg_len = NLMSG_LENGTH(sizeof(msg.ifa)),
625 .nlm.nlmsg_type = RTM_GETADDR,
626 .nlm.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
628 .ifa.ifa_family = AF_UNSPEC,
630 send(fd, &msg, msg.nlm.nlmsg_len, 0);
634 static void netlink_parse_link(meshlink_handle_t *mesh, const struct nlmsghdr *nlm) {
635 const struct ifinfomsg *ifi = (const struct ifinfomsg *)(nlm + 1);
637 if(ifi->ifi_flags & IFF_UP && ifi->ifi_flags & IFF_MULTICAST) {
638 iface_up(mesh, ifi->ifi_index);
640 iface_down(mesh, ifi->ifi_index);
644 static void netlink_parse_addr(meshlink_handle_t *mesh, const struct nlmsghdr *nlm) {
645 const struct ifaddrmsg *ifa = (const struct ifaddrmsg *)(nlm + 1);
646 const uint8_t *ptr = (const uint8_t *)(ifa + 1);
647 size_t len = nlm->nlmsg_len - (ptr - (const uint8_t *)nlm);
649 while(len >= sizeof(struct rtattr)) {
650 const struct rtattr *rta = (const struct rtattr *)ptr;
652 if(rta->rta_len <= 0 || rta->rta_len > len) {
656 if(rta->rta_type == IFA_ADDRESS) {
657 discovery_address_t addr = {
658 .index = ifa->ifa_index,
661 if(rta->rta_len == 8) {
662 addr.address.sa.sa_family = AF_INET;
663 memcpy(&addr.address.in.sin_addr, ptr + 4, 4);
664 addr.address.in.sin_port = 5353;
665 } else if(rta->rta_len == 20) {
666 addr.address.sa.sa_family = AF_INET6;
667 memcpy(&addr.address.in6.sin6_addr, ptr + 4, 16);
668 addr.address.in6.sin6_port = 5353;
669 addr.address.in6.sin6_scope_id = ifa->ifa_index;
671 addr.address.sa.sa_family = AF_UNKNOWN;
674 if(addr.address.sa.sa_family != AF_UNKNOWN) {
675 if(nlm->nlmsg_type == RTM_NEWADDR) {
676 addr_add(mesh, &addr);
678 addr_del(mesh, &addr);
683 unsigned short rta_len = (rta->rta_len + 3) & ~3;
689 static void netlink_parse(meshlink_handle_t *mesh, const void *data, size_t len) {
690 const uint8_t *ptr = data;
692 while(len >= sizeof(struct nlmsghdr)) {
693 const struct nlmsghdr *nlm = (const struct nlmsghdr *)ptr;
695 if(nlm->nlmsg_len > len) {
699 switch(nlm->nlmsg_type) {
702 netlink_parse_link(mesh, nlm);
707 netlink_parse_addr(mesh, nlm);
710 ptr += nlm->nlmsg_len;
711 len -= nlm->nlmsg_len;
715 static void netlink_io_handler(event_loop_t *loop, void *data, int flags) {
717 static time_t prev_update;
718 meshlink_handle_t *mesh = data;
726 ssize_t result = recv(mesh->pfroute_io.fd, &msg, sizeof(msg), MSG_DONTWAIT);
729 if(result == 0 || errno == EAGAIN || errno == EINTR) {
733 logger(mesh, MESHLINK_ERROR, "Reading from Netlink socket failed: %s\n", strerror(errno));
734 io_set(loop, &mesh->pfroute_io, 0);
737 if((size_t)result < sizeof(msg.nlm)) {
738 logger(mesh, MESHLINK_ERROR, "Invalid Netlink message\n");
742 if(msg.nlm.nlmsg_type == NLMSG_DONE) {
743 if(msg.nlm.nlmsg_seq == 1) {
744 // We just got the result of GETLINK, now send GETADDR.
745 netlink_getaddr(mesh->pfroute_io.fd);
748 netlink_parse(mesh, &msg, result);
750 if(loop->now.tv_sec > prev_update + 5) {
751 prev_update = loop->now.tv_sec;
752 handle_network_change(mesh, 1);
757 #elif defined(RTM_NEWADDR)
758 static void pfroute_io_handler(event_loop_t *loop, void *data, int flags) {
760 static time_t prev_update;
761 meshlink_handle_t *mesh = data;
764 struct rt_msghdr rtm;
769 msg.rtm.rtm_version = 0;
770 ssize_t result = recv(mesh->pfroute_io.fd, &msg, sizeof(msg), MSG_DONTWAIT);
773 if(result == 0 || errno == EAGAIN || errno == EINTR) {
777 logger(mesh, MESHLINK_ERROR, "Reading from PFROUTE socket failed: %s\n", strerror(errno));
778 io_set(loop, &mesh->pfroute_io, 0);
781 if(msg.rtm.rtm_version != RTM_VERSION) {
782 logger(mesh, MESHLINK_ERROR, "Invalid PFROUTE message version\n");
786 switch(msg.rtm.rtm_type) {
790 if(loop->now.tv_sec > prev_update + 5) {
791 prev_update = loop->now.tv_sec;
792 handle_network_change(mesh, 1);
804 bool discovery_start(meshlink_handle_t *mesh) {
805 logger(mesh, MESHLINK_DEBUG, "discovery_start called\n");
808 assert(!mesh->catta_poll);
809 assert(!mesh->catta_server);
810 assert(!mesh->catta_browser);
811 assert(!mesh->discovery_threadstarted);
812 assert(!mesh->catta_servicetype);
814 if(pthread_mutex_lock(&mesh->discovery_mutex) != 0) {
818 // Start the discovery thread
819 if(pthread_create(&mesh->discovery_thread, NULL, discovery_loop, mesh) != 0) {
820 pthread_mutex_unlock(&mesh->discovery_mutex);
821 logger(mesh, MESHLINK_ERROR, "Could not start discovery thread: %s\n", strerror(errno));
822 memset(&mesh->discovery_thread, 0, sizeof(mesh)->discovery_thread);
826 pthread_cond_wait(&mesh->discovery_cond, &mesh->discovery_mutex);
827 pthread_mutex_unlock(&mesh->discovery_mutex);
829 mesh->discovery_threadstarted = true;
832 int sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
835 struct sockaddr_nl sa;
836 memset(&sa, 0, sizeof(sa));
837 sa.nl_family = AF_NETLINK;
838 sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
840 if(bind(sock, (struct sockaddr *)&sa, sizeof(sa)) != -1) {
841 io_add(&mesh->loop, &mesh->pfroute_io, netlink_io_handler, mesh, sock, IO_READ);
842 netlink_getlink(sock);
844 logger(mesh, MESHLINK_WARNING, "Could not bind AF_NETLINK socket: %s", strerror(errno));
847 logger(mesh, MESHLINK_WARNING, "Could not open AF_NETLINK socket: %s", strerror(errno));
850 #elif defined(RTM_NEWADDR)
851 int sock = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
854 io_add(&mesh->loop, &mesh->pfroute_io, pfroute_io_handler, mesh, sock, IO_READ);
856 logger(mesh, MESHLINK_WARNING, "Could not open PF_ROUTE socket: %s", strerror(errno));
864 void discovery_stop(meshlink_handle_t *mesh) {
865 logger(mesh, MESHLINK_DEBUG, "discovery_stop called\n");
869 free(mesh->discovery_ifaces);
870 free(mesh->discovery_addresses);
871 mesh->discovery_iface_count = 0;
872 mesh->discovery_address_count = 0;
874 if(mesh->pfroute_io.cb) {
875 close(mesh->pfroute_io.fd);
876 io_del(&mesh->loop, &mesh->pfroute_io);
880 if(mesh->catta_poll) {
881 catta_simple_poll_quit(mesh->catta_poll);
884 // Wait for the discovery thread to finish
885 if(mesh->discovery_threadstarted == true) {
886 if(pthread_join(mesh->discovery_thread, NULL) != 0) {
890 mesh->discovery_threadstarted = false;
893 mesh->catta_interfaces = 0;