+void flx_server_add_address(flxServer *s, gint id, gint interface, guchar protocol, const gchar *name, flxAddress *a) {
+ gchar *n;
+ g_assert(s);
+ g_assert(name);
+ g_assert(a);
+
+ n = flx_normalize_name(name);
+
+ if (a->family == AF_INET) {
+ gchar *r;
+
+ flx_server_add(s, id, interface, protocol, n, FLX_DNS_TYPE_A, &a->ipv4, sizeof(a->ipv4));
+
+ r = flx_reverse_lookup_name_ipv4(&a->ipv4);
+ g_assert(r);
+ flx_server_add(s, id, interface, protocol, r, FLX_DNS_TYPE_PTR, n, strlen(n)+1);
+ g_free(r);
+
+ } else {
+ gchar *r;
+
+ flx_server_add(s, id, interface, protocol, n, FLX_DNS_TYPE_AAAA, &a->ipv6, sizeof(a->ipv6));
+
+ r = flx_reverse_lookup_name_ipv6_arpa(&a->ipv6);
+ g_assert(r);
+ flx_server_add(s, id, interface, protocol, r, FLX_DNS_TYPE_PTR, n, strlen(n)+1);
+ g_free(r);
+
+ r = flx_reverse_lookup_name_ipv6_int(&a->ipv6);
+ g_assert(r);
+ flx_server_add(s, id, interface, protocol, r, FLX_DNS_TYPE_PTR, n, strlen(n)+1);
+ g_free(r);
+ }
+
+ g_free(n);
+}
+
+flxQueryJob* flx_query_job_new(void) {
+ flxQueryJob *job = g_new(flxQueryJob);
+ job->query.name = NULL;
+ job->query.class = 0;
+ job->query.type = 0;
+ job->ref = 1;
+ return job;
+}
+
+flxQueryJob* flx_query_job_ref(flxQueryJob *job) {
+ g_assert(job);
+ g_assert(job->ref >= 1);
+ job->ref++;
+ return job;
+}
+
+void flx_query_job_unref(flxQueryJob *job) {
+ g_assert(job);
+ g_assert(job->ref >= 1);
+ if (!(--job->ref))
+ g_free(job);
+}
+
+static void post_query_job(flxServer *s, gint interface, guchar protocol, flxQueryJob *job) {
+ flxQueryJobInstance *i;
+ g_assert(s);
+ g_assert(job);
+
+ if (interface <= 0) {
+ flxInterface *i;
+
+ for (i = s->monitor->interfaces; i; i = i->next)
+ post_query_job(s, i->index, protocol, job);
+ } else if (protocol == AF_UNSPEC) {
+ post_query_job(s, index, AF_INET, job);
+ post_query_job(s, index, AF_INET6, job);
+ } else {
+
+ if (query_job_exists(s, interface, protocol, &job->query))
+ return;
+
+ i = g_new(flxQueryJobInstance, 1);
+ i->job = flx_query_job_ref(job);
+ i->interface = interface;
+ i->protocol = protocol;
+ if (i->prev = s->last_query_job)
+ i->prev->next = i;
+ else
+ s->first_query_job = i;
+ i->next = NULL;
+ s->last_query_job = i;
+ }
+}
+
+void flx_server_post_query_job(flxServer *s, gint interface, guchar protocol, const flxQuery *q) {
+ flxQueryJob *job;
+ g_assert(s);
+ g_assert(q);
+
+ job = flx_query_job_new();
+ job->query.name = g_strdup(q->name);
+ job->query.class = q->class;
+ job->query.type = q->type;
+ post_query_job(s, interface, protocol, job);
+}
+
+void flx_server_drop_query_job(flxServer *s, gint interface, guchar protocol, const flxQuery *q) {
+ flxQueryJobInstance *i, *next;
+ g_assert(s);
+ g_assert(interface > 0);
+ g_assert(protocol != AF_UNSPEC);
+ g_assert(q);
+
+ for (i = s->first_query_job; i; i = next) {
+ next = i->next;
+
+ if (flx_query_equal(i->query, q))
+ flx_server_remove_query_job_instance(s, i);
+ }
+}
+
+gboolean flx_query_equal(const flxQuery *a, const flxQuery *b) {
+ return strcmp(a->name, b->name) == 0 && a->type == b->type && a->class == b->class;
+}
+
+void flx_server_remove_query_job_instance(flxServer *s, flxQueryJobInstance *i) {
+ g_assert(s);
+ g_assert(i);
+
+ if (i->prev)
+ i->prev = i->next;
+ else
+ s->first_query_job = i->next;
+
+ if (i->next)
+ i->next = i->prev;
+ else
+ s->last_query_job = i->prev;
+
+ flx_query_job_unref(i->job);
+ g_free(i);
+}