X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=avahi-core%2Fresponse-sched.c;h=abac0a1e594dd83f9560f2b0a165870923131b9d;hb=9c0f9c65093cfa53d45f9b68782321eb8063a032;hp=f88c63a4559a25ae80b21902532f4329054a812c;hpb=4de3df3db7df43474176533d0b5fac851dd4a9b4;p=catta diff --git a/avahi-core/response-sched.c b/avahi-core/response-sched.c index f88c63a..abac0a1 100644 --- a/avahi-core/response-sched.c +++ b/avahi-core/response-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,12 +21,25 @@ #include #endif +#include + +#include +#include + #include "response-sched.h" -#include "util.h" +#include "log.h" +#include "rr-util.h" + +/* Local packets are supressed this long after sending them */ +#define AVAHI_RESPONSE_HISTORY_MSEC 500 -#define AVAHI_RESPONSE_HISTORY_MSEC 700 +/* Local packets are deferred this long before sending them */ #define AVAHI_RESPONSE_DEFER_MSEC 20 + +/* Additional jitter for deferred packets */ #define AVAHI_RESPONSE_JITTER_MSEC 100 + +/* Remote packets can suppress local traffic as long as this value */ #define AVAHI_RESPONSE_SUPPRESS_MSEC 700 typedef struct AvahiResponseJob AvahiResponseJob; @@ -42,15 +53,15 @@ typedef enum { struct AvahiResponseJob { AvahiResponseScheduler *scheduler; AvahiTimeEvent *time_event; - + AvahiResponseJobState state; - GTimeVal delivery; + struct timeval delivery; AvahiRecord *record; - gboolean flush_cache; + int flush_cache; AvahiAddress querier; - gboolean querier_valid; - + int querier_valid; + AVAHI_LLIST_FIELDS(AvahiResponseJob, jobs); }; @@ -65,18 +76,22 @@ struct AvahiResponseScheduler { static AvahiResponseJob* job_new(AvahiResponseScheduler *s, AvahiRecord *record, AvahiResponseJobState state) { AvahiResponseJob *rj; - - g_assert(s); - g_assert(record); - rj = g_new(AvahiResponseJob, 1); + assert(s); + assert(record); + + if (!(rj = avahi_new(AvahiResponseJob, 1))) { + avahi_log_error(__FILE__": Out of memory"); + return NULL; + } + rj->scheduler = s; rj->record = avahi_record_ref(record); rj->time_event = NULL; - rj->flush_cache = FALSE; - rj->querier_valid = FALSE; - - if ((rj->state = state) == AVAHI_SCHEDULED) + rj->flush_cache = 0; + rj->querier_valid = 0; + + if ((rj->state = state) == AVAHI_SCHEDULED) AVAHI_LLIST_PREPEND(AvahiResponseJob, jobs, s->jobs, rj); else if (rj->state == AVAHI_DONE) AVAHI_LLIST_PREPEND(AvahiResponseJob, jobs, s->history, rj); @@ -87,11 +102,11 @@ static AvahiResponseJob* job_new(AvahiResponseScheduler *s, AvahiRecord *record, } static void job_free(AvahiResponseScheduler *s, AvahiResponseJob *rj) { - g_assert(s); - g_assert(rj); + assert(s); + assert(rj); if (rj->time_event) - avahi_time_event_queue_remove(s->time_event_queue, rj->time_event); + avahi_time_event_free(rj->time_event); if (rj->state == AVAHI_SCHEDULED) AVAHI_LLIST_REMOVE(AvahiResponseJob, jobs, s->jobs, rj); @@ -101,30 +116,30 @@ static void job_free(AvahiResponseScheduler *s, AvahiResponseJob *rj) { AVAHI_LLIST_REMOVE(AvahiResponseJob, jobs, s->suppressed, rj); avahi_record_unref(rj->record); - g_free(rj); + avahi_free(rj); } -static void elapse_callback(AvahiTimeEvent *e, gpointer data); +static void elapse_callback(AvahiTimeEvent *e, void* data); -static void job_set_elapse_time(AvahiResponseScheduler *s, AvahiResponseJob *rj, guint msec, guint jitter) { - GTimeVal tv; +static void job_set_elapse_time(AvahiResponseScheduler *s, AvahiResponseJob *rj, unsigned msec, unsigned jitter) { + struct timeval tv; - g_assert(s); - g_assert(rj); + assert(s); + assert(rj); avahi_elapse_time(&tv, msec, jitter); if (rj->time_event) - avahi_time_event_queue_update(s->time_event_queue, rj->time_event, &tv); + avahi_time_event_update(rj->time_event, &tv); else - rj->time_event = avahi_time_event_queue_add(s->time_event_queue, &tv, elapse_callback, rj); + rj->time_event = avahi_time_event_new(s->time_event_queue, &tv, elapse_callback, rj); } static void job_mark_done(AvahiResponseScheduler *s, AvahiResponseJob *rj) { - g_assert(s); - g_assert(rj); + assert(s); + assert(rj); - g_assert(rj->state == AVAHI_SCHEDULED); + assert(rj->state == AVAHI_SCHEDULED); AVAHI_LLIST_REMOVE(AvahiResponseJob, jobs, s->jobs, rj); AVAHI_LLIST_PREPEND(AvahiResponseJob, jobs, s->history, rj); @@ -133,17 +148,21 @@ static void job_mark_done(AvahiResponseScheduler *s, AvahiResponseJob *rj) { job_set_elapse_time(s, rj, AVAHI_RESPONSE_HISTORY_MSEC, 0); - g_get_current_time(&rj->delivery); + gettimeofday(&rj->delivery, NULL); } AvahiResponseScheduler *avahi_response_scheduler_new(AvahiInterface *i) { AvahiResponseScheduler *s; - g_assert(i); + assert(i); + + if (!(s = avahi_new(AvahiResponseScheduler, 1))) { + avahi_log_error(__FILE__": Out of memory"); + return NULL; + } - s = g_new(AvahiResponseScheduler, 1); s->interface = i; s->time_event_queue = i->monitor->server->time_event_queue; - + AVAHI_LLIST_HEAD_INIT(AvahiResponseJob, s->jobs); AVAHI_LLIST_HEAD_INIT(AvahiResponseJob, s->history); AVAHI_LLIST_HEAD_INIT(AvahiResponseJob, s->suppressed); @@ -152,15 +171,15 @@ AvahiResponseScheduler *avahi_response_scheduler_new(AvahiInterface *i) { } void avahi_response_scheduler_free(AvahiResponseScheduler *s) { - g_assert(s); + assert(s); avahi_response_scheduler_clear(s); - g_free(s); + avahi_free(s); } void avahi_response_scheduler_clear(AvahiResponseScheduler *s) { - g_assert(s); - + assert(s); + while (s->jobs) job_free(s, s->jobs); while (s->history) @@ -169,40 +188,41 @@ void avahi_response_scheduler_clear(AvahiResponseScheduler *s) { job_free(s, s->suppressed); } -static void enumerate_aux_records_callback(AvahiServer *s, AvahiRecord *r, gboolean flush_cache, gpointer userdata) { +static void enumerate_aux_records_callback(AVAHI_GCC_UNUSED AvahiServer *s, AvahiRecord *r, int flush_cache, void* userdata) { AvahiResponseJob *rj = userdata; - - g_assert(r); - g_assert(rj); - avahi_response_scheduler_post(rj->scheduler, r, flush_cache, rj->querier_valid ? &rj->querier : NULL, FALSE); + assert(r); + assert(rj); + + avahi_response_scheduler_post(rj->scheduler, r, flush_cache, rj->querier_valid ? &rj->querier : NULL, 0); } -static gboolean packet_add_response_job(AvahiResponseScheduler *s, AvahiDnsPacket *p, AvahiResponseJob *rj) { - g_assert(s); - g_assert(p); - g_assert(rj); +static int packet_add_response_job(AvahiResponseScheduler *s, AvahiDnsPacket *p, AvahiResponseJob *rj) { + assert(s); + assert(p); + assert(rj); /* Try to add this record to the packet */ if (!avahi_dns_packet_append_record(p, rj->record, rj->flush_cache, 0)) - return FALSE; + return 0; /* Ok, this record will definitely be sent, so schedule the * auxilliary packets, too */ avahi_server_enumerate_aux_records(s->interface->monitor->server, s->interface, rj->record, enumerate_aux_records_callback, rj); job_mark_done(s, rj); - - return TRUE; + + return 1; } static void send_response_packet(AvahiResponseScheduler *s, AvahiResponseJob *rj) { AvahiDnsPacket *p; - guint n; + unsigned n; - g_assert(s); - g_assert(rj); + assert(s); + assert(rj); - p = avahi_dns_packet_new_response(s->interface->hardware->mtu, TRUE); + if (!(p = avahi_dns_packet_new_response(s->interface->hardware->mtu, 1))) + return; /* OOM */ n = 1; /* Put it in the packet. */ @@ -210,30 +230,28 @@ static void send_response_packet(AvahiResponseScheduler *s, AvahiResponseJob *rj /* Try to fill up packet with more responses, if available */ while (s->jobs) { - + if (!packet_add_response_job(s, p, s->jobs)) break; - + n++; } - + } else { - guint size; - + size_t size; + avahi_dns_packet_free(p); /* OK, the packet was too small, so create one that fits */ size = avahi_record_get_estimate_size(rj->record) + AVAHI_DNS_PACKET_HEADER_SIZE; - if (size > AVAHI_DNS_PACKET_MAX_SIZE) - size = AVAHI_DNS_PACKET_MAX_SIZE; - - p = avahi_dns_packet_new_response(size, TRUE); + if (!(p = avahi_dns_packet_new_response(size + AVAHI_DNS_PACKET_EXTRA_SIZE, 1))) + return; /* OOM */ if (!packet_add_response_job(s, p, rj)) { avahi_dns_packet_free(p); - g_warning("Record too large, cannot send"); + avahi_log_warn("Record too large, cannot send"); job_mark_done(s, rj); return; } @@ -244,12 +262,12 @@ static void send_response_packet(AvahiResponseScheduler *s, AvahiResponseJob *rj avahi_dns_packet_free(p); } -static void elapse_callback(AvahiTimeEvent *e, gpointer data) { +static void elapse_callback(AVAHI_GCC_UNUSED AvahiTimeEvent *e, void* data) { AvahiResponseJob *rj = data; - g_assert(rj); + assert(rj); - if (rj->state == AVAHI_DONE || rj->state == AVAHI_SUPPRESSED) + if (rj->state == AVAHI_DONE || rj->state == AVAHI_SUPPRESSED) job_free(rj->scheduler, rj); /* Lets drop this entry */ else send_response_packet(rj->scheduler, rj); @@ -258,12 +276,12 @@ static void elapse_callback(AvahiTimeEvent *e, gpointer data) { static AvahiResponseJob* find_scheduled_job(AvahiResponseScheduler *s, AvahiRecord *record) { AvahiResponseJob *rj; - g_assert(s); - g_assert(record); + assert(s); + assert(record); for (rj = s->jobs; rj; rj = rj->jobs_next) { - g_assert(rj->state == AVAHI_SCHEDULED); - + assert(rj->state == AVAHI_SCHEDULED); + if (avahi_record_equal_no_ttl(rj->record, record)) return rj; } @@ -273,22 +291,24 @@ static AvahiResponseJob* find_scheduled_job(AvahiResponseScheduler *s, AvahiReco static AvahiResponseJob* find_history_job(AvahiResponseScheduler *s, AvahiRecord *record) { AvahiResponseJob *rj; - - g_assert(s); - g_assert(record); + + assert(s); + assert(record); for (rj = s->history; rj; rj = rj->jobs_next) { - g_assert(rj->state == AVAHI_DONE); + assert(rj->state == AVAHI_DONE); if (avahi_record_equal_no_ttl(rj->record, record)) { /* Check whether this entry is outdated */ - if (avahi_age(&rj->delivery) > AVAHI_RESPONSE_HISTORY_MSEC*1000) { +/* avahi_log_debug("history age: %u", (unsigned) (avahi_age(&rj->delivery)/1000)); */ + + if (avahi_age(&rj->delivery)/1000 > AVAHI_RESPONSE_HISTORY_MSEC) { /* it is outdated, so let's remove it */ job_free(s, rj); return NULL; } - + return rj; } } @@ -298,15 +318,15 @@ static AvahiResponseJob* find_history_job(AvahiResponseScheduler *s, AvahiRecord static AvahiResponseJob* find_suppressed_job(AvahiResponseScheduler *s, AvahiRecord *record, const AvahiAddress *querier) { AvahiResponseJob *rj; - - g_assert(s); - g_assert(record); - g_assert(querier); + + assert(s); + assert(record); + assert(querier); for (rj = s->suppressed; rj; rj = rj->jobs_next) { - g_assert(rj->state == AVAHI_SUPPRESSED); - g_assert(rj->querier_valid); - + assert(rj->state == AVAHI_SUPPRESSED); + assert(rj->querier_valid); + if (avahi_record_equal_no_ttl(rj->record, record) && avahi_address_cmp(&rj->querier, querier) == 0) { /* Check whether this entry is outdated */ @@ -324,14 +344,19 @@ static AvahiResponseJob* find_suppressed_job(AvahiResponseScheduler *s, AvahiRec return NULL; } -gboolean avahi_response_scheduler_post(AvahiResponseScheduler *s, AvahiRecord *record, gboolean flush_cache, const AvahiAddress *querier, gboolean immediately) { +int avahi_response_scheduler_post(AvahiResponseScheduler *s, AvahiRecord *record, int flush_cache, const AvahiAddress *querier, int immediately) { AvahiResponseJob *rj; - GTimeVal tv; - - g_assert(s); - g_assert(record); + struct timeval tv; +/* char *t; */ + + assert(s); + assert(record); + + assert(!avahi_key_is_pattern(record->key)); - g_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 && @@ -339,8 +364,8 @@ gboolean avahi_response_scheduler_post(AvahiResponseScheduler *s, AvahiRecord *r avahi_record_is_goodbye(record) == avahi_record_is_goodbye(rj->record) && rj->record->ttl >= record->ttl/2) { -/* g_message("Response suppressed by known answer suppression."); */ - return FALSE; +/* avahi_log_debug("Response suppressed by known answer suppression."); */ + return 0; } /* Check if we already sent this response recently */ @@ -349,8 +374,8 @@ gboolean avahi_response_scheduler_post(AvahiResponseScheduler *s, AvahiRecord *r if (avahi_record_is_goodbye(record) == avahi_record_is_goodbye(rj->record) && rj->record->ttl >= record->ttl/2 && (rj->flush_cache || !flush_cache)) { -/* g_message("Response suppressed by local duplicate suppression (history)"); */ - return FALSE; +/* avahi_log_debug("Response suppressed by local duplicate suppression (history)"); */ + return 0; } /* Outdated ... */ @@ -358,55 +383,57 @@ gboolean avahi_response_scheduler_post(AvahiResponseScheduler *s, AvahiRecord *r } avahi_elapse_time(&tv, immediately ? 0 : AVAHI_RESPONSE_DEFER_MSEC, immediately ? 0 : AVAHI_RESPONSE_JITTER_MSEC); - + if ((rj = find_scheduled_job(s, record))) { -/* g_message("Response suppressed by local duplicate suppression (scheduled)"); */ +/* 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_queue_update(s->time_event_queue, rj->time_event, &rj->delivery); + avahi_time_event_update(rj->time_event, &rj->delivery); } /* Update the flush cache bit */ if (flush_cache) - rj->flush_cache = TRUE; + rj->flush_cache = 1; /* Update the querier field */ if (!querier || (rj->querier_valid && avahi_address_cmp(querier, &rj->querier) != 0)) - rj->querier_valid = FALSE; + rj->querier_valid = 0; /* Update record data (just for the TTL) */ avahi_record_unref(rj->record); rj->record = avahi_record_ref(record); - return TRUE; + return 1; } else { -/* g_message("Accepted new response job."); */ +/* avahi_log_debug("Accepted new response job."); */ /* Create a new job and schedule it */ - rj = job_new(s, record, AVAHI_SCHEDULED); + if (!(rj = job_new(s, record, AVAHI_SCHEDULED))) + return 0; /* OOM */ + rj->delivery = tv; - rj->time_event = avahi_time_event_queue_add(s->time_event_queue, &rj->delivery, elapse_callback, rj); + 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 TRUE; + return 1; } } -void avahi_response_scheduler_incoming(AvahiResponseScheduler *s, AvahiRecord *record, gboolean flush_cache) { +void avahi_response_scheduler_incoming(AvahiResponseScheduler *s, AvahiRecord *record, int flush_cache) { AvahiResponseJob *rj; - g_assert(s); + assert(s); /* This function is called whenever an incoming response was * receieved. We drop scheduled responses which match here. The * keyword is "DUPLICATE ANSWER SUPPRESION". */ - + if ((rj = find_scheduled_job(s, record))) { if ((!rj->flush_cache || flush_cache) && /* flush cache bit was set correctly */ @@ -414,7 +441,7 @@ void avahi_response_scheduler_incoming(AvahiResponseScheduler *s, AvahiRecord *r record->ttl >= rj->record->ttl/2) { /* sensible TTL */ /* A matching entry was found, so let's mark it done */ -/* g_message("Response suppressed by distributed duplicate suppression"); */ +/* avahi_log_debug("Response suppressed by distributed duplicate suppression"); */ job_mark_done(s, rj); } @@ -427,30 +454,31 @@ void avahi_response_scheduler_incoming(AvahiResponseScheduler *s, AvahiRecord *r rj->record = avahi_record_ref(record); } else /* Found no existing history job, so let's create a new one */ - rj = job_new(s, record, AVAHI_DONE); + if (!(rj = job_new(s, record, AVAHI_DONE))) + return; /* OOM */ rj->flush_cache = flush_cache; - rj->querier_valid = FALSE; - - g_get_current_time(&rj->delivery); + rj->querier_valid = 0; + + gettimeofday(&rj->delivery, NULL); job_set_elapse_time(s, rj, AVAHI_RESPONSE_HISTORY_MSEC, 0); } void avahi_response_scheduler_suppress(AvahiResponseScheduler *s, AvahiRecord *record, const AvahiAddress *querier) { AvahiResponseJob *rj; - - g_assert(s); - g_assert(record); - g_assert(querier); + + assert(s); + assert(record); + assert(querier); if ((rj = find_scheduled_job(s, record))) { - + if (rj->querier_valid && avahi_address_cmp(querier, &rj->querier) == 0 && /* same originator */ avahi_record_is_goodbye(record) == avahi_record_is_goodbye(rj->record) && /* both goodbye packets, or both not */ record->ttl >= rj->record->ttl/2) { /* sensible TTL */ /* A matching entry was found, so let's drop it */ -/* g_message("Known answer suppression active!"); */ +/* avahi_log_debug("Known answer suppression active!"); */ job_free(s, rj); } } @@ -460,21 +488,22 @@ void avahi_response_scheduler_suppress(AvahiResponseScheduler *s, AvahiRecord *r /* Let's update the old entry */ avahi_record_unref(rj->record); rj->record = avahi_record_ref(record); - + } else { /* Create a new entry */ - rj = job_new(s, record, AVAHI_SUPPRESSED); - rj->querier_valid = TRUE; + if (!(rj = job_new(s, record, AVAHI_SUPPRESSED))) + return; /* OOM */ + rj->querier_valid = 1; rj->querier = *querier; } - g_get_current_time(&rj->delivery); + gettimeofday(&rj->delivery, NULL); job_set_elapse_time(s, rj, AVAHI_RESPONSE_SUPPRESS_MSEC, 0); } void avahi_response_scheduler_force(AvahiResponseScheduler *s) { - g_assert(s); + assert(s); /* Send all scheduled responses immediately */ while (s->jobs)