]> git.meshlink.io Git - catta/blob - avahi-client/resolver.c
f08ce77b455ff6e63c952ac0d835e941919aa4e0
[catta] / avahi-client / resolver.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 <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #include <dbus/dbus.h>
31
32 #include <avahi-client/client.h>
33 #include <avahi-common/dbus.h>
34 #include <avahi-common/llist.h>
35 #include <avahi-common/error.h>
36 #include <avahi-common/malloc.h>
37
38 #include "client.h"
39 #include "internal.h"
40
41 /* AvahiServiceResolver implementation */
42
43 DBusHandlerResult avahi_service_resolver_event (AvahiClient *client, AvahiResolverEvent event, DBusMessage *message) {
44     AvahiServiceResolver *r = NULL;
45     DBusError error;
46     const char *path;
47     AvahiStringList *strlst = NULL;
48
49     assert(client);
50     assert(message);
51     
52     dbus_error_init (&error);
53
54     if (!(path = dbus_message_get_path(message)))
55         goto fail;
56
57     for (r = client->service_resolvers; r; r = r->service_resolvers_next)
58         if (strcmp (r->path, path) == 0)
59             break;
60
61     if (!r)
62         goto fail;
63
64     if (event == AVAHI_RESOLVER_FOUND) {
65         int j;
66         int32_t interface, flags, protocol, aprotocol;
67         char *name, *type, *domain, *host, *address;
68         uint16_t port;
69         DBusMessageIter iter, sub;
70         AvahiAddress a;
71         
72         if (!dbus_message_get_args(
73                 message, &error,
74                 DBUS_TYPE_INT32, &interface,
75                 DBUS_TYPE_INT32, &protocol,
76                 DBUS_TYPE_STRING, &name,
77                 DBUS_TYPE_STRING, &type,
78                 DBUS_TYPE_STRING, &domain,
79                 DBUS_TYPE_STRING, &host,
80                 DBUS_TYPE_INT32, &aprotocol,
81                 DBUS_TYPE_STRING, &address,
82                 DBUS_TYPE_UINT16, &port,
83                 DBUS_TYPE_INVALID) ||
84             dbus_error_is_set (&error)) {
85             
86             fprintf(stderr, "Failed to parse resolver event.\n");
87             goto fail;
88         }
89         
90         dbus_message_iter_init(message, &iter);
91         
92         for (j = 0; j < 9; j++)
93             dbus_message_iter_next(&iter);
94         
95         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
96             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_ARRAY) {
97             fprintf(stderr, "Error parsing service resolving message\n");
98             goto fail;
99         }
100         
101         strlst = NULL;
102         dbus_message_iter_recurse(&iter, &sub);
103         
104         for (;;) {
105             DBusMessageIter sub2;
106             int at;
107             
108             if ((at = dbus_message_iter_get_arg_type(&sub)) == DBUS_TYPE_INVALID)
109                 break;
110             
111             assert(at == DBUS_TYPE_ARRAY);
112             
113             if (dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_BYTE) {
114                 fprintf(stderr, "Error parsing service resolving message\n");
115                 goto fail;
116             }
117             
118             dbus_message_iter_recurse(&sub, &sub2);
119
120             if (dbus_message_iter_get_array_len(&sub2) > 0) {
121                 uint8_t *k;
122                 int n;
123                 
124                 dbus_message_iter_get_fixed_array(&sub2, &k, &n);
125                 strlst = avahi_string_list_add_arbitrary(strlst, k, n);
126             }
127             
128             dbus_message_iter_next(&sub);
129         }
130
131         dbus_message_iter_next(&iter);
132
133         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
134             fprintf(stderr, "Failed to parse resolver event. XXX %i\n", dbus_message_iter_get_arg_type(&iter));
135             goto fail;
136         }
137
138         dbus_message_iter_get_basic(&iter, &flags);
139                                     
140         assert(address);
141         if (!avahi_address_parse(address, (AvahiProtocol) aprotocol, &a)) {
142             fprintf(stderr, "Failed to parse address\n");
143             goto fail;
144         }
145     
146         r->callback(r, (AvahiIfIndex) interface, (AvahiProtocol) protocol, AVAHI_RESOLVER_FOUND, name, type, domain, host, &a, port, strlst, (AvahiLookupResultFlags) flags, r->userdata);
147         
148         avahi_string_list_free(strlst);
149
150     } else
151         r->callback(r, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, event, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, r->userdata);
152
153     return DBUS_HANDLER_RESULT_HANDLED;
154
155     
156 fail:
157     dbus_error_free (&error);
158     avahi_string_list_free(strlst);
159     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
160 }
161
162
163 AvahiServiceResolver * avahi_service_resolver_new(
164     AvahiClient *client,
165     AvahiIfIndex interface,
166     AvahiProtocol protocol,
167     const char *name,
168     const char *type,
169     const char *domain,
170     AvahiProtocol aprotocol,
171     AvahiLookupFlags flags,
172     AvahiServiceResolverCallback callback,
173     void *userdata) {
174
175     DBusError error;
176     AvahiServiceResolver *r;
177     DBusMessage *message = NULL, *reply = NULL;
178     int32_t i_interface, i_protocol, i_aprotocol, i_flags;
179     char *path;
180     
181     assert(client);
182     assert(type);
183
184     if (!domain)
185         domain = "";
186
187     if (!name)
188         name = "";
189     
190     dbus_error_init (&error);
191
192     if (client->state == AVAHI_CLIENT_DISCONNECTED) {
193         avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
194         goto fail;
195     }
196
197     if (!(r = avahi_new(AvahiServiceResolver, 1))) {
198         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
199         goto fail;
200     }
201
202     r->client = client;
203     r->callback = callback;
204     r->userdata = userdata;
205     r->path = NULL;
206     
207     AVAHI_LLIST_PREPEND(AvahiServiceResolver, service_resolvers, client->service_resolvers, r);
208
209     if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "ServiceResolverNew"))) {
210         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
211         goto fail;
212     }
213
214     i_interface = (int32_t) interface;
215     i_protocol = (int32_t) protocol;
216     i_aprotocol = (int32_t) aprotocol;
217     i_flags = (int32_t) flags;
218
219     if (!(dbus_message_append_args(
220               message,
221               DBUS_TYPE_INT32, &i_interface,
222               DBUS_TYPE_INT32, &i_protocol,
223               DBUS_TYPE_STRING, &name,
224               DBUS_TYPE_STRING, &type,
225               DBUS_TYPE_STRING, &domain,
226               DBUS_TYPE_INT32, &i_aprotocol,
227               DBUS_TYPE_INT32, &i_flags,
228               DBUS_TYPE_INVALID))) {
229         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
230         goto fail;
231     }
232
233     if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
234         dbus_error_is_set(&error)) {
235         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
236         goto fail;
237     }
238
239     if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) ||
240         dbus_error_is_set(&error) ||
241         !path) {
242         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
243         goto fail;
244     }
245
246     if (!(r->path = avahi_strdup(path))) {
247
248         /* FIXME: We don't remove the object on the server side */
249
250         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
251         goto fail;
252     }
253         
254
255     dbus_message_unref(message);
256     dbus_message_unref(reply);
257
258     return r;
259     
260 fail:
261
262     if (dbus_error_is_set(&error)) {
263         avahi_client_set_dbus_error(client, &error);
264         dbus_error_free(&error);
265     }
266
267     if (r)
268         avahi_service_resolver_free(r);
269     
270     if (message)
271         dbus_message_unref(message);
272
273     if (reply)
274         dbus_message_unref(reply);
275     
276     return NULL;
277
278 }
279
280 AvahiClient* avahi_service_resolver_get_client (AvahiServiceResolver *r) {
281     assert (r);
282
283     return r->client;
284 }
285
286 int avahi_service_resolver_free(AvahiServiceResolver *r) {
287     AvahiClient *client;
288     int ret = AVAHI_OK;
289
290     assert(r);
291     client = r->client;
292
293     if (r->path && client->state != AVAHI_CLIENT_DISCONNECTED)
294         ret = avahi_client_simple_method_call(client, r->path, AVAHI_DBUS_INTERFACE_SERVICE_RESOLVER, "Free");
295
296     AVAHI_LLIST_REMOVE(AvahiServiceResolver, service_resolvers, client->service_resolvers, r);
297
298     avahi_free(r->path);
299     avahi_free(r);
300
301     return ret;
302 }
303
304 /* AvahiHostNameResolver implementation */
305
306 DBusHandlerResult avahi_host_name_resolver_event (AvahiClient *client, AvahiResolverEvent event, DBusMessage *message) {
307     AvahiHostNameResolver *r = NULL;
308     DBusError error;
309     const char *path;
310
311     assert(client);
312     assert(message);
313     
314     dbus_error_init (&error);
315
316     if (!(path = dbus_message_get_path(message)))
317         goto fail;
318
319     for (r = client->host_name_resolvers; r; r = r->host_name_resolvers_next)
320         if (strcmp (r->path, path) == 0)
321             break;
322
323     if (!r)
324         goto fail;
325
326     if (event == AVAHI_RESOLVER_FOUND) {
327         int32_t interface, protocol, aprotocol, flags;
328         char *name, *address;
329         AvahiAddress a;
330         
331         if (!dbus_message_get_args(
332                 message, &error,
333                 DBUS_TYPE_INT32, &interface,
334                 DBUS_TYPE_INT32, &protocol,
335                 DBUS_TYPE_STRING, &name,
336                 DBUS_TYPE_INT32, &aprotocol,
337                 DBUS_TYPE_STRING, &address,
338                 DBUS_TYPE_INT32, &flags,
339                 DBUS_TYPE_INVALID) ||
340             dbus_error_is_set (&error)) {
341             fprintf(stderr, "Failed to parse resolver event.\n");
342             goto fail;
343         }
344         
345         assert(address);
346         if (!avahi_address_parse(address, (AvahiProtocol) aprotocol, &a)) {
347             fprintf(stderr, "Failed to parse address\n");
348             goto fail;
349         }
350     
351         r->callback(r, (AvahiIfIndex) interface, (AvahiProtocol) protocol, AVAHI_RESOLVER_FOUND, name, &a, flags, r->userdata);
352
353     } else
354         r->callback(r, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, event, NULL, NULL, 0, r->userdata);
355
356     return DBUS_HANDLER_RESULT_HANDLED;
357     
358 fail:
359     dbus_error_free (&error);
360     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
361 }
362
363
364 AvahiHostNameResolver * avahi_host_name_resolver_new(
365     AvahiClient *client,
366     AvahiIfIndex interface,
367     AvahiProtocol protocol,
368     const char *name,
369     AvahiProtocol aprotocol,
370     AvahiLookupFlags flags,
371     AvahiHostNameResolverCallback callback,
372     void *userdata) {
373
374     DBusError error;
375     AvahiHostNameResolver *r;
376     DBusMessage *message = NULL, *reply = NULL;
377     int32_t i_interface, i_protocol, i_aprotocol, i_flags;
378     char *path;
379     
380     assert(client);
381     assert(name);
382
383     dbus_error_init (&error);
384
385     if (client->state == AVAHI_CLIENT_DISCONNECTED) {
386         avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
387         goto fail;
388     }
389
390     if (!(r = avahi_new(AvahiHostNameResolver, 1))) {
391         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
392         goto fail;
393     }
394
395     r->client = client;
396     r->callback = callback;
397     r->userdata = userdata;
398     r->path = NULL;
399     
400     AVAHI_LLIST_PREPEND(AvahiHostNameResolver, host_name_resolvers, client->host_name_resolvers, r);
401
402     if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "HostNameResolverNew"))) {
403         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
404         goto fail;
405     }
406
407     i_interface = (int32_t) interface;
408     i_protocol = (int32_t) protocol;
409     i_aprotocol = (int32_t) aprotocol;
410     i_flags = (int32_t) flags;
411
412     if (!(dbus_message_append_args(
413               message,
414               DBUS_TYPE_INT32, &i_interface,
415               DBUS_TYPE_INT32, &i_protocol,
416               DBUS_TYPE_STRING, &name,
417               DBUS_TYPE_INT32, &i_aprotocol,
418               DBUS_TYPE_INT32, &i_flags,
419               DBUS_TYPE_INVALID))) {
420         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
421         goto fail;
422     }
423
424     if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
425         dbus_error_is_set(&error)) {
426         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
427         goto fail;
428     }
429
430     if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) ||
431         dbus_error_is_set(&error) ||
432         !path) {
433         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
434         goto fail;
435     }
436
437     if (!(r->path = avahi_strdup(path))) {
438
439         /* FIXME: We don't remove the object on the server side */
440
441         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
442         goto fail;
443     }
444
445     dbus_message_unref(message);
446     dbus_message_unref(reply);
447
448     return r;
449     
450 fail:
451
452     if (dbus_error_is_set(&error)) {
453         avahi_client_set_dbus_error(client, &error);
454         dbus_error_free(&error);
455     }
456
457     if (r)
458         avahi_host_name_resolver_free(r);
459     
460     if (message)
461         dbus_message_unref(message);
462
463     if (reply)
464         dbus_message_unref(reply);
465
466     return NULL;
467
468 }
469
470 int avahi_host_name_resolver_free(AvahiHostNameResolver *r) {
471     int ret = AVAHI_OK;
472     AvahiClient *client;
473
474     assert(r);
475     client = r->client;
476
477     if (r->path && client->state != AVAHI_CLIENT_DISCONNECTED)
478         ret = avahi_client_simple_method_call(client, r->path, AVAHI_DBUS_INTERFACE_HOST_NAME_RESOLVER, "Free");
479
480     AVAHI_LLIST_REMOVE(AvahiHostNameResolver, host_name_resolvers, client->host_name_resolvers, r);
481
482     avahi_free(r->path);
483     avahi_free(r);
484
485     return ret;
486 }
487
488 AvahiClient* avahi_host_name_resolver_get_client (AvahiHostNameResolver *r) {
489     assert (r);
490
491     return r->client;
492 }
493
494 /* AvahiAddressResolver implementation */
495
496 DBusHandlerResult avahi_address_resolver_event (AvahiClient *client, AvahiResolverEvent event, DBusMessage *message) {
497     AvahiAddressResolver *r = NULL;
498     DBusError error;
499     const char *path;
500
501     assert(client);
502     assert(message);
503     
504     dbus_error_init (&error);
505
506     if (!(path = dbus_message_get_path(message)))
507         goto fail;
508
509     for (r = client->address_resolvers; r; r = r->address_resolvers_next)
510         if (strcmp (r->path, path) == 0)
511             break;
512
513     if (!r)
514         goto fail;
515
516     if (event == AVAHI_RESOLVER_FOUND) {
517         int32_t interface, protocol, aprotocol, flags;
518         char *name, *address;
519         AvahiAddress a;
520         
521         if (!dbus_message_get_args(
522                 message, &error,
523                 DBUS_TYPE_INT32, &interface,
524                 DBUS_TYPE_INT32, &protocol,
525                 DBUS_TYPE_INT32, &aprotocol,
526                 DBUS_TYPE_STRING, &address,
527                 DBUS_TYPE_STRING, &name,
528                 DBUS_TYPE_INT32, &flags,
529                 DBUS_TYPE_INVALID) ||
530             dbus_error_is_set (&error)) {
531             fprintf(stderr, "Failed to parse resolver event.\n");
532             goto fail;
533         }
534         
535         assert(address);
536         if (!avahi_address_parse(address, (AvahiProtocol) aprotocol, &a)) {
537             fprintf(stderr, "Failed to parse address\n");
538             goto fail;
539         }
540     
541         r->callback(r, (AvahiIfIndex) interface, (AvahiProtocol) protocol, AVAHI_RESOLVER_FOUND, (AvahiProtocol) aprotocol, &a, name, (AvahiLookupResultFlags) flags, r->userdata);
542     } else
543         r->callback(r, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, event, AVAHI_PROTO_UNSPEC, NULL, NULL, 0, r->userdata);
544
545     return DBUS_HANDLER_RESULT_HANDLED;
546     
547 fail:
548     dbus_error_free (&error);
549     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
550 }
551
552 AvahiAddressResolver * avahi_address_resolver_new_a(
553     AvahiClient *client,
554     AvahiIfIndex interface,
555     AvahiProtocol protocol,
556     const AvahiAddress *a,
557     AvahiLookupFlags flags,
558     AvahiAddressResolverCallback callback,
559     void *userdata) {
560
561     char addr[64];
562
563     assert (a);
564
565     if (!avahi_address_snprint (addr, sizeof (addr), a)) {
566         avahi_client_set_errno(client, AVAHI_ERR_INVALID_ADDRESS);
567         return NULL;
568     }
569
570     return avahi_address_resolver_new(
571         client, interface, protocol,
572         addr, flags,
573         callback, userdata);
574 }
575
576 AvahiAddressResolver * avahi_address_resolver_new(
577     AvahiClient *client,
578     AvahiIfIndex interface,
579     AvahiProtocol protocol,
580     const char *address,
581     AvahiLookupFlags flags, 
582     AvahiAddressResolverCallback callback,
583     void *userdata) {
584
585     DBusError error;
586     AvahiAddressResolver *r;
587     DBusMessage *message = NULL, *reply = NULL;
588     int32_t i_interface, i_protocol, i_flags;
589     char *path;
590     
591     assert(client);
592
593     dbus_error_init (&error);
594
595     if (client->state == AVAHI_CLIENT_DISCONNECTED) {
596         avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
597         goto fail;
598     }
599
600     if (!(r = avahi_new(AvahiAddressResolver, 1))) {
601         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
602         goto fail;
603     }
604
605     r->client = client;
606     r->callback = callback;
607     r->userdata = userdata;
608     r->path = NULL;
609     
610     AVAHI_LLIST_PREPEND(AvahiAddressResolver, address_resolvers, client->address_resolvers, r);
611
612     if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "AddressResolverNew"))) {
613         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
614         goto fail;
615     }
616
617     i_interface = (int32_t) interface;
618     i_protocol = (int32_t) protocol;
619     i_flags = (int32_t) flags;
620
621     if (!(dbus_message_append_args(
622               message,
623               DBUS_TYPE_INT32, &i_interface,
624               DBUS_TYPE_INT32, &i_protocol,
625               DBUS_TYPE_STRING, &address,
626               DBUS_TYPE_INT32, &i_flags,
627               DBUS_TYPE_INVALID))) {
628         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
629         goto fail;
630     }
631
632     if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
633         dbus_error_is_set(&error)) {
634         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
635         goto fail;
636     }
637
638     if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) ||
639         dbus_error_is_set(&error) ||
640         !path) {
641         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
642         goto fail;
643     }
644     
645     if (!(r->path = avahi_strdup(path))) {
646
647         /* FIXME: We don't remove the object on the server side */
648
649         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
650         goto fail;
651     }
652
653     dbus_message_unref(message);
654     dbus_message_unref(reply);
655
656     return r;
657     
658 fail:
659
660     if (dbus_error_is_set(&error)) {
661         avahi_client_set_dbus_error(client, &error);
662         dbus_error_free(&error);
663     }
664
665     if (r)
666         avahi_address_resolver_free(r);
667     
668     if (message)
669         dbus_message_unref(message);
670
671     if (reply)
672         dbus_message_unref(reply);
673
674     return NULL;
675
676 }
677
678 AvahiClient* avahi_address_resolver_get_client (AvahiAddressResolver *r) {
679     assert (r);
680
681     return r->client;
682 }
683
684 int avahi_address_resolver_free(AvahiAddressResolver *r) {
685     AvahiClient *client;
686     int ret = AVAHI_OK;
687
688     assert(r);
689     client = r->client;
690
691     if (r->path && client->state != AVAHI_CLIENT_DISCONNECTED)
692         ret = avahi_client_simple_method_call(client, r->path, AVAHI_DBUS_INTERFACE_ADDRESS_RESOLVER, "Free");
693
694     AVAHI_LLIST_REMOVE(AvahiAddressResolver, address_resolvers, client->address_resolvers, r);
695
696     avahi_free(r->path);
697     avahi_free(r);
698
699     return ret;
700 }
701