]> git.meshlink.io Git - catta/blob - avahi-core/browse.c
* Add avahi-client examples to doxygen
[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 AvahiSRecordBrowser *avahi_s_record_browser_new(AvahiServer *server, AvahiIfIndex interface, AvahiProtocol protocol, AvahiKey *key, AvahiSRecordBrowserCallback callback, void* userdata) {
130     AvahiSRecordBrowser *b, *t;
131     struct timeval tv;
132
133     assert(server);
134     assert(key);
135     assert(callback);
136
137     if (avahi_key_is_pattern(key)) {
138         avahi_server_set_errno(server, AVAHI_ERR_IS_PATTERN);
139         return NULL;
140     }
141
142     if (!avahi_key_is_valid(key)) {
143         avahi_server_set_errno(server, AVAHI_ERR_INVALID_KEY);
144         return NULL;
145     }
146     
147     if (!(b = avahi_new(AvahiSRecordBrowser, 1))) {
148         avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
149         return NULL;
150     }
151     
152     b->dead = 0;
153     b->server = server;
154     b->key = avahi_key_ref(key);
155     b->interface = interface;
156     b->protocol = protocol;
157     b->callback = callback;
158     b->userdata = userdata;
159     b->sec_delay = 1;
160
161     avahi_server_post_query(b->server, b->interface, b->protocol, b->key);
162     
163     avahi_elapse_time(&tv, b->sec_delay*1000, 0);
164     b->query_time_event = avahi_time_event_new(server->time_event_queue, &tv, elapse_callback, b);
165
166     AVAHI_LLIST_PREPEND(AvahiSRecordBrowser, browser, server->record_browsers, b);
167
168     /* Add the new entry to the record_browser hash table */
169     t = avahi_hashmap_lookup(server->record_browser_hashmap, key);
170     AVAHI_LLIST_PREPEND(AvahiSRecordBrowser, by_key, t, b);
171     avahi_hashmap_replace(server->record_browser_hashmap, key, t);
172
173     /* The currenlty cached entries are scanned a bit later */
174     b->scan_time_event = avahi_time_event_new(server->time_event_queue, NULL, scan_callback, b);
175     assert(b->scan_time_event);
176     return b;
177 }
178
179 void avahi_s_record_browser_free(AvahiSRecordBrowser *b) {
180     assert(b);
181     assert(!b->dead);
182
183     b->dead = 1;
184     b->server->need_browser_cleanup = 1;
185
186     if (b->query_time_event) {
187         avahi_time_event_free(b->query_time_event);
188         b->query_time_event = NULL;
189     }
190
191     if (b->scan_time_event) {
192         avahi_time_event_free(b->scan_time_event);
193         b->scan_time_event = NULL;
194     }
195 }
196
197 void avahi_s_record_browser_destroy(AvahiSRecordBrowser *b) {
198     AvahiSRecordBrowser *t;
199     
200     assert(b);
201     
202     AVAHI_LLIST_REMOVE(AvahiSRecordBrowser, browser, b->server->record_browsers, b);
203
204     t = avahi_hashmap_lookup(b->server->record_browser_hashmap, b->key);
205     AVAHI_LLIST_REMOVE(AvahiSRecordBrowser, by_key, t, b);
206     if (t)
207         avahi_hashmap_replace(b->server->record_browser_hashmap, t->key, t);
208     else
209         avahi_hashmap_remove(b->server->record_browser_hashmap, b->key);
210
211     if (b->query_time_event)
212         avahi_time_event_free(b->query_time_event);
213     if (b->scan_time_event)
214         avahi_time_event_free(b->scan_time_event);
215
216     avahi_key_unref(b->key);
217     
218     avahi_free(b);
219 }
220
221 void avahi_browser_cleanup(AvahiServer *server) {
222     AvahiSRecordBrowser *b;
223     AvahiSRecordBrowser *n;
224     
225     assert(server);
226
227     for (b = server->record_browsers; b; b = n) {
228         n = b->browser_next;
229         
230         if (b->dead)
231             avahi_s_record_browser_destroy(b);
232     }
233
234     server->need_browser_cleanup = 0;
235 }
236
237 void avahi_browser_notify(AvahiServer *server, AvahiInterface *i, AvahiRecord *record, AvahiBrowserEvent event) {
238     AvahiSRecordBrowser *b;
239     
240     assert(server);
241     assert(record);
242
243     for (b = avahi_hashmap_lookup(server->record_browser_hashmap, record->key); b; b = b->by_key_next)
244         if (!b->dead && avahi_interface_match(i, b->interface, b->protocol))
245                 b->callback(b, i->hardware->index, i->protocol, event, record, b->userdata);
246 }
247
248 int avahi_is_subscribed(AvahiServer *server, AvahiInterface *i, AvahiKey *k) {
249     AvahiSRecordBrowser *b;
250     assert(server);
251     assert(k);
252
253     for (b = avahi_hashmap_lookup(server->record_browser_hashmap, k); b; b = b->by_key_next)
254         if (!b->dead && avahi_interface_match(i, b->interface, b->protocol))
255             return 1;
256
257     return 0;
258 }
259
260 void avahi_browser_new_interface(AvahiServer*s, AvahiInterface *i) {
261     AvahiSRecordBrowser *b;
262     
263     assert(s);
264     assert(i);
265     
266     for (b = s->record_browsers; b; b = b->browser_next)
267         if (avahi_interface_match(i, b->interface, b->protocol))
268             avahi_interface_post_query(i, b->key, 0);
269 }