예제 #1
0
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;
}
예제 #2
0
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;
}
예제 #3
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);
}
예제 #4
0
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);
}
예제 #5
0
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);
            }
        }
    }
}
예제 #6
0
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);
}
예제 #7
0
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);
}
예제 #8
0
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);
}
예제 #9
0
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;
}
예제 #10
0
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);
}
예제 #11
0
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;
}
예제 #12
0
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;
}
예제 #13
0
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;
}
예제 #14
0
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;
}
예제 #15
0
파일: announce.c 프로젝트: Dessperado/avahi
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;
}
예제 #16
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;
}
예제 #17
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);
}
예제 #18
0
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;
}
예제 #19
0
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;
}