]> git.meshlink.io Git - catta/blob - announce.c
* add DNS packet name compression
[catta] / announce.c
1 #include "announce.h"
2 #include "util.h"
3
4 #define FLX_ANNOUNCEMENT_JITTER_MSEC 0
5
6 static void remove_announcement(flxServer *s, flxAnnouncement *a) {
7     g_assert(s);
8     g_assert(a);
9
10     flx_time_event_queue_remove(s->time_event_queue, a->time_event);
11
12     FLX_LLIST_REMOVE(flxAnnouncement, by_interface, a->interface->announcements, a);
13     FLX_LLIST_REMOVE(flxAnnouncement, by_entry, a->entry->announcements, a);
14     
15     g_free(a);
16 }
17
18 static void elapse_announce(flxTimeEvent *e, void *userdata);
19
20 static void send_packet(flxAnnouncement *a) {
21     GTimeVal tv;
22     g_assert(a);
23
24 /*     g_message("%i -- %u", a->state, a->n_iteration); */
25     
26     if (a->state == FLX_PROBING && a->n_iteration >= 1) {
27         flx_interface_post_probe(a->interface, a->entry->record, FALSE);
28     } else if (a->state == FLX_ANNOUNCING && a->n_iteration >= 1)
29         flx_interface_post_response(a->interface, NULL, a->entry->record, a->entry->flags & FLX_SERVER_ENTRY_UNIQUE, TRUE);
30
31     a->n_iteration++;
32
33     if (a->state == FLX_PROBING) {
34
35         if (a->n_iteration == 1)
36             flx_elapse_time(&tv, 0, 250);
37         else
38             flx_elapse_time(&tv, 250, 0);
39
40         /* Probing done */
41         if (a->n_iteration >= 4) {
42             gchar *t;
43             g_message("Enough probes for record [%s]", t = flx_record_to_string(a->entry->record));
44             g_free(t);
45             a->state = FLX_ANNOUNCING;
46             a->n_iteration = 1;
47         }
48         
49     } else if (a->state == FLX_ANNOUNCING) {
50
51         flx_elapse_time(&tv, a->sec_delay*1000, FLX_ANNOUNCEMENT_JITTER_MSEC);
52         
53         if (a->n_iteration < 10)
54             a->sec_delay *= 2;
55
56         /* Announcing done */
57         if (a->n_iteration >= 4) {
58             gchar *t;
59             g_message("Enough announcements for record [%s]", t = flx_record_to_string(a->entry->record));
60             g_free(t);
61             remove_announcement(a->server, a);
62             return;
63         }
64     }
65
66     if (a->time_event) 
67         flx_time_event_queue_update(a->server->time_event_queue, a->time_event, &tv);
68     else
69         a->time_event = flx_time_event_queue_add(a->server->time_event_queue, &tv, elapse_announce, a);
70 }
71
72 static void elapse_announce(flxTimeEvent *e, void *userdata) {
73     g_assert(e);
74
75     send_packet(userdata);
76 }
77
78 static flxAnnouncement *get_announcement(flxServer *s, flxServerEntry *e, flxInterface *i) {
79     flxAnnouncement *a;
80     
81     g_assert(s);
82     g_assert(e);
83     g_assert(i);
84
85     for (a = e->announcements; a; a = a->by_entry_next)
86         if (a->interface == i)
87             return a;
88
89     return NULL;
90 }
91
92 static void new_announcement(flxServer *s, flxInterface *i, flxServerEntry *e) {
93     flxAnnouncement *a;
94     GTimeVal tv;
95     gchar *t; 
96
97     g_assert(s);
98     g_assert(i);
99     g_assert(e);
100
101 /*     g_message("NEW ANNOUNCEMENT: %s.%i [%s]", i->hardware->name, i->protocol, t = flx_record_to_string(e->record)); */
102 /*     g_free(t); */
103     
104     if (!flx_interface_match(i, e->interface, e->protocol) || !i->announcing || e->flags & FLX_SERVER_ENTRY_NOANNOUNCE)
105         return;
106
107     /* We don't want duplicate announcements */
108     if (get_announcement(s, e, i))
109         return;
110
111     g_message("New announcement on interface %s.%i for entry [%s]", i->hardware->name, i->protocol, t = flx_record_to_string(e->record));
112     g_free(t);
113
114     a = g_new(flxAnnouncement, 1);
115     a->server = s;
116     a->interface = i;
117     a->entry = e;
118
119     a->state = (e->flags & FLX_SERVER_ENTRY_UNIQUE) && !(e->flags & FLX_SERVER_ENTRY_NOPROBE) ? FLX_PROBING : FLX_ANNOUNCING;
120     a->n_iteration = 0;
121     a->sec_delay = 1;
122     a->time_event = NULL;
123     
124     FLX_LLIST_PREPEND(flxAnnouncement, by_interface, i->announcements, a);
125     FLX_LLIST_PREPEND(flxAnnouncement, by_entry, e->announcements, a);
126
127     send_packet(a);
128 }
129
130 void flx_announce_interface(flxServer *s, flxInterface *i) {
131     flxServerEntry *e;
132     
133     g_assert(s);
134     g_assert(i);
135
136     if (!i->announcing)
137         return;
138
139 /*     g_message("ANNOUNCE INTERFACE"); */
140     
141     for (e = s->entries; e; e = e->entry_next)
142         new_announcement(s, i, e);
143 }
144
145 static void announce_walk_callback(flxInterfaceMonitor *m, flxInterface *i, gpointer userdata) {
146     flxServerEntry *e = userdata;
147     
148     g_assert(m);
149     g_assert(i);
150     g_assert(e);
151
152     new_announcement(m->server, i, e);
153 }
154
155 void flx_announce_entry(flxServer *s, flxServerEntry *e) {
156     g_assert(s);
157     g_assert(e);
158
159 /*     g_message("ANNOUNCE ENTRY"); */
160
161     flx_interface_monitor_walk(s->monitor, e->interface, e->protocol, announce_walk_callback, e);
162 }
163
164 gboolean flx_entry_established(flxServer *s, flxServerEntry *e, flxInterface *i) {
165     flxAnnouncement *a;
166
167     g_assert(s);
168     g_assert(e);
169     g_assert(i);
170
171     if (!(e->flags & FLX_SERVER_ENTRY_UNIQUE) || (e->flags & FLX_SERVER_ENTRY_NOPROBE))
172         return TRUE;
173
174     if ((a = get_announcement(s, e, i)))
175         if (a->state == FLX_PROBING)
176             return FALSE;
177
178     return TRUE;
179 }
180
181
182 static flxRecord *make_goodbye_record(flxRecord *r) {
183     gchar *t;
184     flxRecord *g;
185     
186     g_assert(r);
187
188     g_message("Preparing goodbye for record [%s]", t = flx_record_to_string(r));
189     g_free(t);
190
191     g = flx_record_copy(r);
192     g_assert(g->ref == 1);
193     g->ttl = 0;
194
195     return g;
196 }
197
198
199 static void send_goodbye_callback(flxInterfaceMonitor *m, flxInterface *i, gpointer userdata) {
200     flxServerEntry *e = userdata;
201     flxRecord *g;
202     
203     g_assert(m);
204     g_assert(i);
205     g_assert(e);
206
207     if (!flx_interface_match(i, e->interface, e->protocol))
208         return;
209
210     if (e->flags & FLX_SERVER_ENTRY_NOANNOUNCE)
211         return;
212
213     if (!flx_entry_established(m->server, e, i))
214         return;
215     
216     g = make_goodbye_record(e->record);
217     flx_interface_post_response(i, NULL, g, e->flags & FLX_SERVER_ENTRY_UNIQUE, TRUE);
218     flx_record_unref(g);
219 }
220     
221 void flx_goodbye_interface(flxServer *s, flxInterface *i, gboolean goodbye) {
222     g_assert(s);
223     g_assert(i);
224
225     g_message("goodbye interface: %s.%u", i->hardware->name, i->protocol);
226
227     if (goodbye && flx_interface_relevant(i)) {
228         flxServerEntry *e;
229         
230         for (e = s->entries; e; e = e->entry_next)
231             send_goodbye_callback(s->monitor, i, e);
232     }
233
234     while (i->announcements)
235         remove_announcement(s, i->announcements);
236
237     g_message("goodbye interface done: %s.%u", i->hardware->name, i->protocol);
238
239 }
240
241 void flx_goodbye_entry(flxServer *s, flxServerEntry *e, gboolean goodbye) {
242     g_assert(s);
243     g_assert(e);
244
245     g_message("goodbye entry: %p", e);
246     
247     if (goodbye)
248         flx_interface_monitor_walk(s->monitor, 0, AF_UNSPEC, send_goodbye_callback, e);
249
250     while (e->announcements)
251         remove_announcement(s, e->announcements);
252
253     g_message("goodbye entry done: %p", e);
254
255 }
256
257 void flx_goodbye_all(flxServer *s, gboolean goodbye) {
258     flxServerEntry *e;
259     
260     g_assert(s);
261
262     g_message("goodbye all: %p", e);
263
264     for (e = s->entries; e; e = e->entry_next)
265         flx_goodbye_entry(s, e, goodbye);
266
267     g_message("goodbye all done: %p", e);
268
269 }
270