]> git.meshlink.io Git - catta/blob - avahi-core/resolve-service.c
* Add avahi-client examples to doxygen
[catta] / avahi-core / resolve-service.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 <string.h>
27 #include <stdio.h>
28
29 #include <avahi-common/domain.h>
30 #include <avahi-common/timeval.h>
31 #include <avahi-common/malloc.h>
32 #include <avahi-common/error.h>
33
34 #include "browse.h"
35
36 struct AvahiSServiceResolver {
37     AvahiServer *server;
38     char *service_name;
39     char *service_type;
40     char *domain_name;
41     AvahiProtocol address_protocol;
42
43     AvahiIfIndex interface;
44     AvahiProtocol protocol;
45
46     AvahiSRecordBrowser *record_browser_srv;
47     AvahiSRecordBrowser *record_browser_txt;
48     AvahiSRecordBrowser *record_browser_a;
49     AvahiSRecordBrowser *record_browser_aaaa;
50
51     AvahiRecord *srv_record, *txt_record, *address_record;
52     
53     AvahiSServiceResolverCallback callback;
54     void* userdata;
55
56     AvahiTimeEvent *time_event;
57
58     AVAHI_LLIST_FIELDS(AvahiSServiceResolver, resolver);
59 };
60
61 static void finish(AvahiSServiceResolver *r, AvahiResolverEvent event) {
62     assert(r);
63
64     if (r->record_browser_a) {
65         avahi_s_record_browser_free(r->record_browser_a);
66         r->record_browser_a = NULL;
67     }
68
69     if (r->record_browser_aaaa) {
70         avahi_s_record_browser_free(r->record_browser_aaaa);
71         r->record_browser_aaaa = NULL;
72     }
73
74     if (r->record_browser_srv) {
75         avahi_s_record_browser_free(r->record_browser_srv);
76         r->record_browser_srv = NULL;
77     }
78
79     if (r->record_browser_txt) {
80         avahi_s_record_browser_free(r->record_browser_txt);
81         r->record_browser_txt = NULL;
82     }
83
84     if (r->time_event) {
85         avahi_time_event_free(r->time_event);
86         r->time_event = NULL;
87     }
88
89     if (event == AVAHI_RESOLVER_TIMEOUT)
90         r->callback(r, r->interface, r->protocol, event, r->service_name, r->service_type, r->domain_name, NULL, NULL, 0, NULL, r->userdata);
91     else {
92         AvahiAddress a;
93         char sn[256], st[256];
94         size_t i;
95         
96         assert(r->srv_record);
97         assert(r->txt_record);
98         assert(r->address_record);
99         
100         switch (r->address_record->key->type) {
101             case AVAHI_DNS_TYPE_A:
102                 a.family = AVAHI_PROTO_INET;
103                 a.data.ipv4 = r->address_record->data.a.address;
104                 break;
105                 
106             case AVAHI_DNS_TYPE_AAAA:
107                 a.family = AVAHI_PROTO_INET6;
108                 a.data.ipv6 = r->address_record->data.aaaa.address;
109                 break;
110                 
111             default:
112                 assert(0);
113         }
114
115         snprintf(sn, sizeof(sn), r->service_name);
116         snprintf(st, sizeof(st), r->service_type);
117
118         if ((i = strlen(sn)) > 0 && sn[i-1] == '.')
119             sn[i-1] = 0;
120
121         if ((i = strlen(st)) > 0 && st[i-1] == '.')
122             st[i-1] = 0;
123
124         r->callback(r, r->interface, r->protocol, event, sn, st, r->domain_name, r->srv_record->data.srv.name, &a, r->srv_record->data.srv.port, r->txt_record->data.txt.string_list, r->userdata);
125
126     }
127 }
128
129 static void record_browser_callback(AvahiSRecordBrowser*rr, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, AvahiRecord *record, void* userdata) {
130     AvahiSServiceResolver *r = userdata;
131
132     assert(rr);
133     assert(record);
134     assert(r);
135
136     if (!(event == AVAHI_BROWSER_NEW))
137         return;
138
139     if (r->interface > 0 && interface != r->interface)
140         return;
141
142     if (r->protocol != AVAHI_PROTO_UNSPEC && protocol != r->protocol)
143         return;
144     
145     if (r->interface <= 0)
146         r->interface = interface;
147
148     if (r->protocol == AVAHI_PROTO_UNSPEC)
149         r->protocol = protocol;
150     
151     switch (record->key->type) {
152         case AVAHI_DNS_TYPE_SRV:
153             if (!r->srv_record) {
154                 r->srv_record = avahi_record_ref(record);
155
156                 assert(!r->record_browser_a && !r->record_browser_aaaa);
157                 
158                 if (r->address_protocol == AVAHI_PROTO_INET || r->address_protocol == AVAHI_PROTO_UNSPEC) {
159                     AvahiKey *k = avahi_key_new(r->srv_record->data.srv.name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_A);
160                     r->record_browser_a = avahi_s_record_browser_new(r->server, r->interface, r->protocol, k, record_browser_callback, r);
161                     avahi_key_unref(k);
162                 } 
163                 
164                 if (r->address_protocol == AVAHI_PROTO_INET6 || r->address_protocol == AVAHI_PROTO_UNSPEC) {
165                     AvahiKey *k = avahi_key_new(r->srv_record->data.srv.name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA);
166                     r->record_browser_aaaa = avahi_s_record_browser_new(r->server, r->interface, r->protocol, k, record_browser_callback, r);
167                     avahi_key_unref(k);
168                 }
169             }
170             break;
171             
172         case AVAHI_DNS_TYPE_TXT:
173             if (!r->txt_record)
174                 r->txt_record = avahi_record_ref(record);
175             break;
176
177         case AVAHI_DNS_TYPE_A:
178         case AVAHI_DNS_TYPE_AAAA:
179             if (!r->address_record)
180                 r->address_record = avahi_record_ref(record);
181             break;
182             
183         default:
184             assert(0);
185     }
186
187     if (r->txt_record && r->srv_record && r->address_record)
188         finish(r, AVAHI_RESOLVER_FOUND);
189 }
190
191 static void time_event_callback(AvahiTimeEvent *e, void *userdata) {
192     AvahiSServiceResolver *r = userdata;
193     
194     assert(e);
195     assert(r);
196
197     finish(r, AVAHI_RESOLVER_TIMEOUT);
198 }
199
200 AvahiSServiceResolver *avahi_s_service_resolver_new(AvahiServer *server, AvahiIfIndex interface, AvahiProtocol protocol, const char *name, const char *type, const char *domain, AvahiProtocol aprotocol, AvahiSServiceResolverCallback callback, void* userdata) {
201     AvahiSServiceResolver *r;
202     AvahiKey *k;
203     struct timeval tv;
204     char t[256], *n;
205     size_t l;
206     
207     assert(server);
208     assert(name);
209     assert(type);
210     assert(callback);
211
212     assert(aprotocol == AVAHI_PROTO_UNSPEC || aprotocol == AVAHI_PROTO_INET || aprotocol == AVAHI_PROTO_INET6);
213
214     if (!avahi_is_valid_service_name(name)) {
215         avahi_server_set_errno(server, AVAHI_ERR_INVALID_SERVICE_NAME);
216         return NULL;
217     }
218
219     if (!avahi_is_valid_service_type(type)) {
220         avahi_server_set_errno(server, AVAHI_ERR_INVALID_SERVICE_TYPE);
221         return NULL;
222     }
223
224     if (!avahi_is_valid_domain_name(domain)) {
225         avahi_server_set_errno(server, AVAHI_ERR_INVALID_DOMAIN_NAME);
226         return NULL;
227     }
228     
229     if (!(r = avahi_new(AvahiSServiceResolver, 1))) {
230         avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
231         return NULL;
232     }
233     
234     r->server = server;
235     r->service_name = avahi_strdup(name);
236     r->service_type = avahi_normalize_name(type);
237     r->domain_name = avahi_normalize_name(domain);
238     r->callback = callback;
239     r->userdata = userdata;
240     r->address_protocol = aprotocol;
241     r->srv_record = r->txt_record = r->address_record = NULL;
242     r->interface = interface;
243     r->protocol = protocol;
244     
245     n = t;
246     l = sizeof(t);
247     avahi_escape_label((const uint8_t*) name, strlen(name), &n, &l);
248     snprintf(n, l, ".%s.%s", r->service_type, r->domain_name);
249
250     avahi_elapse_time(&tv, 1000, 0);
251     r->time_event = avahi_time_event_new(server->time_event_queue, &tv, time_event_callback, r);
252     
253     AVAHI_LLIST_PREPEND(AvahiSServiceResolver, resolver, server->service_resolvers, r);
254
255     r->record_browser_a = r->record_browser_aaaa = r->record_browser_srv = r->record_browser_txt = NULL;
256     
257     k = avahi_key_new(t, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV);
258     r->record_browser_srv = avahi_s_record_browser_new(server, interface, protocol, k, record_browser_callback, r);
259     avahi_key_unref(k);
260
261     if (!r->record_browser_srv) {
262         avahi_s_service_resolver_free(r);
263         return NULL;
264     }
265     
266     k = avahi_key_new(t, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_TXT);
267     r->record_browser_txt = avahi_s_record_browser_new(server, interface, protocol, k, record_browser_callback, r);
268     avahi_key_unref(k);
269
270     if (!r->record_browser_txt) {
271         avahi_s_service_resolver_free(r);
272         return NULL;
273     }
274
275     return r;
276 }
277
278 void avahi_s_service_resolver_free(AvahiSServiceResolver *r) {
279     assert(r);
280
281     AVAHI_LLIST_REMOVE(AvahiSServiceResolver, resolver, r->server->service_resolvers, r);
282
283     if (r->time_event)
284         avahi_time_event_free(r->time_event);
285     
286     if (r->record_browser_srv)
287         avahi_s_record_browser_free(r->record_browser_srv);
288     if (r->record_browser_txt)
289         avahi_s_record_browser_free(r->record_browser_txt);
290     if (r->record_browser_a)
291         avahi_s_record_browser_free(r->record_browser_a);
292     if (r->record_browser_aaaa)
293         avahi_s_record_browser_free(r->record_browser_aaaa);
294
295     if (r->srv_record)
296         avahi_record_unref(r->srv_record);
297     if (r->txt_record)
298         avahi_record_unref(r->txt_record);
299     if (r->address_record)
300         avahi_record_unref(r->address_record);
301     
302     avahi_free(r->service_name);
303     avahi_free(r->service_type);
304     avahi_free(r->domain_name);
305     avahi_free(r);
306 }