]> git.meshlink.io Git - catta/blobdiff - avahi-core/iface.c
Match rr_pending increases/decreases. Fixed crash (assert rr_pending>0)
[catta] / avahi-core / iface.c
index 86710449744e25fc30bdaf7b14a0874fb807b44b..38d9909cb28c6d91a7490676b14712a7e6a2b569 100644 (file)
@@ -32,6 +32,7 @@
 #include <net/if.h>
 #include <stdio.h>
 
+#include <avahi-common/error.h>
 #include <avahi-common/malloc.h>
 
 #include "iface.h"
@@ -46,7 +47,9 @@ static void update_address_rr(AvahiInterfaceMonitor *m, AvahiInterfaceAddress *a
     assert(m);
     assert(a);
 
-    if (avahi_interface_address_relevant(a) &&
+    if (a->interface->announcing &&
+        m->list == LIST_DONE &&
+        avahi_interface_address_relevant(a) &&
         !remove_rrs &&
         m->server->config.publish_addresses &&
         (m->server->state == AVAHI_SERVER_RUNNING ||
@@ -54,32 +57,41 @@ static void update_address_rr(AvahiInterfaceMonitor *m, AvahiInterfaceAddress *a
 
         /* Fill the entry group */
         if (!a->entry_group) 
-            a->entry_group = avahi_entry_group_new(m->server, avahi_host_rr_entry_group_callback, NULL);
+            a->entry_group = avahi_s_entry_group_new(m->server, avahi_host_rr_entry_group_callback, NULL);
 
         if (!a->entry_group) /* OOM */
             return;
         
-        if (avahi_entry_group_is_empty(a->entry_group)) {
+        if (avahi_s_entry_group_is_empty(a->entry_group)) {
+            char t[64];
+            avahi_address_snprint(t, sizeof(t), &a->address);
+
+            avahi_log_info("Registering new address %s on %s.", t, a->interface->hardware->name);
 
             if (avahi_server_add_address(m->server, a->entry_group, a->interface->hardware->index, a->interface->protocol, 0, NULL, &a->address) < 0) {
                 avahi_log_warn(__FILE__": avahi_server_add_address() failed: %s", avahi_strerror(m->server->error));
-                avahi_entry_group_free(a->entry_group);
+                avahi_s_entry_group_free(a->entry_group);
                 a->entry_group = NULL;
                 return;
             }
 
-            avahi_entry_group_commit(a->entry_group);
+            avahi_s_entry_group_commit(a->entry_group);
         }
     } else {
 
         /* Clear the entry group */
 
-        if (a->entry_group && !avahi_entry_group_is_empty(a->entry_group)) {
+        if (a->entry_group && !avahi_s_entry_group_is_empty(a->entry_group)) {
+            char t[64];
+            avahi_address_snprint(t, sizeof(t), &a->address);
 
-            if (avahi_entry_group_get_state(a->entry_group) == AVAHI_ENTRY_GROUP_REGISTERING)
+            if (avahi_s_entry_group_get_state(a->entry_group) == AVAHI_ENTRY_GROUP_REGISTERING &&
+               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_entry_group_reset(a->entry_group);
+            avahi_s_entry_group_reset(a->entry_group);
         }
     } 
 }
@@ -103,18 +115,19 @@ static void update_hw_interface_rr(AvahiInterfaceMonitor *m, AvahiHwInterface *h
     for (i = hw->interfaces; i; i = i->by_hardware_next)
         update_interface_rr(m, i, remove_rrs);
 
-    if (!remove_rrs &&
+    if (m->list == LIST_DONE &&
+        !remove_rrs &&
         m->server->config.publish_workstation &&
         (m->server->state == AVAHI_SERVER_RUNNING ||
         m->server->state == AVAHI_SERVER_REGISTERING)) {
 
         if (!hw->entry_group)
-            hw->entry_group = avahi_entry_group_new(m->server, avahi_host_rr_entry_group_callback, NULL);
+            hw->entry_group = avahi_s_entry_group_new(m->server, avahi_host_rr_entry_group_callback, NULL);
 
         if (!hw->entry_group)
             return; /* OOM */
         
-        if (avahi_entry_group_is_empty(hw->entry_group)) {
+        if (avahi_s_entry_group_is_empty(hw->entry_group)) {
             char *name;
             char *t;
 
@@ -129,22 +142,22 @@ static void update_hw_interface_rr(AvahiInterfaceMonitor *m, AvahiHwInterface *h
             
             if (avahi_server_add_service(m->server, hw->entry_group, hw->index, AVAHI_PROTO_UNSPEC, name, "_workstation._tcp", NULL, NULL, 9, NULL) < 0) { 
                 avahi_log_warn(__FILE__": avahi_server_add_service() failed.");
-                avahi_entry_group_free(hw->entry_group);
+                avahi_s_entry_group_free(hw->entry_group);
                 hw->entry_group = NULL;
             } else
-                avahi_entry_group_commit(hw->entry_group);
+                avahi_s_entry_group_commit(hw->entry_group);
 
             avahi_free(name);
         }
         
     } else {
 
-        if (hw->entry_group && !avahi_entry_group_is_empty(hw->entry_group)) {
+        if (hw->entry_group && !avahi_s_entry_group_is_empty(hw->entry_group)) {
 
-            if (avahi_entry_group_get_state(hw->entry_group) == AVAHI_ENTRY_GROUP_REGISTERING)
+            if (avahi_s_entry_group_get_state(hw->entry_group) == AVAHI_ENTRY_GROUP_REGISTERING)
                 avahi_server_decrease_host_rr_pending(m->server);
 
-            avahi_entry_group_reset(hw->entry_group);
+            avahi_s_entry_group_reset(hw->entry_group);
         }
     }
 }
@@ -158,7 +171,7 @@ static void free_address(AvahiInterfaceMonitor *m, AvahiInterfaceAddress *a) {
     AVAHI_LLIST_REMOVE(AvahiInterfaceAddress, address, a->interface->addresses, a);
 
     if (a->entry_group)
-        avahi_entry_group_free(a->entry_group);
+        avahi_s_entry_group_free(a->entry_group);
     
     avahi_free(a);
 }
@@ -198,7 +211,7 @@ static void free_hw_interface(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, in
         free_interface(m, hw->interfaces, send_goodbye);
 
     if (hw->entry_group)
-        avahi_entry_group_free(hw->entry_group);
+        avahi_s_entry_group_free(hw->entry_group);
     
     AVAHI_LLIST_REMOVE(AvahiHwInterface, hardware, m->hw_interfaces, hw);
     avahi_hashmap_remove(m->hashmap, &hw->index);
@@ -293,8 +306,8 @@ static void check_interface_relevant(AvahiInterfaceMonitor *m, AvahiInterface *i
 
     b = avahi_interface_relevant(i);
 
-    if (b && !i->announcing) {
-        avahi_log_debug("New relevant interface %s.%i (#%i)", i->hardware->name, i->protocol, i->hardware->index);
+    if (m->list == LIST_DONE && b && !i->announcing) {
+        avahi_log_info("New relevant interface %s.%i.", i->hardware->name, i->protocol);
 
         if (i->protocol == AVAHI_PROTO_INET)
             avahi_mdns_mcast_join_ipv4(m->server->fd_ipv4, i->hardware->index);
@@ -305,7 +318,7 @@ static void check_interface_relevant(AvahiInterfaceMonitor *m, AvahiInterface *i
         avahi_announce_interface(m->server, i);
         avahi_browser_new_interface(m->server, i);
     } else if (!b && i->announcing) {
-        avahi_log_debug("Interface %s.%i no longer relevant", i->hardware->name, i->protocol);
+        avahi_log_info("Interface %s.%i no longer relevant.", i->hardware->name, i->protocol);
 
         if (i->protocol == AVAHI_PROTO_INET)
             avahi_mdns_mcast_leave_ipv4(m->server->fd_ipv4, i->hardware->index);
@@ -332,6 +345,14 @@ static void check_hw_interface_relevant(AvahiInterfaceMonitor *m, AvahiHwInterfa
         check_interface_relevant(m, i);
 }
 
+static void check_all_interfaces_relevant(AvahiInterfaceMonitor *m) {
+    AvahiInterface *i;
+    assert(m);
+
+    for (i = m->interfaces; i; i = i->interface_next)
+        check_interface_relevant(m, i);
+}
+
 static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdata) {
     AvahiInterfaceMonitor *m = userdata;
     
@@ -344,7 +365,7 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdat
         AvahiHwInterface *hw;
         struct rtattr *a = NULL;
         size_t l;
-
+        
         if (ifinfomsg->ifi_family != AF_UNSPEC)
             return;
 
@@ -405,8 +426,8 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdat
             a = RTA_NEXT(a, l);
         }
 
-        update_hw_interface_rr(m, hw, 0);
         check_hw_interface_relevant(m, hw);
+        update_hw_interface_rr(m, hw, 0);
         
     } else if (n->nlmsg_type == RTM_DELLINK) {
         struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
@@ -418,7 +439,6 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdat
         if (!(hw = avahi_interface_monitor_get_hw_interface(m, (AvahiIfIndex) ifinfomsg->ifi_index)))
             return;
 
-        update_hw_interface_rr(m, hw, 1);
         free_hw_interface(m, hw, 0);
         
     } else if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
@@ -482,32 +502,36 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdat
             addr->flags = ifaddrmsg->ifa_flags;
             addr->scope = ifaddrmsg->ifa_scope;
             addr->prefix_len = ifaddrmsg->ifa_prefixlen;
-
-            update_address_rr(m, addr, 0);
         } else {
             AvahiInterfaceAddress *addr;
             
             if (!(addr = get_address(m, i, &raddr)))
                 return;
 
-            update_address_rr(m, addr, 1);
             free_address(m, addr);
         }
 
         check_interface_relevant(m, i);
+        update_interface_rr(m, i, 0);
         
     } else if (n->nlmsg_type == NLMSG_DONE) {
         
         if (m->list == LIST_IFACE) {
-            m->list = LIST_DONE;
             
-            if (netlink_list_items(m->netlink, RTM_GETADDR, &m->query_addr_seq) < 0)
+            if (netlink_list_items(m->netlink, RTM_GETADDR, &m->query_addr_seq) < 0) {
                 avahi_log_warn("NETLINK: Failed to list addrs: %s", strerror(errno));
-            else
+                m->list = LIST_DONE;
+            } else
                 m->list = LIST_ADDR;
-        } else {
+
+        } else
+            /* We're through */
             m->list = LIST_DONE;
-            avahi_log_debug("Enumeration complete");
+
+        if (m->list == LIST_DONE) {
+            check_all_interfaces_relevant(m);
+            avahi_update_host_rrs(m, 0);
+            avahi_log_info("Network interface enumeration completed.");
         }
         
     } else if (n->nlmsg_type == NLMSG_ERROR && (n->nlmsg_seq == m->query_link_seq || n->nlmsg_seq == m->query_addr_seq)) {
@@ -703,12 +727,32 @@ int avahi_interface_relevant(AvahiInterface *i) {
         relevant_address;
 }
 
-int avahi_interface_address_relevant(AvahiInterfaceAddress *a) { 
+int avahi_interface_address_relevant(AvahiInterfaceAddress *a) {
+    AvahiInterfaceAddress *b;
     assert(a);
 
-    return a->scope == RT_SCOPE_UNIVERSE;
-}
+    /* Publish public IP addresses */
+    if (a->scope == RT_SCOPE_UNIVERSE ||
+        a->scope == RT_SCOPE_SITE)
+        return 1;
+
+    if (a->scope == RT_SCOPE_LINK) {
+        
+        /* Publish link local IP addresses if they are the only ones on the link */
+        for (b = a->interface->addresses; b; b = b->address_next) {
+            if (b == a)
+                continue;
+            
+            if (b->scope == RT_SCOPE_UNIVERSE ||
+                b->scope == RT_SCOPE_SITE)
+                return 0;
+        }
 
+        return 1;
+    }
+
+    return 0;
+}
 
 int avahi_interface_match(AvahiInterface *i, AvahiIfIndex idx, AvahiProtocol protocol) {
     assert(i);
@@ -822,3 +866,21 @@ int avahi_interface_address_on_link(AvahiInterface *i, const AvahiAddress *a) {
 
     return 0;
 }
+
+int avahi_interface_has_address(AvahiInterfaceMonitor *m, AvahiIfIndex iface, const AvahiAddress *a) {
+    AvahiInterface *i;
+    AvahiInterfaceAddress *j;
+    
+    assert(m);
+    assert(iface != AVAHI_IF_UNSPEC);
+    assert(a);
+
+    if (!(i = avahi_interface_monitor_get_interface(m, iface, a->family)))
+        return 0;
+
+    for (j = i->addresses; j; j = j->address_next)
+        if (avahi_address_cmp(a, &j->address) == 0)
+            return 1;
+
+    return 0;
+}