]> git.meshlink.io Git - catta/blob - announce.c
fix two memory leaks
[catta] / announce.c
1 #include "announce.h"
2 #include "util.h"
3
4 #define FLX_ANNOUNCEMENT_JITTER_MSEC 250
5 #define FLX_PROBE_JITTER_MSEC 250
6 #define FLX_PROBE_INTERVAL_MSEC 250
7
8 static void remove_announcement(flxServer *s, flxAnnouncement *a) {
9     g_assert(s);
10     g_assert(a);
11
12     if (a->time_event)
13         flx_time_event_queue_remove(s->time_event_queue, a->time_event);
14
15     FLX_LLIST_REMOVE(flxAnnouncement, by_interface, a->interface->announcements, a);
16     FLX_LLIST_REMOVE(flxAnnouncement, by_entry, a->entry->announcements, a);
17     
18     g_free(a);
19 }
20
21 static void elapse_announce(flxTimeEvent *e, void *userdata);
22
23 static void set_timeout(flxAnnouncement *a, const GTimeVal *tv) {
24     g_assert(a);
25
26     if (!tv) {
27         if (a->time_event) {
28             flx_time_event_queue_remove(a->server->time_event_queue, a->time_event);
29             a->time_event = NULL;
30         }
31     } else {
32
33         if (a->time_event) 
34             flx_time_event_queue_update(a->server->time_event_queue, a->time_event, tv);
35         else
36             a->time_event = flx_time_event_queue_add(a->server->time_event_queue, tv, elapse_announce, a);
37     }
38 }
39
40 static void next_state(flxAnnouncement *a);
41
42 void flx_entry_group_check_probed(flxEntryGroup *g, gboolean immediately) {
43     flxEntry *e;
44     g_assert(g);
45     g_assert(!g->dead);
46
47     /* Check whether all group members have been probed */
48     
49     if (g->status != FLX_ENTRY_GROUP_REGISTERING || g->n_probing > 0) 
50         return;
51
52     flx_entry_group_run_callback(g, g->status = FLX_ENTRY_GROUP_ESTABLISHED);
53
54     if (g->dead)
55         return;
56     
57     for (e = g->entries; e; e = e->entries_next) {
58         flxAnnouncement *a;
59         
60         for (a = e->announcements; a; a = a->by_entry_next) {
61
62             if (a->state != FLX_WAITING)
63                 continue;
64             
65             a->state = FLX_ANNOUNCING;
66
67             if (immediately) {
68                 /* Shortcut */
69                 
70                 a->n_iteration = 1;
71                 next_state(a);
72             } else {
73                 GTimeVal tv;
74                 a->n_iteration = 0;
75                 flx_elapse_time(&tv, 0, FLX_ANNOUNCEMENT_JITTER_MSEC);
76                 set_timeout(a, &tv);
77             }
78         }
79     }
80 }
81
82 static void next_state(flxAnnouncement *a) {
83     g_assert(a);
84
85     g_message("%i -- %u", a->state, a->n_iteration);  
86     
87     if (a->state == FLX_WAITING) {
88
89         g_assert(a->entry->group);
90
91         flx_entry_group_check_probed(a->entry->group, TRUE);
92         
93     } else if (a->state == FLX_PROBING) {
94
95         if (a->n_iteration >= 4) {
96             /* Probing done */
97             
98             gchar *t;
99
100             g_message("Enough probes for record [%s]", t = flx_record_to_string(a->entry->record));
101             g_free(t);
102
103             if (a->entry->group) {
104                 g_assert(a->entry->group->n_probing);
105                 a->entry->group->n_probing--;
106             }
107             
108             if (a->entry->group && a->entry->group->status == FLX_ENTRY_GROUP_REGISTERING)
109                 a->state = FLX_WAITING;
110             else {
111                 a->state = FLX_ANNOUNCING;
112                 a->n_iteration = 1;
113             }
114
115             set_timeout(a, NULL);
116             next_state(a);
117         } else {
118             GTimeVal tv;
119
120             flx_interface_post_probe(a->interface, a->entry->record, FALSE);
121             
122             flx_elapse_time(&tv, FLX_PROBE_INTERVAL_MSEC, 0);
123             set_timeout(a, &tv);
124             
125             a->n_iteration++;
126         }
127
128     } else if (a->state == FLX_ANNOUNCING) {
129
130         flx_interface_post_response(a->interface, NULL, a->entry->record, a->entry->flags & FLX_ENTRY_UNIQUE, FALSE);
131
132         if (++a->n_iteration >= 4) {
133             gchar *t;
134             /* Announcing done */
135
136             g_message("Enough announcements for record [%s]", t = flx_record_to_string(a->entry->record));
137             g_free(t);
138
139             a->state = FLX_ESTABLISHED;
140
141             set_timeout(a, NULL);
142         } else {
143             GTimeVal tv;
144             flx_elapse_time(&tv, a->sec_delay*1000, FLX_ANNOUNCEMENT_JITTER_MSEC);
145         
146             if (a->n_iteration < 10)
147                 a->sec_delay *= 2;
148             
149             set_timeout(a, &tv);
150         }
151     }
152 }
153
154 static void elapse_announce(flxTimeEvent *e, void *userdata) {
155     g_assert(e);
156
157     next_state(userdata);
158 }
159
160 flxAnnouncement *flx_get_announcement(flxServer *s, flxEntry *e, flxInterface *i) {
161     flxAnnouncement *a;
162     
163     g_assert(s);
164     g_assert(e);
165     g_assert(i);
166
167     for (a = e->announcements; a; a = a->by_entry_next)
168         if (a->interface == i)
169             return a;
170
171     return NULL;
172 }
173
174 static void new_announcement(flxServer *s, flxInterface *i, flxEntry *e) {
175     flxAnnouncement *a;
176     GTimeVal tv;
177     gchar *t; 
178
179     g_assert(s);
180     g_assert(i);
181     g_assert(e);
182     g_assert(!e->dead);
183
184 /*     g_message("NEW ANNOUNCEMENT: %s.%i [%s]", i->hardware->name, i->protocol, t = flx_record_to_string(e->record)); */
185 /*     g_free(t); */
186     
187     if (!flx_interface_match(i, e->interface, e->protocol) || !i->announcing || !flx_entry_commited(e))
188         return;
189
190     /* We don't want duplicate announcements */
191     if (flx_get_announcement(s, e, i))
192         return;
193
194     a = g_new(flxAnnouncement, 1);
195     a->server = s;
196     a->interface = i;
197     a->entry = e;
198
199     if ((e->flags & FLX_ENTRY_UNIQUE) && !(e->flags & FLX_ENTRY_NOPROBE))
200         a->state = FLX_PROBING;
201     else if (!(e->flags & FLX_ENTRY_NOANNOUNCE)) {
202
203         if (!e->group || e->group->status == FLX_ENTRY_GROUP_ESTABLISHED)
204             a->state = FLX_ANNOUNCING;
205         else
206             a->state = FLX_WAITING;
207         
208     } else
209         a->state = FLX_ESTABLISHED;
210
211
212     g_message("New announcement on interface %s.%i for entry [%s] state=%i", i->hardware->name, i->protocol, t = flx_record_to_string(e->record), a->state);
213     g_free(t);
214
215     a->n_iteration = 1;
216     a->sec_delay = 1;
217     a->time_event = NULL;
218
219     if (a->state == FLX_PROBING)
220         if (e->group)
221             e->group->n_probing++;
222     
223     FLX_LLIST_PREPEND(flxAnnouncement, by_interface, i->announcements, a);
224     FLX_LLIST_PREPEND(flxAnnouncement, by_entry, e->announcements, a);
225
226     if (a->state == FLX_PROBING) {
227         flx_elapse_time(&tv, 0, FLX_PROBE_JITTER_MSEC);
228         set_timeout(a, &tv);
229     } else if (a->state == FLX_ANNOUNCING) {
230         flx_elapse_time(&tv, 0, FLX_ANNOUNCEMENT_JITTER_MSEC);
231         set_timeout(a, &tv);
232     }
233 }
234
235 void flx_announce_interface(flxServer *s, flxInterface *i) {
236     flxEntry *e;
237     
238     g_assert(s);
239     g_assert(i);
240
241     if (!i->announcing)
242         return;
243
244     for (e = s->entries; e; e = e->entries_next)
245         if (!e->dead)
246             new_announcement(s, i, e);
247 }
248
249 static void announce_walk_callback(flxInterfaceMonitor *m, flxInterface *i, gpointer userdata) {
250     flxEntry *e = userdata;
251     
252     g_assert(m);
253     g_assert(i);
254     g_assert(e);
255     g_assert(!e->dead);
256
257     new_announcement(m->server, i, e);
258 }
259
260 void flx_announce_entry(flxServer *s, flxEntry *e) {
261     g_assert(s);
262     g_assert(e);
263     g_assert(!e->dead);
264
265     flx_interface_monitor_walk(s->monitor, e->interface, e->protocol, announce_walk_callback, e);
266 }
267
268 void flx_announce_group(flxServer *s, flxEntryGroup *g) {
269     flxEntry *e;
270     
271     g_assert(s);
272     g_assert(g);
273
274     for (e = g->entries; e; e = e->by_group_next)
275         if (!e->dead)
276             flx_announce_entry(s, e);
277 }
278
279 gboolean flx_entry_registered(flxServer *s, flxEntry *e, flxInterface *i) {
280     flxAnnouncement *a;
281
282     g_assert(s);
283     g_assert(e);
284     g_assert(i);
285     g_assert(!e->dead);
286
287     if (!(a = flx_get_announcement(s, e, i)))
288         return FALSE;
289     
290     return a->state == FLX_ANNOUNCING || a->state == FLX_ESTABLISHED;
291 }
292
293 gboolean flx_entry_registering(flxServer *s, flxEntry *e, flxInterface *i) {
294     flxAnnouncement *a;
295
296     g_assert(s);
297     g_assert(e);
298     g_assert(i);
299     g_assert(!e->dead);
300
301     if (!(a = flx_get_announcement(s, e, i)))
302         return FALSE;
303     
304     return a->state == FLX_PROBING || a->state == FLX_WAITING;
305 }
306
307 static flxRecord *make_goodbye_record(flxRecord *r) {
308     gchar *t;
309     flxRecord *g;
310     
311     g_assert(r);
312
313     g_message("Preparing goodbye for record [%s]", t = flx_record_to_string(r));
314     g_free(t);
315
316     g = flx_record_copy(r);
317     g_assert(g->ref == 1);
318     g->ttl = 0;
319
320     return g;
321 }
322
323 static void send_goodbye_callback(flxInterfaceMonitor *m, flxInterface *i, gpointer userdata) {
324     flxEntry *e = userdata;
325     flxRecord *g;
326     
327     g_assert(m);
328     g_assert(i);
329     g_assert(e);
330     g_assert(!e->dead);
331
332     if (!flx_interface_match(i, e->interface, e->protocol))
333         return;
334
335     if (e->flags & FLX_ENTRY_NOANNOUNCE)
336         return;
337
338     if (!flx_entry_registered(m->server, e, i))
339         return;
340     
341     g = make_goodbye_record(e->record);
342     flx_interface_post_response(i, NULL, g, e->flags & FLX_ENTRY_UNIQUE, TRUE);
343     flx_record_unref(g);
344 }
345     
346 void flx_goodbye_interface(flxServer *s, flxInterface *i, gboolean goodbye) {
347     g_assert(s);
348     g_assert(i);
349
350     g_message("goodbye interface: %s.%u", i->hardware->name, i->protocol);
351
352     if (goodbye && flx_interface_relevant(i)) {
353         flxEntry *e;
354         
355         for (e = s->entries; e; e = e->entries_next)
356             if (!e->dead)
357                 send_goodbye_callback(s->monitor, i, e);
358     }
359
360     while (i->announcements)
361         remove_announcement(s, i->announcements);
362
363     g_message("goodbye interface done: %s.%u", i->hardware->name, i->protocol);
364
365 }
366
367 void flx_goodbye_entry(flxServer *s, flxEntry *e, gboolean goodbye) {
368     g_assert(s);
369     g_assert(e);
370     g_assert(!e->dead);
371     
372     g_message("goodbye entry: %p", e);
373     
374     if (goodbye)
375         flx_interface_monitor_walk(s->monitor, 0, AF_UNSPEC, send_goodbye_callback, e);
376
377     while (e->announcements)
378         remove_announcement(s, e->announcements);
379
380     g_message("goodbye entry done: %p", e);
381
382 }
383
384 void flx_goodbye_all(flxServer *s, gboolean goodbye) {
385     flxEntry *e;
386     
387     g_assert(s);
388
389     g_message("goodbye all");
390
391     for (e = s->entries; e; e = e->entries_next)
392         if (!e->dead)
393             flx_goodbye_entry(s, e, goodbye);
394
395     g_message("goodbye all done");
396
397 }
398