4 This file is part of avahi.
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.
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.
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
28 #include <avahi-common/domain.h>
29 #include <avahi-common/timeval.h>
32 struct AvahiServiceResolver {
37 AvahiProtocol address_protocol;
39 AvahiIfIndex interface;
40 AvahiProtocol protocol;
42 AvahiRecordBrowser *record_browser_srv;
43 AvahiRecordBrowser *record_browser_txt;
44 AvahiRecordBrowser *record_browser_a;
45 AvahiRecordBrowser *record_browser_aaaa;
47 AvahiRecord *srv_record, *txt_record, *address_record;
49 AvahiServiceResolverCallback callback;
52 AvahiTimeEvent *time_event;
54 AVAHI_LLIST_FIELDS(AvahiServiceResolver, resolver);
57 static void finish(AvahiServiceResolver *r, AvahiResolverEvent event) {
60 if (r->record_browser_a) {
61 avahi_record_browser_free(r->record_browser_a);
62 r->record_browser_a = NULL;
65 if (r->record_browser_aaaa) {
66 avahi_record_browser_free(r->record_browser_aaaa);
67 r->record_browser_aaaa = NULL;
70 if (r->record_browser_srv) {
71 avahi_record_browser_free(r->record_browser_srv);
72 r->record_browser_srv = NULL;
75 if (r->record_browser_txt) {
76 avahi_record_browser_free(r->record_browser_txt);
77 r->record_browser_txt = NULL;
81 avahi_time_event_queue_remove(r->server->time_event_queue, r->time_event);
85 if (event == AVAHI_RESOLVER_TIMEOUT)
86 r->callback(r, r->interface, r->protocol, event, r->service_name, r->service_type, r->domain_name, NULL, NULL, 0, NULL, r->userdata);
89 gchar sn[256], st[256];
92 g_assert(r->srv_record);
93 g_assert(r->txt_record);
94 g_assert(r->address_record);
96 switch (r->address_record->key->type) {
97 case AVAHI_DNS_TYPE_A:
98 a.family = AVAHI_PROTO_INET;
99 a.data.ipv4 = r->address_record->data.a.address;
102 case AVAHI_DNS_TYPE_AAAA:
103 a.family = AVAHI_PROTO_INET6;
104 a.data.ipv6 = r->address_record->data.aaaa.address;
111 g_snprintf(sn, sizeof(sn), r->service_name);
112 g_snprintf(st, sizeof(st), r->service_type);
114 if ((i = strlen(sn)) > 0 && sn[i-1] == '.')
117 if ((i = strlen(st)) > 0 && st[i-1] == '.')
120 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 static void record_browser_callback(AvahiRecordBrowser*rr, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, AvahiRecord *record, gpointer userdata) {
126 AvahiServiceResolver *r = userdata;
132 if (!(event == AVAHI_BROWSER_NEW))
135 if (r->interface > 0 && interface != r->interface)
138 if (r->protocol != AVAHI_PROTO_UNSPEC && protocol != r->protocol)
141 if (r->interface <= 0)
142 r->interface = interface;
144 if (r->protocol == AVAHI_PROTO_UNSPEC)
145 r->protocol = protocol;
147 switch (record->key->type) {
148 case AVAHI_DNS_TYPE_SRV:
149 if (!r->srv_record) {
150 r->srv_record = avahi_record_ref(record);
152 g_assert(!r->record_browser_a && !r->record_browser_aaaa);
154 if (r->address_protocol == AVAHI_PROTO_INET || r->address_protocol == AVAHI_PROTO_UNSPEC) {
155 AvahiKey *k = avahi_key_new(r->srv_record->data.srv.name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_A);
156 r->record_browser_a = avahi_record_browser_new(r->server, r->interface, r->protocol, k, record_browser_callback, r);
160 if (r->address_protocol == AVAHI_PROTO_INET6 || r->address_protocol == AVAHI_PROTO_UNSPEC) {
161 AvahiKey *k = avahi_key_new(r->srv_record->data.srv.name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA);
162 r->record_browser_aaaa = avahi_record_browser_new(r->server, r->interface, r->protocol, k, record_browser_callback, r);
168 case AVAHI_DNS_TYPE_TXT:
170 r->txt_record = avahi_record_ref(record);
173 case AVAHI_DNS_TYPE_A:
174 case AVAHI_DNS_TYPE_AAAA:
175 if (!r->address_record)
176 r->address_record = avahi_record_ref(record);
183 if (r->txt_record && r->srv_record && r->address_record)
184 finish(r, AVAHI_RESOLVER_FOUND);
187 static void time_event_callback(AvahiTimeEvent *e, void *userdata) {
188 AvahiServiceResolver *r = userdata;
193 finish(r, AVAHI_RESOLVER_TIMEOUT);
196 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) {
197 AvahiServiceResolver *r;
208 g_assert(aprotocol == AVAHI_PROTO_UNSPEC || aprotocol == AVAHI_PROTO_INET || aprotocol == AVAHI_PROTO_INET6);
210 if (!avahi_valid_service_name(name)) {
211 avahi_server_set_errno(server, AVAHI_ERR_INVALID_SERVICE_NAME);
215 if (!avahi_valid_service_type(type)) {
216 avahi_server_set_errno(server, AVAHI_ERR_INVALID_SERVICE_TYPE);
220 if (!avahi_valid_domain_name(domain)) {
221 avahi_server_set_errno(server, AVAHI_ERR_INVALID_DOMAIN_NAME);
225 r = g_new(AvahiServiceResolver, 1);
227 r->service_name = g_strdup(name);
228 r->service_type = avahi_normalize_name(type);
229 r->domain_name = avahi_normalize_name(domain);
230 r->callback = callback;
231 r->userdata = userdata;
232 r->address_protocol = aprotocol;
233 r->srv_record = r->txt_record = r->address_record = NULL;
234 r->interface = interface;
235 r->protocol = protocol;
239 avahi_escape_label((const guint8*) name, strlen(name), &n, &l);
240 g_snprintf(n, l, ".%s.%s", r->service_type, r->domain_name);
242 avahi_elapse_time(&tv, 1000, 0);
243 r->time_event = avahi_time_event_queue_add(server->time_event_queue, &tv, time_event_callback, r);
245 AVAHI_LLIST_PREPEND(AvahiServiceResolver, resolver, server->service_resolvers, r);
247 r->record_browser_a = r->record_browser_aaaa = r->record_browser_srv = r->record_browser_txt = NULL;
249 k = avahi_key_new(t, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV);
250 r->record_browser_srv = avahi_record_browser_new(server, interface, protocol, k, record_browser_callback, r);
253 if (!r->record_browser_srv) {
254 avahi_service_resolver_free(r);
258 k = avahi_key_new(t, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_TXT);
259 r->record_browser_txt = avahi_record_browser_new(server, interface, protocol, k, record_browser_callback, r);
262 if (!r->record_browser_txt) {
263 avahi_service_resolver_free(r);
270 void avahi_service_resolver_free(AvahiServiceResolver *r) {
273 AVAHI_LLIST_REMOVE(AvahiServiceResolver, resolver, r->server->service_resolvers, r);
276 avahi_time_event_queue_remove(r->server->time_event_queue, r->time_event);
278 if (r->record_browser_srv)
279 avahi_record_browser_free(r->record_browser_srv);
280 if (r->record_browser_txt)
281 avahi_record_browser_free(r->record_browser_txt);
282 if (r->record_browser_a)
283 avahi_record_browser_free(r->record_browser_a);
284 if (r->record_browser_aaaa)
285 avahi_record_browser_free(r->record_browser_aaaa);
288 avahi_record_unref(r->srv_record);
290 avahi_record_unref(r->txt_record);
291 if (r->address_record)
292 avahi_record_unref(r->address_record);
294 g_free(r->service_name);
295 g_free(r->service_type);
296 g_free(r->domain_name);