From 6d236291b17f2d02e15d4c6f1c87bc7b3fc4e982 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 26 Sep 2005 01:34:43 +0000 Subject: * Implement POOF aka "Passive Observation of Failure" git-svn-id: file:///home/lennart/svn/public/avahi/trunk@632 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- avahi-core/cache.c | 137 ++++++++++++++++++++++++++++++++++++++++------------ avahi-core/cache.h | 15 +++++- avahi-core/server.c | 5 +- 3 files changed, 124 insertions(+), 33 deletions(-) diff --git a/avahi-core/cache.c b/avahi-core/cache.c index 6332b12..23e9036 100644 --- a/avahi-core/cache.c +++ b/avahi-core/cache.c @@ -165,41 +165,48 @@ static void next_expiry(AvahiCache *c, AvahiCacheEntry *e, unsigned percent); static void elapse_func(AvahiTimeEvent *t, void *userdata) { AvahiCacheEntry *e = userdata; /* char *txt; */ + unsigned percent = 0; assert(t); assert(e); /* txt = avahi_record_to_string(e->record); */ - if (e->state == AVAHI_CACHE_FINAL) { - remove_entry(e->cache, e); + switch (e->state) { + + case AVAHI_CACHE_EXPIRY_FINAL: + case AVAHI_CACHE_POOF_FINAL: + case AVAHI_CACHE_GOODBYE_FINAL: + case AVAHI_CACHE_REPLACE_FINAL: + + remove_entry(e->cache, e); + + e = NULL; /* avahi_log_debug("Removing entry from cache due to expiration (%s)", txt); */ - } else { - unsigned percent = 0; - - switch (e->state) { - case AVAHI_CACHE_VALID: - e->state = AVAHI_CACHE_EXPIRY1; - percent = 85; - break; - - case AVAHI_CACHE_EXPIRY1: - e->state = AVAHI_CACHE_EXPIRY2; - percent = 90; - break; - case AVAHI_CACHE_EXPIRY2: - e->state = AVAHI_CACHE_EXPIRY3; - percent = 95; - break; + break; + + case AVAHI_CACHE_VALID: + case AVAHI_CACHE_POOF: + e->state = AVAHI_CACHE_EXPIRY1; + percent = 85; + break; - case AVAHI_CACHE_EXPIRY3: - e->state = AVAHI_CACHE_FINAL; - percent = 100; - break; + case AVAHI_CACHE_EXPIRY1: + e->state = AVAHI_CACHE_EXPIRY2; + percent = 90; + break; + case AVAHI_CACHE_EXPIRY2: + e->state = AVAHI_CACHE_EXPIRY3; + percent = 95; + break; + + case AVAHI_CACHE_EXPIRY3: + e->state = AVAHI_CACHE_EXPIRY_FINAL; + percent = 100; + break; + } - default: - ; - } + if (e) { assert(percent > 0); @@ -208,9 +215,10 @@ static void elapse_func(AvahiTimeEvent *t, void *userdata) { /* avahi_log_debug("Requesting cache entry update at %i%% for %s.", percent, txt); */ avahi_interface_post_query(e->cache->interface, e->record->key, 1); } - + /* Check again later */ next_expiry(e->cache, e, percent); + } /* avahi_free(txt); */ @@ -248,11 +256,11 @@ static void next_expiry(AvahiCache *c, AvahiCacheEntry *e, unsigned percent) { update_time_event(c, e); } -static void expire_in_one_second(AvahiCache *c, AvahiCacheEntry *e) { +static void expire_in_one_second(AvahiCache *c, AvahiCacheEntry *e, AvahiCacheEntryState state) { assert(c); assert(e); - e->state = AVAHI_CACHE_FINAL; + e->state = state; gettimeofday(&e->expiry, NULL); avahi_timeval_add(&e->expiry, 1000000); /* 1s */ update_time_event(c, e); @@ -272,7 +280,7 @@ void avahi_cache_update(AvahiCache *c, AvahiRecord *r, int cache_flush, const Av AvahiCacheEntry *e; if ((e = avahi_cache_lookup_record(c, r))) - expire_in_one_second(c, e); + expire_in_one_second(c, e, AVAHI_CACHE_GOODBYE_FINAL); } else { AvahiCacheEntry *e = NULL, *first; @@ -293,7 +301,7 @@ void avahi_cache_update(AvahiCache *c, AvahiRecord *r, int cache_flush, const Av t = avahi_timeval_diff(&now, &e->timestamp); if (t > 1000000) - expire_in_one_second(c, e); + expire_in_one_second(c, e, AVAHI_CACHE_REPLACE_FINAL); } } @@ -421,3 +429,70 @@ void avahi_cache_flush(AvahiCache *c) { while (c->entries) remove_entry(c, c->entries); } + +/*** Passive observation of failure ***/ + +static void* start_poof_callback(AvahiCache *c, AvahiKey *pattern, AvahiCacheEntry *e, void *userdata) { + AvahiAddress *a = userdata; + + assert(c); + assert(pattern); + assert(e); + assert(a); + + switch (e->state) { + case AVAHI_CACHE_VALID: + + /* The entry was perfectly valid till, now, so let's enter + * POOF mode */ + + e->state = AVAHI_CACHE_POOF; + e->poof_address = *a; + + break; + + case AVAHI_CACHE_POOF: + + /* This is the second time we got no response, so let's + * fucking remove this entry. */ + + expire_in_one_second(c, e, AVAHI_CACHE_POOF_FINAL); + break; + + default: + ; + } + + return NULL; +} + +void avahi_cache_start_poof(AvahiCache *c, AvahiKey *key, const AvahiAddress *a) { + assert(c); + assert(key); + + avahi_cache_walk(c, key, start_poof_callback, a); +} + +void avahi_cache_stop_poof(AvahiCache *c, AvahiRecord *record, const AvahiAddress *a) { + AvahiCacheEntry *e; + + assert(c); + assert(record); + assert(a); + + if (!(e = avahi_cache_lookup_record(c, record))) + return; + + /* This function is called for each response suppression + record. If the matching cache entry is in POOF state and the + query address is the same, we put it back into valid mode */ + + if (e->state == AVAHI_CACHE_POOF || e->state == AVAHI_CACHE_POOF_FINAL) + if (avahi_address_cmp(a, &e->poof_address) == 0) { + e->state = AVAHI_CACHE_VALID; + next_expiry(c, e, 80); + } +} + + + diff --git a/avahi-core/cache.h b/avahi-core/cache.h index fa723e9..bd1cd6c 100644 --- a/avahi-core/cache.h +++ b/avahi-core/cache.h @@ -35,7 +35,11 @@ typedef enum { AVAHI_CACHE_EXPIRY1, AVAHI_CACHE_EXPIRY2, AVAHI_CACHE_EXPIRY3, - AVAHI_CACHE_FINAL + AVAHI_CACHE_EXPIRY_FINAL, + AVAHI_CACHE_POOF, /* Passive observation of failure */ + AVAHI_CACHE_POOF_FINAL, + AVAHI_CACHE_GOODBYE_FINAL, + AVAHI_CACHE_REPLACE_FINAL } AvahiCacheEntryState; typedef struct AvahiCacheEntry AvahiCacheEntry; @@ -52,6 +56,8 @@ struct AvahiCacheEntry { AvahiCacheEntryState state; AvahiTimeEvent *time_event; + AvahiAddress poof_address; + AVAHI_LLIST_FIELDS(AvahiCacheEntry, by_key); AVAHI_LLIST_FIELDS(AvahiCacheEntry, entry); }; @@ -83,6 +89,13 @@ void* avahi_cache_walk(AvahiCache *c, AvahiKey *pattern, AvahiCacheWalkCallback int avahi_cache_entry_half_ttl(AvahiCache *c, AvahiCacheEntry *e); +/** Start the "Passive observation of Failure" algorithm for all + * records of the specified key. The specified address is */ +void avahi_cache_start_poof(AvahiCache *c, AvahiKey *key, const AvahiAddress *a); + +/* Stop a previously started POOF algorithm for a record. (Used for response suppresions records */ +void avahi_cache_stop_poof(AvahiCache *c, AvahiRecord *record, const AvahiAddress *a); + void avahi_cache_flush(AvahiCache *c); #endif diff --git a/avahi-core/server.c b/avahi-core/server.c index 2714298..dc63c67 100644 --- a/avahi-core/server.c +++ b/avahi-core/server.c @@ -613,8 +613,10 @@ static void handle_query_packet(AvahiServer *s, AvahiDnsPacket *p, AvahiInterfac goto fail; } - if (!legacy_unicast && !from_local_iface) + if (!legacy_unicast && !from_local_iface) { reflect_query(s, i, key); + avahi_cache_start_poof(i->cache, key, a); + } if (avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ANCOUNT) == 0 && !(avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS) & AVAHI_DNS_FLAG_TC)) @@ -641,6 +643,7 @@ static void handle_query_packet(AvahiServer *s, AvahiDnsPacket *p, AvahiInterfac if (handle_conflict(s, i, record, unique, a)) { avahi_response_scheduler_suppress(i->response_scheduler, record, a); avahi_record_list_drop(s->record_list, record); + avahi_cache_stop_poof(i->cache, record, a); } avahi_record_unref(record); -- cgit