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