]> git.meshlink.io Git - catta/blobdiff - avahi-core/server.c
* remove lots of DOXYGEN_SHOULD_SKIP_THIS from the header files, use doxygen macro...
[catta] / avahi-core / server.c
index 2252fde49946c44aced62fe5befb8e3ec77c1861..7b0a56eec5752275a60ca90a693d9e73f2ae6e5c 100644 (file)
 #include <avahi-common/malloc.h>
 #include <avahi-common/error.h>
 
-#include "server.h"
+#include "internal.h"
 #include "iface.h"
 #include "socket.h"
 #include "browse.h"
 #include "log.h"
 #include "util.h"
 #include "dns-srv-rr.h"
+#include "addr-util.h"
+#include "domain-util.h"
+#include "rr-util.h"
 
 static void enum_aux_records(AvahiServer *s, AvahiInterface *i, const char *name, uint16_t type, void (*callback)(AvahiServer *s, AvahiRecord *r, int flush_cache, void* userdata), void* userdata) {
-    AvahiKey *k;
-    AvahiEntry *e;
-
     assert(s);
     assert(i);
     assert(name);
     assert(callback);
 
-    assert(type != AVAHI_DNS_TYPE_ANY);
-
-    if (!(k = avahi_key_new(name, AVAHI_DNS_CLASS_IN, type)))
-        return; /** OOM */
-
-    for (e = avahi_hashmap_lookup(s->entries_by_key, k); e; e = e->by_key_next)
-        if (!e->dead && avahi_entry_is_registered(s, e, i)) 
-            callback(s, e->record, e->flags & AVAHI_PUBLISH_UNIQUE, userdata);
+    if (type == AVAHI_DNS_TYPE_ANY) {
+        AvahiEntry *e;
+        
+        for (e = s->entries; e; e = e->entries_next)
+            if (!e->dead &&
+                avahi_entry_is_registered(s, e, i) &&
+                e->record->key->clazz == AVAHI_DNS_CLASS_IN &&
+                avahi_domain_equal(name, e->record->key->name))
+                callback(s, e->record, e->flags & AVAHI_PUBLISH_UNIQUE, userdata);
 
-    avahi_key_unref(k);
+    } else {
+        AvahiEntry *e;
+        AvahiKey *k;
+        
+        if (!(k = avahi_key_new(name, AVAHI_DNS_CLASS_IN, type)))
+            return; /** OOM */
+        
+        for (e = avahi_hashmap_lookup(s->entries_by_key, k); e; e = e->by_key_next)
+            if (!e->dead && avahi_entry_is_registered(s, e, i)) 
+                callback(s, e->record, e->flags & AVAHI_PUBLISH_UNIQUE, userdata);
+        
+        avahi_key_unref(k);
+    }
 }
 
 void avahi_server_enumerate_aux_records(AvahiServer *s, AvahiInterface *i, AvahiRecord *r, void (*callback)(AvahiServer *s, AvahiRecord *r, int flush_cache, void* userdata), void* userdata) {
@@ -72,6 +85,8 @@ void avahi_server_enumerate_aux_records(AvahiServer *s, AvahiInterface *i, Avahi
     assert(i);
     assert(r);
     assert(callback);
+
+    /* Call the specified callback far all records referenced by the one specified in *r */
     
     if (r->key->clazz == AVAHI_DNS_CLASS_IN) {
         if (r->key->type == AVAHI_DNS_TYPE_PTR) {
@@ -80,7 +95,8 @@ void avahi_server_enumerate_aux_records(AvahiServer *s, AvahiInterface *i, Avahi
         } else if (r->key->type == AVAHI_DNS_TYPE_SRV) {
             enum_aux_records(s, i, r->data.srv.name, AVAHI_DNS_TYPE_A, callback, userdata);
             enum_aux_records(s, i, r->data.srv.name, AVAHI_DNS_TYPE_AAAA, callback, userdata);
-        }
+        } else if (r->key->type == AVAHI_DNS_TYPE_CNAME)
+            enum_aux_records(s, i, r->data.cname.name, AVAHI_DNS_TYPE_ANY, callback, userdata);
     }
 }
 
@@ -93,17 +109,14 @@ void avahi_server_prepare_response(AvahiServer *s, AvahiInterface *i, AvahiEntry
 }
 
 void avahi_server_prepare_matching_responses(AvahiServer *s, AvahiInterface *i, AvahiKey *k, int unicast_response) {
-    AvahiEntry *e;
-/*     char *txt; */
-    
     assert(s);
     assert(i);
     assert(k);
 
-/*     avahi_log_debug("Posting responses matching [%s]", txt = avahi_key_to_string(k)); */
-/*     avahi_free(txt); */
+    /* Push all records that match the specified key to the record list */
 
     if (avahi_key_is_pattern(k)) {
+        AvahiEntry *e;
 
         /* Handle ANY query */
         
@@ -112,6 +125,7 @@ void avahi_server_prepare_matching_responses(AvahiServer *s, AvahiInterface *i,
                 avahi_server_prepare_response(s, i, e, unicast_response, 0);
 
     } else {
+        AvahiEntry *e;
 
         /* Handle all other queries */
         
@@ -119,21 +133,40 @@ void avahi_server_prepare_matching_responses(AvahiServer *s, AvahiInterface *i,
             if (!e->dead && avahi_entry_is_registered(s, e, i))
                 avahi_server_prepare_response(s, i, e, unicast_response, 0);
     }
+
+    /* Look for CNAME records */
+
+    if ((k->clazz == AVAHI_DNS_CLASS_IN || k->clazz == AVAHI_DNS_CLASS_ANY)
+        && k->type != AVAHI_DNS_TYPE_CNAME && k->type != AVAHI_DNS_TYPE_ANY) {
+
+        AvahiKey *cname_key;
+
+        if (!(cname_key = avahi_key_new(k->name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_CNAME)))
+            return;
+        
+        avahi_server_prepare_matching_responses(s, i, cname_key, unicast_response);
+        avahi_key_unref(cname_key);
+    }
 }
 
 static void withdraw_entry(AvahiServer *s, AvahiEntry *e) {
     assert(s);
     assert(e);
+
+    /* Withdraw the specified entry, and if is part of an entry group,
+     * put that into COLLISION state */
+
+    if (e->dead)
+        return;
     
     if (e->group) {
         AvahiEntry *k;
         
-        for (k = e->group->entries; k; k = k->by_group_next) {
+        for (k = e->group->entries; k; k = k->by_group_next) 
             if (!k->dead) {
                 avahi_goodbye_entry(s, k, 0, 1);
                 k->dead = 1;
             }
-        }
 
         e->group->n_probing = 0;
 
@@ -152,24 +185,22 @@ static void withdraw_rrset(AvahiServer *s, AvahiKey *key) {
     assert(s);
     assert(key);
 
-   for (e = avahi_hashmap_lookup(s->entries_by_key, key); e; e = e->by_key_next)
-       if (!e->dead)
-           withdraw_entry(s, e);
+    /* Withdraw an entry RRSset */
+    
+    for (e = avahi_hashmap_lookup(s->entries_by_key, key); e; e = e->by_key_next)
+        withdraw_entry(s, e);
 }
 
 static void incoming_probe(AvahiServer *s, AvahiRecord *record, AvahiInterface *i) {
     AvahiEntry *e, *n;
-    char *t;
     int ours = 0, won = 0, lost = 0;
     
     assert(s);
     assert(record);
     assert(i);
 
-    t = avahi_record_to_string(record);
-
-/*     avahi_log_debug("incoming_probe()");  */
-
+    /* Handle incoming probes and check if they conflict our own probes */
+    
     for (e = avahi_hashmap_lookup(s->entries_by_key, record->key); e; e = n) {
         int cmp;
         n = e->by_key_next;
@@ -192,17 +223,17 @@ static void incoming_probe(AvahiServer *s, AvahiRecord *record, AvahiInterface *
     }
 
     if (!ours) {
-
+        char *t = avahi_record_to_string(record);
+        
         if (won)
             avahi_log_debug("Recieved conflicting probe [%s]. Local host won.", t);
         else if (lost) {
             avahi_log_debug("Recieved conflicting probe [%s]. Local host lost. Withdrawing.", t);
             withdraw_rrset(s, record->key);
-        }/*  else */
-/*             avahi_log_debug("Not conflicting probe"); */
+        }
+        
+        avahi_free(t);
     }
-
-    avahi_free(t);
 }
 
 static int handle_conflict(AvahiServer *s, AvahiInterface *i, AvahiRecord *record, int unique, const AvahiAddress *a) {
@@ -213,9 +244,8 @@ static int handle_conflict(AvahiServer *s, AvahiInterface *i, AvahiRecord *recor
     assert(i);
     assert(record);
 
-
-/*     avahi_log_debug("CHECKING FOR CONFLICT: [%s]", t);   */
-
+    /* Check whether an incoming record conflicts with one of our own */
+    
     for (e = avahi_hashmap_lookup(s->entries_by_key, record->key); e; e = n) {
         n = e->by_key_next;
 
@@ -286,8 +316,6 @@ static int handle_conflict(AvahiServer *s, AvahiInterface *i, AvahiRecord *recor
         }
     }
 
-/*     avahi_log_debug("ours=%i conflict=%i", ours, conflict); */
-
     if (!ours && conflict) {
         char *t;
  
@@ -409,8 +437,8 @@ void avahi_server_generate_response(AvahiServer *s, AvahiInterface *i, AvahiDnsP
 
                         avahi_dns_packet_free(reply);
                         size = avahi_record_get_estimate_size(r) + AVAHI_DNS_PACKET_HEADER_SIZE;
-                        if (size > AVAHI_DNS_PACKET_MAX_SIZE)
-                            size = AVAHI_DNS_PACKET_MAX_SIZE;
+                        if (size > AVAHI_DNS_PACKET_SIZE_MAX)
+                            size = AVAHI_DNS_PACKET_SIZE_MAX;
 
                         if (!(reply = avahi_dns_packet_new_reply(p, size, 0, 1)))
                             break; /* OOM */
@@ -652,10 +680,10 @@ static AvahiLegacyUnicastReflectSlot* allocate_slot(AvahiServer *s) {
     assert(s);
 
     if (!s->legacy_unicast_reflect_slots)
-        s->legacy_unicast_reflect_slots = avahi_new0(AvahiLegacyUnicastReflectSlot*, AVAHI_MAX_LEGACY_UNICAST_REFLECT_SLOTS);
+        s->legacy_unicast_reflect_slots = avahi_new0(AvahiLegacyUnicastReflectSlot*, AVAHI_LEGACY_UNICAST_REFLECT_SLOTS_MAX);
 
-    for (n = 0; n < AVAHI_MAX_LEGACY_UNICAST_REFLECT_SLOTS; n++, s->legacy_unicast_reflect_id++) {
-        idx = s->legacy_unicast_reflect_id % AVAHI_MAX_LEGACY_UNICAST_REFLECT_SLOTS;
+    for (n = 0; n < AVAHI_LEGACY_UNICAST_REFLECT_SLOTS_MAX; n++, s->legacy_unicast_reflect_id++) {
+        idx = s->legacy_unicast_reflect_id % AVAHI_LEGACY_UNICAST_REFLECT_SLOTS_MAX;
         
         if (!s->legacy_unicast_reflect_slots[idx])
             break;
@@ -680,7 +708,7 @@ static void deallocate_slot(AvahiServer *s, AvahiLegacyUnicastReflectSlot *slot)
     assert(s);
     assert(slot);
 
-    idx = slot->id % AVAHI_MAX_LEGACY_UNICAST_REFLECT_SLOTS;
+    idx = slot->id % AVAHI_LEGACY_UNICAST_REFLECT_SLOTS_MAX;
 
     assert(s->legacy_unicast_reflect_slots[idx] == slot);
 
@@ -697,7 +725,7 @@ static void free_slots(AvahiServer *s) {
     if (!s->legacy_unicast_reflect_slots)
         return;
 
-    for (idx = 0; idx < AVAHI_MAX_LEGACY_UNICAST_REFLECT_SLOTS; idx ++)
+    for (idx = 0; idx < AVAHI_LEGACY_UNICAST_REFLECT_SLOTS_MAX; idx ++)
         if (s->legacy_unicast_reflect_slots[idx])
             deallocate_slot(s, s->legacy_unicast_reflect_slots[idx]);
 
@@ -713,7 +741,7 @@ static AvahiLegacyUnicastReflectSlot* find_slot(AvahiServer *s, uint16_t id) {
     if (!s->legacy_unicast_reflect_slots)
         return NULL;
     
-    idx = id % AVAHI_MAX_LEGACY_UNICAST_REFLECT_SLOTS;
+    idx = id % AVAHI_LEGACY_UNICAST_REFLECT_SLOTS_MAX;
 
     if (!s->legacy_unicast_reflect_slots[idx] || s->legacy_unicast_reflect_slots[idx]->id != id)
         return NULL;
@@ -862,7 +890,7 @@ static void dispatch_packet(AvahiServer *s, AvahiDnsPacket *p, const struct sock
         return;
     }
 
-/*     avahi_log_debug("new packet recieved on interface '%s.%i'.", i->hardware->name, i->protocol); */
+/*     avahi_log_debug("new packet received on interface '%s.%i'.", i->hardware->name, i->protocol); */
 
     port = avahi_port_from_sockaddr(sa);
     avahi_address_from_sockaddr(sa, &a);
@@ -923,7 +951,7 @@ static void dispatch_packet(AvahiServer *s, AvahiDnsPacket *p, const struct sock
 
         if (!is_mdns_mcast_address(dest) &&
             !avahi_interface_address_on_link(i, &a)) {
-            avahi_log_warn("Recivied non-local response on interface '%s.%i'.", i->hardware->name, i->protocol);
+            avahi_log_warn("Received non-local response on interface '%s.%i'.", i->hardware->name, i->protocol);
             return;
         }
         
@@ -955,7 +983,7 @@ static void dispatch_legacy_unicast_packet(AvahiServer *s, AvahiDnsPacket *p, co
         return;
     }
 
-/*     avahi_log_debug("new legacy unicast packet recieved on interface '%s.%i'.", i->hardware->name, i->protocol); */
+/*     avahi_log_debug("new legacy unicast packet received on interface '%s.%i'.", i->hardware->name, i->protocol); */
 
     avahi_address_from_sockaddr(sa, &a);
     
@@ -1313,18 +1341,21 @@ AvahiServer *avahi_server_new(const AvahiPoll *poll_api, const AvahiServerConfig
         
         return NULL;
     }
-
     
     s->n_host_rr_pending = 0;
     s->need_entry_cleanup = 0;
     s->need_group_cleanup = 0;
     s->need_browser_cleanup = 0;
-    
-    s->time_event_queue = avahi_time_event_queue_new(poll_api);
-    
+    s->hinfo_entry_group = NULL;
+    s->browse_domain_entry_group = NULL;
+    s->error = AVAHI_OK;
+    s->state = AVAHI_SERVER_INVALID;
+
     s->callback = callback;
     s->userdata = userdata;
-    
+
+    s->time_event_queue = avahi_time_event_queue_new(poll_api);
+
     s->entries_by_key = avahi_hashmap_new((AvahiHashFunc) avahi_key_hash, (AvahiEqualFunc) avahi_key_equal, NULL, NULL);
     AVAHI_LLIST_HEAD_INIT(AvahiEntry, s->entries);
     AVAHI_LLIST_HEAD_INIT(AvahiGroup, s->groups);
@@ -1342,17 +1373,7 @@ AvahiServer *avahi_server_new(const AvahiPoll *poll_api, const AvahiServerConfig
     s->legacy_unicast_reflect_slots = NULL;
     s->legacy_unicast_reflect_id = 0;
 
-    if (s->config.enable_wide_area) {
-        s->wide_area_lookup_engine = avahi_wide_area_engine_new(s);
-        avahi_wide_area_set_servers(s->wide_area_lookup_engine, s->config.wide_area_servers, s->config.n_wide_area_servers);
-    } else
-        s->wide_area_lookup_engine = NULL;
-
-    s->multicast_lookup_engine = avahi_multicast_lookup_engine_new(s);
-
-    do {
-        s->local_service_cookie = (uint32_t) rand() * (uint32_t) rand();
-    } while (s->local_service_cookie == AVAHI_SERVICE_COOKIE_INVALID);
+    s->record_list = avahi_record_list_new();
     
     /* Get host name */
     s->host_name = s->config.host_name ? avahi_normalize_name_strdup(s->config.host_name) : avahi_get_host_name_strdup();
@@ -1361,20 +1382,23 @@ AvahiServer *avahi_server_new(const AvahiPoll *poll_api, const AvahiServerConfig
     s->host_name_fqdn = NULL;
     update_fqdn(s);
 
-    s->record_list = avahi_record_list_new();
+    do {
+        s->local_service_cookie = (uint32_t) rand() * (uint32_t) rand();
+    } while (s->local_service_cookie == AVAHI_SERVICE_COOKIE_INVALID);
 
-    s->state = AVAHI_SERVER_INVALID;
+    if (s->config.enable_wide_area) {
+        s->wide_area_lookup_engine = avahi_wide_area_engine_new(s);
+        avahi_wide_area_set_servers(s->wide_area_lookup_engine, s->config.wide_area_servers, s->config.n_wide_area_servers);
+    } else
+        s->wide_area_lookup_engine = NULL;
 
+    s->multicast_lookup_engine = avahi_multicast_lookup_engine_new(s);
+    
     s->monitor = avahi_interface_monitor_new(s);
     avahi_interface_monitor_sync(s->monitor);
 
     register_localhost(s);
-
-    s->hinfo_entry_group = NULL;
-    s->browse_domain_entry_group = NULL;
     register_stuff(s);
-
-    s->error = AVAHI_OK;
     
     return s;
 }
@@ -1566,17 +1590,40 @@ uint32_t avahi_server_get_local_service_cookie(AvahiServer *s) {
     return s->local_service_cookie;
 }
 
-int avahi_server_is_service_local(AvahiServer *s, AvahiIfIndex interface, AvahiProtocol protocol, const char *name, const char *type, const char*domain) {
+static AvahiEntry *find_entry(AvahiServer *s, AvahiIfIndex interface, AvahiProtocol protocol, AvahiKey *key) {
+    AvahiEntry *e;
+    
+    assert(s);
+    assert(key);
+
+    for (e = avahi_hashmap_lookup(s->entries_by_key, key); e; e = e->by_key_next)
+
+        if ((e->interface == interface || e->interface <= 0 || interface <= 0) &&
+            (e->protocol == protocol || e->protocol == AVAHI_PROTO_UNSPEC || protocol == AVAHI_PROTO_UNSPEC) &&
+            (!e->group || e->group->state == AVAHI_ENTRY_GROUP_ESTABLISHED || e->group->state == AVAHI_ENTRY_GROUP_REGISTERING))
+
+            return e;
+
+    return NULL;
+}
+
+int avahi_server_get_group_of_service(AvahiServer *s, AvahiIfIndex interface, AvahiProtocol protocol, const char *name, const char *type, const char *domain, AvahiSEntryGroup** ret_group) {
     AvahiKey *key = NULL;
-    char n[256];
-    int ret;
     AvahiEntry *e;
+    int ret;
+    char n[AVAHI_DOMAIN_NAME_MAX];
     
     assert(s);
     assert(name);
     assert(type);
-    assert(domain);
+    assert(ret_group);
 
+    if (!AVAHI_IF_VALID(interface))
+        return avahi_server_set_errno(s, AVAHI_ERR_INVALID_INTERFACE);
+
+    if (!AVAHI_IF_VALID(protocol))
+        return avahi_server_set_errno(s, AVAHI_ERR_INVALID_PROTOCOL);
+    
     if (!avahi_is_valid_service_name(name))
         return avahi_server_set_errno(s, AVAHI_ERR_INVALID_SERVICE_NAME);
 
@@ -1592,21 +1639,54 @@ int avahi_server_is_service_local(AvahiServer *s, AvahiIfIndex interface, AvahiP
     if (!(key = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV)))
         return avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY);
 
-    ret = 0;
-    
-    for (e = avahi_hashmap_lookup(s->entries_by_key, key); e; e = e->by_key_next) {
+    e = find_entry(s, interface, protocol, key);
+    avahi_key_unref(key);
 
-        if ((e->interface == interface || e->interface <= 0 || interface <= 0) &&
-            (e->protocol == protocol || e->protocol == AVAHI_PROTO_UNSPEC || protocol == AVAHI_PROTO_UNSPEC) &&
-            !(e->flags & AVAHI_PUBLISH_IS_PROXY)) {
-            ret = 1;
-            break;
-        }
+    if (e) {
+        *ret_group = e->group;
+        return AVAHI_OK;
     }
+
+    return avahi_server_set_errno(s, AVAHI_ERR_NOT_FOUND);
+}
+
+int avahi_server_is_service_local(AvahiServer *s, AvahiIfIndex interface, AvahiProtocol protocol, const char *name) {
+    AvahiKey *key = NULL;
+    AvahiEntry *e;
+
+    assert(s);
+    assert(name);
+
+    if (!s->host_name_fqdn)
+        return 0;
     
+    if (!(key = avahi_key_new(name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV)))
+        return 0;
+
+    e = find_entry(s, interface, protocol, key);
     avahi_key_unref(key);
+
+    if (!e)
+        return 0;
     
-    return ret;
+    return avahi_domain_equal(s->host_name_fqdn, e->record->data.srv.name);
+}
+
+int avahi_server_is_record_local(AvahiServer *s, AvahiIfIndex interface, AvahiProtocol protocol, AvahiRecord *record) {
+    AvahiEntry *e;
+
+    assert(s);
+    assert(record);
+    
+    for (e = avahi_hashmap_lookup(s->entries_by_key, record->key); e; e = e->by_key_next)
+
+        if ((e->interface == interface || e->interface <= 0 || interface <= 0) &&
+            (e->protocol == protocol || e->protocol == AVAHI_PROTO_UNSPEC || protocol == AVAHI_PROTO_UNSPEC) &&
+            (!e->group || e->group->state == AVAHI_ENTRY_GROUP_ESTABLISHED || e->group->state == AVAHI_ENTRY_GROUP_REGISTERING) &&
+            avahi_record_equal_no_ttl(record, e->record))
+            return 1;
+
+    return 0;
 }
 
 /** Set the wide area DNS servers */