diff options
Diffstat (limited to 'avahi-core/psched.c')
-rw-r--r-- | avahi-core/psched.c | 241 |
1 files changed, 139 insertions, 102 deletions
diff --git a/avahi-core/psched.c b/avahi-core/psched.c index 60bf40c..5121054 100644 --- a/avahi-core/psched.c +++ b/avahi-core/psched.c @@ -229,7 +229,7 @@ static void query_elapse(AvahiTimeEvent *e, gpointer data) { append_known_answers_and_send(s, p); } -AvahiQueryJob* query_job_new(AvahiPacketScheduler *s, AvahiKey *key) { +static AvahiQueryJob* query_job_new(AvahiPacketScheduler *s, AvahiKey *key) { AvahiQueryJob *qj; g_assert(s); @@ -246,6 +246,19 @@ AvahiQueryJob* query_job_new(AvahiPacketScheduler *s, AvahiKey *key) { return qj; } +static AvahiQueryJob* look_for_query(AvahiPacketScheduler *s, AvahiKey *key) { + AvahiQueryJob *qj; + + g_assert(s); + g_assert(key); + + for (qj = s->query_jobs; qj; qj = qj->jobs_next) + if (avahi_key_equal(qj->key, key)) + return qj; + + return NULL; +} + gboolean avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *key, gboolean immediately) { GTimeVal tv; AvahiQueryJob *qj; @@ -255,22 +268,23 @@ gboolean avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *ke avahi_elapse_time(&tv, immediately ? 0 : AVAHI_QUERY_DEFER_MSEC, 0); - for (qj = s->query_jobs; qj; qj = qj->jobs_next) { - - if (avahi_key_equal(qj->key, key)) { + if ((qj = look_for_query(s, key))) { + glong d = avahi_timeval_diff(&tv, &qj->delivery); - glong d = avahi_timeval_diff(&tv, &qj->delivery); - - /* Duplicate questions suppression */ - if (d >= 0 && d <= AVAHI_QUERY_HISTORY_MSEC*1000) { - g_message("WARNING! DUPLICATE QUERY SUPPRESSION ACTIVE!"); - return FALSE; - } + /* Duplicate questions suppression */ + if (!qj->done || d <= AVAHI_QUERY_HISTORY_MSEC*1000) { + g_message("WARNING! DUPLICATE QUERY SUPPRESSION ACTIVE!"); + if (!qj->done && d < 0) { + /* If the new entry should be scheduled earlier, + * update the old entry */ + qj->delivery = tv; + avahi_time_event_queue_update(s->server->time_event_queue, qj->time_event, &qj->delivery); + } + + return FALSE; + } else query_job_free(s, qj); - break; - } - } qj = query_job_new(s, key); @@ -279,6 +293,34 @@ gboolean avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *ke return TRUE; } + +void avahi_packet_scheduler_incoming_query(AvahiPacketScheduler *s, AvahiKey *key) { + AvahiQueryJob *qj; + GTimeVal tv; + + g_assert(s); + g_assert(key); + + /* This function is called whenever an incoming query was + * receieved. We mark all matching queries that match as done. The + * keyword is "DUPLICATE QUESTION SUPPRESION". */ + + if (!(qj = look_for_query(s, key))) + qj = query_job_new(s, key); + + qj->done = TRUE; + + /* Drop the query after some time */ + avahi_elapse_time(&tv, AVAHI_QUERY_HISTORY_MSEC, 0); + + if (qj->time_event) + avahi_time_event_queue_update(s->server->time_event_queue, qj->time_event, &tv); + else + qj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &tv, query_elapse, qj); + + g_get_current_time(&qj->delivery); +} + static guint8* packet_add_response_job(AvahiPacketScheduler *s, AvahiDnsPacket *p, AvahiResponseJob *rj) { guint8 *d; @@ -376,13 +418,14 @@ static AvahiResponseJob* response_job_new(AvahiPacketScheduler *s, AvahiRecord * rj->done = FALSE; rj->time_event = NULL; rj->flush_cache = FALSE; + rj->querier_valid = FALSE; AVAHI_LLIST_PREPEND(AvahiResponseJob, jobs, s->response_jobs, rj); return rj; } -gboolean avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, AvahiRecord *record, gboolean flush_cache, gboolean immediately) { +gboolean avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, AvahiRecord *record, gboolean flush_cache, gboolean immediately, const AvahiAddress *querier) { AvahiResponseJob *rj; GTimeVal tv; @@ -396,70 +439,48 @@ gboolean avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, AvahiReco /* Don't send out duplicates */ if ((rj = look_for_response(s, record))) { - glong d; - - d = avahi_timeval_diff(&tv, &rj->delivery); + glong d = avahi_timeval_diff(&tv, &rj->delivery); + /* If there's already a matching packet in our history or in * the schedule, we do nothing. */ - if (!!record->ttl == !!rj->record->ttl && - d >= 0 && d <= AVAHI_RESPONSE_HISTORY_MSEC*1000) { - g_message("WARNING! DUPLICATE RESPONSE SUPPRESSION ACTIVE!"); - - rj->flush_cache = flush_cache; + + if ((!!record->ttl == !!rj->record->ttl) && + (rj->flush_cache || !flush_cache) && + ((!rj->done && d >= 0) || (rj->done && d <= AVAHI_RESPONSE_HISTORY_MSEC*1000))) { + g_message("Duplicate suppresion active."); return FALSE; } - /* Either one was a goodbye packet, but the other was not, so - * let's drop the older one. */ + /* If the old job was not yet done but scheduled earlier than + * our new one, we chedule our new job at the same time. */ + if (!rj->done && d > 0) + tv = rj->delivery; + + /* If the old job had the flush_cache bit enabled, we must + enable it on our new one, too */ + if (!rj->done && rj->flush_cache) + flush_cache = TRUE; + + /* For known answer suppresion we have record for which host this data was intended */ + if (querier && !rj->done && (!rj->querier_valid || avahi_address_cmp(&rj->querier, querier) != 0)) + querier = NULL; + + /* The old job wasn't good enough, so let's drop it */ response_job_free(s, rj); } -/* g_message("ACCEPTED NEW RESPONSE [%s]", t = avahi_record_to_string(record)); */ -/* g_free(t); */ - /* Create a new job and schedule it */ rj = response_job_new(s, record); rj->flush_cache = flush_cache; rj->delivery = tv; rj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &rj->delivery, response_elapse, rj); - return TRUE; -} - -void avahi_packet_scheduler_incoming_query(AvahiPacketScheduler *s, AvahiKey *key) { - GTimeVal tv; - AvahiQueryJob *qj; - - g_assert(s); - g_assert(key); + if ((rj->querier_valid = !!querier)) + rj->querier = *querier; - /* This function is called whenever an incoming query was - * receieved. We drop all scheduled queries which match here. The - * keyword is "DUPLICATE QUESTION SUPPRESION". */ - - for (qj = s->query_jobs; qj; qj = qj->jobs_next) - if (avahi_key_equal(qj->key, key)) { - - if (qj->done) - return; - - goto mark_done; - } - - - /* No matching job was found. Add the query to the history */ - qj = query_job_new(s, key); - -mark_done: - qj->done = TRUE; - - /* Drop the query after some time */ - avahi_elapse_time(&tv, AVAHI_QUERY_HISTORY_MSEC, 0); - qj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &tv, query_elapse, qj); - - g_get_current_time(&qj->delivery); + return TRUE; } void response_job_set_elapse_time(AvahiPacketScheduler *s, AvahiResponseJob *rj, guint msec, guint jitter) { @@ -476,8 +497,8 @@ void response_job_set_elapse_time(AvahiPacketScheduler *s, AvahiResponseJob *rj, rj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &tv, response_elapse, rj); } -void avahi_packet_scheduler_incoming_response(AvahiPacketScheduler *s, AvahiRecord *record) { - AvahiResponseJob *rj; +void avahi_packet_scheduler_incoming_response(AvahiPacketScheduler *s, AvahiRecord *record, gboolean flush_cache) { + AvahiResponseJob *rj = NULL; g_assert(s); g_assert(record); @@ -485,51 +506,39 @@ void avahi_packet_scheduler_incoming_response(AvahiPacketScheduler *s, AvahiReco /* This function is called whenever an incoming response was * receieved. We drop all scheduled responses which match * here. The keyword is "DUPLICATE ANSWER SUPPRESION". */ - - for (rj = s->response_jobs; rj; rj = rj->jobs_next) - if (avahi_record_equal_no_ttl(rj->record, record)) { - - if (rj->done) { - - if (!!record->ttl == !!rj->record->ttl) { - /* An entry like this is already in our history, - * so let's get out of here! */ - - return; - - } else { - /* Either one was a goodbye packet but other was - * none. We remove the history entry, and add a - * new one */ - - response_job_free(s, rj); - break; - } - - } else { - - if (!!record->ttl == !!rj->record->ttl) { - /* The incoming packet matches our scheduled - * record, so let's mark that one as done */ - - goto mark_done; - - } else { + if ((rj = look_for_response(s, record))) { + + if (!rj->done) { - /* Either one was a goodbye packet but other was - * none. We ignore the incoming packet. */ + if (rj->flush_cache && !flush_cache) + /* The incoming response didn't have flush_cache + * set, but our scheduled has => we still have to + * send our response */ + return; - return; - } + + if (!!record->ttl != !!rj->record->ttl) { + /* Either one was a goodbye packet but other was + * none => we still have to send our response */ + return; } } + + /* The two responses match, so let's mark the history + * entry as done or update it */ + } /* No matching job was found. Add the query to the history */ - rj = response_job_new(s, record); - -mark_done: + if (!rj) + rj = response_job_new(s, record); + else { + avahi_record_unref(rj->record); + rj->record = avahi_record_ref(record); + } + rj->done = TRUE; + rj->flush_cache = rj->flush_cache || flush_cache; /* Drop response after 500ms from history */ response_job_set_elapse_time(s, rj, AVAHI_RESPONSE_HISTORY_MSEC, 0); @@ -537,6 +546,34 @@ mark_done: g_get_current_time(&rj->delivery); } + +void avahi_packet_scheduler_incoming_known_answer(AvahiPacketScheduler *s, AvahiRecord *record, const AvahiAddress *querier) { + AvahiResponseJob *rj; + + g_assert(s); + g_assert(record); + g_assert(querier); + + /* Check whether a matching job has been scheduled */ + if (!(rj = look_for_response(s, record)) || rj->done) + return; + + /* Chech whether another querier demanded the original job */ + if (!rj->querier_valid || avahi_address_cmp(&rj->querier, querier) != 0) + return; + + /* Check whether one of them is a goodbye packet, while the other is not */ + if (!!record->ttl != !!rj->record->ttl) + return; + + /* Check whether the known answer has a good TTL */ + if (record->ttl <= rj->record->ttl/2) + return; + + g_message("Known answer suppression active!"); + response_job_free(s, rj); +} + void avahi_packet_scheduler_flush_responses(AvahiPacketScheduler *s) { AvahiResponseJob *rj; @@ -660,7 +697,7 @@ static void probe_elapse(AvahiTimeEvent *e, gpointer data) { if (!pj->chosen) continue; - if (!avahi_dns_packet_append_record(p, pj->record, TRUE, 0)) { + if (!avahi_dns_packet_append_record(p, pj->record, FALSE, 0)) { g_warning("Bad probe size estimate!"); /* Unmark all following jobs */ |