static void job_set_elapse_time(AvahiProbeScheduler *s, AvahiProbeJob *pj, unsigned msec, unsigned jitter) {
    struct timeval tv;

    assert(s);
    assert(pj);

    avahi_elapse_time(&tv, msec, jitter);

    if (pj->time_event)
        avahi_time_event_update(pj->time_event, &tv);
    else
        pj->time_event = avahi_time_event_new(s->time_event_queue, &tv, elapse_callback, pj);
}
Exemple #2
0
static void set_timeout(AvahiAnnouncer *a, const struct timeval *tv) {
    assert(a);

    if (!tv) {
        if (a->time_event) {
            avahi_time_event_free(a->time_event);
            a->time_event = NULL;
        }
    } else {

        if (a->time_event)
            avahi_time_event_update(a->time_event, tv);
        else
            a->time_event = avahi_time_event_new(a->server->time_event_queue, tv, elapse_announce, a);
    }
}
Exemple #3
0
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_llmnr_query_scheduler_post(AvahiLLMNRQueryScheduler *s, AvahiLLMNRQuery *lq, int immediately) {
    AvahiLLMNRQueryJob *qj;
    struct timeval tv;

    assert(s);
    assert(lq);

    if (!(qj = job_new(s, lq)))
        return 0;

    qj->time_event = avahi_time_event_new(s->time_event_queue,
                                          avahi_elapse_time(&tv, 0, immediately ? 0 : AVAHI_LLMNR_JITTER),
                                          elapse_timeout_callback,
                                          qj);

    return 1;
}
Exemple #5
0
int avahi_query_scheduler_post(AvahiQueryScheduler *s, AvahiKey *key, int immediately, unsigned *ret_id) {
    struct timeval tv;
    AvahiQueryJob *qj;

    assert(s);
    assert(key);

    if ((qj = find_history_job(s, key)))
        return 0;

    avahi_elapse_time(&tv, immediately ? 0 : AVAHI_QUERY_DEFER_MSEC, 0);

    if ((qj = find_scheduled_job(s, key))) {
        /* Duplicate questions suppression */

        if (avahi_timeval_compare(&tv, &qj->delivery) < 0) {
            /* If the new entry should be scheduled earlier,
             * update the old entry */
            qj->delivery = tv;
            avahi_time_event_update(qj->time_event, &qj->delivery);
        }

        qj->n_posted++;

    } else {

        if (!(qj = job_new(s, key, 0)))
            return 0; /* OOM */

        qj->delivery = tv;
        qj->time_event = avahi_time_event_new(s->time_event_queue, &qj->delivery, elapse_callback, qj);
    }

    if (ret_id)
        *ret_id = qj->id;

    return 1;
}
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_s_entry_group_commit(AvahiSEntryGroup *g) {
    struct timeval now;
    
    assert(g);
    assert(!g->dead);

    if (g->state != AVAHI_ENTRY_GROUP_UNCOMMITED && g->state != AVAHI_ENTRY_GROUP_COLLISION)
        return avahi_server_set_errno(g->server, AVAHI_ERR_BAD_STATE);

    if (avahi_s_entry_group_is_empty(g))
        return avahi_server_set_errno(g->server, AVAHI_ERR_IS_EMPTY);

    g->n_register_try++;

    avahi_timeval_add(&g->register_time,
                      1000*(g->n_register_try >= AVAHI_RR_RATE_LIMIT_COUNT ?
                            AVAHI_RR_HOLDOFF_MSEC_RATE_LIMIT :
                            AVAHI_RR_HOLDOFF_MSEC));

    gettimeofday(&now, NULL);

    if (avahi_timeval_compare(&g->register_time, &now) <= 0) {

        /* Holdoff time passed, so let's start probing */
        entry_group_commit_real(g);
    } else {

         /* Holdoff time has not yet passed, so let's wait */
        assert(!g->register_time_event);
        g->register_time_event = avahi_time_event_new(g->server->time_event_queue, &g->register_time, entry_group_register_time_event_callback, g);
        
        avahi_s_entry_group_change_state(g, AVAHI_ENTRY_GROUP_REGISTERING);
    }

    return AVAHI_OK;
}
Exemple #8
0
AvahiSDomainBrowser *avahi_s_domain_browser_prepare(
    AvahiServer *server,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    const char *domain,
    AvahiDomainBrowserType type,
    AvahiLookupFlags flags,
    AvahiSDomainBrowserCallback callback,
    void* userdata) {

    static const char * const type_table[AVAHI_DOMAIN_BROWSER_MAX] = {
        "b",
        "db",
        "r",
        "dr",
        "lb"
    };

    AvahiSDomainBrowser *b;
    AvahiKey *k = NULL;
    char n[AVAHI_DOMAIN_NAME_MAX];
    int r;

    assert(server);
    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, type < AVAHI_DOMAIN_BROWSER_MAX, AVAHI_ERR_INVALID_FLAGS);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_FLAGS_VALID(flags, AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS);

    if (!domain)
        domain = server->domain_name;

    if ((r = avahi_service_name_join(n, sizeof(n), type_table[type], "_dns-sd._udp", domain)) < 0) {
        avahi_server_set_errno(server, r);
        return NULL;
    }

    if (!(b = avahi_new(AvahiSDomainBrowser, 1))) {
        avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
        return NULL;
    }

    b->ref = 1;
    b->server = server;
    b->callback = callback;
    b->userdata = userdata;
    b->record_browser = NULL;
    b->type = type;
    b->all_for_now_scheduled = 0;
    b->defer_event = NULL;

    AVAHI_LLIST_PREPEND(AvahiSDomainBrowser, browser, server->domain_browsers, b);

    if (!(k = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_PTR))) {
        avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
        goto fail;
    }

    if (!(b->record_browser = avahi_s_record_browser_prepare(server, interface, protocol, k, flags, record_browser_callback, b)))
        goto fail;

    avahi_key_unref(k);

    if (type == AVAHI_DOMAIN_BROWSER_BROWSE && b->server->config.browse_domains)
        b->defer_event = avahi_time_event_new(server->time_event_queue, NULL, defer_callback, b);

    return b;

fail:

    if (k)
        avahi_key_unref(k);

    avahi_s_domain_browser_free(b);

    return NULL;
}
Exemple #9
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;
}
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;
    }
}