]> git.meshlink.io Git - catta/blob - avahi-core/resolve-address.c
in order to reduce our code/API size, drop support for reverse IPv6 name lookups...
[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     switch (event) {
112         case AVAHI_BROWSER_NEW: 
113             assert(record);
114             assert(record->key->type == AVAHI_DNS_TYPE_PTR);
115             
116             if (r->interface > 0 && interface != r->interface)
117                 return;
118             
119             if (r->protocol != AVAHI_PROTO_UNSPEC && protocol != r->protocol)
120                 return;
121             
122             if (r->interface <= 0)
123                 r->interface = interface;
124             
125             if (r->protocol == AVAHI_PROTO_UNSPEC)
126                 r->protocol = protocol;
127             
128             if (!r->ptr_record) {
129                 r->ptr_record = avahi_record_ref(record);
130                 r->flags = flags;
131                 
132                 finish(r, AVAHI_RESOLVER_FOUND);
133             }
134             break;
135             
136         case AVAHI_BROWSER_REMOVE:
137             assert(record);
138             assert(record->key->type == AVAHI_DNS_TYPE_PTR);
139             
140             if (r->ptr_record && avahi_record_equal_no_ttl(record, r->ptr_record)) {
141                 avahi_record_unref(r->ptr_record);
142                 r->ptr_record = NULL;
143                 r->flags = flags;
144                 
145                 /** Look for a replacement */
146                 avahi_s_record_browser_restart(r->record_browser);
147                 start_timeout(r);
148             }
149
150             break;
151             
152         case AVAHI_BROWSER_CACHE_EXHAUSTED:
153         case AVAHI_BROWSER_ALL_FOR_NOW:
154             break;
155
156         case AVAHI_BROWSER_FAILURE:
157
158             if (r->retry_with_multicast) {
159                 r->retry_with_multicast = 0;
160
161                 avahi_s_record_browser_free(r->record_browser);
162                 r->record_browser = avahi_s_record_browser_new(r->server, r->interface, r->protocol, r->key, AVAHI_LOOKUP_USE_MULTICAST, record_browser_callback, r);
163
164                 if (r->record_browser) {
165                     start_timeout(r);
166                     break;
167                 }
168             }
169
170             r->flags = flags;
171             finish(r, AVAHI_RESOLVER_FAILURE);
172             break;
173     }
174 }
175
176 AvahiSAddressResolver *avahi_s_address_resolver_new(
177     AvahiServer *server,
178     AvahiIfIndex interface,
179     AvahiProtocol protocol,
180     const AvahiAddress *address,
181     AvahiLookupFlags flags,
182     AvahiSAddressResolverCallback callback,
183     void* userdata) {
184     
185     AvahiSAddressResolver *r;
186     AvahiKey *k;
187     char *n;
188
189     assert(server);
190     assert(address);
191     assert(callback);
192
193     assert(address->proto == AVAHI_PROTO_INET || address->proto == AVAHI_PROTO_INET6);
194
195     if (!AVAHI_IF_VALID(interface)) {
196         avahi_server_set_errno(server, AVAHI_ERR_INVALID_INTERFACE);
197         return NULL;
198     }
199
200     if (!AVAHI_FLAGS_VALID(flags, AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_MULTICAST)) {
201         avahi_server_set_errno(server, AVAHI_ERR_INVALID_FLAGS);
202         return NULL;
203     }
204
205     if (address->proto == AVAHI_PROTO_INET)
206         n = avahi_reverse_lookup_name_ipv4(&address->data.ipv4);
207     else 
208         n = avahi_reverse_lookup_name_ipv6(&address->data.ipv6);
209
210     if (!n) {
211         avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
212         return NULL;
213     }
214
215     k = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_PTR);
216     avahi_free(n);
217
218     if (!k) {
219         avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
220         return NULL;
221     }
222
223     if (!(r = avahi_new(AvahiSAddressResolver, 1))) {
224         avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
225         avahi_key_unref(k);
226         return NULL;
227     }
228     
229     r->server = server;
230     r->address = *address;
231     r->callback = callback;
232     r->userdata = userdata;
233     r->ptr_record = NULL;
234     r->interface = interface;
235     r->protocol = protocol;
236     r->flags = 0;
237     r->retry_with_multicast = 0;
238     r->key = k;
239
240     r->record_browser = NULL;
241     AVAHI_LLIST_PREPEND(AvahiSAddressResolver, resolver, server->address_resolvers, r);
242
243     r->time_event = NULL;
244
245     if (!(flags & (AVAHI_LOOKUP_USE_MULTICAST|AVAHI_LOOKUP_USE_WIDE_AREA))) {
246
247         if (!server->wide_area_lookup_engine || !avahi_wide_area_has_servers(server->wide_area_lookup_engine))
248             flags |= AVAHI_LOOKUP_USE_MULTICAST;
249         else {
250             flags |= AVAHI_LOOKUP_USE_WIDE_AREA;
251             r->retry_with_multicast = 1;
252         }
253     }
254     
255     r->record_browser = avahi_s_record_browser_new(server, interface, protocol, k, flags, record_browser_callback, r);
256
257     if (!r->record_browser) {
258         avahi_s_address_resolver_free(r);
259         return NULL;
260     }
261
262     start_timeout(r);
263     
264     return r;
265 }
266
267 void avahi_s_address_resolver_free(AvahiSAddressResolver *r) {
268     assert(r);
269
270     AVAHI_LLIST_REMOVE(AvahiSAddressResolver, resolver, r->server->address_resolvers, r);
271
272     if (r->record_browser)
273         avahi_s_record_browser_free(r->record_browser);
274
275     if (r->time_event)
276         avahi_time_event_free(r->time_event);
277
278     if (r->ptr_record)
279         avahi_record_unref(r->ptr_record);
280
281     if (r->key)
282         avahi_key_unref(r->key);
283     
284     avahi_free(r);
285 }