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