void* avahi_cache_walk(AvahiCache *c, AvahiKey *pattern, AvahiCacheWalkCallback cb, void* userdata) { void* ret; assert(c); assert(pattern); assert(cb); if (avahi_key_is_pattern(pattern)) { AvahiCacheEntry *e, *n; for (e = c->entries; e; e = n) { n = e->entry_next; if (avahi_key_pattern_match(pattern, e->record->key)) if ((ret = cb(c, pattern, e, userdata))) return ret; } } else { AvahiCacheEntry *e, *n; for (e = lookup_key(c, pattern); e; e = n) { n = e->by_key_next; if ((ret = cb(c, pattern, e, userdata))) return ret; } } return NULL; }
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); }
AvahiSRecordBrowser *avahi_s_record_browser_new( AvahiServer *server, AvahiIfIndex interface, AvahiProtocol protocol, AvahiKey *key, AvahiLookupFlags flags, AvahiSRecordBrowserCallback callback, void* userdata) { AvahiSRecordBrowser *b; assert(server); assert(key); assert(callback); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, !avahi_key_is_pattern(key), AVAHI_ERR_IS_PATTERN); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, avahi_key_is_valid(key), AVAHI_ERR_INVALID_KEY); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_FLAGS_VALID(flags, AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, !(flags & AVAHI_LOOKUP_USE_WIDE_AREA) || !(flags & AVAHI_LOOKUP_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS); if (!(b = avahi_new(AvahiSRecordBrowser, 1))) { avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY); return NULL; } b->dead = 0; b->server = server; b->interface = interface; b->protocol = protocol; b->key = avahi_key_ref(key); b->flags = flags; b->callback = callback; b->userdata = userdata; b->n_lookups = 0; AVAHI_LLIST_HEAD_INIT(AvahiSRBLookup, b->lookups); b->root_lookup = NULL; AVAHI_LLIST_PREPEND(AvahiSRecordBrowser, browser, server->record_browsers, b); /* The currently cached entries are scanned a bit later, and than we will start querying, too */ b->defer_time_event = avahi_time_event_new(server->time_event_queue, NULL, defer_callback, b); assert(b->defer_time_event); return b; }
int avahi_probe_scheduler_post(AvahiProbeScheduler *s, AvahiRecord *record, int immediately) { AvahiProbeJob *pj; struct timeval tv; assert(s); assert(record); assert(!avahi_key_is_pattern(record->key)); if ((pj = find_history_job(s, record))) return 0; avahi_elapse_time(&tv, immediately ? 0 : AVAHI_PROBE_DEFER_MSEC, 0); if ((pj = find_scheduled_job(s, record))) { if (avahi_timeval_compare(&tv, &pj->delivery) < 0) { /* If the new entry should be scheduled earlier, update the old entry */ pj->delivery = tv; avahi_time_event_update(pj->time_event, &pj->delivery); } return 1; } else { /* Create a new job and schedule it */ if (!(pj = job_new(s, record, 0))) return 0; /* OOM */ pj->delivery = tv; pj->time_event = avahi_time_event_new(s->time_event_queue, &pj->delivery, elapse_callback, pj); /* avahi_log_debug("Accepted new probe job."); */ return 1; } }
int avahi_response_scheduler_post(AvahiResponseScheduler *s, AvahiRecord *record, int flush_cache, const AvahiAddress *querier, int immediately) { AvahiResponseJob *rj; struct timeval tv; /* char *t; */ assert(s); assert(record); assert(!avahi_key_is_pattern(record->key)); /* t = avahi_record_to_string(record); */ /* avahi_log_debug("post %i %s", immediately, t); */ /* avahi_free(t); */ /* Check whether this response is suppressed */ if (querier && (rj = find_suppressed_job(s, record, querier)) && avahi_record_is_goodbye(record) == avahi_record_is_goodbye(rj->record) && rj->record->ttl >= record->ttl/2) { /* avahi_log_debug("Response suppressed by known answer suppression."); */ return 0; } /* Check if we already sent this response recently */ if ((rj = find_history_job(s, record))) { if (avahi_record_is_goodbye(record) == avahi_record_is_goodbye(rj->record) && rj->record->ttl >= record->ttl/2 && (rj->flush_cache || !flush_cache)) { /* avahi_log_debug("Response suppressed by local duplicate suppression (history)"); */ return 0; } /* Outdated ... */ job_free(s, rj); } avahi_elapse_time(&tv, immediately ? 0 : AVAHI_RESPONSE_DEFER_MSEC, immediately ? 0 : AVAHI_RESPONSE_JITTER_MSEC); if ((rj = find_scheduled_job(s, record))) { /* avahi_log_debug("Response suppressed by local duplicate suppression (scheduled)"); */ /* Update a little ... */ /* Update the time if the new is prior to the old */ if (avahi_timeval_compare(&tv, &rj->delivery) < 0) { rj->delivery = tv; avahi_time_event_update(rj->time_event, &rj->delivery); } /* Update the flush cache bit */ if (flush_cache) rj->flush_cache = 1; /* Update the querier field */ if (!querier || (rj->querier_valid && avahi_address_cmp(querier, &rj->querier) != 0)) rj->querier_valid = 0; /* Update record data (just for the TTL) */ avahi_record_unref(rj->record); rj->record = avahi_record_ref(record); return 1; } else { /* avahi_log_debug("Accepted new response job."); */ /* Create a new job and schedule it */ if (!(rj = job_new(s, record, AVAHI_SCHEDULED))) return 0; /* OOM */ rj->delivery = tv; rj->time_event = avahi_time_event_new(s->time_event_queue, &rj->delivery, elapse_callback, rj); rj->flush_cache = flush_cache; if ((rj->querier_valid = !!querier)) rj->querier = *querier; return 1; } }
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; }