static void browse_record_callback(AvahiRecordBrowser *b, AvahiIfIndex intf, AvahiProtocol proto, AvahiBrowserEvent event, const char *hostname, uint16_t clazz, uint16_t type, const void *rdata, size_t size, AvahiLookupResultFlags flags, void *userdata) { struct mdns_record_browser *rb_data; AvahiAddress addr; char address[AVAHI_ADDRESS_STR_MAX]; int family; int ret; rb_data = (struct mdns_record_browser *)userdata; if (event == AVAHI_BROWSER_CACHE_EXHAUSTED) DPRINTF(E_DBG, L_MDNS, "Avahi Record Browser (%s, proto %d): no more results (CACHE_EXHAUSTED)\n", hostname, proto); else if (event == AVAHI_BROWSER_ALL_FOR_NOW) DPRINTF(E_DBG, L_MDNS, "Avahi Record Browser (%s, proto %d): no more results (ALL_FOR_NOW)\n", hostname, proto); else if (event == AVAHI_BROWSER_FAILURE) DPRINTF(E_LOG, L_MDNS, "Avahi Record Browser (%s, proto %d) failure: %s\n", hostname, proto, MDNSERR); else if (event == AVAHI_BROWSER_REMOVE) return; // Not handled - record browser lifetime too short for this to happen if (event != AVAHI_BROWSER_NEW) goto out_free_record_browser; ret = avahi_address_make(&addr, proto, rdata, size); // Not an avahi function despite the name if (ret < 0) return; family = avahi_proto_to_af(proto); avahi_address_snprint(address, sizeof(address), &addr); // Avahi will sometimes give us link-local addresses in 169.254.0.0/16 or // fe80::/10, which (most of the time) are useless // - see also https://lists.freedesktop.org/archives/avahi/2012-September/002183.html if ((proto == AVAHI_PROTO_INET && is_v4ll(&addr.data.ipv4)) || (proto == AVAHI_PROTO_INET6 && is_v6ll(&addr.data.ipv6))) { DPRINTF(E_WARN, L_MDNS, "Ignoring announcement from %s, address %s is link-local\n", hostname, address); return; } DPRINTF(E_DBG, L_MDNS, "Avahi Record Browser (%s, proto %d): NEW record %s for service type '%s'\n", hostname, proto, address, rb_data->mb->type); // Execute callback (mb->cb) with all the data rb_data->mb->cb(rb_data->name, rb_data->mb->type, rb_data->domain, hostname, family, address, rb_data->port, &rb_data->txt_kv); // Stop record browser out_free_record_browser: keyval_clear(&rb_data->txt_kv); free(rb_data->name); free(rb_data->domain); free(rb_data); avahi_record_browser_free(b); }
static void browse_record_callback_v4(AvahiRecordBrowser *b, AvahiIfIndex intf, AvahiProtocol proto, AvahiBrowserEvent event, const char *hostname, uint16_t clazz, uint16_t type, const void *rdata, size_t size, AvahiLookupResultFlags flags, void *userdata) { char address[INET_ADDRSTRLEN]; struct in_addr addr; struct mdns_record_browser *rb_data; int ll; rb_data = (struct mdns_record_browser *)userdata; switch (event) { case AVAHI_BROWSER_NEW: if (size != sizeof(addr.s_addr)) { DPRINTF(E_WARN, L_MDNS, "Got RR type A size %ld (should be %ld)\n", (long)size, (long)sizeof(addr.s_addr)); return; } memcpy(&addr.s_addr, rdata, sizeof(addr.s_addr)); ll = is_v4ll(&addr); if (ll && !(rb_data->mb->flags & MDNS_WANT_V4LL)) { DPRINTF(E_DBG, L_MDNS, "Discarding IPv4 LL, not interested (service %s)\n", rb_data->name); return; } else if (!ll && !(rb_data->mb->flags & MDNS_WANT_V4)) { DPRINTF(E_DBG, L_MDNS, "Discarding IPv4, not interested (service %s)\n", rb_data->name); return; } if (!inet_ntop(AF_INET, &addr.s_addr, address, sizeof(address))) { DPRINTF(E_LOG, L_MDNS, "Could not print IPv4 address: %s\n", strerror(errno)); return; } DPRINTF(E_DBG, L_MDNS, "Service %s, hostname %s resolved to %s\n", rb_data->name, hostname, address); /* Execute callback (mb->cb) with all the data */ rb_data->mb->cb(rb_data->name, rb_data->mb->type, rb_data->domain, hostname, AF_INET, address, rb_data->port, &rb_data->txt_kv); /* Got a suitable address, stop record browser */ break; case AVAHI_BROWSER_REMOVE: /* Not handled - record browser lifetime too short for this to happen */ return; case AVAHI_BROWSER_CACHE_EXHAUSTED: case AVAHI_BROWSER_ALL_FOR_NOW: DPRINTF(E_DBG, L_MDNS, "Avahi Record Browser (%s v4): no more results (%s)\n", hostname, (event == AVAHI_BROWSER_CACHE_EXHAUSTED) ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW"); break; case AVAHI_BROWSER_FAILURE: DPRINTF(E_LOG, L_MDNS, "Avahi Record Browser (%s v4) failure: %s\n", hostname, avahi_strerror(avahi_client_errno(avahi_record_browser_get_client(b)))); break; } keyval_clear(&rb_data->txt_kv); free(rb_data->name); free(rb_data->domain); free(rb_data); avahi_record_browser_free(b); }
static void mdns_browse_call_cb(struct mdns_addr_lookup *lu, const char *hostname, const struct sockaddr *address) { char addr_str[INET6_ADDRSTRLEN]; if (address->sa_family == AF_INET) { struct sockaddr_in *addr = (struct sockaddr_in *)address; if (!inet_ntop(AF_INET, &addr->sin_addr, addr_str, sizeof(addr_str))) { DPRINTF(E_LOG, L_MDNS, "Could not print IPv4 address: %s\n", strerror(errno)); return; } if (!(lu->rs->mb->protocol & kDNSServiceProtocol_IPv4)) { DPRINTF(E_DBG, L_MDNS, "Discarding IPv4, not interested (service %s)\n", lu->rs->service); return; } else if (is_v4ll(&addr->sin_addr)) { DPRINTF(E_WARN, L_MDNS, "Ignoring announcement from %s, address %s is link-local\n", hostname, addr_str); return; } } else if (address->sa_family == AF_INET6) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)address; if (!inet_ntop(AF_INET6, &addr6->sin6_addr, addr_str, sizeof(addr_str))) { DPRINTF(E_LOG, L_MDNS, "Could not print IPv6 address: %s\n", strerror(errno)); return; } if (!(lu->rs->mb->protocol & kDNSServiceProtocol_IPv6)) { DPRINTF(E_DBG, L_MDNS, "Discarding IPv6, not interested (service %s)\n", lu->rs->service); return; } else if (is_v6ll(&addr6->sin6_addr)) { DPRINTF(E_WARN, L_MDNS, "Ignoring announcement from %s, address %s is link-local\n", hostname, addr_str); return; } } DPRINTF(E_DBG, L_MDNS, "Service %s, hostname %s resolved to %s\n", lu->rs->service, hostname, addr_str); /* Execute callback (mb->cb) with all the data */ lu->rs->mb->cb(lu->rs->service, lu->rs->regtype, lu->rs->domain, hostname, address->sa_family, addr_str, lu->port, &lu->txt_kv); }