]> git.meshlink.io Git - catta/blob - announce.c
add client part of known answer suppresion
[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     flxAnnouncement *a = userdata;
20     GTimeVal tv;
21     gchar *t;
22         
23     g_assert(e);
24     g_assert(a);
25
26     flx_interface_post_response(a->interface, a->entry->record, FALSE);
27
28     if (a->n_announced++ <= 8)
29         a->sec_delay *= 2;
30
31     g_message("Announcement #%i on interface %s.%i for entry [%s]", a->n_announced, a->interface->hardware->name, a->interface->protocol, t = flx_record_to_string(a->entry->record));
32     g_free(t);
33
34     if (a->n_announced >= 4) {
35         g_message("Enough announcements for record [%s]", t = flx_record_to_string(a->entry->record));
36         g_free(t);
37         remove_announcement(a->server, a);
38     } else { 
39         flx_elapse_time(&tv, a->sec_delay*1000, FLX_ANNOUNCEMENT_JITTER_MSEC);
40         flx_time_event_queue_update(a->server->time_event_queue, a->time_event, &tv);
41     }
42 }
43
44 static void new_announcement(flxServer *s, flxInterface *i, flxServerEntry *e) {
45     flxAnnouncement *a;
46     GTimeVal tv;
47     gchar *t;
48
49     g_assert(s);
50     g_assert(i);
51     g_assert(e);
52
53     g_message("NEW ANNOUNCEMENT: %s.%i [%s]", i->hardware->name, i->protocol, t = flx_record_to_string(e->record));
54     g_free(t);
55     
56     if (!flx_interface_match(i, e->interface, e->protocol) || !i->announcing)
57         return;
58
59     /* We don't want duplicates */
60     for (a = e->announcements; a; a = a->by_entry_next)
61         if (a->interface == i)
62             return;
63     
64     g_message("New announcement on interface %s.%i for entry [%s]", i->hardware->name, i->protocol, t = flx_record_to_string(e->record));
65     g_free(t);
66     
67     flx_interface_post_response(i, e->record, FALSE);
68     
69     a = g_new(flxAnnouncement, 1);
70     a->server = s;
71     a->interface = i;
72     a->entry = e;
73     a->n_announced = 1;
74     a->sec_delay = 1;
75     
76     FLX_LLIST_PREPEND(flxAnnouncement, by_interface, i->announcements, a);
77     FLX_LLIST_PREPEND(flxAnnouncement, by_entry, e->announcements, a);
78     
79     flx_elapse_time(&tv, a->sec_delay*1000, FLX_ANNOUNCEMENT_JITTER_MSEC);
80     a->time_event = flx_time_event_queue_add(s->time_event_queue, &tv, elapse_announce, a);
81 }
82
83 void flx_announce_interface(flxServer *s, flxInterface *i) {
84     flxServerEntry *e;
85     
86     g_assert(s);
87     g_assert(i);
88
89     if (!i->announcing)
90         return;
91
92     g_message("ANNOUNCE INTERFACE");
93     
94     for (e = s->entries; e; e = e->entry_next)
95         new_announcement(s, i, e);
96 }
97
98 static void announce_walk_callback(flxInterfaceMonitor *m, flxInterface *i, gpointer userdata) {
99     flxServerEntry *e = userdata;
100     
101     g_assert(m);
102     g_assert(i);
103     g_assert(e);
104
105     new_announcement(m->server, i, e);
106 }
107
108 void flx_announce_entry(flxServer *s, flxServerEntry *e) {
109     g_assert(s);
110     g_assert(e);
111
112     g_message("ANNOUNCE ENTRY");
113
114     flx_interface_monitor_walk(s->monitor, e->interface, e->protocol, announce_walk_callback, e);
115 }
116
117 static flxRecord *make_goodbye_record(flxRecord *r) {
118     gchar *t;
119     
120     g_assert(r);
121
122     g_message("Preparing goodbye for record [%s]", t = flx_record_to_string(r));
123     g_free(t);
124
125     return flx_record_new(r->key, r->data, r->size, 0);
126 }
127     
128 void flx_goodbye_interface(flxServer *s, flxInterface *i, gboolean goodbye) {
129     g_assert(s);
130     g_assert(i);
131
132     while (i->announcements)
133         remove_announcement(s, i->announcements);
134
135     if (goodbye && flx_interface_relevant(i)) {
136         flxServerEntry *e;
137         
138         for (e = s->entries; e; e = e->entry_next)
139             if (flx_interface_match(i, e->interface, e->protocol)) {
140                 flxRecord *g = make_goodbye_record(e->record);
141                 flx_interface_post_response(i, g, TRUE);
142                 flx_record_unref(g);
143             }
144     }
145 }
146
147 void flx_goodbye_entry(flxServer *s, flxServerEntry *e, gboolean goodbye) {
148     g_assert(s);
149     g_assert(e);
150     
151     while (e->announcements)
152         remove_announcement(s, e->announcements);
153     
154     if (goodbye) {
155         flxRecord *g = make_goodbye_record(e->record);
156         flx_server_post_response(s, e->interface, e->protocol, g);
157         flx_record_unref(g);
158     }
159 }
160
161 void flx_goodbye_all(flxServer *s, gboolean goodbye) {
162     flxServerEntry *e;
163     
164     g_assert(s);
165
166     for (e = s->entries; e; e = e->entry_next)
167         flx_goodbye_entry(s, e, goodbye);
168 }