From cb7d65f23e1529221b7eb311d886ff5260952945 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 1 Nov 2005 23:12:23 +0000 Subject: [PATCH] * Always specfify the local IP address when joining mcast groups. This increases compatibility with *BSD and is smoother on other systems, too git-svn-id: file:///home/lennart/svn/public/avahi/trunk@921 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- avahi-core/iface.c | 116 ++++++++++++++++++++++++++++++++++---------- avahi-core/iface.h | 2 + avahi-core/socket.c | 23 +++++---- avahi-core/socket.h | 9 +--- 4 files changed, 108 insertions(+), 42 deletions(-) diff --git a/avahi-core/iface.c b/avahi-core/iface.c index 6a92b8e..6fc66d3 100644 --- a/avahi-core/iface.c +++ b/avahi-core/iface.c @@ -172,6 +172,88 @@ 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]; + assert(i); + + assert((join && !i->mcast_joined) || (!join && i->mcast_joined)); + + 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) { + avahi_log_warn(__FILE__": interface_mdns_mcast_join() called but no local address available."); + 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) { + if (avahi_mdns_mcast_join_ipv6(i->monitor->server->fd_ipv6, &i->local_mcast_address.data.ipv6, i->hardware->index, join) < 0) + return -1; + + } else { + assert(i->protocol == AVAHI_PROTO_INET); + + if (avahi_mdns_mcast_join_ipv4(i->monitor->server->fd_ipv4, &i->local_mcast_address.data.ipv4, i->hardware->index, join) < 0) + return -1; + } + + 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); @@ -181,6 +263,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); } @@ -193,6 +277,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); @@ -246,6 +333,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); @@ -333,30 +421,6 @@ AvahiInterfaceAddress *avahi_interface_address_new(AvahiInterfaceMonitor *m, Ava return a; } -static int interface_mdns_mcast_join(AvahiInterface *i, int join) { - - if (i->protocol == AVAHI_PROTO_INET6) - return avahi_mdns_mcast_join_ipv6(i->monitor->server->fd_ipv6, i->hardware->index, join); - else if (i->protocol == AVAHI_PROTO_INET) { - -#ifdef HAVE_STRUCT_IP_MREQN - return avahi_mdns_mcast_join_ipv4(i->monitor->server->fd_ipv4, i->hardware->index, join); - -#else - AvahiInterfaceAddress *ia; - int r = 0; - - for (ia = i->addresses; ia; ia = ia->address_next) - r |= avahi_mdns_mcast_join_ipv4(i->monitor->server->fd_ipv4, &ia->address, join); - - return r; -#endif - } - - abort(); -} - - void avahi_interface_check_relevant(AvahiInterface *i) { int b; AvahiInterfaceMonitor *m; @@ -388,7 +452,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) { diff --git a/avahi-core/iface.h b/avahi-core/iface.h index 24da316..e7c2298 100644 --- a/avahi-core/iface.h +++ b/avahi-core/iface.h @@ -99,6 +99,8 @@ struct AvahiInterface { AvahiProtocol protocol; int announcing; + AvahiAddress local_mcast_address; + int mcast_joined; AvahiCache *cache; diff --git a/avahi-core/socket.c b/avahi-core/socket.c index c03cc34..728bea5 100644 --- a/avahi-core/socket.c +++ b/avahi-core/socket.c @@ -102,25 +102,25 @@ static void ipv6_address_to_sockaddr(struct sockaddr_in6 *ret_sa, const AvahiIPv memcpy(&ret_sa->sin6_addr, a, sizeof(AvahiIPv6Address)); } +int avahi_mdns_mcast_join_ipv4(int fd, const AvahiIPv4Address *a, int idx, int join) { #ifdef HAVE_STRUCT_IP_MREQN -int avahi_mdns_mcast_join_ipv4(int fd, int idx, int join) { struct ip_mreqn mreq; #else -int avahi_mdns_mcast_join_ipv4(int fd, const AvahiAddress *a, int join) { struct ip_mreq mreq; #endif - struct sockaddr_in sa; - memset(&mreq, 0, sizeof(mreq)); + assert(fd >= 0); + assert(idx >= 0); + assert(a); + + memset(&mreq, 0, sizeof(mreq)); #ifdef HAVE_STRUCT_IP_MREQN mreq.imr_ifindex = idx; + mreq.imr_address.s_addr = a->address; #else - assert(a); - assert(a->proto == AVAHI_PROTO_INET); - mreq.imr_interface.s_addr = a->data.ipv4.address; + mreq.imr_interface.s_addr = a->address; #endif - mdns_mcast_group_ipv4(&sa); mreq.imr_multiaddr = sa.sin_addr; @@ -132,13 +132,16 @@ int avahi_mdns_mcast_join_ipv4(int fd, const AvahiAddress *a, int join) { return 0; } -int avahi_mdns_mcast_join_ipv6(int fd, int idx, int join) { +int avahi_mdns_mcast_join_ipv6(int fd, const AvahiIPv6Address *a, int idx, int join) { struct ipv6_mreq mreq6; struct sockaddr_in6 sa6; - mdns_mcast_group_ipv6 (&sa6); + assert(fd >= 0); + assert(idx >= 0); + assert(a); memset(&mreq6, 0, sizeof(mreq6)); + mdns_mcast_group_ipv6 (&sa6); mreq6.ipv6mr_multiaddr = sa6.sin6_addr; mreq6.ipv6mr_interface = idx; diff --git a/avahi-core/socket.h b/avahi-core/socket.h index 02990b7..57f9153 100644 --- a/avahi-core/socket.h +++ b/avahi-core/socket.h @@ -44,12 +44,7 @@ int avahi_send_dns_packet_ipv6(int fd, int iface, AvahiDnsPacket *p, const Avahi AvahiDnsPacket *avahi_recv_dns_packet_ipv4(int fd, struct sockaddr_in*ret_sa, AvahiIPv4Address *ret_dest_address, int *ret_iface, uint8_t *ret_ttl); AvahiDnsPacket *avahi_recv_dns_packet_ipv6(int fd, struct sockaddr_in6*ret_sa, AvahiIPv6Address *ret_dest_address, int *ret_iface, uint8_t *ret_ttl); -#ifdef HAVE_STRUCT_IP_MREQN -int avahi_mdns_mcast_join_ipv4(int fd, int idx, int join); -#else -int avahi_mdns_mcast_join_ipv4(int fd, const AvahiAddress *a, int join); -#endif - -int avahi_mdns_mcast_join_ipv6(int fd, int idx, int join); +int avahi_mdns_mcast_join_ipv4(int fd, const AvahiIPv4Address *a, int iface, int join); +int avahi_mdns_mcast_join_ipv6(int fd, const AvahiIPv6Address *a, int iface, int join); #endif -- 2.39.2