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