]> git.meshlink.io Git - catta/blob - avahi-core/resolve-address.c
* drop AVAHI_RESOLVER_TIMEOUT, AVAHI_RESOLVER_NOT_FOUND and AVAHI_BROWSER_NOT_FOUND...
[catta] / avahi-core / resolve-address.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
32 #define TIMEOUT_MSEC 5000
33
34 struct AvahiSAddressResolver {
35     AvahiServer *server;
36     AvahiAddress address;
37     
38     AvahiSRecordBrowser *record_browser;
39
40     AvahiSAddressResolverCallback callback;
41     void* userdata;
42
43     AvahiRecord *ptr_record;
44     AvahiIfIndex interface;
45     AvahiProtocol protocol;
46     AvahiLookupResultFlags flags;
47
48     int retry_with_multicast;
49     AvahiKey *key;
50
51     AvahiTimeEvent *time_event;
52
53     AVAHI_LLIST_FIELDS(AvahiSAddressResolver, resolver);
54 };
55
56 static void finish(AvahiSAddressResolver *r, AvahiResolverEvent event) {
57     assert(r);
58     
59     if (r->time_event) {
60         avahi_time_event_free(r->time_event);
61         r->time_event = NULL;
62     }
63
64     switch (event) {
65         case AVAHI_RESOLVER_FAILURE:
66             r->callback(r, r->interface, r->protocol, event, &r->address, NULL, r->flags, r->userdata);
67             break;
68
69         case AVAHI_RESOLVER_FOUND:
70             assert(r->ptr_record);
71             r->callback(r, r->interface, r->protocol, event, &r->address, r->ptr_record->data.ptr.name, r->flags, r->userdata);
72             break;
73     }
74 }
75
76 static void time_event_callback(AvahiTimeEvent *e, void *userdata) {
77     AvahiSAddressResolver *r = userdata;
78     
79     assert(e);
80     assert(r);
81
82     avahi_server_set_errno(r->server, AVAHI_ERR_TIMEOUT);
83     finish(r, AVAHI_RESOLVER_FAILURE);
84 }
85
86 static void start_timeout(AvahiSAddressResolver *r) {
87     struct timeval tv;
88     assert(r);
89
90     if (r->time_event)
91         return;
92
93     avahi_elapse_time(&tv, TIMEOUT_MSEC, 0);
94     r->time_event = avahi_time_event_new(r->server->time_event_queue, &tv, time_event_callback, r);
95 }
96
97 static void record_browser_callback(
98     AvahiSRecordBrowser*rr,
99     AvahiIfIndex interface,
100     AvahiProtocol protocol,
101     AvahiBrowserEvent event,
102     AvahiRecord *record,
103     AvahiLookupResultFlags flags,
104     void* userdata) {
105     
106     AvahiSAddressResolver *r = userdata;
107
108     assert(rr);
109     assert(r);
110
111
112     switch (event) {
113         case AVAHI_BROWSER_NEW: 
114             assert(record);
115             assert(record->key->type == AVAHI_DNS_TYPE_PTR);
116             
117             if (r->interface > 0 && interface != r->interface)
118                 return;
119             
120             if (r->protocol != AVAHI_PROTO_UNSPEC && protocol != r->protocol)
121                 return;
122             
123             if (r->interface <= 0)
124                 r->interface = interface;
125             
126             if (r->protocol == AVAHI_PROTO_UNSPEC)
127                 r->protocol = protocol;
128             
129             if (!r->ptr_record) {
130                 r->ptr_record = avahi_record_ref(record);
131                 r->flags = flags;
132                 
133                 finish(r, AVAHI_RESOLVER_FOUND);
134             }
135             break;
136             
137         case AVAHI_BROWSER_REMOVE:
138             assert(record);
139             assert(record->key->type == AVAHI_DNS_TYPE_PTR);
140             
141             if (r->ptr_record && avahi_record_equal_no_ttl(record, r->ptr_record)) {
142                 avahi_record_unref(r->ptr_record);
143                 r->ptr_record = NULL;
144                 r->flags = flags;
145                 
146                 /** Look for a replacement */
147                 avahi_s_record_browser_restart(r->record_browser);
148                 start_timeout(r);
149             }
150
151             break;
152             
153         case AVAHI_BROWSER_CACHE_EXHAUSTED:
154         case AVAHI_BROWSER_ALL_FOR_NOW:
155             break;
156
157         case AVAHI_BROWSER_FAILURE:
158
159             if (r->retry_with_multicast) {
160                 r->retry_with_multicast = 0;
161
162                 avahi_s_record_browser_free(r->record_browser);
163                 r->record_browser = avahi_s_record_browser_new(r->server, r->interface, r->protocol, r->key, AVAHI_LOOKUP_USE_MULTICAST, record_browser_callback, r);
164
165                 if (r->record_browser) {
166                     start_timeout(r);
167                     break;
168                 }
169             }
170
171             r->flags = flags;
172             finish(r, AVAHI_RESOLVER_FAILURE);
173             break;
174     }
175 }
176
177 AvahiSAddressResolver *avahi_s_address_resolver_new(
178     AvahiServer *server,
179     AvahiIfIndex interface,
180     AvahiProtocol protocol,
181     const AvahiAddress *address,
182     AvahiLookupFlags flags,
183     AvahiSAddressResolverCallback callback,
184     void* userdata) {
185     
186     AvahiSAddressResolver *r;
187     AvahiKey *k;
188     char *n;
189
190     assert(server);
191     assert(address);
192     assert(callback);
193
194     assert(address->proto == AVAHI_PROTO_INET || address->proto == AVAHI_PROTO_INET6);
195
196     if (!AVAHI_IF_VALID(interface)) {
197         avahi_server_set_errno(server, AVAHI_ERR_INVALID_INTERFACE);
198         return NULL;
199     }
200
201     if (!AVAHI_FLAGS_VALID(flags, AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_MULTICAST)) {
202         avahi_server_set_errno(server, AVAHI_ERR_INVALID_FLAGS);
203         return NULL;
204     }
205
206     if (address->proto == AVAHI_PROTO_INET)
207         n = avahi_reverse_lookup_name_ipv4(&address->data.ipv4);
208     else 
209         n = avahi_reverse_lookup_name_ipv6_arpa(&address->data.ipv6);
210
211     if (!n) {
212         avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
213         return NULL;
214     }
215
216     k = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_PTR);
217     avahi_free(n);
218
219     if (!k) {
220         avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
221         return NULL;
222     }
223
224     if (!(r = avahi_new(AvahiSAddressResolver, 1))) {
225         avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
226         avahi_key_unref(k);
227         return NULL;
228     }
229     
230     r->server = server;
231     r->address = *address;
232     r->callback = callback;
233     r->userdata = userdata;
234     r->ptr_record = NULL;
235     r->interface = interface;
236     r->protocol = protocol;
237     r->flags = 0;
238     r->retry_with_multicast = 0;
239     r->key = k;
240
241     r->record_browser = NULL;
242     AVAHI_LLIST_PREPEND(AvahiSAddressResolver, resolver, server->address_resolvers, r);
243
244     r->time_event = NULL;
245
246     if (!(flags & (AVAHI_LOOKUP_USE_MULTICAST|AVAHI_LOOKUP_USE_WIDE_AREA))) {
247
248         if (!server->wide_area_lookup_engine || !avahi_wide_area_has_servers(server->wide_area_lookup_engine))
249             flags |= AVAHI_LOOKUP_USE_MULTICAST;
250         else {
251             flags |= AVAHI_LOOKUP_USE_WIDE_AREA;
252             r->retry_with_multicast = 1;
253         }
254     }
255     
256     r->record_browser = avahi_s_record_browser_new(server, interface, protocol, k, flags, record_browser_callback, r);
257
258     if (!r->record_browser) {
259         avahi_s_address_resolver_free(r);
260         return NULL;
261     }
262
263     start_timeout(r);
264     
265     return r;
266 }
267
268 void avahi_s_address_resolver_free(AvahiSAddressResolver *r) {
269     assert(r);
270
271     AVAHI_LLIST_REMOVE(AvahiSAddressResolver, resolver, r->server->address_resolvers, r);
272
273     if (r->record_browser)
274         avahi_s_record_browser_free(r->record_browser);
275
276     if (r->time_event)
277         avahi_time_event_free(r->time_event);
278
279     if (r->ptr_record)
280         avahi_record_unref(r->ptr_record);
281
282     if (r->key)
283         avahi_key_unref(r->key);
284     
285     avahi_free(r);
286 }