#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) {
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) {
} 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);
}
}
}
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 */
avahi_server_prepare_response(s, i, e, unicast_response, 0);
} else {
+ AvahiEntry *e;
/* Handle all other queries */
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;
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;
}
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) {
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;
}
}
-/* avahi_log_debug("ours=%i conflict=%i", ours, conflict); */
-
if (!ours && conflict) {
char *t;
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 */
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;
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);
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]);
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;
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);
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;
}
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);
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);
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();
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;
}
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);
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 */