X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=avahi-core%2Fprobe-sched.c;h=1e63411ce167fb585ee5f9a8bf2de35260e5c666;hb=9c0f9c65093cfa53d45f9b68782321eb8063a032;hp=9089bbae523b3c7f8bdbbfeba10f35b75fb1f88a;hpb=4de3df3db7df43474176533d0b5fac851dd4a9b4;p=catta diff --git a/avahi-core/probe-sched.c b/avahi-core/probe-sched.c index 9089bba..1e63411 100644 --- a/avahi-core/probe-sched.c +++ b/avahi-core/probe-sched.c @@ -1,18 +1,16 @@ -/* $Id$ */ - /*** This file is part of avahi. - + avahi is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + avahi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with avahi; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -23,22 +21,31 @@ #include #endif +#include + +#include +#include +#include + #include "probe-sched.h" -#include "util.h" +#include "log.h" +#include "rr-util.h" -#define AVAHI_PROBE_DEFER_MSEC 70 +#define AVAHI_PROBE_HISTORY_MSEC 150 +#define AVAHI_PROBE_DEFER_MSEC 50 typedef struct AvahiProbeJob AvahiProbeJob; struct AvahiProbeJob { AvahiProbeScheduler *scheduler; AvahiTimeEvent *time_event; - - gboolean chosen; /* Use for packet assembling */ - GTimeVal delivery; + + int chosen; /* Use for packet assembling */ + int done; + struct timeval delivery; AvahiRecord *record; - + AVAHI_LLIST_FIELDS(AvahiProbeJob, jobs); }; @@ -47,77 +54,125 @@ struct AvahiProbeScheduler { AvahiTimeEventQueue *time_event_queue; AVAHI_LLIST_HEAD(AvahiProbeJob, jobs); + AVAHI_LLIST_HEAD(AvahiProbeJob, history); }; -static AvahiProbeJob* job_new(AvahiProbeScheduler *s, AvahiRecord *record) { +static AvahiProbeJob* job_new(AvahiProbeScheduler *s, AvahiRecord *record, int done) { AvahiProbeJob *pj; - - g_assert(s); - g_assert(record); - pj = g_new(AvahiProbeJob, 1); + assert(s); + assert(record); + + if (!(pj = avahi_new(AvahiProbeJob, 1))) { + avahi_log_error(__FILE__": Out of memory"); + return NULL; /* OOM */ + } + pj->scheduler = s; pj->record = avahi_record_ref(record); pj->time_event = NULL; - pj->chosen = FALSE; - - AVAHI_LLIST_PREPEND(AvahiProbeJob, jobs, s->jobs, pj); + pj->chosen = 0; + + if ((pj->done = done)) + AVAHI_LLIST_PREPEND(AvahiProbeJob, jobs, s->history, pj); + else + AVAHI_LLIST_PREPEND(AvahiProbeJob, jobs, s->jobs, pj); return pj; } static void job_free(AvahiProbeScheduler *s, AvahiProbeJob *pj) { - g_assert(pj); + assert(pj); if (pj->time_event) - avahi_time_event_queue_remove(s->time_event_queue, pj->time_event); + avahi_time_event_free(pj->time_event); - AVAHI_LLIST_REMOVE(AvahiProbeJob, jobs, s->jobs, pj); + if (pj->done) + AVAHI_LLIST_REMOVE(AvahiProbeJob, jobs, s->history, pj); + else + AVAHI_LLIST_REMOVE(AvahiProbeJob, jobs, s->jobs, pj); avahi_record_unref(pj->record); - g_free(pj); + avahi_free(pj); +} + +static void elapse_callback(AvahiTimeEvent *e, void* data); + +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); } +static void job_mark_done(AvahiProbeScheduler *s, AvahiProbeJob *pj) { + assert(s); + assert(pj); + + assert(!pj->done); + + AVAHI_LLIST_REMOVE(AvahiProbeJob, jobs, s->jobs, pj); + AVAHI_LLIST_PREPEND(AvahiProbeJob, jobs, s->history, pj); + + pj->done = 1; + + job_set_elapse_time(s, pj, AVAHI_PROBE_HISTORY_MSEC, 0); + gettimeofday(&pj->delivery, NULL); +} AvahiProbeScheduler *avahi_probe_scheduler_new(AvahiInterface *i) { AvahiProbeScheduler *s; - g_assert(i); + assert(i); + + if (!(s = avahi_new(AvahiProbeScheduler, 1))) { + avahi_log_error(__FILE__": Out of memory"); + return NULL; + } - s = g_new(AvahiProbeScheduler, 1); s->interface = i; s->time_event_queue = i->monitor->server->time_event_queue; AVAHI_LLIST_HEAD_INIT(AvahiProbeJob, s->jobs); - + AVAHI_LLIST_HEAD_INIT(AvahiProbeJob, s->history); + return s; } void avahi_probe_scheduler_free(AvahiProbeScheduler *s) { - g_assert(s); + assert(s); avahi_probe_scheduler_clear(s); - g_free(s); + avahi_free(s); } void avahi_probe_scheduler_clear(AvahiProbeScheduler *s) { - g_assert(s); - + assert(s); + while (s->jobs) job_free(s, s->jobs); + while (s->history) + job_free(s, s->history); } - -static gboolean packet_add_probe_query(AvahiProbeScheduler *s, AvahiDnsPacket *p, AvahiProbeJob *pj) { - guint size; + +static int packet_add_probe_query(AvahiProbeScheduler *s, AvahiDnsPacket *p, AvahiProbeJob *pj) { + size_t size; AvahiKey *k; - gboolean b; + int b; - g_assert(s); - g_assert(p); - g_assert(pj); + assert(s); + assert(p); + assert(pj); + + assert(!pj->chosen); - g_assert(!pj->chosen); - /* Estimate the size for this record */ size = avahi_key_get_estimate_size(pj->record->key) + @@ -125,15 +180,17 @@ static gboolean packet_add_probe_query(AvahiProbeScheduler *s, AvahiDnsPacket *p /* Too large */ if (size > avahi_dns_packet_space(p)) - return FALSE; + return 0; /* Create the probe query */ - k = avahi_key_new(pj->record->key->name, pj->record->key->class, AVAHI_DNS_TYPE_ANY); - b = !!avahi_dns_packet_append_key(p, k, FALSE); - g_assert(b); + if (!(k = avahi_key_new(pj->record->key->name, pj->record->key->clazz, AVAHI_DNS_TYPE_ANY))) + return 0; /* OOM */ + + b = !!avahi_dns_packet_append_key(p, k, 0); + assert(b); /* Mark this job for addition to the packet */ - pj->chosen = TRUE; + pj->chosen = 1; /* Scan for more jobs whith matching key pattern */ for (pj = s->jobs; pj; pj = pj->jobs_next) { @@ -141,39 +198,46 @@ static gboolean packet_add_probe_query(AvahiProbeScheduler *s, AvahiDnsPacket *p continue; /* Does the record match the probe? */ - if (k->class != pj->record->key->class || !avahi_domain_equal(k->name, pj->record->key->name)) + if (k->clazz != pj->record->key->clazz || !avahi_domain_equal(k->name, pj->record->key->name)) continue; - + /* This job wouldn't fit in */ if (avahi_record_get_estimate_size(pj->record) > avahi_dns_packet_space(p)) break; /* Mark this job for addition to the packet */ - pj->chosen = TRUE; + pj->chosen = 1; } avahi_key_unref(k); - - return TRUE; + + return 1; } -static void elapse_callback(AvahiTimeEvent *e, gpointer data) { +static void elapse_callback(AVAHI_GCC_UNUSED AvahiTimeEvent *e, void* data) { AvahiProbeJob *pj = data, *next; AvahiProbeScheduler *s; AvahiDnsPacket *p; - guint n; + unsigned n; - g_assert(pj); + assert(pj); s = pj->scheduler; - p = avahi_dns_packet_new_query(s->interface->hardware->mtu); + if (pj->done) { + /* Lets remove it from the history */ + job_free(s, pj); + return; + } + + if (!(p = avahi_dns_packet_new_query(s->interface->hardware->mtu))) + return; /* OOM */ n = 1; - + /* Add the import probe */ if (!packet_add_probe_query(s, p, pj)) { - guint size; + size_t size; AvahiKey *k; - gboolean b; + int b; avahi_dns_packet_free(p); @@ -183,14 +247,16 @@ static void elapse_callback(AvahiTimeEvent *e, gpointer data) { avahi_key_get_estimate_size(pj->record->key) + avahi_record_get_estimate_size(pj->record) + AVAHI_DNS_PACKET_HEADER_SIZE; - - if (size > AVAHI_DNS_PACKET_MAX_SIZE) - size = AVAHI_DNS_PACKET_MAX_SIZE; - - p = avahi_dns_packet_new_query(size); - - k = avahi_key_new(pj->record->key->name, pj->record->key->class, AVAHI_DNS_TYPE_ANY); - b = avahi_dns_packet_append_key(p, k, FALSE) && avahi_dns_packet_append_record(p, pj->record, FALSE, 0); + + if (!(p = avahi_dns_packet_new_query(size + AVAHI_DNS_PACKET_EXTRA_SIZE))) + return; /* OOM */ + + if (!(k = avahi_key_new(pj->record->key->name, pj->record->key->clazz, AVAHI_DNS_TYPE_ANY))) { + avahi_dns_packet_free(p); + return; /* OOM */ + } + + b = avahi_dns_packet_append_key(p, k, 0) && avahi_dns_packet_append_record(p, pj->record, 0, 0); avahi_key_unref(k); if (b) { @@ -198,10 +264,10 @@ static void elapse_callback(AvahiTimeEvent *e, gpointer data) { avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_QDCOUNT, 1); avahi_interface_send_packet(s->interface, p); } else - g_warning("Probe record too large, cannot send"); - + avahi_log_warn("Probe record too large, cannot send"); + avahi_dns_packet_free(p); - job_free(s, pj); + job_mark_done(s, pj); return; } @@ -211,10 +277,10 @@ static void elapse_callback(AvahiTimeEvent *e, gpointer data) { if (pj->chosen) continue; - + if (!packet_add_probe_query(s, p, pj)) break; - + n++; } @@ -230,21 +296,21 @@ static void elapse_callback(AvahiTimeEvent *e, gpointer data) { if (!pj->chosen) continue; - if (!avahi_dns_packet_append_record(p, pj->record, FALSE, 0)) { - g_warning("Bad probe size estimate!"); + if (!avahi_dns_packet_append_record(p, pj->record, 0, 0)) { +/* avahi_log_warn("Bad probe size estimate!"); */ /* Unmark all following jobs */ for (; pj; pj = pj->jobs_next) - pj->chosen = FALSE; - + pj->chosen = 0; + break; } - job_free(s, pj); - + job_mark_done(s, pj); + n ++; } - + avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_NSCOUNT, n); /* Send it now */ @@ -252,22 +318,80 @@ static void elapse_callback(AvahiTimeEvent *e, gpointer data) { avahi_dns_packet_free(p); } -gboolean avahi_probe_scheduler_post(AvahiProbeScheduler *s, AvahiRecord *record, gboolean immediately) { +static AvahiProbeJob* find_scheduled_job(AvahiProbeScheduler *s, AvahiRecord *record) { + AvahiProbeJob *pj; + + assert(s); + assert(record); + + for (pj = s->jobs; pj; pj = pj->jobs_next) { + assert(!pj->done); + + if (avahi_record_equal_no_ttl(pj->record, record)) + return pj; + } + + return NULL; +} + +static AvahiProbeJob* find_history_job(AvahiProbeScheduler *s, AvahiRecord *record) { AvahiProbeJob *pj; - GTimeVal tv; - - g_assert(s); - g_assert(record); - g_assert(!avahi_key_is_pattern(record->key)); - + + assert(s); + assert(record); + + for (pj = s->history; pj; pj = pj->jobs_next) { + assert(pj->done); + + if (avahi_record_equal_no_ttl(pj->record, record)) { + /* Check whether this entry is outdated */ + + if (avahi_age(&pj->delivery) > AVAHI_PROBE_HISTORY_MSEC*1000) { + /* it is outdated, so let's remove it */ + job_free(s, pj); + return NULL; + } + + return pj; + } + } + + return NULL; +} + +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); - /* Create a new job and schedule it */ - pj = job_new(s, record); - pj->delivery = tv; - pj->time_event = avahi_time_event_queue_add(s->time_event_queue, &pj->delivery, elapse_callback, pj); + 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); -/* g_message("Accepted new probe job."); */ - return TRUE; +/* avahi_log_debug("Accepted new probe job."); */ + + return 1; + } }