]> git.meshlink.io Git - catta/blob - server.c
f85de456636193bceeed7982ab57eb3cb5d58ac7
[catta] / server.c
1 #include <sys/socket.h>
2 #include <arpa/inet.h>
3 #include <string.h>
4 #include <sys/utsname.h>
5 #include <unistd.h>
6
7 #include "server.h"
8 #include "util.h"
9 #include "iface.h"
10 #include "socket.h"
11
12 static void add_default_entries(flxServer *s) {
13     gint length = 0;
14     struct utsname utsname;
15     gchar *hinfo;
16     flxAddress a;
17     
18     g_assert(s);
19     
20     /* Fill in HINFO rr */
21     uname(&utsname);
22     hinfo = g_strdup_printf("%s%c%s%n", g_strup(utsname.machine), 0, g_strup(utsname.sysname), &length);
23     
24     flx_server_add_full(s, 0, 0, AF_UNSPEC, TRUE,
25                         s->hostname, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_HINFO, hinfo, length+1, FLX_DEFAULT_TTL);
26
27     g_free(hinfo);
28
29     /* Add localhost entries */
30     flx_address_parse("127.0.0.1", AF_INET, &a);
31     flx_server_add_address(s, 0, 0, AF_UNSPEC, TRUE, "localhost", &a);
32
33     flx_address_parse("::1", AF_INET6, &a);
34     flx_server_add_address(s, 0, 0, AF_UNSPEC, TRUE, "ip6-localhost", &a);
35 }
36
37 flxServer *flx_server_new(GMainContext *c) {
38     gchar *hn, *e;
39     flxServer *s;
40
41     s = g_new(flxServer, 1);
42
43     s->fd_ipv4 = flx_open_socket_ipv4();
44     s->fd_ipv6 = flx_open_socket_ipv6();
45     
46     if (s->fd_ipv6 < 0 && s->fd_ipv4 < 0) {
47         g_critical("Failed to create sockets.\n");
48         g_free(s);
49         return NULL;
50     }
51
52     if (s->fd_ipv4 < 0)
53         g_message("Failed to create IPv4 socket, proceeding in IPv6 only mode");
54     else if (s->fd_ipv6 < 0)
55         g_message("Failed to create IPv6 socket, proceeding in IPv4 only mode");
56     
57     if (c)
58         g_main_context_ref(s->context = c);
59     else
60         s->context = g_main_context_default();
61     
62     s->current_id = 1;
63     s->rrset_by_id = g_hash_table_new(g_int_hash, g_int_equal);
64     s->rrset_by_name = g_hash_table_new((GHashFunc) flx_key_hash, (GEqualFunc) flx_key_equal);
65
66     FLX_LLIST_HEAD_INIT(flxEntry, s->entries);
67
68     s->monitor = flx_interface_monitor_new(s);
69     s->time_event_queue = flx_time_event_queue_new(s->context);
70     
71     /* Get host name */
72     hn = flx_get_host_name();
73     if ((e = strchr(hn, '.')))
74         *e = 0;
75
76     s->hostname = g_strdup_printf("%s.local.", hn);
77     g_free(hn);
78
79     add_default_entries(s);
80
81     return s;
82 }
83
84 void flx_server_free(flxServer* s) {
85     g_assert(s);
86
87     flx_interface_monitor_free(s->monitor);
88     
89     flx_server_remove(s, 0);
90     
91     g_hash_table_destroy(s->rrset_by_id);
92     g_hash_table_destroy(s->rrset_by_name);
93
94     flx_time_event_queue_free(s->time_event_queue);
95     g_main_context_unref(s->context);
96
97     if (s->fd_ipv4 >= 0)
98         close(s->fd_ipv4);
99     if (s->fd_ipv6 >= 0)
100         close(s->fd_ipv6);
101     
102     g_free(s->hostname);
103     g_free(s);
104 }
105
106 gint flx_server_get_next_id(flxServer *s) {
107     g_assert(s);
108
109     return s->current_id++;
110 }
111
112 void flx_server_add(
113     flxServer *s,
114     gint id,
115     gint interface,
116     guchar protocol,
117     gboolean unique,
118     flxRecord *r) {
119     
120     flxEntry *e, *t;
121     g_assert(s);
122     g_assert(r);
123
124     e = g_new(flxEntry, 1);
125     e->record = flx_record_ref(r);
126     e->id = id;
127     e->interface = interface;
128     e->protocol = protocol;
129     e->unique = unique;
130
131     FLX_LLIST_PREPEND(flxEntry, entry, s->entries, e);
132
133     /* Insert into hash table indexed by id */
134     t = g_hash_table_lookup(s->rrset_by_id, &e->id);
135     FLX_LLIST_PREPEND(flxEntry, by_id, t, e);
136     g_hash_table_replace(s->rrset_by_id, &e->id, t);
137     
138     /* Insert into hash table indexed by name */
139     t = g_hash_table_lookup(s->rrset_by_name, e->record->key);
140     FLX_LLIST_PREPEND(flxEntry, by_name, t, e);
141     g_hash_table_replace(s->rrset_by_name, e->record->key, t);
142 }
143
144 void flx_server_add_full(
145     flxServer *s,
146     gint id,
147     gint interface,
148     guchar protocol,
149     gboolean unique,
150     const gchar *name,
151     guint16 class,
152     guint16 type,
153     gconstpointer data,
154     guint size,
155     guint32 ttl) {
156     
157     flxRecord *r;
158     g_assert(s);
159     g_assert(data);
160     g_assert(size);
161
162     r = flx_record_new_full(name ? name : s->hostname, class, type, data, size, ttl);
163     flx_server_add(s, id, interface, protocol, unique, r);
164     flx_record_unref(r);
165 }
166
167 const flxRecord *flx_server_iterate(flxServer *s, gint id, void **state) {
168     flxEntry **e = (flxEntry**) state;
169     g_assert(s);
170     g_assert(e);
171
172     if (e)
173         *e = id > 0 ? (*e)->by_id_next : (*e)->entry_next;
174     else
175         *e = id > 0 ? g_hash_table_lookup(s->rrset_by_id, &id) : s->entries;
176         
177     if (!*e)
178         return NULL;
179
180     return flx_record_ref((*e)->record);
181 }
182
183 static void free_entry(flxServer*s, flxEntry *e) {
184     flxEntry *t;
185     
186     g_assert(e);
187
188     /* Remove from linked list */
189     FLX_LLIST_REMOVE(flxEntry, entry, s->entries, e);
190
191     /* Remove from hash table indexed by id */
192     t = g_hash_table_lookup(s->rrset_by_id, &e->id);
193     FLX_LLIST_REMOVE(flxEntry, by_id, t, e);
194     if (t)
195         g_hash_table_replace(s->rrset_by_id, &t->id, t);
196     else
197         g_hash_table_remove(s->rrset_by_id, &e->id);
198     
199     /* Remove from hash table indexed by name */
200     t = g_hash_table_lookup(s->rrset_by_name, e->record->key);
201     FLX_LLIST_REMOVE(flxEntry, by_name, t, e);
202     if (t)
203         g_hash_table_replace(s->rrset_by_name, t->record->key, t);
204     else
205         g_hash_table_remove(s->rrset_by_name, e->record->key);
206
207     flx_record_unref(e->record);
208     g_free(e);
209 }
210
211 void flx_server_remove(flxServer *s, gint id) {
212     g_assert(s);
213
214     if (id <= 0) {
215         while (s->entries)
216             free_entry(s, s->entries);
217     } else {
218         flxEntry *e;
219
220         while ((e = g_hash_table_lookup(s->rrset_by_id, &id)))
221             free_entry(s, e);
222     }
223 }
224
225 void flx_server_dump(flxServer *s, FILE *f) {
226     flxEntry *e;
227     g_assert(s);
228     g_assert(f);
229
230     for (e = s->entries; e; e = e->entry_next) {
231         gchar *t;
232
233         t = flx_record_to_string(e->record);
234         fprintf(f, "%s\n", t);
235         g_free(t);
236     }
237 }
238
239 void flx_server_add_address(
240     flxServer *s,
241     gint id,
242     gint interface,
243     guchar protocol,
244     gboolean unique,
245     const gchar *name,
246     flxAddress *a) {
247
248     gchar *n;
249     g_assert(s);
250     g_assert(a);
251
252     n = name ? flx_normalize_name(name) : s->hostname;
253     
254     if (a->family == AF_INET) {
255         gchar *r;
256         
257         flx_server_add_full(s, id, interface, protocol, unique, n, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_A, &a->ipv4, sizeof(a->ipv4), FLX_DEFAULT_TTL);
258
259         r = flx_reverse_lookup_name_ipv4(&a->ipv4);
260         g_assert(r);
261         flx_server_add_full(s, id, interface, protocol, unique, r, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_PTR, n, strlen(n)+1, FLX_DEFAULT_TTL);
262         g_free(r);
263         
264     } else {
265         gchar *r;
266             
267         flx_server_add_full(s, id, interface, protocol, unique, n, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_AAAA, &a->ipv6, sizeof(a->ipv6), FLX_DEFAULT_TTL);
268
269         r = flx_reverse_lookup_name_ipv6_arpa(&a->ipv6);
270         g_assert(r);
271         flx_server_add_full(s, id, interface, protocol, unique, r, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_PTR, n, strlen(n)+1, FLX_DEFAULT_TTL);
272         g_free(r);
273     
274         r = flx_reverse_lookup_name_ipv6_int(&a->ipv6);
275         g_assert(r);
276         flx_server_add_full(s, id, interface, protocol, unique, r, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_PTR, n, strlen(n)+1, FLX_DEFAULT_TTL);
277         g_free(r);
278     }
279     
280     g_free(n);
281 }
282
283 void flx_server_add_text(
284     flxServer *s,
285     gint id,
286     gint interface,
287     guchar protocol,
288     gboolean unique,
289     const gchar *name,
290     const gchar *text) {
291     
292     g_assert(s);
293     g_assert(text);
294
295     flx_server_add_full(s, id, interface, protocol, unique, name, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_TXT, text, strlen(text), FLX_DEFAULT_TTL);
296 }
297
298 void flx_server_send_query(flxServer *s, gint interface, guchar protocol, flxKey *k) {
299     g_assert(s);
300     g_assert(k);
301
302     if (interface <= 0) {
303         flxInterface *i;
304
305         for (i = flx_interface_monitor_get_first(s->monitor); i; i = i->interface_next)
306             flx_interface_send_query(i, protocol, k);
307         
308     } else {
309         flxInterface *i;
310
311         if (!(i = flx_interface_monitor_get_interface(s->monitor, interface)))
312             return;
313
314         flx_interface_send_query(i, protocol, k);
315     }
316 }