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