unsigned avahi_wide_area_scan_cache(AvahiWideAreaLookupEngine *e, AvahiKey *key, AvahiWideAreaLookupCallback callback, void *userdata) { AvahiWideAreaCacheEntry *c; AvahiKey *cname_key; unsigned n = 0; assert(e); assert(key); assert(callback); for (c = avahi_hashmap_lookup(e->cache_by_key, key); c; c = c->by_key_next) { callback(e, AVAHI_BROWSER_NEW, AVAHI_LOOKUP_RESULT_WIDE_AREA|AVAHI_LOOKUP_RESULT_CACHED, c->record, userdata); n++; } if ((cname_key = avahi_key_new_cname(key))) { for (c = avahi_hashmap_lookup(e->cache_by_key, cname_key); c; c = c->by_key_next) { callback(e, AVAHI_BROWSER_NEW, AVAHI_LOOKUP_RESULT_WIDE_AREA|AVAHI_LOOKUP_RESULT_CACHED, c->record, userdata); n++; } avahi_key_unref(cname_key); } return n; }
static int check_record_conflict(AvahiServer *s, AvahiIfIndex interface, AvahiProtocol protocol, AvahiRecord *r, AvahiPublishFlags flags) { AvahiEntry *e; assert(s); assert(r); for (e = avahi_hashmap_lookup(s->entries_by_key, r->key); e; e = e->by_key_next) { if (e->dead) continue; if (!(flags & AVAHI_PUBLISH_UNIQUE) && !(e->flags & AVAHI_PUBLISH_UNIQUE)) continue; if ((flags & AVAHI_PUBLISH_ALLOW_MULTIPLE) && (e->flags & AVAHI_PUBLISH_ALLOW_MULTIPLE) ) continue; if ((interface <= 0 || e->interface <= 0 || e->interface == interface) && (protocol == AVAHI_PROTO_UNSPEC || e->protocol == AVAHI_PROTO_UNSPEC || e->protocol == protocol)) return -1; } return 0; }
static void lookup_destroy(AvahiWideAreaLookup *l) { AvahiWideAreaLookup *t; assert(l); lookup_stop(l); t = avahi_hashmap_lookup(l->engine->lookups_by_key, l->key); AVAHI_LLIST_REMOVE(AvahiWideAreaLookup, by_key, t, l); if (t) avahi_hashmap_replace(l->engine->lookups_by_key, avahi_key_ref(l->key), t); else avahi_hashmap_remove(l->engine->lookups_by_key, l->key); AVAHI_LLIST_REMOVE(AvahiWideAreaLookup, lookups, l->engine->lookups, l); avahi_hashmap_remove(l->engine->lookups_by_id, &l->id); avahi_dns_packet_free(l->packet); if (l->key) avahi_key_unref(l->key); if (l->cname_key) avahi_key_unref(l->cname_key); avahi_free(l); }
static void remove_entry(AvahiCache *c, AvahiCacheEntry *e) { AvahiCacheEntry *t; assert(c); assert(e); /* avahi_log_debug("removing from cache: %p %p", c, e); */ /* Remove from hash table */ t = avahi_hashmap_lookup(c->hashmap, e->record->key); AVAHI_LLIST_REMOVE(AvahiCacheEntry, by_key, t, e); if (t) avahi_hashmap_replace(c->hashmap, t->record->key, t); else avahi_hashmap_remove(c->hashmap, e->record->key); /* Remove from linked list */ AVAHI_LLIST_REMOVE(AvahiCacheEntry, entry, c->entries, e); if (e->time_event) avahi_time_event_free(e->time_event); avahi_multicast_lookup_engine_notify(c->server->mdns.multicast_lookup_engine, c->interface, e->record, AVAHI_BROWSER_REMOVE); avahi_record_unref(e->record); avahi_free(e); assert(c->n_entries-- >= 1); }
static void run_callbacks(AvahiWideAreaLookupEngine *e, AvahiRecord *r) { AvahiWideAreaLookup *l; assert(e); assert(r); for (l = avahi_hashmap_lookup(e->lookups_by_key, r->key); l; l = l->by_key_next) { if (l->dead || !l->callback) continue; l->callback(e, AVAHI_BROWSER_NEW, AVAHI_LOOKUP_RESULT_WIDE_AREA, r, l->userdata); } if (r->key->clazz == AVAHI_DNS_CLASS_IN && r->key->type == AVAHI_DNS_TYPE_CNAME) { /* It's a CNAME record, so we have to scan the all lookups to see if one matches */ for (l = e->lookups; l; l = l->lookups_next) { AvahiKey *key; if (l->dead || !l->callback) continue; if ((key = avahi_key_new_cname(l->key))) { if (avahi_key_equal(r->key, key)) l->callback(e, AVAHI_BROWSER_NEW, AVAHI_LOOKUP_RESULT_WIDE_AREA, r, l->userdata); avahi_key_unref(key); } } } }
void avahi_entry_free(AvahiServer*s, AvahiEntry *e) { AvahiEntry *t; assert(s); assert(e); avahi_goodbye_entry(s, e, 1, 1); /* Remove from linked list */ AVAHI_LLIST_REMOVE(AvahiEntry, entries, s->entries, e); /* Remove from hash table indexed by name */ t = avahi_hashmap_lookup(s->entries_by_key, e->record->key); AVAHI_LLIST_REMOVE(AvahiEntry, by_key, t, e); if (t) avahi_hashmap_replace(s->entries_by_key, t->record->key, t); else avahi_hashmap_remove(s->entries_by_key, e->record->key); /* Remove from associated group */ if (e->group) AVAHI_LLIST_REMOVE(AvahiEntry, by_group, e->group->entries, e); avahi_record_unref(e->record); avahi_free(e); }
static AvahiCacheEntry *lookup_key(AvahiCache *c, AvahiKey *k) { assert(c); assert(k); assert(!avahi_key_is_pattern(k)); return avahi_hashmap_lookup(c->hashmap, k); }
static void withdraw_rrset(AvahiServer *s, AvahiKey *key) { AvahiEntry *e; assert(s); assert(key); for (e = avahi_hashmap_lookup(s->llmnr.entries_by_key, key); e; e = e->by_key_next) withdraw_llmnr_entry(s, e); }
static AvahiWideAreaCacheEntry* find_record_in_cache(AvahiWideAreaLookupEngine *e, AvahiRecord *r) { AvahiWideAreaCacheEntry *c; assert(e); assert(r); for (c = avahi_hashmap_lookup(e->cache_by_key, r->key); c; c = c->by_key_next) if (avahi_record_equal_no_ttl(r, c->record)) return c; return NULL; }
static void add_to_cache(AvahiWideAreaLookupEngine *e, AvahiRecord *r) { AvahiWideAreaCacheEntry *c; int is_new; assert(e); assert(r); if ((c = find_record_in_cache(e, r))) { is_new = 0; /* Update the existing entry */ avahi_record_unref(c->record); } else { AvahiWideAreaCacheEntry *t; is_new = 1; /* Enforce cache size */ if (e->cache_n_entries >= CACHE_ENTRIES_MAX) /* Eventually we should improve the caching algorithm here */ goto finish; c = avahi_new(AvahiWideAreaCacheEntry, 1); c->engine = e; c->time_event = NULL; AVAHI_LLIST_PREPEND(AvahiWideAreaCacheEntry, cache, e->cache, c); /* Add the new entry to the cache entry hash table */ t = avahi_hashmap_lookup(e->cache_by_key, r->key); AVAHI_LLIST_PREPEND(AvahiWideAreaCacheEntry, by_key, t, c); avahi_hashmap_replace(e->cache_by_key, avahi_key_ref(r->key), t); e->cache_n_entries ++; } c->record = avahi_record_ref(r); gettimeofday(&c->timestamp, NULL); c->expiry = c->timestamp; avahi_timeval_add(&c->expiry, r->ttl * 1000000); if (c->time_event) avahi_time_event_update(c->time_event, &c->expiry); else c->time_event = avahi_time_event_new(e->server->time_event_queue, &c->expiry, expiry_event, c); finish: if (is_new) run_callbacks(e, r); }
void avahi_llmnr_query_job_remove(AvahiInterface *i, AvahiKey *key) { AvahiLLMNRQueryJob *qj; assert(i); assert(key); if(!(qj = avahi_hashmap_lookup(i->llmnr.queryjobs_by_key, key))) /* No AvahiLLMNRQueryJob object present for this key*/ return; avahi_llmnr_query_job_destroy(qj->scheduler, qj); return; }
void avahi_llmnr_query_remove(AvahiInterface *i, AvahiKey *key) { /* First find for the AvahiLLMNRQueryJob object for this 'i' and 'key' */ AvahiLLMNRQueryJob *qj; assert(i); assert(key); /* Interface is maintaing hashmap of AvahiLLMNRQueryJob's by key*/ if(!(qj = avahi_hashmap_lookup(i->llmnr.queryjobs_by_key, key))) return; /* get 'qj' -> destroy(s, qj) -> destroy(lq) */ avahi_llmnr_query_job_destroy(qj->scheduler, qj); return; }
static AvahiWideAreaLookup* find_lookup(AvahiWideAreaLookupEngine *e, uint16_t id) { AvahiWideAreaLookup *l; int i = (int) id; assert(e); if (!(l = avahi_hashmap_lookup(e->lookups_by_id, &i))) return NULL; assert(l->id == id); if (l->dead) return NULL; return l; }
static AvahiLLMNRQuery* find_query(AvahiLLMNRLookupEngine *e, uint16_t id) { AvahiLLMNRQuery *lq; /* Convert to 32 bit integer*/ uint32_t i = (uint32_t) id; assert(e); if(!(lq = avahi_hashmap_lookup(e->queries_by_id, &i))) return NULL; assert(lq->id == id); if(lq->dead) return NULL; return lq; }
static int is_duplicate_entry(AvahiServer *s, AvahiEntry *e) { AvahiEntry *i; assert(s); assert(e); for (i = avahi_hashmap_lookup(s->entries_by_key, e->record->key); i; i = i->by_key_next) { if ((i == e) || (i->dead)) continue; if (!avahi_record_equal_no_ttl(i->record, e->record)) continue; return 1; } return 0; }
static int is_duplicate_entry(AvahiServer *s, AvahiEntry *e) { AvahiEntry *i; assert(s); assert(e && e->type == AVAHI_ENTRY_MDNS); for (i = avahi_hashmap_lookup(s->mdns.entries_by_key, e->record->key); i; i = i->by_key_next) { assert(i->type == AVAHI_ENTRY_MDNS); if (i == e) continue; if (!avahi_record_equal_no_ttl(i->record, e->record)) continue; return 1; } return 0; }
static void cache_entry_free(AvahiWideAreaCacheEntry *c) { AvahiWideAreaCacheEntry *t; assert(c); if (c->time_event) avahi_time_event_free(c->time_event); AVAHI_LLIST_REMOVE(AvahiWideAreaCacheEntry, cache, c->engine->cache, c); t = avahi_hashmap_lookup(c->engine->cache_by_key, c->record->key); AVAHI_LLIST_REMOVE(AvahiWideAreaCacheEntry, by_key, t, c); if (t) avahi_hashmap_replace(c->engine->cache_by_key, avahi_key_ref(c->record->key), t); else avahi_hashmap_remove(c->engine->cache_by_key, c->record->key); c->engine->cache_n_entries --; avahi_record_unref(c->record); avahi_free(c); }
AvahiWideAreaLookup *avahi_wide_area_lookup_new( AvahiWideAreaLookupEngine *e, AvahiKey *key, AvahiWideAreaLookupCallback callback, void *userdata) { struct timeval tv; AvahiWideAreaLookup *l, *t; uint8_t *p; assert(e); assert(key); assert(callback); assert(userdata); l = avahi_new(AvahiWideAreaLookup, 1); l->engine = e; l->dead = 0; l->key = avahi_key_ref(key); l->cname_key = avahi_key_new_cname(l->key); l->callback = callback; l->userdata = userdata; /* If more than 65K wide area quries are issued simultaneously, * this will break. This should be limited by some higher level */ for (;; e->next_id++) if (!find_lookup(e, e->next_id)) break; /* This ID is not yet used. */ l->id = e->next_id++; /* We keep the packet around in case we need to repeat our query */ l->packet = avahi_dns_packet_new(0); avahi_dns_packet_set_field(l->packet, AVAHI_DNS_FIELD_ID, (uint16_t) l->id); avahi_dns_packet_set_field(l->packet, AVAHI_DNS_FIELD_FLAGS, AVAHI_DNS_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, 0, 0)); p = avahi_dns_packet_append_key(l->packet, key, 0); assert(p); avahi_dns_packet_set_field(l->packet, AVAHI_DNS_FIELD_QDCOUNT, 1); if (send_to_dns_server(l, l->packet) < 0) { avahi_log_error(__FILE__": Failed to send packet."); avahi_dns_packet_free(l->packet); avahi_key_unref(l->key); if (l->cname_key) avahi_key_unref(l->cname_key); avahi_free(l); return NULL; } l->n_send = 1; l->time_event = avahi_time_event_new(e->server->time_event_queue, avahi_elapse_time(&tv, 500, 0), sender_timeout_callback, l); avahi_hashmap_insert(e->lookups_by_id, &l->id, l); t = avahi_hashmap_lookup(e->lookups_by_key, l->key); AVAHI_LLIST_PREPEND(AvahiWideAreaLookup, by_key, t, l); avahi_hashmap_replace(e->lookups_by_key, avahi_key_ref(l->key), t); AVAHI_LLIST_PREPEND(AvahiWideAreaLookup, lookups, e->lookups, l); return l; }
static AvahiEntry * server_add_internal( AvahiServer *s, AvahiSEntryGroup *g, AvahiIfIndex interface, AvahiProtocol protocol, AvahiPublishFlags flags, AvahiRecord *r) { AvahiEntry *e; assert(s); assert(r); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, s->state != AVAHI_SERVER_FAILURE && s->state != AVAHI_SERVER_INVALID, AVAHI_ERR_BAD_STATE); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, AVAHI_FLAGS_VALID( flags, AVAHI_PUBLISH_NO_ANNOUNCE| AVAHI_PUBLISH_NO_PROBE| AVAHI_PUBLISH_UNIQUE| AVAHI_PUBLISH_ALLOW_MULTIPLE| AVAHI_PUBLISH_UPDATE| AVAHI_PUBLISH_USE_WIDE_AREA| AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, avahi_is_valid_domain_name(r->key->name), AVAHI_ERR_INVALID_HOST_NAME); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, r->ttl != 0, AVAHI_ERR_INVALID_TTL); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, !avahi_key_is_pattern(r->key), AVAHI_ERR_IS_PATTERN); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, avahi_record_is_valid(r), AVAHI_ERR_INVALID_RECORD); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, r->key->clazz == AVAHI_DNS_CLASS_IN, AVAHI_ERR_INVALID_DNS_CLASS); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, (r->key->type != 0) && (r->key->type != AVAHI_DNS_TYPE_ANY) && (r->key->type != AVAHI_DNS_TYPE_OPT) && (r->key->type != AVAHI_DNS_TYPE_TKEY) && (r->key->type != AVAHI_DNS_TYPE_TSIG) && (r->key->type != AVAHI_DNS_TYPE_IXFR) && (r->key->type != AVAHI_DNS_TYPE_AXFR), AVAHI_ERR_INVALID_DNS_TYPE); transport_flags_from_domain(s, &flags, r->key->name); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, !s->config.disable_publishing, AVAHI_ERR_NOT_PERMITTED); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, !g || (g->state != AVAHI_ENTRY_GROUP_ESTABLISHED && g->state != AVAHI_ENTRY_GROUP_REGISTERING) || (flags & AVAHI_PUBLISH_UPDATE), AVAHI_ERR_BAD_STATE); if (flags & AVAHI_PUBLISH_UPDATE) { AvahiRecord *old_record; int is_first = 1; /* Update and existing record */ /* Find the first matching entry */ for (e = avahi_hashmap_lookup(s->entries_by_key, r->key); e; e = e->by_key_next) { if (!e->dead && e->group == g && e->interface == interface && e->protocol == protocol) break; is_first = 0; } /* Hmm, nothing found? */ if (!e) { avahi_server_set_errno(s, AVAHI_ERR_NOT_FOUND); return NULL; } /* Update the entry */ old_record = e->record; e->record = avahi_record_ref(r); e->flags = flags; /* Announce our changes when needed */ if (!avahi_record_equal_no_ttl(old_record, r) && (!g || g->state != AVAHI_ENTRY_GROUP_UNCOMMITED)) { /* Remove the old entry from all caches, if needed */ if (!(e->flags & AVAHI_PUBLISH_UNIQUE)) avahi_goodbye_entry(s, e, 1, 0); /* Reannounce our updated entry */ avahi_reannounce_entry(s, e); } /* If we were the first entry in the list, we need to update the key */ if (is_first) avahi_hashmap_replace(s->entries_by_key, e->record->key, e); avahi_record_unref(old_record); } else { AvahiEntry *t; /* Add a new record */ if (check_record_conflict(s, interface, protocol, r, flags) < 0) { avahi_server_set_errno(s, AVAHI_ERR_COLLISION); return NULL; } if (!(e = avahi_new(AvahiEntry, 1))) { avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); return NULL; } e->server = s; e->record = avahi_record_ref(r); e->group = g; e->interface = interface; e->protocol = protocol; e->flags = flags; e->dead = 0; AVAHI_LLIST_HEAD_INIT(AvahiAnnouncer, e->announcers); AVAHI_LLIST_PREPEND(AvahiEntry, entries, s->entries, e); /* Insert into hash table indexed by name */ t = avahi_hashmap_lookup(s->entries_by_key, e->record->key); AVAHI_LLIST_PREPEND(AvahiEntry, by_key, t, e); avahi_hashmap_replace(s->entries_by_key, e->record->key, t); /* Insert into group list */ if (g) AVAHI_LLIST_PREPEND(AvahiEntry, by_group, g->entries, e); avahi_announce_entry(s, e); } return e; }