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