X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=avahi-core%2Fiface.c;h=8098de4a38bb335465feaebbab7c9af5d0947755;hb=9a048b843719ad831c17b030ac522bc1e57122f8;hp=39d26c3a72d53779de41e2a1fcd28d04093e194e;hpb=3adbda2cd5be48b7c630325f0f92e315d7eb2cfb;p=catta diff --git a/avahi-core/iface.c b/avahi-core/iface.c index 39d26c3..8098de4 100644 --- a/avahi-core/iface.c +++ b/avahi-core/iface.c @@ -24,9 +24,12 @@ #endif #include -#include #include #include +#include +#include +#include +#include #include #include @@ -47,9 +50,9 @@ void avahi_interface_address_update_rrs(AvahiInterfaceAddress *a, int remove_rrs assert(a); m = a->monitor; - if (a->interface->announcing && - m->list_complete && + if (m->list_complete && avahi_interface_address_is_relevant(a) && + avahi_interface_is_relevant(a->interface) && !remove_rrs && m->server->config.publish_addresses && (m->server->state == AVAHI_SERVER_RUNNING || @@ -64,11 +67,15 @@ void avahi_interface_address_update_rrs(AvahiInterfaceAddress *a, int remove_rrs if (avahi_s_entry_group_is_empty(a->entry_group)) { char t[AVAHI_ADDRESS_STR_MAX]; - avahi_address_snprint(t, sizeof(t), &a->address); + AvahiProtocol p; - avahi_log_info("Registering new address %s on %s.", t, a->interface->hardware->name); + p = (a->interface->protocol == AVAHI_PROTO_INET && m->server->config.publish_a_on_ipv6) || + (a->interface->protocol == AVAHI_PROTO_INET6 && m->server->config.publish_aaaa_on_ipv4) ? AVAHI_PROTO_UNSPEC : a->interface->protocol; + + avahi_address_snprint(t, sizeof(t), &a->address); + avahi_log_info("Registering new address record for %s on %s.%s.", t, a->interface->hardware->name, p == AVAHI_PROTO_UNSPEC ? "*" : avahi_proto_to_string(p)); - if (avahi_server_add_address(m->server, a->entry_group, a->interface->hardware->index, a->interface->protocol, 0, NULL, &a->address) < 0) { + if (avahi_server_add_address(m->server, a->entry_group, a->interface->hardware->index, p, 0, NULL, &a->address) < 0) { avahi_log_warn(__FILE__": avahi_server_add_address() failed: %s", avahi_strerror(m->server->error)); avahi_s_entry_group_free(a->entry_group); a->entry_group = NULL; @@ -89,7 +96,7 @@ void avahi_interface_address_update_rrs(AvahiInterfaceAddress *a, int remove_rrs m->server->state == AVAHI_SERVER_REGISTERING) avahi_server_decrease_host_rr_pending(m->server); - avahi_log_info("Withdrawing address %s on %s.", t, a->interface->hardware->name); + avahi_log_info("Withdrawing address record for %s on %s.", t, a->interface->hardware->name); avahi_s_entry_group_reset(a->entry_group); } @@ -118,8 +125,7 @@ void avahi_hw_interface_update_rrs(AvahiHwInterface *hw, int remove_rrs) { if (m->list_complete && !remove_rrs && m->server->config.publish_workstation && - (m->server->state == AVAHI_SERVER_RUNNING || - m->server->state == AVAHI_SERVER_REGISTERING)) { + (m->server->state == AVAHI_SERVER_RUNNING)) { if (!hw->entry_group) hw->entry_group = avahi_s_entry_group_new(m->server, avahi_host_rr_entry_group_callback, NULL); @@ -128,18 +134,11 @@ void avahi_hw_interface_update_rrs(AvahiHwInterface *hw, int remove_rrs) { return; /* OOM */ if (avahi_s_entry_group_is_empty(hw->entry_group)) { - char name[AVAHI_LABEL_MAX]; - char *t; - - if (!(t = avahi_format_mac_address(hw->mac_address, hw->mac_address_size))) - return; /* OOM */ + char name[AVAHI_LABEL_MAX], mac[256]; - snprintf(name, sizeof(name), "%s [%s]", m->server->host_name, t); - avahi_free(t); + avahi_format_mac_address(mac, sizeof(mac), hw->mac_address, hw->mac_address_size); + snprintf(name, sizeof(name), "%s [%s]", m->server->host_name, mac); - if (!name) - return; /* OOM */ - if (avahi_server_add_service(m->server, hw->entry_group, hw->index, AVAHI_PROTO_UNSPEC, 0, name, "_workstation._tcp", NULL, NULL, 9, NULL) < 0) { avahi_log_warn(__FILE__": avahi_server_add_service() failed: %s", avahi_strerror(m->server->error)); avahi_s_entry_group_free(hw->entry_group); @@ -169,6 +168,93 @@ void avahi_interface_monitor_update_rrs(AvahiInterfaceMonitor *m, int remove_rrs avahi_hw_interface_update_rrs(hw, remove_rrs); } +static int interface_mdns_mcast_join(AvahiInterface *i, int join) { + char at[AVAHI_ADDRESS_STR_MAX]; + int r; + assert(i); + + if (!!join == !!i->mcast_joined) + return 0; + + if ((i->protocol == AVAHI_PROTO_INET6 && i->monitor->server->fd_ipv6 < 0) || + (i->protocol == AVAHI_PROTO_INET && i->monitor->server->fd_ipv4 < 0)) + return -1; + + if (join) { + AvahiInterfaceAddress *a; + + /* Look if there's an address with global scope */ + for (a = i->addresses; a; a = a->address_next) + if (a->global_scope) + break; + + /* No address with a global scope has been found, so let's use + * any. */ + if (!a) + a = i->addresses; + + /* Hmm, there is no address available. */ + if (!a) + return -1; + + i->local_mcast_address = a->address; + } + + avahi_log_info("%s mDNS multicast group on interface %s.%s with address %s.", + join ? "Joining" : "Leaving", + i->hardware->name, + avahi_proto_to_string(i->protocol), + avahi_address_snprint(at, sizeof(at), &i->local_mcast_address)); + + if (i->protocol == AVAHI_PROTO_INET6) + r = avahi_mdns_mcast_join_ipv6(i->monitor->server->fd_ipv6, &i->local_mcast_address.data.ipv6, i->hardware->index, join); + else { + assert(i->protocol == AVAHI_PROTO_INET); + + r = avahi_mdns_mcast_join_ipv4(i->monitor->server->fd_ipv4, &i->local_mcast_address.data.ipv4, i->hardware->index, join); + } + + if (r < 0) + i->mcast_joined = 0; + else + i->mcast_joined = join; + + return 0; +} + +static int interface_mdns_mcast_rejoin(AvahiInterface *i) { + AvahiInterfaceAddress *a, *usable = NULL, *found = NULL; + assert(i); + + if (!i->mcast_joined) + return 0; + + /* Check whether old address we joined with is still available. If + * not, rejoin using an other address. */ + + for (a = i->addresses; a; a = a->address_next) { + if (a->global_scope && !usable) + usable = a; + + if (avahi_address_cmp(&a->address, &i->local_mcast_address) == 0) { + + if (a->global_scope) + /* No action necessary: the address still exists and + * has global scope. */ + return 0; + + found = a; + } + } + + if (found && !usable) + /* No action necessary: the address still exists and no better one has been found */ + return 0; + + interface_mdns_mcast_join(i, 0); + return interface_mdns_mcast_join(i, 1); +} + void avahi_interface_address_free(AvahiInterfaceAddress *a) { assert(a); assert(a->interface); @@ -178,6 +264,8 @@ void avahi_interface_address_free(AvahiInterfaceAddress *a) { if (a->entry_group) avahi_s_entry_group_free(a->entry_group); + + interface_mdns_mcast_rejoin(a->interface); avahi_free(a); } @@ -190,6 +278,9 @@ void avahi_interface_free(AvahiInterface *i, int send_goodbye) { avahi_response_scheduler_force(i->response_scheduler); assert(!i->announcers); + if (i->mcast_joined) + interface_mdns_mcast_join(i, 0); + /* Remove queriers */ avahi_querier_free_all(i); avahi_hashmap_free(i->queriers_by_key); @@ -243,6 +334,7 @@ AvahiInterface* avahi_interface_new(AvahiInterfaceMonitor *m, AvahiHwInterface * i->hardware = hw; i->protocol = protocol; i->announcing = 0; + i->mcast_joined = 0; AVAHI_LLIST_HEAD_INIT(AvahiInterfaceAddress, i->addresses); AVAHI_LLIST_HEAD_INIT(AvahiAnnouncer, i->announcers); @@ -301,9 +393,9 @@ AvahiHwInterface *avahi_hw_interface_new(AvahiInterfaceMonitor *m, AvahiIfIndex avahi_hashmap_insert(m->hashmap, &hw->index, hw); - if (m->server->fd_ipv4 >= 0) + if (m->server->fd_ipv4 >= 0 || m->server->config.publish_a_on_ipv6) avahi_interface_new(m, hw, AVAHI_PROTO_INET); - if (m->server->fd_ipv6 >= 0) + if (m->server->fd_ipv6 >= 0 || m->server->config.publish_aaaa_on_ipv4) avahi_interface_new(m, hw, AVAHI_PROTO_INET6); return hw; @@ -340,23 +432,20 @@ void avahi_interface_check_relevant(AvahiInterface *i) { b = avahi_interface_is_relevant(i); if (m->list_complete && b && !i->announcing) { - avahi_log_info("New relevant interface %s.%s.", i->hardware->name, avahi_proto_to_string(i->protocol)); + interface_mdns_mcast_join(i, 1); - if (i->protocol == AVAHI_PROTO_INET) - avahi_mdns_mcast_join_ipv4(m->server->fd_ipv4, i->hardware->index); - if (i->protocol == AVAHI_PROTO_INET6) - avahi_mdns_mcast_join_ipv6(m->server->fd_ipv6, i->hardware->index); + if (i->mcast_joined) { + avahi_log_info("New relevant interface %s.%s for mDNS.", i->hardware->name, avahi_proto_to_string(i->protocol)); - i->announcing = 1; - avahi_announce_interface(m->server, i); - avahi_multicast_lookup_engine_new_interface(m->server->multicast_lookup_engine, i); + i->announcing = 1; + avahi_announce_interface(m->server, i); + avahi_multicast_lookup_engine_new_interface(m->server->multicast_lookup_engine, i); + } + } else if (!b && i->announcing) { - avahi_log_info("Interface %s.%s no longer relevant.", i->hardware->name, avahi_proto_to_string(i->protocol)); + avahi_log_info("Interface %s.%s no longer relevant for mDNS.", i->hardware->name, avahi_proto_to_string(i->protocol)); - if (i->protocol == AVAHI_PROTO_INET) - avahi_mdns_mcast_leave_ipv4(m->server->fd_ipv4, i->hardware->index); - if (i->protocol == AVAHI_PROTO_INET6) - avahi_mdns_mcast_leave_ipv6(m->server->fd_ipv6, i->hardware->index); + interface_mdns_mcast_join(i, 0); avahi_goodbye_interface(m->server, i, 0, 1); avahi_querier_free_all(i); @@ -367,7 +456,9 @@ void avahi_interface_check_relevant(AvahiInterface *i) { avahi_cache_flush(i->cache); i->announcing = 0; - } + + } else + interface_mdns_mcast_rejoin(i); } void avahi_hw_interface_check_relevant(AvahiHwInterface *hw) { @@ -448,7 +539,7 @@ AvahiInterface* avahi_interface_monitor_get_interface(AvahiInterfaceMonitor *m, AvahiHwInterface* avahi_interface_monitor_get_hw_interface(AvahiInterfaceMonitor *m, AvahiIfIndex idx) { assert(m); - assert(idx > 0); + assert(idx >= 0); return avahi_hashmap_lookup(m->hashmap, &idx); } @@ -467,26 +558,19 @@ AvahiInterfaceAddress* avahi_interface_monitor_get_address(AvahiInterfaceMonitor return NULL; } - void avahi_interface_send_packet_unicast(AvahiInterface *i, AvahiDnsPacket *p, const AvahiAddress *a, uint16_t port) { assert(i); assert(p); -/* char t[AVAHI_ADDRESS_STR_MAX]; */ - if (!avahi_interface_is_relevant(i)) + if (!i->announcing) return; assert(!a || a->proto == i->protocol); -/* if (a) */ -/* avahi_log_debug("unicast sending on '%s.%i' to %s:%u", i->hardware->name, i->protocol, avahi_address_snprint(t, sizeof(t), a), port); */ -/* else */ -/* avahi_log_debug("multicast sending on '%s.%i'", i->hardware->name, i->protocol); */ - if (i->protocol == AVAHI_PROTO_INET && i->monitor->server->fd_ipv4 >= 0) - avahi_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->hardware->index, p, a ? &a->data.ipv4 : NULL, port); + avahi_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->hardware->index, p, i->mcast_joined ? &i->local_mcast_address.data.ipv4 : NULL, a ? &a->data.ipv4 : NULL, port); else if (i->protocol == AVAHI_PROTO_INET6 && i->monitor->server->fd_ipv6 >= 0) - avahi_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->hardware->index, p, a ? &a->data.ipv6 : NULL, port); + avahi_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->hardware->index, p, i->mcast_joined ? &i->local_mcast_address.data.ipv6 : NULL, a ? &a->data.ipv6 : NULL, port); } void avahi_interface_send_packet(AvahiInterface *i, AvahiDnsPacket *p) { @@ -496,34 +580,39 @@ void avahi_interface_send_packet(AvahiInterface *i, AvahiDnsPacket *p) { avahi_interface_send_packet_unicast(i, p, NULL, 0); } -int avahi_interface_post_query(AvahiInterface *i, AvahiKey *key, int immediately) { +int avahi_interface_post_query(AvahiInterface *i, AvahiKey *key, int immediately, unsigned *ret_id) { assert(i); assert(key); - if (avahi_interface_is_relevant(i)) - return avahi_query_scheduler_post(i->query_scheduler, key, immediately); + if (!i->announcing) + return 0; + + return avahi_query_scheduler_post(i->query_scheduler, key, immediately, ret_id); +} + +int avahi_interface_withraw_query(AvahiInterface *i, unsigned id) { - return 0; + return avahi_query_scheduler_withdraw_by_id(i->query_scheduler, id); } int avahi_interface_post_response(AvahiInterface *i, AvahiRecord *record, int flush_cache, const AvahiAddress *querier, int immediately) { assert(i); assert(record); - if (avahi_interface_is_relevant(i)) - return avahi_response_scheduler_post(i->response_scheduler, record, flush_cache, querier, immediately); - - return 0; + if (!i->announcing) + return 0; + + return avahi_response_scheduler_post(i->response_scheduler, record, flush_cache, querier, immediately); } int avahi_interface_post_probe(AvahiInterface *i, AvahiRecord *record, int immediately) { assert(i); assert(record); - if (avahi_interface_is_relevant(i)) - return avahi_probe_scheduler_post(i->probe_scheduler, record, immediately); + if (!i->announcing) + return 0; - return 0; + return avahi_probe_scheduler_post(i->probe_scheduler, record, immediately); } int avahi_dump_caches(AvahiInterfaceMonitor *m, AvahiDumpCallback callback, void* userdata) { @@ -545,21 +634,19 @@ int avahi_dump_caches(AvahiInterfaceMonitor *m, AvahiDumpCallback callback, void int avahi_interface_is_relevant(AvahiInterface *i) { AvahiInterfaceAddress *a; - int relevant_address; assert(i); - relevant_address = 0; + if (!i->hardware->flags_ok) + return 0; for (a = i->addresses; a; a = a->address_next) - if (avahi_interface_address_is_relevant(a)) { - relevant_address = 1; - break; - } + if (avahi_interface_address_is_relevant(a)) + return 1; - return i->hardware->flags_ok && relevant_address; + return 0; } - + int avahi_interface_address_is_relevant(AvahiInterfaceAddress *a) { AvahiInterfaceAddress *b; assert(a); @@ -706,3 +793,27 @@ int avahi_interface_has_address(AvahiInterfaceMonitor *m, AvahiIfIndex iface, co return 0; } + +AvahiIfIndex avahi_find_interface_for_address(AvahiInterfaceMonitor *m, const AvahiAddress *a) { + AvahiInterface *i; + assert(m); + + /* Some stupid OS don't support passing the interface index when a + * packet is received. We have to work around that limitation by + * looking for an interface that has the incoming address + * attached. This is sometimes ambiguous, but we have to live with + * it. */ + + for (i = m->interfaces; i; i = i->interface_next) { + AvahiInterfaceAddress *ai; + + if (i->protocol != a->proto) + continue; + + for (ai = i->addresses; ai; ai = ai->address_next) + if (avahi_address_cmp(a, &ai->address) == 0) + return i->hardware->index; + } + + return AVAHI_IF_UNSPEC; +}