]> git.meshlink.io Git - catta/blob - server.c
initial commit
[catta] / server.c
1 #include <sys/socket.h>
2 #include <arpa/inet.h>
3 #include <string.h>
4
5 #include "server.h"
6 #include "util.h"
7
8 flxServer *flx_server_new(GMainContext *c) {
9     flxServer *s = g_new(flxServer, 1);
10
11     if (c) {
12         g_main_context_ref(c);
13         s->context = c;
14     } else
15         s->context = g_main_context_default();
16     
17     s->current_id = 1;
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);
20     s->entries = NULL;
21
22     s->monitor = flx_interface_monitor_new(s->context);
23     
24     return s;
25 }
26
27 void flx_server_free(flxServer* s) {
28     g_assert(s);
29
30     flx_interface_monitor_free(s->monitor);
31
32     flx_server_remove(s, 0);
33     
34     g_hash_table_destroy(s->rrset_by_id);
35     g_hash_table_destroy(s->rrset_by_name);
36     g_main_context_unref(s->context);
37     g_free(s);
38 }
39
40 gint flx_server_get_next_id(flxServer *s) {
41     g_assert(s);
42
43     return s->current_id++;
44 }
45
46 void flx_server_add_rr(flxServer *s, gint id, gint interface, const flxRecord *rr) {
47     flxEntry *e;
48     g_assert(s);
49     g_assert(rr);
50     g_assert(rr->name);
51     g_assert(rr->data);
52     g_assert(rr->size);
53
54     e = g_new(flxEntry, 1);
55     flx_record_copy_normalize(&e->rr, rr);
56     e->id = id;
57     e->interface = interface;
58
59     /* Insert into linked list */
60     e->prev = NULL;
61     if ((e->next = s->entries))
62         e->next->prev = e;
63     s->entries = e;
64
65     /* Insert into hash table indexed by id */
66     e->prev_by_id = NULL;
67     if ((e->next_by_id = g_hash_table_lookup(s->rrset_by_id, &id)))
68         e->next_by_id->prev = e;
69     g_hash_table_replace(s->rrset_by_id, &e->id, e);
70
71     /* Insert into hash table indexed by name */
72     e->prev_by_name = NULL;
73     if ((e->next_by_name = g_hash_table_lookup(s->rrset_by_name, e->rr.name)))
74         e->next_by_name->prev = e;
75     g_hash_table_replace(s->rrset_by_name, e->rr.name, e);
76 }
77
78 void flx_server_add(flxServer *s, gint id, const gchar *name, gint interface, guint16 type, gconstpointer data, guint size) {
79     flxRecord rr;
80     g_assert(s);
81     g_assert(name);
82     g_assert(data);
83     g_assert(size);
84
85     rr.name = (gchar*) name;
86     rr.type = type;
87     rr.class = FLX_DNS_CLASS_IN;
88     rr.data = (gpointer) data;
89     rr.size = size;
90     rr.interface = interface;
91     rr.ttl = FLX_DEFAULT_TTL;
92     flx_server_add_rr(s, id, 0, &rr);
93 }
94
95 const flxRecord *flx_server_iterate(flxServer *s, gint id, void **state) {
96     flxEntry **e = (flxEntry**) state;
97     g_assert(s);
98     g_assert(e);
99
100     if (e)
101         *e = id > 0 ? (*e)->next_by_id : (*e)->next;
102     else
103         *e = id > 0 ? g_hash_table_lookup(s->rrset_by_id, &id) : s->entries;
104         
105     if (!*e)
106         return NULL;
107
108     return &(*e)->rr;
109 }
110
111 static void free_entry(flxServer*s, flxEntry *e) {
112     g_assert(e);
113
114     /* Remove from linked list */
115     if (e->prev)
116         e->prev->next = e->next;
117     else
118         s->entries = e->next;
119     
120     if (e->next)
121         e->next->prev = e->prev;
122
123     /* Remove from hash table indexed by id */
124     if (e->prev_by_id)
125         e->prev_by_id = e->next_by_id;
126     else {
127         if (e->next_by_id)
128             g_hash_table_replace(s->rrset_by_id, &e->next_by_id->id, e->next_by_id);
129         else
130             g_hash_table_remove(s->rrset_by_id, &e->id);
131     }
132
133     if (e->next_by_id)
134         e->next_by_id->prev_by_id = e->prev_by_id;
135
136     /* Remove from hash table indexed by name */
137     if (e->prev_by_name)
138         e->prev_by_name = e->next_by_name;
139     else {
140         if (e->next_by_name)
141             g_hash_table_replace(s->rrset_by_name, &e->next_by_name->rr.name, e->next_by_name);
142         else
143             g_hash_table_remove(s->rrset_by_name, &e->rr.name);
144     }
145     
146     if (e->next_by_name)
147         e->next_by_name->prev_by_name = e->prev_by_name;
148 }
149
150 void flx_server_remove(flxServer *s, gint id) {
151     g_assert(s);
152
153     if (id <= 0) {
154         while (s->entries)
155             free_entry(s, s->entries);
156     } else {
157         flxEntry *e;
158
159         while ((e = g_hash_table_lookup(s->rrset_by_id, &id)))
160             free_entry(s, e);
161     }
162 }
163
164 flxRecord *flx_record_copy_normalize(flxRecord *ret_dest, const flxRecord*src) {
165     g_assert(ret_dest);
166     g_assert(src);
167
168     *ret_dest = *src;
169     ret_dest->name = flx_normalize_name(src->name);
170     ret_dest->data = g_memdup(src->data, src->size);
171
172     return ret_dest;    
173 }
174
175 static const gchar *dns_class_to_string(guint16 class) {
176     if (class == FLX_DNS_CLASS_IN)
177         return "IN";
178
179     return NULL;
180 }
181
182 static const gchar *dns_type_to_string(guint16 type) {
183     switch (type) {
184         case FLX_DNS_TYPE_A:
185             return "A";
186         case FLX_DNS_TYPE_AAAA:
187             return "AAAA";
188         case FLX_DNS_TYPE_PTR:
189             return "PTR";
190         case FLX_DNS_TYPE_HINFO:
191             return "HINFO";
192         case FLX_DNS_TYPE_TXT:
193             return "TXT";
194         default:
195             return NULL;
196     }
197 }
198
199 void flx_server_dump(flxServer *s, FILE *f) {
200     flxEntry *e;
201     g_assert(s);
202     g_assert(f);
203
204     for (e = s->entries; e; e = e->next) {
205         char t[256];
206         fprintf(f, "%-40s %-8s %-8s ", e->rr.name, dns_class_to_string(e->rr.class), dns_type_to_string(e->rr.type));
207
208         t[0] = 0;
209         
210         if (e->rr.class == FLX_DNS_CLASS_IN) {
211             if (e->rr.type == FLX_DNS_TYPE_A)
212                 inet_ntop(AF_INET, e->rr.data, t, sizeof(t));
213             else if (e->rr.type == FLX_DNS_TYPE_AAAA)
214                 inet_ntop(AF_INET6, e->rr.data, t, sizeof(t));
215             else if (e->rr.type == FLX_DNS_TYPE_PTR)
216                 g_strlcpy(t, e->rr.data, sizeof(t));
217             else if (e->rr.type == FLX_DNS_TYPE_HINFO) {
218                 char *s2;
219
220                 if ((s2 = memchr(e->rr.data, 0, e->rr.size))) {
221                     s2++;
222                     if (memchr(s2, 0, e->rr.size - ((char*) s2 - (char*) e->rr.data)))
223                         snprintf(t, sizeof(t), "'%s' '%s'", (char*) e->rr.data, s2);
224                 }
225                 
226             }
227         }
228             
229         fprintf(f, "%s\n", t);
230     }
231 }
232