]> git.meshlink.io Git - catta/blob - avahi-core/browse.c
add support for RR modification in service data
[catta] / avahi-core / browse.c
1 /* $Id$ */
2
3 /***
4   This file is part of avahi.
5  
6   avahi is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10  
11   avahi is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14   Public License for more details.
15  
16   You should have received a copy of the GNU Lesser General Public
17   License along with avahi; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <avahi-common/timeval.h>
27 #include <avahi-common/malloc.h>
28 #include <avahi-common/error.h>
29
30 #include "browse.h"
31 #include "log.h"
32
33 struct AvahiSRecordBrowser {
34     int dead;
35     
36     AvahiServer *server;
37     AvahiKey *key;
38     AvahiIfIndex interface;
39     AvahiProtocol protocol;
40     unsigned sec_delay;
41
42     AvahiTimeEvent *query_time_event;
43     AvahiTimeEvent *scan_time_event;
44
45     AvahiSRecordBrowserCallback callback;
46     void* userdata;
47
48     AVAHI_LLIST_FIELDS(AvahiSRecordBrowser, browser);
49     AVAHI_LLIST_FIELDS(AvahiSRecordBrowser, by_key);
50 };
51
52 static void elapse_callback(AvahiTimeEvent *e, void *userdata) {
53     AvahiSRecordBrowser *s = userdata;
54     struct timeval tv;
55 /*     char *t;  */
56     
57     assert(s);
58
59     avahi_server_post_query(s->server, s->interface, s->protocol, s->key);
60
61     s->sec_delay *= 2;
62     
63     if (s->sec_delay >= 60*60)  /* 1h */
64         s->sec_delay = 60*60;
65     
66 /*     avahi_log_debug("Continuous querying for %s (%i)", t = avahi_key_to_string(s->key), s->sec_delay);  */
67 /*     avahi_free(t);  */
68     
69     avahi_elapse_time(&tv, s->sec_delay*1000, 0);
70     avahi_time_event_update(s->query_time_event, &tv);
71 }
72
73 struct cbdata {
74     AvahiSRecordBrowser *record_browser;
75     AvahiInterface *interface;
76 };
77
78 static void* scan_cache_callback(AvahiCache *c, AvahiKey *pattern, AvahiCacheEntry *e, void* userdata) {
79     struct cbdata *cbdata = userdata;
80
81     assert(c);
82     assert(pattern);
83     assert(e);
84     assert(cbdata);
85
86     if (cbdata->record_browser->dead)
87         return NULL;
88
89     cbdata->record_browser->callback(
90         cbdata->record_browser,
91         cbdata->interface->hardware->index,
92         cbdata->interface->protocol,
93         AVAHI_BROWSER_NEW,
94         e->record,
95         cbdata->record_browser->userdata);
96
97     return NULL;
98 }
99
100 static void scan_interface_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, void* userdata) {
101     AvahiSRecordBrowser *b = userdata;
102     struct cbdata cbdata;
103
104     cbdata.record_browser = b;
105     cbdata.interface = i;
106
107     assert(m);
108     assert(i);
109     assert(b);
110
111     if (!b->dead)
112         avahi_cache_walk(i->cache, b->key, scan_cache_callback, &cbdata);
113 }
114
115 static void scan_callback(AvahiTimeEvent *e, void *userdata) {
116     AvahiSRecordBrowser *b = userdata;
117     assert(b);
118
119     /* Scan the caches */
120     if (!b->dead)
121         avahi_interface_monitor_walk(b->server->monitor, b->interface, b->protocol, scan_interface_callback, b);
122
123     if (b->scan_time_event) {
124         avahi_time_event_free(b->scan_time_event);
125         b->scan_time_event = NULL;
126     }
127 }
128
129 void avahi_s_record_browser_restart(AvahiSRecordBrowser *b) {
130     assert(b);
131
132     if (!b->scan_time_event) {
133         b->scan_time_event = avahi_time_event_new(b->server->time_event_queue, NULL, scan_callback, b);
134         assert(b->scan_time_event);
135     }
136
137     avahi_server_post_query(b->server, b->interface, b->protocol, b->key);
138 }
139
140 AvahiSRecordBrowser *avahi_s_record_browser_new(AvahiServer *server, AvahiIfIndex interface, AvahiProtocol protocol, AvahiKey *key, AvahiSRecordBrowserCallback callback, void* userdata) {
141     AvahiSRecordBrowser *b, *t;
142     struct timeval tv;
143
144     assert(server);
145     assert(key);
146     assert(callback);
147
148     if (avahi_key_is_pattern(key)) {
149         avahi_server_set_errno(server, AVAHI_ERR_IS_PATTERN);
150         return NULL;
151     }
152
153     if (!avahi_key_is_valid(key)) {
154         avahi_server_set_errno(server, AVAHI_ERR_INVALID_KEY);
155         return NULL;
156     }
157     
158     if (!(b = avahi_new(AvahiSRecordBrowser, 1))) {
159         avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
160         return NULL;
161     }
162     
163     b->dead = 0;
164     b->server = server;
165     b->key = avahi_key_ref(key);
166     b->interface = interface;
167     b->protocol = protocol;
168     b->callback = callback;
169     b->userdata = userdata;
170     b->sec_delay = 1;
171
172     avahi_server_post_query(b->server, b->interface, b->protocol, b->key);
173     
174     avahi_elapse_time(&tv, b->sec_delay*1000, 0);
175     b->query_time_event = avahi_time_event_new(server->time_event_queue, &tv, elapse_callback, b);
176
177     AVAHI_LLIST_PREPEND(AvahiSRecordBrowser, browser, server->record_browsers, b);
178
179     /* Add the new entry to the record_browser hash table */
180     t = avahi_hashmap_lookup(server->record_browser_hashmap, key);
181     AVAHI_LLIST_PREPEND(AvahiSRecordBrowser, by_key, t, b);
182     avahi_hashmap_replace(server->record_browser_hashmap, key, t);
183
184     /* The currenlty cached entries are scanned a bit later */
185     b->scan_time_event = avahi_time_event_new(server->time_event_queue, NULL, scan_callback, b);
186     assert(b->scan_time_event);
187     return b;
188 }
189
190 void avahi_s_record_browser_free(AvahiSRecordBrowser *b) {
191     assert(b);
192     assert(!b->dead);
193
194     b->dead = 1;
195     b->server->need_browser_cleanup = 1;
196
197     if (b->query_time_event) {
198         avahi_time_event_free(b->query_time_event);
199         b->query_time_event = NULL;
200     }
201
202     if (b->scan_time_event) {
203         avahi_time_event_free(b->scan_time_event);
204         b->scan_time_event = NULL;
205     }
206 }
207
208 void avahi_s_record_browser_destroy(AvahiSRecordBrowser *b) {
209     AvahiSRecordBrowser *t;
210     
211     assert(b);
212     
213     AVAHI_LLIST_REMOVE(AvahiSRecordBrowser, browser, b->server->record_browsers, b);
214
215     t = avahi_hashmap_lookup(b->server->record_browser_hashmap, b->key);
216     AVAHI_LLIST_REMOVE(AvahiSRecordBrowser, by_key, t, b);
217     if (t)
218         avahi_hashmap_replace(b->server->record_browser_hashmap, t->key, t);
219     else
220         avahi_hashmap_remove(b->server->record_browser_hashmap, b->key);
221
222     if (b->query_time_event)
223         avahi_time_event_free(b->query_time_event);
224     if (b->scan_time_event)
225         avahi_time_event_free(b->scan_time_event);
226
227     avahi_key_unref(b->key);
228     
229     avahi_free(b);
230 }
231
232 void avahi_browser_cleanup(AvahiServer *server) {
233     AvahiSRecordBrowser *b;
234     AvahiSRecordBrowser *n;
235     
236     assert(server);
237
238     for (b = server->record_browsers; b; b = n) {
239         n = b->browser_next;
240         
241         if (b->dead)
242             avahi_s_record_browser_destroy(b);
243     }
244
245     server->need_browser_cleanup = 0;
246 }
247
248 void avahi_browser_notify(AvahiServer *server, AvahiInterface *i, AvahiRecord *record, AvahiBrowserEvent event) {
249     AvahiSRecordBrowser *b;
250     
251     assert(server);
252     assert(record);
253
254     for (b = avahi_hashmap_lookup(server->record_browser_hashmap, record->key); b; b = b->by_key_next)
255         if (!b->dead && avahi_interface_match(i, b->interface, b->protocol))
256                 b->callback(b, i->hardware->index, i->protocol, event, record, b->userdata);
257 }
258
259 int avahi_is_subscribed(AvahiServer *server, AvahiInterface *i, AvahiKey *k) {
260     AvahiSRecordBrowser *b;
261     assert(server);
262     assert(k);
263
264     for (b = avahi_hashmap_lookup(server->record_browser_hashmap, k); b; b = b->by_key_next)
265         if (!b->dead && avahi_interface_match(i, b->interface, b->protocol))
266             return 1;
267
268     return 0;
269 }
270
271 void avahi_browser_new_interface(AvahiServer*s, AvahiInterface *i) {
272     AvahiSRecordBrowser *b;
273     
274     assert(s);
275     assert(i);
276     
277     for (b = s->record_browsers; b; b = b->browser_next)
278         if (avahi_interface_match(i, b->interface, b->protocol))
279             avahi_interface_post_query(i, b->key, 0);
280 }