From 0a985aa6c5453fe09bf0a3a79fe66d49c698b309 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 14 Apr 2005 01:41:09 +0000 Subject: [PATCH] add client part of probing git-svn-id: file:///home/lennart/svn/public/avahi/trunk@25 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- announce.c | 191 ++++++++++++++++++++++++++++++++++++------------ announce.h | 13 +++- dns.c | 26 ++++--- dns.h | 25 ++++--- flx.h | 19 +++-- iface.c | 14 +++- iface.h | 3 +- main.c | 14 ++-- psched.c | 207 +++++++++++++++++++++++++++++++++++++++++++++++++---- psched.h | 17 ++++- rr.c | 51 +++++++++++++ rr.h | 11 ++- server.c | 81 +++++++++++---------- server.h | 2 +- 14 files changed, 532 insertions(+), 142 deletions(-) diff --git a/announce.c b/announce.c index 1671758..cd2b1fa 100644 --- a/announce.c +++ b/announce.c @@ -15,69 +15,116 @@ static void remove_announcement(flxServer *s, flxAnnouncement *a) { g_free(a); } -static void elapse_announce(flxTimeEvent *e, void *userdata) { - flxAnnouncement *a = userdata; +static void elapse_announce(flxTimeEvent *e, void *userdata); + +static void send_packet(flxAnnouncement *a) { GTimeVal tv; - gchar *t; - - g_assert(e); g_assert(a); - flx_interface_post_response(a->interface, NULL, a->entry->record, FALSE); +/* g_message("%i -- %u", a->state, a->n_iteration); */ + + if (a->state == FLX_PROBING && a->n_iteration >= 1) { + flx_interface_post_probe(a->interface, a->entry->record, FALSE); + } else if (a->state == FLX_ANNOUNCING && a->n_iteration >= 1) + flx_interface_post_response(a->interface, NULL, a->entry->record, a->entry->flags & FLX_SERVER_ENTRY_UNIQUE, TRUE); + + a->n_iteration++; - if (a->n_announced++ <= 8) - a->sec_delay *= 2; + if (a->state == FLX_PROBING) { - g_message("Announcement #%i on interface %s.%i for entry [%s]", a->n_announced, a->interface->hardware->name, a->interface->protocol, t = flx_record_to_string(a->entry->record)); - g_free(t); + if (a->n_iteration == 1) + flx_elapse_time(&tv, 0, 250); + else + flx_elapse_time(&tv, 250, 0); + + /* Probing done */ + if (a->n_iteration >= 4) { + gchar *t; + g_message("Enough probes for record [%s]", t = flx_record_to_string(a->entry->record)); + g_free(t); + a->state = FLX_ANNOUNCING; + a->n_iteration = 1; + } + + } else if (a->state == FLX_ANNOUNCING) { - if (a->n_announced >= 4) { - g_message("Enough announcements for record [%s]", t = flx_record_to_string(a->entry->record)); - g_free(t); - remove_announcement(a->server, a); - } else { flx_elapse_time(&tv, a->sec_delay*1000, FLX_ANNOUNCEMENT_JITTER_MSEC); - flx_time_event_queue_update(a->server->time_event_queue, a->time_event, &tv); + + if (a->n_iteration < 10) + a->sec_delay *= 2; + + /* Announcing done */ + if (a->n_iteration >= 4) { + gchar *t; + g_message("Enough announcements for record [%s]", t = flx_record_to_string(a->entry->record)); + g_free(t); + remove_announcement(a->server, a); + return; + } } + + if (a->time_event) + flx_time_event_queue_update(a->server->time_event_queue, a->time_event, &tv); + else + a->time_event = flx_time_event_queue_add(a->server->time_event_queue, &tv, elapse_announce, a); +} + +static void elapse_announce(flxTimeEvent *e, void *userdata) { + g_assert(e); + + send_packet(userdata); +} + +static flxAnnouncement *get_announcement(flxServer *s, flxServerEntry *e, flxInterface *i) { + flxAnnouncement *a; + + g_assert(s); + g_assert(e); + g_assert(i); + + for (a = e->announcements; a; a = a->by_entry_next) + if (a->interface == i) + return a; + + return NULL; } static void new_announcement(flxServer *s, flxInterface *i, flxServerEntry *e) { flxAnnouncement *a; GTimeVal tv; - gchar *t; + gchar *t; g_assert(s); g_assert(i); g_assert(e); - g_message("NEW ANNOUNCEMENT: %s.%i [%s]", i->hardware->name, i->protocol, t = flx_record_to_string(e->record)); - g_free(t); +/* g_message("NEW ANNOUNCEMENT: %s.%i [%s]", i->hardware->name, i->protocol, t = flx_record_to_string(e->record)); */ +/* g_free(t); */ - if (!flx_interface_match(i, e->interface, e->protocol) || !i->announcing) + if (!flx_interface_match(i, e->interface, e->protocol) || !i->announcing || e->flags & FLX_SERVER_ENTRY_NOANNOUNCE) + return; + + /* We don't want duplicate announcements */ + if (get_announcement(s, e, i)) return; - /* We don't want duplicates */ - for (a = e->announcements; a; a = a->by_entry_next) - if (a->interface == i) - return; - g_message("New announcement on interface %s.%i for entry [%s]", i->hardware->name, i->protocol, t = flx_record_to_string(e->record)); g_free(t); - - flx_interface_post_response(i, NULL, e->record, FALSE); - + a = g_new(flxAnnouncement, 1); a->server = s; a->interface = i; a->entry = e; - a->n_announced = 1; + + a->state = (e->flags & FLX_SERVER_ENTRY_UNIQUE) && !(e->flags & FLX_SERVER_ENTRY_NOPROBE) ? FLX_PROBING : FLX_ANNOUNCING; + a->n_iteration = 0; a->sec_delay = 1; + a->time_event = NULL; FLX_LLIST_PREPEND(flxAnnouncement, by_interface, i->announcements, a); FLX_LLIST_PREPEND(flxAnnouncement, by_entry, e->announcements, a); - - flx_elapse_time(&tv, a->sec_delay*1000, FLX_ANNOUNCEMENT_JITTER_MSEC); - a->time_event = flx_time_event_queue_add(s->time_event_queue, &tv, elapse_announce, a); + + send_packet(a); } void flx_announce_interface(flxServer *s, flxInterface *i) { @@ -89,7 +136,7 @@ void flx_announce_interface(flxServer *s, flxInterface *i) { if (!i->announcing) return; - g_message("ANNOUNCE INTERFACE"); +/* g_message("ANNOUNCE INTERFACE"); */ for (e = s->entries; e; e = e->entry_next) new_announcement(s, i, e); @@ -109,11 +156,29 @@ void flx_announce_entry(flxServer *s, flxServerEntry *e) { g_assert(s); g_assert(e); - g_message("ANNOUNCE ENTRY"); +/* g_message("ANNOUNCE ENTRY"); */ flx_interface_monitor_walk(s->monitor, e->interface, e->protocol, announce_walk_callback, e); } +gboolean flx_entry_established(flxServer *s, flxServerEntry *e, flxInterface *i) { + flxAnnouncement *a; + + g_assert(s); + g_assert(e); + g_assert(i); + + if (!(e->flags & FLX_SERVER_ENTRY_UNIQUE) || (e->flags & FLX_SERVER_ENTRY_NOPROBE)) + return TRUE; + + if ((a = get_announcement(s, e, i))) + if (a->state == FLX_PROBING) + return FALSE; + + return TRUE; +} + + static flxRecord *make_goodbye_record(flxRecord *r) { gchar *t; flxRecord *g; @@ -129,38 +194,64 @@ static flxRecord *make_goodbye_record(flxRecord *r) { return g; } + + +static void send_goodbye_callback(flxInterfaceMonitor *m, flxInterface *i, gpointer userdata) { + flxServerEntry *e = userdata; + flxRecord *g; + + g_assert(m); + g_assert(i); + g_assert(e); + + if (!flx_interface_match(i, e->interface, e->protocol)) + return; + + if (e->flags & FLX_SERVER_ENTRY_NOANNOUNCE) + return; + + if (!flx_entry_established(m->server, e, i)) + return; + + g = make_goodbye_record(e->record); + flx_interface_post_response(i, NULL, g, e->flags & FLX_SERVER_ENTRY_UNIQUE, TRUE); + flx_record_unref(g); +} void flx_goodbye_interface(flxServer *s, flxInterface *i, gboolean goodbye) { g_assert(s); g_assert(i); - while (i->announcements) - remove_announcement(s, i->announcements); + g_message("goodbye interface: %s.%u", i->hardware->name, i->protocol); if (goodbye && flx_interface_relevant(i)) { flxServerEntry *e; for (e = s->entries; e; e = e->entry_next) - if (flx_interface_match(i, e->interface, e->protocol)) { - flxRecord *g = make_goodbye_record(e->record); - flx_interface_post_response(i, NULL, g, TRUE); - flx_record_unref(g); - } + send_goodbye_callback(s->monitor, i, e); } + + while (i->announcements) + remove_announcement(s, i->announcements); + + g_message("goodbye interface done: %s.%u", i->hardware->name, i->protocol); + } void flx_goodbye_entry(flxServer *s, flxServerEntry *e, gboolean goodbye) { g_assert(s); g_assert(e); + + g_message("goodbye entry: %p", e); + if (goodbye) + flx_interface_monitor_walk(s->monitor, 0, AF_UNSPEC, send_goodbye_callback, e); + while (e->announcements) remove_announcement(s, e->announcements); - - if (goodbye) { - flxRecord *g = make_goodbye_record(e->record); - flx_server_post_response(s, e->interface, e->protocol, g); - flx_record_unref(g); - } + + g_message("goodbye entry done: %p", e); + } void flx_goodbye_all(flxServer *s, gboolean goodbye) { @@ -168,6 +259,12 @@ void flx_goodbye_all(flxServer *s, gboolean goodbye) { g_assert(s); + g_message("goodbye all: %p", e); + for (e = s->entries; e; e = e->entry_next) flx_goodbye_entry(s, e, goodbye); + + g_message("goodbye all done: %p", e); + } + diff --git a/announce.h b/announce.h index 49c5f13..ab8ce12 100644 --- a/announce.h +++ b/announce.h @@ -10,13 +10,20 @@ typedef struct _flxAnnouncement flxAnnouncement; #include "server.h" #include "timeeventq.h" +typedef enum { + FLX_PROBING, + FLX_ANNOUNCING, +} flxAnnouncementState; + struct _flxAnnouncement { flxServer *server; flxInterface *interface; flxServerEntry *entry; - + flxTimeEvent *time_event; - guint n_announced; + + flxAnnouncementState state; + guint n_iteration; guint sec_delay; FLX_LLIST_FIELDS(flxAnnouncement, by_interface); @@ -26,6 +33,8 @@ struct _flxAnnouncement { void flx_announce_interface(flxServer *s, flxInterface *i); void flx_announce_entry(flxServer *s, flxServerEntry *e); +gboolean flx_entry_established(flxServer *s, flxServerEntry *e, flxInterface *i); + void flx_goodbye_interface(flxServer *s, flxInterface *i, gboolean send); void flx_goodbye_entry(flxServer *s, flxServerEntry *e, gboolean send); diff --git a/dns.c b/dns.c index 9126100..073eaba 100644 --- a/dns.c +++ b/dns.c @@ -26,7 +26,7 @@ flxDnsPacket* flx_dns_packet_new_query(guint max_size) { flxDnsPacket *p; p = flx_dns_packet_new(max_size); - flx_dns_packet_set_field(p, DNS_FIELD_FLAGS, DNS_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); + flx_dns_packet_set_field(p, FLX_DNS_FIELD_FLAGS, FLX_DNS_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); return p; } @@ -34,7 +34,7 @@ flxDnsPacket* flx_dns_packet_new_response(guint max_size) { flxDnsPacket *p; p = flx_dns_packet_new(max_size); - flx_dns_packet_set_field(p, DNS_FIELD_FLAGS, DNS_FLAGS(1, 0, 0, 0, 0, 0, 0, 0, 0, 0)); + flx_dns_packet_set_field(p, FLX_DNS_FIELD_FLAGS, FLX_DNS_FLAGS(1, 0, 0, 0, 0, 0, 0, 0, 0, 0)); return p; } @@ -200,9 +200,9 @@ gint flx_dns_packet_check_valid(flxDnsPacket *p) { if (p->size < 12) return -1; - flags = flx_dns_packet_get_field(p, DNS_FIELD_FLAGS); + flags = flx_dns_packet_get_field(p, FLX_DNS_FIELD_FLAGS); - if (flags & DNS_FLAG_OPCODE || flags & DNS_FLAG_RCODE) + if (flags & FLX_DNS_FLAG_OPCODE || flags & FLX_DNS_FLAG_RCODE) return -1; return 0; @@ -211,7 +211,7 @@ gint flx_dns_packet_check_valid(flxDnsPacket *p) { gint flx_dns_packet_is_query(flxDnsPacket *p) { g_assert(p); - return !(flx_dns_packet_get_field(p, DNS_FIELD_FLAGS) & DNS_FLAG_QR); + return !(flx_dns_packet_get_field(p, FLX_DNS_FIELD_FLAGS) & FLX_DNS_FLAG_QR); } static gint consume_labels(flxDnsPacket *p, guint index, gchar *ret_name, guint l) { @@ -501,8 +501,8 @@ flxRecord* flx_dns_packet_consume_record(flxDnsPacket *p, gboolean *ret_cache_fl if ((guint8*) flx_dns_packet_get_rptr(p) - (guint8*) start != rdlength) goto fail; - *ret_cache_flush = !!(class & MDNS_CACHE_FLUSH); - class &= ~ MDNS_CACHE_FLUSH; + *ret_cache_flush = !!(class & FLX_DNS_CACHE_FLUSH); + class &= ~ FLX_DNS_CACHE_FLUSH; r->ttl = ttl; @@ -526,7 +526,7 @@ flxKey* flx_dns_packet_consume_key(flxDnsPacket *p) { flx_dns_packet_consume_uint16(p, &class) < 0) return NULL; - class &= ~ MDNS_CACHE_FLUSH; + class &= ~ FLX_DNS_CACHE_FLUSH; return flx_key_new(name, class, type); } @@ -561,7 +561,7 @@ guint8* flx_dns_packet_append_record(flxDnsPacket *p, flxRecord *r, gboolean cac if (!(t = flx_dns_packet_append_name(p, r->key->name)) || !flx_dns_packet_append_uint16(p, r->key->type) || - !flx_dns_packet_append_uint16(p, cache_flush ? (r->key->class | MDNS_CACHE_FLUSH) : (r->key->class &~ MDNS_CACHE_FLUSH)) || + !flx_dns_packet_append_uint16(p, cache_flush ? (r->key->class | FLX_DNS_CACHE_FLUSH) : (r->key->class &~ FLX_DNS_CACHE_FLUSH)) || !flx_dns_packet_append_uint32(p, r->ttl) || !(l = flx_dns_packet_append_uint16(p, 0))) goto fail; @@ -658,3 +658,11 @@ gboolean flx_dns_packet_is_empty(flxDnsPacket *p) { return p->size <= FLX_DNS_PACKET_HEADER_SIZE; } + +guint flx_dns_packet_space(flxDnsPacket *p) { + g_assert(p); + + g_assert(p->size <= p->max_size); + + return p->max_size - p->size; +} diff --git a/dns.h b/dns.h index 38944d3..4515132 100644 --- a/dns.h +++ b/dns.h @@ -50,20 +50,21 @@ gconstpointer flx_dns_packet_get_rptr(flxDnsPacket *p); gint flx_dns_packet_skip(flxDnsPacket *p, guint length); gboolean flx_dns_packet_is_empty(flxDnsPacket *p); +guint flx_dns_packet_space(flxDnsPacket *p); -#define DNS_FIELD_ID 0 -#define DNS_FIELD_FLAGS 1 -#define DNS_FIELD_QDCOUNT 2 -#define DNS_FIELD_ANCOUNT 3 -#define DNS_FIELD_NSCOUNT 4 -#define DNS_FIELD_ARCOUNT 5 +#define FLX_DNS_FIELD_ID 0 +#define FLX_DNS_FIELD_FLAGS 1 +#define FLX_DNS_FIELD_QDCOUNT 2 +#define FLX_DNS_FIELD_ANCOUNT 3 +#define FLX_DNS_FIELD_NSCOUNT 4 +#define FLX_DNS_FIELD_ARCOUNT 5 -#define DNS_FLAG_QR (1 << 15) -#define DNS_FLAG_OPCODE (15 << 11) -#define DNS_FLAG_RCODE (15) -#define DNS_FLAG_TC (1 << 9) +#define FLX_DNS_FLAG_QR (1 << 15) +#define FLX_DNS_FLAG_OPCODE (15 << 11) +#define FLX_DNS_FLAG_RCODE (15) +#define FLX_DNS_FLAG_TC (1 << 9) -#define DNS_FLAGS(qr, opcode, aa, tc, rd, ra, z, ad, cd, rcode) \ +#define FLX_DNS_FLAGS(qr, opcode, aa, tc, rd, ra, z, ad, cd, rcode) \ (((guint16) !!qr << 15) | \ ((guint16) (opcode & 15) << 11) | \ ((guint16) !!aa << 10) | \ @@ -75,7 +76,5 @@ gboolean flx_dns_packet_is_empty(flxDnsPacket *p); ((guint16) (rd & 15))) -#define MDNS_CACHE_FLUSH 0x8000 - #endif diff --git a/flx.h b/flx.h index 8f8b0ba..d60dede 100644 --- a/flx.h +++ b/flx.h @@ -9,6 +9,13 @@ typedef struct _flxServer flxServer; #include "address.h" #include "rr.h" +typedef enum { + FLX_SERVER_ENTRY_NULL = 0, + FLX_SERVER_ENTRY_UNIQUE = 1, + FLX_SERVER_ENTRY_NOPROBE = 2, + FLX_SERVER_ENTRY_NOANNOUNCE = 4 +} flxServerEntryFlags; + flxServer *flx_server_new(GMainContext *c); void flx_server_free(flxServer* s); @@ -19,7 +26,7 @@ void flx_server_add( gint id, gint interface, guchar protocol, - gboolean unique, + flxServerEntryFlags flags, flxRecord *r); void flx_server_add_ptr( @@ -27,7 +34,7 @@ void flx_server_add_ptr( gint id, gint interface, guchar protocol, - gboolean unique, + flxServerEntryFlags flags, const gchar *name, const gchar *dest); @@ -36,7 +43,7 @@ void flx_server_add_address( gint id, gint interface, guchar protocol, - gboolean unique, + flxServerEntryFlags flags, const gchar *name, flxAddress *a); @@ -45,7 +52,7 @@ void flx_server_add_text( gint id, gint interface, guchar protocol, - gboolean unique, + flxServerEntryFlags flags, const gchar *name, ... /* text records, terminated by NULL */); @@ -54,7 +61,7 @@ void flx_server_add_text_va( gint id, gint interface, guchar protocol, - gboolean unique, + flxServerEntryFlags flags, const gchar *name, va_list va); @@ -86,7 +93,7 @@ void flx_server_add_service_va( void flx_server_remove(flxServer *s, gint id); void flx_server_post_query(flxServer *s, gint interface, guchar protocol, flxKey *key); -void flx_server_post_response(flxServer *s, gint interface, guchar protocol, flxRecord *record); +void flx_server_post_response(flxServer *s, gint interface, guchar protocol, flxRecord *record, gboolean flush_cache); const flxRecord *flx_server_iterate(flxServer *s, gint id, void **state); diff --git a/iface.c b/iface.c index d2daf40..0afdb70 100644 --- a/iface.c +++ b/iface.c @@ -24,7 +24,7 @@ static void update_address_rr(flxInterfaceMonitor *m, flxInterfaceAddress *a, in } else { if (a->rr_id < 0) { a->rr_id = flx_server_get_next_id(m->server); - flx_server_add_address(m->server, a->rr_id, a->interface->hardware->index, AF_UNSPEC, FALSE, m->server->hostname, &a->address); + flx_server_add_address(m->server, a->rr_id, a->interface->hardware->index, AF_UNSPEC, 0, NULL, &a->address); } } } @@ -447,12 +447,20 @@ void flx_interface_post_query(flxInterface *i, flxKey *key, gboolean immediately } -void flx_interface_post_response(flxInterface *i, const flxAddress *a, flxRecord *record, gboolean immediately) { +void flx_interface_post_response(flxInterface *i, const flxAddress *a, flxRecord *record, gboolean flush_cache, gboolean immediately) { g_assert(i); g_assert(record); if (flx_interface_relevant(i)) - flx_packet_scheduler_post_response(i->scheduler, a, record, immediately); + flx_packet_scheduler_post_response(i->scheduler, a, record, flush_cache, immediately); +} + +void flx_interface_post_probe(flxInterface *i, flxRecord *record, gboolean immediately) { + g_assert(i); + g_assert(record); + + if (flx_interface_relevant(i)) + flx_packet_scheduler_post_probe(i->scheduler, record, immediately); } void flx_dump_caches(flxInterfaceMonitor *m, FILE *f) { diff --git a/iface.h b/iface.h index 4b0aef8..53d3441 100644 --- a/iface.h +++ b/iface.h @@ -83,7 +83,8 @@ flxHwInterface* flx_interface_monitor_get_hw_interface(flxInterfaceMonitor *m, g void flx_interface_send_packet(flxInterface *i, flxDnsPacket *p); void flx_interface_post_query(flxInterface *i, flxKey *k, gboolean immediately); -void flx_interface_post_response(flxInterface *i, const flxAddress *a, flxRecord *rr, gboolean immediately); +void flx_interface_post_probe(flxInterface *i, flxRecord *p, gboolean immediately); +void flx_interface_post_response(flxInterface *i, const flxAddress *a, flxRecord *record, gboolean flush_cache, gboolean immediately); void flx_dump_caches(flxInterfaceMonitor *m, FILE *f); diff --git a/main.c b/main.c index 3bf4360..139279c 100644 --- a/main.c +++ b/main.c @@ -15,13 +15,13 @@ static gboolean send_timeout(gpointer data) { flxServer *flx = data; flxKey *k; - k = flx_key_new("ecstasy.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_TXT); - flx_server_post_query(flx, 0, AF_UNSPEC, k); - flx_key_unref(k); +/* k = flx_key_new("ecstasy.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_TXT); */ +/* flx_server_post_query(flx, 0, AF_UNSPEC, k); */ +/* flx_key_unref(k); */ - k = flx_key_new("ecstasy.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_A); - flx_server_post_query(flx, 0, AF_INET, k); - flx_key_unref(k); +/* k = flx_key_new("ecstasy.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_A); */ +/* flx_server_post_query(flx, 0, AF_INET, k); */ +/* flx_key_unref(k); */ return FALSE; } @@ -56,7 +56,7 @@ int main(int argc, char *argv[]) { flx = flx_server_new(NULL); - flx_server_add_text(flx, 0, 0, AF_UNSPEC, FALSE, NULL, "hallo", NULL); + flx_server_add_text(flx, 0, 0, AF_UNSPEC, FLX_SERVER_ENTRY_UNIQUE, NULL, "hallo", NULL); flx_server_add_service(flx, 0, 0, AF_UNSPEC, "_http._tcp", "gurke", NULL, NULL, 80, "foo", NULL); /* k = flx_key_new("ecstasy.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_ANY); */ diff --git a/psched.c b/psched.c index 1b6d26c..e9f77b9 100644 --- a/psched.c +++ b/psched.c @@ -3,11 +3,12 @@ #include "util.h" #include "psched.h" -#define FLX_QUERY_HISTORY_MSEC 700 +#define FLX_QUERY_HISTORY_MSEC 100 #define FLX_QUERY_DEFER_MSEC 100 #define FLX_RESPONSE_HISTORY_MSEC 700 #define FLX_RESPONSE_DEFER_MSEC 20 #define FLX_RESPONSE_JITTER_MSEC 100 +#define FLX_PROBE_DEFER_MSEC 100 flxPacketScheduler *flx_packet_scheduler_new(flxServer *server, flxInterface *i) { flxPacketScheduler *s; @@ -22,6 +23,7 @@ flxPacketScheduler *flx_packet_scheduler_new(flxServer *server, flxInterface *i) FLX_LLIST_HEAD_INIT(flxQueryJob, s->query_jobs); FLX_LLIST_HEAD_INIT(flxResponseJob, s->response_jobs); FLX_LLIST_HEAD_INIT(flxKnownAnswer, s->known_answers); + FLX_LLIST_HEAD_INIT(flxProbeJob, s->probe_jobs); return s; } @@ -50,9 +52,22 @@ static void response_job_free(flxPacketScheduler *s, flxResponseJob *rj) { g_free(rj); } +static void probe_job_free(flxPacketScheduler *s, flxProbeJob *pj) { + g_assert(pj); + + if (pj->time_event) + flx_time_event_queue_remove(pj->scheduler->server->time_event_queue, pj->time_event); + + FLX_LLIST_REMOVE(flxProbeJob, jobs, s->probe_jobs, pj); + + flx_record_unref(pj->record); + g_free(pj); +} + void flx_packet_scheduler_free(flxPacketScheduler *s) { flxQueryJob *qj; flxResponseJob *rj; + flxProbeJob *pj; flxTimeEvent *e; g_assert(s); @@ -63,6 +78,8 @@ void flx_packet_scheduler_free(flxPacketScheduler *s) { query_job_free(s, qj); while ((rj = s->response_jobs)) response_job_free(s, rj); + while ((pj = s->probe_jobs)) + probe_job_free(s, pj); g_free(s); } @@ -126,8 +143,8 @@ static void append_known_answers_and_send(flxPacketScheduler *s, flxDnsPacket *p g_assert(!flx_dns_packet_is_empty(p)); - flx_dns_packet_set_field(p, DNS_FIELD_FLAGS, flx_dns_packet_get_field(p, DNS_FIELD_FLAGS) | DNS_FLAG_TC); - flx_dns_packet_set_field(p, DNS_FIELD_ANCOUNT, n); + flx_dns_packet_set_field(p, FLX_DNS_FIELD_FLAGS, flx_dns_packet_get_field(p, FLX_DNS_FIELD_FLAGS) | FLX_DNS_FLAG_TC); + flx_dns_packet_set_field(p, FLX_DNS_FIELD_ANCOUNT, n); flx_interface_send_packet(s->interface, p); flx_dns_packet_free(p); @@ -142,7 +159,7 @@ static void append_known_answers_and_send(flxPacketScheduler *s, flxDnsPacket *p n++; } - flx_dns_packet_set_field(p, DNS_FIELD_ANCOUNT, n); + flx_dns_packet_set_field(p, FLX_DNS_FIELD_ANCOUNT, n); flx_interface_send_packet(s->interface, p); flx_dns_packet_free(p); } @@ -182,7 +199,7 @@ static void query_elapse(flxTimeEvent *e, gpointer data) { n++; } - flx_dns_packet_set_field(p, DNS_FIELD_QDCOUNT, n); + flx_dns_packet_set_field(p, FLX_DNS_FIELD_QDCOUNT, n); /* Now add known answers */ append_known_answers_and_send(s, p); @@ -242,7 +259,7 @@ static guint8* packet_add_response_job(flxPacketScheduler *s, flxDnsPacket *p, f g_assert(p); g_assert(rj); - if ((d = flx_dns_packet_append_record(p, rj->record, FALSE))) { + if ((d = flx_dns_packet_append_record(p, rj->record, rj->flush_cache))) { GTimeVal tv; rj->done = 1; @@ -286,7 +303,7 @@ static void send_response_packet(flxPacketScheduler *s, flxResponseJob *rj) { n++; } - flx_dns_packet_set_field(p, DNS_FIELD_ANCOUNT, n); + flx_dns_packet_set_field(p, FLX_DNS_FIELD_ANCOUNT, n); flx_interface_send_packet(s->interface, p); flx_dns_packet_free(p); } @@ -331,13 +348,15 @@ static flxResponseJob* response_job_new(flxPacketScheduler *s, flxRecord *record rj->record = flx_record_ref(record); rj->done = FALSE; rj->time_event = NULL; + rj->address_valid = FALSE; + rj->flush_cache = FALSE; FLX_LLIST_PREPEND(flxResponseJob, jobs, s->response_jobs, rj); return rj; } -void flx_packet_scheduler_post_response(flxPacketScheduler *s, const flxAddress *a, flxRecord *record, gboolean immediately) { +void flx_packet_scheduler_post_response(flxPacketScheduler *s, const flxAddress *a, flxRecord *record, gboolean flush_cache, gboolean immediately) { flxResponseJob *rj; GTimeVal tv; gchar *t; @@ -365,7 +384,11 @@ void flx_packet_scheduler_post_response(flxPacketScheduler *s, const flxAddress /* This job is no longer specific to a single querier, so * make sure it isn't suppressed by known answer * suppresion */ - rj->address_valid = FALSE; + + if (rj->address_valid && (!a || flx_address_cmp(a, &rj->address) != 0)) + rj->address_valid = FALSE; + + rj->flush_cache = flush_cache; return; } @@ -380,6 +403,7 @@ void flx_packet_scheduler_post_response(flxPacketScheduler *s, const flxAddress /* Create a new job and schedule it */ rj = response_job_new(s, record); + rj->flush_cache = flush_cache; rj->delivery = tv; rj->time_event = flx_time_event_queue_add(s->server->time_event_queue, &rj->delivery, response_elapse, rj); @@ -508,18 +532,22 @@ void flx_packet_scheduler_incoming_known_answer(flxPacketScheduler *s, flxRecord g_assert(record); g_assert(a); - for (rj = s->response_jobs; rj; rj = rj->jobs_next) - if (flx_record_equal_no_ttl(rj->record, record) && - rj->address_valid && - flx_address_cmp(&rj->address, a) && - record->ttl >= rj->record->ttl/2) { + for (rj = s->response_jobs; rj; rj = rj->jobs_next) { + + g_assert(record->ttl > 0); + g_assert(rj->record->ttl/2); + + if (flx_record_equal_no_ttl(rj->record, record)) + if (rj->address_valid) + if (flx_address_cmp(&rj->address, a)) + if (record->ttl >= rj->record->ttl/2) { /* Let's suppress it */ response_job_free(s, rj); break; } - + } } void flx_packet_scheduler_flush_responses(flxPacketScheduler *s) { @@ -533,3 +561,152 @@ void flx_packet_scheduler_flush_responses(flxPacketScheduler *s) { if (!rj->done) send_response_packet(s, rj); } + +static flxProbeJob* probe_job_new(flxPacketScheduler *s, flxRecord *record) { + flxProbeJob *pj; + + g_assert(s); + g_assert(record); + + pj = g_new(flxProbeJob, 1); + pj->scheduler = s; + pj->record = flx_record_ref(record); + pj->time_event = NULL; + pj->chosen = FALSE; + + FLX_LLIST_PREPEND(flxProbeJob, jobs, s->probe_jobs, pj); + + return pj; +} + +static guint8* packet_add_probe_query(flxPacketScheduler *s, flxDnsPacket *p, flxProbeJob *pj) { + guint size; + guint8 *r; + flxKey *k; + + g_assert(s); + g_assert(p); + g_assert(pj); + + g_assert(!pj->chosen); + + /* Estimate the size for this record */ + size = + flx_key_get_estimate_size(pj->record->key) + + flx_record_get_estimate_size(pj->record); + + /* Too large */ + if (size > flx_dns_packet_space(p)) + return NULL; + + /* Create the probe query */ + k = flx_key_new(pj->record->key->name, pj->record->key->class, FLX_DNS_TYPE_ANY); + r = flx_dns_packet_append_key(p, k); + + /* Mark this job for addition to the packet */ + pj->chosen = TRUE; + + /* Scan for more jobs whith matching key pattern */ + for (pj = s->probe_jobs; pj; pj = pj->jobs_next) { + if (pj->chosen) + continue; + + /* Does the record match the probe? */ + if (k->class != pj->record->key->class || strcmp(k->name, pj->record->key->name)) + continue; + + /* This job wouldn't fit in */ + if (flx_record_get_estimate_size(pj->record) > flx_dns_packet_space(p)) + break; + + /* Mark this job for addition to the packet */ + pj->chosen = TRUE; + } + + flx_key_unref(k); + + return r; +} + +static void probe_elapse(flxTimeEvent *e, gpointer data) { + flxProbeJob *pj = data, *next; + flxPacketScheduler *s; + flxDnsPacket *p; + guint n; + guint8 *d; + + g_assert(pj); + s = pj->scheduler; + + p = flx_dns_packet_new_query(s->interface->hardware->mtu - 48); + + /* Add the import probe */ + if (!packet_add_probe_query(s, p, pj)) { + g_warning("Record too large!"); + flx_dns_packet_free(p); + return; + } + + n = 1; + + /* Try to fill up packet with more probes, if available */ + for (pj = s->probe_jobs; pj; pj = pj->jobs_next) { + + if (pj->chosen) + continue; + + if (!packet_add_probe_query(s, p, pj)) + break; + + n++; + } + + flx_dns_packet_set_field(p, FLX_DNS_FIELD_QDCOUNT, n); + + n = 0; + + /* Now add the chosen records to the authorative section */ + for (pj = s->probe_jobs; pj; pj = next) { + + next = pj->jobs_next; + + if (!pj->chosen) + continue; + + if (!flx_dns_packet_append_record(p, pj->record, TRUE)) { + g_warning("Bad probe size estimate!"); + + /* Unmark all following jobs */ + for (; pj; pj = pj->jobs_next) + pj->chosen = FALSE; + + break; + } + + probe_job_free(s, pj); + n ++; + } + + flx_dns_packet_set_field(p, FLX_DNS_FIELD_NSCOUNT, n); + + /* Send it now */ + flx_interface_send_packet(s->interface, p); + flx_dns_packet_free(p); +} + +void flx_packet_scheduler_post_probe(flxPacketScheduler *s, flxRecord *record, gboolean immediately) { + flxProbeJob *pj; + GTimeVal tv; + + g_assert(s); + g_assert(record); + g_assert(!flx_key_is_pattern(record->key)); + + flx_elapse_time(&tv, immediately ? 0 : FLX_PROBE_DEFER_MSEC, 0); + + /* No duplication check here... */ + /* Create a new job and schedule it */ + pj = probe_job_new(s, record); + pj->delivery = tv; + pj->time_event = flx_time_event_queue_add(s->server->time_event_queue, &pj->delivery, probe_elapse, pj); +} diff --git a/psched.h b/psched.h index 7290265..9866f2f 100644 --- a/psched.h +++ b/psched.h @@ -5,6 +5,7 @@ typedef struct _flxQueryJob flxQueryJob; typedef struct _flxResponseJob flxResponseJob; typedef struct _flxPacketScheduler flxPacketScheduler; typedef struct _flxKnownAnswer flxKnownAnswer; +typedef struct _flxProbeJob flxProbeJob; #include "timeeventq.h" #include "rr.h" @@ -28,6 +29,7 @@ struct _flxResponseJob { gboolean address_valid; gboolean done; GTimeVal delivery; + gboolean flush_cache; FLX_LLIST_FIELDS(flxResponseJob, jobs); }; @@ -38,6 +40,17 @@ struct _flxKnownAnswer { FLX_LLIST_FIELDS(flxKnownAnswer, known_answer); }; +struct _flxProbeJob { + flxPacketScheduler *scheduler; + flxTimeEvent *time_event; + flxRecord *record; + + gboolean chosen; /* Use for packet assembling */ + GTimeVal delivery; + + FLX_LLIST_FIELDS(flxProbeJob, jobs); +}; + struct _flxPacketScheduler { flxServer *server; @@ -46,13 +59,15 @@ struct _flxPacketScheduler { FLX_LLIST_HEAD(flxQueryJob, query_jobs); FLX_LLIST_HEAD(flxResponseJob, response_jobs); FLX_LLIST_HEAD(flxKnownAnswer, known_answers); + FLX_LLIST_HEAD(flxProbeJob, probe_jobs); }; flxPacketScheduler *flx_packet_scheduler_new(flxServer *server, flxInterface *i); void flx_packet_scheduler_free(flxPacketScheduler *s); void flx_packet_scheduler_post_query(flxPacketScheduler *s, flxKey *key, gboolean immediately); -void flx_packet_scheduler_post_response(flxPacketScheduler *s, const flxAddress *a, flxRecord *record, gboolean immediately); +void flx_packet_scheduler_post_response(flxPacketScheduler *s, const flxAddress *a, flxRecord *record, gboolean flush_cache, gboolean immediately); +void flx_packet_scheduler_post_probe(flxPacketScheduler *s, flxRecord *record, gboolean immediately); void flx_packet_scheduler_incoming_query(flxPacketScheduler *s, flxKey *key); void flx_packet_scheduler_incoming_response(flxPacketScheduler *s, flxRecord *record); diff --git a/rr.c b/rr.c index fe475eb..f72557b 100644 --- a/rr.c +++ b/rr.c @@ -121,6 +121,9 @@ void flx_record_unref(flxRecord *r) { } const gchar *flx_dns_class_to_string(guint16 class) { + if (class & FLX_DNS_CACHE_FLUSH) + return "FLUSH"; + if (class == FLX_DNS_CLASS_IN) return "IN"; @@ -143,6 +146,8 @@ const gchar *flx_dns_type_to_string(guint16 type) { return "TXT"; case FLX_DNS_TYPE_SRV: return "SRV"; + case FLX_DNS_TYPE_ANY: + return "ANY"; default: return NULL; } @@ -344,3 +349,49 @@ flxRecord *flx_record_copy(flxRecord *r) { return copy; } + + +guint flx_key_get_estimate_size(flxKey *k) { + g_assert(k); + + return strlen(k->name)+1+4; +} + +guint flx_record_get_estimate_size(flxRecord *r) { + guint n; + g_assert(r); + + n = flx_key_get_estimate_size(r->key) + 4 + 2; + + switch (r->key->type) { + case FLX_DNS_TYPE_PTR: + case FLX_DNS_TYPE_CNAME: + n += strlen(r->data.ptr.name) + 1; + break; + + case FLX_DNS_TYPE_SRV: + n += 6 + strlen(r->data.srv.name) + 1; + break; + + case FLX_DNS_TYPE_HINFO: + n += strlen(r->data.hinfo.os) + 1 + strlen(r->data.hinfo.cpu) + 1; + break; + + case FLX_DNS_TYPE_TXT: + n += flx_string_list_serialize(r->data.txt.string_list, NULL, 0); + break; + + case FLX_DNS_TYPE_A: + n += sizeof(flxIPv4Address); + break; + + case FLX_DNS_TYPE_AAAA: + n += sizeof(flxIPv6Address); + break; + + default: + n += r->data.generic.size; + } + + return n; +} diff --git a/rr.h b/rr.h index 1ba6d95..483fcaa 100644 --- a/rr.h +++ b/rr.h @@ -21,7 +21,8 @@ enum { }; enum { - FLX_DNS_CLASS_IN = 0x01 + FLX_DNS_CLASS_IN = 0x01, + FLX_DNS_CACHE_FLUSH = 0x8000 }; #define FLX_DEFAULT_TTL (120*60) @@ -103,4 +104,12 @@ gboolean flx_record_equal_no_ttl(const flxRecord *a, const flxRecord *b); flxRecord *flx_record_copy(flxRecord *r); +/* returns a maximum estimate for the space that is needed to store + * this key in a DNS packet */ +guint flx_key_get_estimate_size(flxKey *k); + +/* ditto */ +guint flx_record_get_estimate_size(flxRecord *r); + + #endif diff --git a/server.c b/server.c index fcf4248..56e4d81 100644 --- a/server.c +++ b/server.c @@ -30,15 +30,15 @@ static void handle_query_key(flxServer *s, flxKey *k, flxInterface *i, const flx for (e = s->entries; e; e = e->entry_next) if (flx_key_pattern_match(k, e->record->key)) - if (flx_interface_match(i, e->interface, e->protocol)) - flx_interface_post_response(i, a, e->record, FALSE); + if (flx_interface_match(i, e->interface, e->protocol) && flx_entry_established(s, e, i)) + flx_interface_post_response(i, a, e->record, e->flags & FLX_SERVER_ENTRY_UNIQUE, FALSE); } else { /* Handle all other queries */ for (e = g_hash_table_lookup(s->rrset_by_key, k); e; e = e->by_key_next) - if (flx_interface_match(i, e->interface, e->protocol)) - flx_interface_post_response(i, a, e->record, FALSE); + if (flx_interface_match(i, e->interface, e->protocol) && flx_entry_established(s, e, i)) + flx_interface_post_response(i, a, e->record, e->flags & FLX_SERVER_ENTRY_UNIQUE, FALSE); } } @@ -50,7 +50,7 @@ static void handle_query(flxServer *s, flxDnsPacket *p, flxInterface *i, const f g_assert(i); g_assert(a); - for (n = flx_dns_packet_get_field(p, DNS_FIELD_QDCOUNT); n > 0; n --) { + for (n = flx_dns_packet_get_field(p, FLX_DNS_FIELD_QDCOUNT); n > 0; n --) { flxKey *key; if (!(key = flx_dns_packet_consume_key(p))) { @@ -63,7 +63,7 @@ static void handle_query(flxServer *s, flxDnsPacket *p, flxInterface *i, const f } /* Known Answer Suppresion */ - for (n = flx_dns_packet_get_field(p, DNS_FIELD_ANCOUNT); n > 0; n --) { + for (n = flx_dns_packet_get_field(p, FLX_DNS_FIELD_ANCOUNT); n > 0; n --) { flxRecord *record; gboolean unique = FALSE; @@ -85,8 +85,8 @@ static void handle_response(flxServer *s, flxDnsPacket *p, flxInterface *i, cons g_assert(i); g_assert(a); - for (n = flx_dns_packet_get_field(p, DNS_FIELD_ANCOUNT) + - flx_dns_packet_get_field(p, DNS_FIELD_ARCOUNT); n > 0; n--) { + for (n = flx_dns_packet_get_field(p, FLX_DNS_FIELD_ANCOUNT) + + flx_dns_packet_get_field(p, FLX_DNS_FIELD_ARCOUNT); n > 0; n--) { flxRecord *record; gboolean cache_flush = FALSE; gchar *txt; @@ -152,9 +152,8 @@ static void dispatch_packet(flxServer *s, flxDnsPacket *p, struct sockaddr *sa, if (flx_dns_packet_is_query(p)) { - if (flx_dns_packet_get_field(p, DNS_FIELD_QDCOUNT) == 0 || - flx_dns_packet_get_field(p, DNS_FIELD_ARCOUNT) != 0 || - flx_dns_packet_get_field(p, DNS_FIELD_NSCOUNT) != 0) { + if (flx_dns_packet_get_field(p, FLX_DNS_FIELD_QDCOUNT) == 0 || + flx_dns_packet_get_field(p, FLX_DNS_FIELD_ARCOUNT) != 0) { g_warning("Invalid query packet."); return; } @@ -162,9 +161,9 @@ static void dispatch_packet(flxServer *s, flxDnsPacket *p, struct sockaddr *sa, handle_query(s, p, i, &a); g_message("Handled query"); } else { - if (flx_dns_packet_get_field(p, DNS_FIELD_QDCOUNT) != 0 || - flx_dns_packet_get_field(p, DNS_FIELD_ANCOUNT) == 0 || - flx_dns_packet_get_field(p, DNS_FIELD_NSCOUNT) != 0) { + if (flx_dns_packet_get_field(p, FLX_DNS_FIELD_QDCOUNT) != 0 || + flx_dns_packet_get_field(p, FLX_DNS_FIELD_ANCOUNT) == 0 || + flx_dns_packet_get_field(p, FLX_DNS_FIELD_NSCOUNT) != 0) { g_warning("Invalid response packet."); return; } @@ -242,15 +241,15 @@ static void add_default_entries(flxServer *s) { uname(&utsname); r->data.hinfo.cpu = g_strdup(g_strup(utsname.machine)); r->data.hinfo.os = g_strdup(g_strup(utsname.sysname)); - flx_server_add(s, 0, 0, AF_UNSPEC, TRUE, r); + flx_server_add(s, 0, 0, AF_UNSPEC, FLX_SERVER_ENTRY_UNIQUE, r); flx_record_unref(r); /* Add localhost entries */ flx_address_parse("127.0.0.1", AF_INET, &a); - flx_server_add_address(s, 0, 0, AF_UNSPEC, TRUE, "localhost", &a); + flx_server_add_address(s, 0, 0, AF_UNSPEC, FLX_SERVER_ENTRY_UNIQUE|FLX_SERVER_ENTRY_NOPROBE|FLX_SERVER_ENTRY_NOANNOUNCE, "localhost", &a); flx_address_parse("::1", AF_INET6, &a); - flx_server_add_address(s, 0, 0, AF_UNSPEC, TRUE, "ip6-localhost", &a); + flx_server_add_address(s, 0, 0, AF_UNSPEC, FLX_SERVER_ENTRY_UNIQUE|FLX_SERVER_ENTRY_NOPROBE|FLX_SERVER_ENTRY_NOANNOUNCE, "ip6-localhost", &a); } flxServer *flx_server_new(GMainContext *c) { @@ -368,7 +367,7 @@ void flx_server_add( gint id, gint interface, guchar protocol, - gboolean unique, + flxServerEntryFlags flags, flxRecord *r) { flxServerEntry *e, *t; @@ -382,7 +381,7 @@ void flx_server_add( e->id = id; e->interface = interface; e->protocol = protocol; - e->unique = unique; + e->flags = flags; FLX_LLIST_HEAD_INIT(flxAnnouncement, e->announcements); @@ -483,7 +482,7 @@ void flx_server_add_ptr( gint id, gint interface, guchar protocol, - gboolean unique, + flxServerEntryFlags flags, const gchar *name, const gchar *dest) { @@ -493,7 +492,7 @@ void flx_server_add_ptr( r = flx_record_new_full(name ? name : s->hostname, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_PTR); r->data.ptr.name = flx_normalize_name(dest); - flx_server_add(s, id, interface, protocol, unique, r); + flx_server_add(s, id, interface, protocol, flags, r); flx_record_unref(r); } @@ -503,7 +502,7 @@ void flx_server_add_address( gint id, gint interface, guchar protocol, - gboolean unique, + flxServerEntryFlags flags, const gchar *name, flxAddress *a) { @@ -519,12 +518,12 @@ void flx_server_add_address( r = flx_record_new_full(name, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_A); r->data.a.address = a->data.ipv4; - flx_server_add(s, id, interface, protocol, unique, r); + flx_server_add(s, id, interface, protocol, flags, r); flx_record_unref(r); reverse = flx_reverse_lookup_name_ipv4(&a->data.ipv4); g_assert(reverse); - flx_server_add_ptr(s, id, interface, protocol, unique, reverse, name); + flx_server_add_ptr(s, id, interface, protocol, flags, reverse, name); g_free(reverse); } else { @@ -533,17 +532,17 @@ void flx_server_add_address( r = flx_record_new_full(name, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_AAAA); r->data.aaaa.address = a->data.ipv6; - flx_server_add(s, id, interface, protocol, unique, r); + flx_server_add(s, id, interface, protocol, flags, r); flx_record_unref(r); reverse = flx_reverse_lookup_name_ipv6_arpa(&a->data.ipv6); g_assert(reverse); - flx_server_add_ptr(s, id, interface, protocol, unique, reverse, name); + flx_server_add_ptr(s, id, interface, protocol, flags, reverse, name); g_free(reverse); reverse = flx_reverse_lookup_name_ipv6_int(&a->data.ipv6); g_assert(reverse); - flx_server_add_ptr(s, id, interface, protocol, unique, reverse, name); + flx_server_add_ptr(s, id, interface, protocol, flags, reverse, name); g_free(reverse); } @@ -555,7 +554,7 @@ void flx_server_add_text_va( gint id, gint interface, guchar protocol, - gboolean unique, + flxServerEntryFlags flags, const gchar *name, va_list va) { @@ -565,7 +564,7 @@ void flx_server_add_text_va( r = flx_record_new_full(name ? name : s->hostname, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_TXT); r->data.txt.string_list = flx_string_list_new_va(va); - flx_server_add(s, id, interface, protocol, unique, r); + flx_server_add(s, id, interface, protocol, flags, r); flx_record_unref(r); } @@ -574,7 +573,7 @@ void flx_server_add_text( gint id, gint interface, guchar protocol, - gboolean unique, + flxServerEntryFlags flags, const gchar *name, ...) { @@ -583,7 +582,7 @@ void flx_server_add_text( g_assert(s); va_start(va, name); - flx_server_add_text_va(s, id, interface, protocol, unique, name, va); + flx_server_add_text_va(s, id, interface, protocol, flags, name, va); va_end(va); } @@ -699,19 +698,29 @@ void flx_server_post_query(flxServer *s, gint interface, guchar protocol, flxKey flx_interface_monitor_walk(s->monitor, interface, protocol, post_query_callback, key); } +struct tmpdata { + flxRecord *record; + gboolean flush_cache; +}; + static void post_response_callback(flxInterfaceMonitor *m, flxInterface *i, gpointer userdata) { - flxRecord *r = userdata; + struct tmpdata *tmpdata = userdata; g_assert(m); g_assert(i); - g_assert(r); + g_assert(tmpdata); - flx_interface_post_response(i, NULL, r, FALSE); + flx_interface_post_response(i, NULL, tmpdata->record, tmpdata->flush_cache, FALSE); } -void flx_server_post_response(flxServer *s, gint interface, guchar protocol, flxRecord *record) { +void flx_server_post_response(flxServer *s, gint interface, guchar protocol, flxRecord *record, gboolean flush_cache) { + struct tmpdata tmpdata; + g_assert(s); g_assert(record); - flx_interface_monitor_walk(s->monitor, interface, protocol, post_response_callback, record); + tmpdata.record = record; + tmpdata.flush_cache = flush_cache; + + flx_interface_monitor_walk(s->monitor, interface, protocol, post_response_callback, &tmpdata); } diff --git a/server.h b/server.h index d050bcc..f90bfe7 100644 --- a/server.h +++ b/server.h @@ -17,7 +17,7 @@ struct _flxServerEntry { gint interface; guchar protocol; - gboolean unique; + flxServerEntryFlags flags; FLX_LLIST_FIELDS(flxServerEntry, entry); FLX_LLIST_FIELDS(flxServerEntry, by_key); -- 2.39.5