1 #include <sys/socket.h>
8 flxServer *flx_server_new(GMainContext *c) {
9 flxServer *s = g_new(flxServer, 1);
12 g_main_context_ref(c);
15 s->context = g_main_context_default();
18 s->rrset_by_id = g_hash_table_new(g_int_hash, g_int_equal);
19 s->rrset_by_name = g_hash_table_new(g_str_hash, g_str_equal);
22 s->first_response_job = s->last_response_job = NULL;
23 s->first_query_jobs = s->last_query_job = NULL;
25 s->monitor = flx_interface_monitor_new(s->context);
30 void flx_server_free(flxServer* s) {
33 flx_interface_monitor_free(s->monitor);
35 flx_server_remove(s, 0);
37 g_hash_table_destroy(s->rrset_by_id);
38 g_hash_table_destroy(s->rrset_by_name);
39 g_main_context_unref(s->context);
43 gint flx_server_get_next_id(flxServer *s) {
46 return s->current_id++;
49 void flx_server_add_rr(flxServer *s, gint id, gint interface, guchar protocol, const flxRecord *rr) {
57 e = g_new(flxEntry, 1);
58 flx_record_copy_normalize(&e->rr, rr);
60 e->interface = interface;
61 e->protocol = protocol;
63 /* Insert into linked list */
65 if ((e->next = s->entries))
69 /* Insert into hash table indexed by id */
71 if ((e->next_by_id = g_hash_table_lookup(s->rrset_by_id, &id)))
72 e->next_by_id->prev = e;
73 g_hash_table_replace(s->rrset_by_id, &e->id, e);
75 /* Insert into hash table indexed by name */
76 e->prev_by_name = NULL;
77 if ((e->next_by_name = g_hash_table_lookup(s->rrset_by_name, e->rr.name)))
78 e->next_by_name->prev = e;
79 g_hash_table_replace(s->rrset_by_name, e->rr.name, e);
82 void flx_server_add(flxServer *s, gint id, gint interface, guchar protocol, const gchar *name, guint16 type, gconstpointer data, guint size) {
89 rr.name = (gchar*) name;
91 rr.class = FLX_DNS_CLASS_IN;
92 rr.data = (gpointer) data;
94 rr.ttl = FLX_DEFAULT_TTL;
95 flx_server_add_rr(s, id, interface, protocol, &rr);
98 const flxRecord *flx_server_iterate(flxServer *s, gint id, void **state) {
99 flxEntry **e = (flxEntry**) state;
104 *e = id > 0 ? (*e)->next_by_id : (*e)->next;
106 *e = id > 0 ? g_hash_table_lookup(s->rrset_by_id, &id) : s->entries;
114 static void free_entry(flxServer*s, flxEntry *e) {
117 /* Remove from linked list */
119 e->prev->next = e->next;
121 s->entries = e->next;
124 e->next->prev = e->prev;
126 /* Remove from hash table indexed by id */
128 e->prev_by_id = e->next_by_id;
131 g_hash_table_replace(s->rrset_by_id, &e->next_by_id->id, e->next_by_id);
133 g_hash_table_remove(s->rrset_by_id, &e->id);
137 e->next_by_id->prev_by_id = e->prev_by_id;
139 /* Remove from hash table indexed by name */
141 e->prev_by_name = e->next_by_name;
144 g_hash_table_replace(s->rrset_by_name, &e->next_by_name->rr.name, e->next_by_name);
146 g_hash_table_remove(s->rrset_by_name, &e->rr.name);
150 e->next_by_name->prev_by_name = e->prev_by_name;
153 void flx_server_remove(flxServer *s, gint id) {
158 free_entry(s, s->entries);
162 while ((e = g_hash_table_lookup(s->rrset_by_id, &id)))
167 flxRecord *flx_record_copy_normalize(flxRecord *ret_dest, const flxRecord*src) {
172 ret_dest->name = flx_normalize_name(src->name);
173 ret_dest->data = g_memdup(src->data, src->size);
178 static const gchar *dns_class_to_string(guint16 class) {
179 if (class == FLX_DNS_CLASS_IN)
185 static const gchar *dns_type_to_string(guint16 type) {
189 case FLX_DNS_TYPE_AAAA:
191 case FLX_DNS_TYPE_PTR:
193 case FLX_DNS_TYPE_HINFO:
195 case FLX_DNS_TYPE_TXT:
202 void flx_server_dump(flxServer *s, FILE *f) {
207 for (e = s->entries; e; e = e->next) {
209 fprintf(f, "%i.%u: %-40s %-8s %-8s ", e->interface, e->protocol, e->rr.name, dns_class_to_string(e->rr.class), dns_type_to_string(e->rr.type));
213 if (e->rr.class == FLX_DNS_CLASS_IN) {
214 if (e->rr.type == FLX_DNS_TYPE_A)
215 inet_ntop(AF_INET, e->rr.data, t, sizeof(t));
216 else if (e->rr.type == FLX_DNS_TYPE_AAAA)
217 inet_ntop(AF_INET6, e->rr.data, t, sizeof(t));
218 else if (e->rr.type == FLX_DNS_TYPE_PTR)
219 g_strlcpy(t, e->rr.data, sizeof(t));
220 else if (e->rr.type == FLX_DNS_TYPE_HINFO) {
223 if ((s2 = memchr(e->rr.data, 0, e->rr.size))) {
225 if (memchr(s2, 0, e->rr.size - ((char*) s2 - (char*) e->rr.data)))
226 snprintf(t, sizeof(t), "'%s' '%s'", (char*) e->rr.data, s2);
232 fprintf(f, "%s\n", t);
236 void flx_server_add_address(flxServer *s, gint id, gint interface, guchar protocol, const gchar *name, flxAddress *a) {
242 n = flx_normalize_name(name);
244 if (a->family == AF_INET) {
247 flx_server_add(s, id, interface, protocol, n, FLX_DNS_TYPE_A, &a->ipv4, sizeof(a->ipv4));
249 r = flx_reverse_lookup_name_ipv4(&a->ipv4);
251 flx_server_add(s, id, interface, protocol, r, FLX_DNS_TYPE_PTR, n, strlen(n)+1);
257 flx_server_add(s, id, interface, protocol, n, FLX_DNS_TYPE_AAAA, &a->ipv6, sizeof(a->ipv6));
259 r = flx_reverse_lookup_name_ipv6_arpa(&a->ipv6);
261 flx_server_add(s, id, interface, protocol, r, FLX_DNS_TYPE_PTR, n, strlen(n)+1);
264 r = flx_reverse_lookup_name_ipv6_int(&a->ipv6);
266 flx_server_add(s, id, interface, protocol, r, FLX_DNS_TYPE_PTR, n, strlen(n)+1);
273 flxQueryJob* flx_query_job_new(void) {
274 flxQueryJob *job = g_new(flxQueryJob);
275 job->query.name = NULL;
276 job->query.class = 0;
282 flxQueryJob* flx_query_job_ref(flxQueryJob *job) {
284 g_assert(job->ref >= 1);
289 void flx_query_job_unref(flxQueryJob *job) {
291 g_assert(job->ref >= 1);
296 static void post_query_job(flxServer *s, gint interface, guchar protocol, flxQueryJob *job) {
297 flxQueryJobInstance *i;
301 if (interface <= 0) {
304 for (i = s->monitor->interfaces; i; i = i->next)
305 post_query_job(s, i->index, protocol, job);
306 } else if (protocol == AF_UNSPEC) {
307 post_query_job(s, index, AF_INET, job);
308 post_query_job(s, index, AF_INET6, job);
311 if (query_job_exists(s, interface, protocol, &job->query))
314 i = g_new(flxQueryJobInstance, 1);
315 i->job = flx_query_job_ref(job);
316 i->interface = interface;
317 i->protocol = protocol;
318 if (i->prev = s->last_query_job)
321 s->first_query_job = i;
323 s->last_query_job = i;
327 void flx_server_post_query_job(flxServer *s, gint interface, guchar protocol, const flxQuery *q) {
332 job = flx_query_job_new();
333 job->query.name = g_strdup(q->name);
334 job->query.class = q->class;
335 job->query.type = q->type;
336 post_query_job(s, interface, protocol, job);
339 void flx_server_drop_query_job(flxServer *s, gint interface, guchar protocol, const flxQuery *q) {
340 flxQueryJobInstance *i, *next;
342 g_assert(interface > 0);
343 g_assert(protocol != AF_UNSPEC);
346 for (i = s->first_query_job; i; i = next) {
349 if (flx_query_equal(i->query, q))
350 flx_server_remove_query_job_instance(s, i);
354 gboolean flx_query_equal(const flxQuery *a, const flxQuery *b) {
355 return strcmp(a->name, b->name) == 0 && a->type == b->type && a->class == b->class;
358 void flx_server_remove_query_job_instance(flxServer *s, flxQueryJobInstance *i) {
365 s->first_query_job = i->next;
370 s->last_query_job = i->prev;
372 flx_query_job_unref(i->job);