]> git.meshlink.io Git - catta/blob - avahi-daemon/dbus-protocol.c
Make AVAHI_PROTO_xxx well defined constants
[catta] / avahi-daemon / dbus-protocol.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 <string.h>
27 #include <sys/ioctl.h>
28 #include <net/if.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <assert.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <stdio.h>
35 #include <signal.h>
36
37 #include <dbus/dbus.h>
38
39 #include <avahi-common/dbus.h>
40 #include <avahi-common/llist.h>
41 #include <avahi-common/malloc.h>
42 #include <avahi-common/dbus.h>
43 #include <avahi-common/dbus-watch-glue.h>
44 #include <avahi-common/alternative.h>
45 #include <avahi-common/error.h>
46 #include <avahi-core/log.h>
47 #include <avahi-core/core.h>
48
49 #include "dbus-protocol.h"
50 #include "main.h"
51
52 typedef struct Server Server;
53 typedef struct Client Client;
54 typedef struct EntryGroupInfo EntryGroupInfo;
55 typedef struct SyncHostNameResolverInfo SyncHostNameResolverInfo;
56 typedef struct AsyncHostNameResolverInfo AsyncHostNameResolverInfo;
57 typedef struct SyncAddressResolverInfo SyncAddressResolverInfo;
58 typedef struct AsyncAddressResolverInfo AsyncAddressResolverInfo;
59 typedef struct DomainBrowserInfo DomainBrowserInfo;
60 typedef struct ServiceTypeBrowserInfo ServiceTypeBrowserInfo;
61 typedef struct ServiceBrowserInfo ServiceBrowserInfo;
62 typedef struct SyncServiceResolverInfo SyncServiceResolverInfo;
63 typedef struct AsyncServiceResolverInfo AsyncServiceResolverInfo;
64
65 #define MAX_CLIENTS 20
66 #define MAX_OBJECTS_PER_CLIENT 50
67 #define MAX_ENTRIES_PER_ENTRY_GROUP 20
68
69 /* #define VALGRIND_WORKAROUND */
70
71 struct EntryGroupInfo {
72     unsigned id;
73     Client *client;
74     AvahiSEntryGroup *entry_group;
75     char *path;
76
77     int n_entries;
78     
79     AVAHI_LLIST_FIELDS(EntryGroupInfo, entry_groups);
80 };
81
82 struct SyncHostNameResolverInfo {
83     Client *client;
84     AvahiSHostNameResolver *host_name_resolver;
85     DBusMessage *message;
86
87     AVAHI_LLIST_FIELDS(SyncHostNameResolverInfo, sync_host_name_resolvers);
88 };
89
90 struct AsyncHostNameResolverInfo {
91     unsigned id;
92     Client *client;
93     AvahiSHostNameResolver *host_name_resolver;
94     char *path;
95
96     AVAHI_LLIST_FIELDS(AsyncHostNameResolverInfo, async_host_name_resolvers);
97 };
98
99 struct SyncAddressResolverInfo {
100     Client *client;
101     AvahiSAddressResolver *address_resolver;
102     DBusMessage *message;
103
104     AVAHI_LLIST_FIELDS(SyncAddressResolverInfo, sync_address_resolvers);
105 };
106
107 struct AsyncAddressResolverInfo {
108     unsigned id;
109     Client *client;
110     AvahiSAddressResolver *address_resolver;
111     char *path;
112
113     AVAHI_LLIST_FIELDS(AsyncAddressResolverInfo, async_address_resolvers);
114 };
115
116 struct DomainBrowserInfo {
117     unsigned id;
118     Client *client;
119     AvahiSDomainBrowser *domain_browser;
120     char *path;
121
122     AVAHI_LLIST_FIELDS(DomainBrowserInfo, domain_browsers);
123 };
124
125 struct ServiceTypeBrowserInfo {
126     unsigned id;
127     Client *client;
128     AvahiSServiceTypeBrowser *service_type_browser;
129     char *path;
130
131     AVAHI_LLIST_FIELDS(ServiceTypeBrowserInfo, service_type_browsers);
132 };
133
134 struct ServiceBrowserInfo {
135     unsigned id;
136     Client *client;
137     AvahiSServiceBrowser *service_browser;
138     char *path;
139
140     AVAHI_LLIST_FIELDS(ServiceBrowserInfo, service_browsers);
141 };
142
143 struct SyncServiceResolverInfo {
144     Client *client;
145     AvahiSServiceResolver *service_resolver;
146     DBusMessage *message;
147
148     AVAHI_LLIST_FIELDS(SyncServiceResolverInfo, sync_service_resolvers);
149 };
150
151 struct AsyncServiceResolverInfo {
152     unsigned id;
153     Client *client;
154     AvahiSServiceResolver *service_resolver;
155     char *path;
156
157     AVAHI_LLIST_FIELDS(AsyncServiceResolverInfo, async_service_resolvers);
158 };
159
160 struct Client {
161     unsigned id;
162     char *name;
163     unsigned current_id;
164     int n_objects;
165     
166     AVAHI_LLIST_FIELDS(Client, clients);
167     AVAHI_LLIST_HEAD(EntryGroupInfo, entry_groups);
168     AVAHI_LLIST_HEAD(SyncHostNameResolverInfo, sync_host_name_resolvers);
169     AVAHI_LLIST_HEAD(AsyncHostNameResolverInfo, async_host_name_resolvers);
170     AVAHI_LLIST_HEAD(SyncAddressResolverInfo, sync_address_resolvers);
171     AVAHI_LLIST_HEAD(AsyncAddressResolverInfo, async_address_resolvers);
172     AVAHI_LLIST_HEAD(DomainBrowserInfo, domain_browsers);
173     AVAHI_LLIST_HEAD(ServiceTypeBrowserInfo, service_type_browsers);
174     AVAHI_LLIST_HEAD(ServiceBrowserInfo, service_browsers);
175     AVAHI_LLIST_HEAD(SyncServiceResolverInfo, sync_service_resolvers);
176     AVAHI_LLIST_HEAD(AsyncServiceResolverInfo, async_service_resolvers);
177 };
178
179 struct Server {
180     DBusConnection *bus;
181     AVAHI_LLIST_HEAD(Client, clients);
182     int n_clients;
183     unsigned current_id;
184 };
185
186 static Server *server = NULL;
187
188 static void entry_group_free(EntryGroupInfo *i) {
189     assert(i);
190
191     if (i->entry_group)
192         avahi_s_entry_group_free(i->entry_group);
193     dbus_connection_unregister_object_path(server->bus, i->path);
194     avahi_free(i->path);
195     AVAHI_LLIST_REMOVE(EntryGroupInfo, entry_groups, i->client->entry_groups, i);
196
197     i->client->n_objects--;
198     assert(i->client->n_objects >= 0);
199     
200     avahi_free(i);
201 }
202
203 static void sync_host_name_resolver_free(SyncHostNameResolverInfo *i) {
204     assert(i);
205
206     if (i->host_name_resolver)
207         avahi_s_host_name_resolver_free(i->host_name_resolver);
208     dbus_message_unref(i->message);
209     AVAHI_LLIST_REMOVE(SyncHostNameResolverInfo, sync_host_name_resolvers, i->client->sync_host_name_resolvers, i);
210
211     i->client->n_objects--;
212     assert(i->client->n_objects >= 0);
213
214     avahi_free(i);
215 }
216
217 static void async_host_name_resolver_free(AsyncHostNameResolverInfo *i) {
218     assert(i);
219
220     if (i->host_name_resolver)
221         avahi_s_host_name_resolver_free(i->host_name_resolver);
222     dbus_connection_unregister_object_path(server->bus, i->path);
223     AVAHI_LLIST_REMOVE(AsyncHostNameResolverInfo, async_host_name_resolvers, i->client->async_host_name_resolvers, i);
224
225     i->client->n_objects--;
226     assert(i->client->n_objects >= 0);
227
228     avahi_free(i);
229 }
230
231 static void sync_address_resolver_free(SyncAddressResolverInfo *i) {
232     assert(i);
233
234     if (i->address_resolver)
235         avahi_s_address_resolver_free(i->address_resolver);
236     dbus_message_unref(i->message);
237     AVAHI_LLIST_REMOVE(SyncAddressResolverInfo, sync_address_resolvers, i->client->sync_address_resolvers, i);
238
239     i->client->n_objects--;
240     assert(i->client->n_objects >= 0);
241
242     avahi_free(i);
243 }
244
245 static void async_address_resolver_free(AsyncAddressResolverInfo *i) {
246     assert(i);
247
248     if (i->address_resolver)
249         avahi_s_address_resolver_free(i->address_resolver);
250     dbus_connection_unregister_object_path(server->bus, i->path);
251     AVAHI_LLIST_REMOVE(AsyncAddressResolverInfo, async_address_resolvers, i->client->async_address_resolvers, i);
252
253     i->client->n_objects--;
254     assert(i->client->n_objects >= 0);
255
256     avahi_free(i);
257 }
258
259 static void domain_browser_free(DomainBrowserInfo *i) {
260     assert(i);
261
262     if (i->domain_browser)
263         avahi_s_domain_browser_free(i->domain_browser);
264     dbus_connection_unregister_object_path(server->bus, i->path);
265     avahi_free(i->path);
266     AVAHI_LLIST_REMOVE(DomainBrowserInfo, domain_browsers, i->client->domain_browsers, i);
267
268     i->client->n_objects--;
269     assert(i->client->n_objects >= 0);
270
271     avahi_free(i);
272 }
273
274 static void service_type_browser_free(ServiceTypeBrowserInfo *i) {
275     assert(i);
276
277     if (i->service_type_browser)
278         avahi_s_service_type_browser_free(i->service_type_browser);
279     dbus_connection_unregister_object_path(server->bus, i->path);
280     avahi_free(i->path);
281     AVAHI_LLIST_REMOVE(ServiceTypeBrowserInfo, service_type_browsers, i->client->service_type_browsers, i);
282
283     i->client->n_objects--;
284     assert(i->client->n_objects >= 0);
285
286     avahi_free(i);
287 }
288
289 static void service_browser_free(ServiceBrowserInfo *i) {
290     assert(i);
291
292     if (i->service_browser)
293         avahi_s_service_browser_free(i->service_browser);
294     dbus_connection_unregister_object_path(server->bus, i->path);
295     avahi_free(i->path);
296     AVAHI_LLIST_REMOVE(ServiceBrowserInfo, service_browsers, i->client->service_browsers, i);
297
298     i->client->n_objects--;
299     assert(i->client->n_objects >= 0);
300
301     avahi_free(i);
302 }
303
304 static void sync_service_resolver_free(SyncServiceResolverInfo *i) {
305     assert(i);
306
307     if (i->service_resolver)
308         avahi_s_service_resolver_free(i->service_resolver);
309     dbus_message_unref(i->message);
310     AVAHI_LLIST_REMOVE(SyncServiceResolverInfo, sync_service_resolvers, i->client->sync_service_resolvers, i);
311
312     i->client->n_objects--;
313     assert(i->client->n_objects >= 0);
314
315     avahi_free(i);
316 }
317
318 static void async_service_resolver_free(AsyncServiceResolverInfo *i) {
319     assert(i);
320
321     if (i->service_resolver)
322         avahi_s_service_resolver_free(i->service_resolver);
323
324     dbus_connection_unregister_object_path(server->bus, i->path);
325     AVAHI_LLIST_REMOVE(AsyncServiceResolverInfo, async_service_resolvers, i->client->async_service_resolvers, i);
326
327     i->client->n_objects--;
328     assert(i->client->n_objects >= 0);
329
330     avahi_free(i);
331 }
332
333 static void client_free(Client *c) {
334     
335     assert(server);
336     assert(c);
337
338     while (c->entry_groups)
339         entry_group_free(c->entry_groups);
340
341     while (c->sync_host_name_resolvers)
342         sync_host_name_resolver_free(c->sync_host_name_resolvers);
343
344     while (c->async_host_name_resolvers)
345         async_host_name_resolver_free(c->async_host_name_resolvers);
346     
347     while (c->sync_address_resolvers)
348         sync_address_resolver_free(c->sync_address_resolvers);
349
350     while (c->async_address_resolvers)
351         async_address_resolver_free(c->async_address_resolvers);
352
353     while (c->domain_browsers)
354         domain_browser_free(c->domain_browsers);
355
356     while (c->service_type_browsers)
357         service_type_browser_free(c->service_type_browsers);
358
359     while (c->service_browsers)
360         service_browser_free(c->service_browsers);
361
362     while (c->sync_service_resolvers)
363         sync_service_resolver_free(c->sync_service_resolvers);
364
365     while (c->async_service_resolvers)
366         async_service_resolver_free(c->async_service_resolvers);
367
368     assert(c->n_objects == 0);
369     
370     avahi_free(c->name);
371     AVAHI_LLIST_REMOVE(Client, clients, server->clients, c);
372     avahi_free(c);
373
374     server->n_clients --;
375     assert(server->n_clients >= 0);
376 }
377
378 static Client *client_get(const char *name, int create) {
379     Client *client;
380
381     assert(server);
382     assert(name);
383
384     for (client = server->clients; client; client = client->clients_next)
385         if (!strcmp(name, client->name))
386             return client;
387
388     if (!create)
389         return NULL;
390
391     if (server->n_clients >= MAX_CLIENTS)
392         return NULL;
393     
394     /* If not existant yet, create a new entry */
395     client = avahi_new(Client, 1);
396     client->id = server->current_id++;
397     client->name = avahi_strdup(name);
398     client->current_id = 0;
399     client->n_objects = 0;
400     
401     AVAHI_LLIST_HEAD_INIT(EntryGroupInfo, client->entry_groups);
402     AVAHI_LLIST_HEAD_INIT(SyncHostNameResolverInfo, client->sync_host_name_resolvers);
403     AVAHI_LLIST_HEAD_INIT(AsyncHostNameResolverInfo, client->async_host_name_resolvers);
404     AVAHI_LLIST_HEAD_INIT(SyncAddressResolverInfo, client->sync_address_resolvers);
405     AVAHI_LLIST_HEAD_INIT(AsyncAddressResolverInfo, client->async_address_resolvers);
406     AVAHI_LLIST_HEAD_INIT(DomainBrowserInfo, client->domain_browsers);
407     AVAHI_LLIST_HEAD_INIT(ServiceTypeBrowserInfo, client->service_type_browsers);
408     AVAHI_LLIST_HEAD_INIT(ServiceBrowserInfo, client->service_browsers);
409     AVAHI_LLIST_HEAD_INIT(SyncServiceResolverInfo, client->sync_service_resolvers);
410     AVAHI_LLIST_HEAD_INIT(AsyncServiceResolverInfo, client->async_service_resolvers);
411
412     AVAHI_LLIST_PREPEND(Client, clients, server->clients, client);
413
414     server->n_clients++;
415     assert(server->n_clients > 0);
416     
417     return client;
418 }
419
420 static DBusHandlerResult respond_error(DBusConnection *c, DBusMessage *m, int error, const char *text) {
421     DBusMessage *reply;
422
423     assert(-error > -AVAHI_OK);
424     assert(-error < -AVAHI_ERR_MAX);
425     
426     reply = dbus_message_new_error(m, avahi_error_number_to_dbus (error), text ? text : avahi_strerror(error));
427     dbus_connection_send(c, reply, NULL);
428     dbus_message_unref(reply);
429     
430     return DBUS_HANDLER_RESULT_HANDLED;
431 }
432
433 static DBusHandlerResult respond_string(DBusConnection *c, DBusMessage *m, const char *text) {
434     DBusMessage *reply;
435
436     reply = dbus_message_new_method_return(m);
437     dbus_message_append_args(reply, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID);
438     dbus_connection_send(c, reply, NULL);
439     dbus_message_unref(reply);
440     
441     return DBUS_HANDLER_RESULT_HANDLED;
442 }
443
444 static DBusHandlerResult respond_int32(DBusConnection *c, DBusMessage *m, int32_t i) {
445     DBusMessage *reply;
446
447     reply = dbus_message_new_method_return(m);
448     dbus_message_append_args(reply, DBUS_TYPE_INT32, &i, DBUS_TYPE_INVALID);
449     dbus_connection_send(c, reply, NULL);
450     dbus_message_unref(reply);
451     
452     return DBUS_HANDLER_RESULT_HANDLED;
453 }
454
455 static DBusHandlerResult respond_uint32(DBusConnection *c, DBusMessage *m, uint32_t u) {
456     DBusMessage *reply;
457
458     reply = dbus_message_new_method_return(m);
459     dbus_message_append_args(reply, DBUS_TYPE_UINT32, &u, DBUS_TYPE_INVALID);
460     dbus_connection_send(c, reply, NULL);
461     dbus_message_unref(reply);
462     
463     return DBUS_HANDLER_RESULT_HANDLED;
464 }
465
466 static DBusHandlerResult respond_boolean(DBusConnection *c, DBusMessage *m, int b) {
467     DBusMessage *reply;
468
469     reply = dbus_message_new_method_return(m);
470     dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &b, DBUS_TYPE_INVALID);
471     dbus_connection_send(c, reply, NULL);
472     dbus_message_unref(reply);
473     
474     return DBUS_HANDLER_RESULT_HANDLED;
475 }
476
477 static DBusHandlerResult respond_ok(DBusConnection *c, DBusMessage *m) {
478     DBusMessage *reply;
479
480     reply = dbus_message_new_method_return(m);
481     dbus_connection_send(c, reply, NULL);
482     dbus_message_unref(reply);
483     
484     return DBUS_HANDLER_RESULT_HANDLED;
485 }
486
487 static DBusHandlerResult respond_path(DBusConnection *c, DBusMessage *m, const char *path) {
488     DBusMessage *reply;
489
490     reply = dbus_message_new_method_return(m);
491     dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
492     dbus_connection_send(c, reply, NULL);
493     dbus_message_unref(reply);
494     
495     return DBUS_HANDLER_RESULT_HANDLED;
496 }
497
498 static char *file_get_contents(char *fname) {
499     int fd = -1;
500     struct stat st;
501     ssize_t size;
502     char *buf = NULL;
503     
504     assert(fname);
505
506     if (!(fd = open(fname, O_RDONLY))) {
507         avahi_log_error("Failed to open %s: %s", fname, strerror(errno));
508         goto fail;
509     }
510
511     if (fstat(fd, &st) < 0) {
512         avahi_log_error("stat(%s) failed: %s", fname, strerror(errno));
513         goto fail;
514     }
515
516     if (!(S_ISREG(st.st_mode))) {
517         avahi_log_error("Invalid file %s", fname);
518         goto fail;
519     }
520
521     if (st.st_size > 1024*1024) { /** 1MB */
522         avahi_log_error("File too large %s", fname);
523         goto fail;
524     }
525
526     buf = avahi_new(char, st.st_size+1);
527
528     if ((size = read(fd, buf, st.st_size)) < 0) {
529         avahi_log_error("read() failed: %s\n", strerror(errno));
530         goto fail;
531     }
532
533     buf[size] = 0;
534
535     close(fd);
536     return buf;
537     
538 fail:
539     if (fd >= 0)
540         close(fd);
541
542     if (buf)
543         avahi_free(buf);
544
545     return NULL;
546         
547 }
548
549 static DBusHandlerResult handle_introspect(DBusConnection *c, DBusMessage *m, const char *fname) {
550     char *path, *contents;
551     DBusError error;
552     
553     assert(c);
554     assert(m);
555     assert(fname);
556
557     dbus_error_init(&error);
558
559     if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
560         avahi_log_error("Error parsing Introspect message: %s", error.message);
561         goto fail;
562     }
563     
564     path = avahi_strdup_printf("%s/%s", AVAHI_DBUS_INTROSPECTION_DIR, fname);
565     contents = file_get_contents(path);
566     avahi_free(path);
567     
568     if (!contents) {
569         avahi_log_error("Failed to load introspection data.");
570         goto fail;
571     }
572     
573     respond_string(c, m, contents);
574     avahi_free(contents);
575     
576     return DBUS_HANDLER_RESULT_HANDLED;
577
578 fail:
579     if (dbus_error_is_set(&error))
580         dbus_error_free(&error);
581     
582     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
583
584 }
585
586 static DBusHandlerResult msg_signal_filter_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
587     DBusError error;
588
589     dbus_error_init(&error);
590
591 /*     avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s", */
592 /*                     dbus_message_get_interface(m), */
593 /*                     dbus_message_get_path(m), */
594 /*                     dbus_message_get_member(m)); */
595
596     if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) {
597         /* No, we shouldn't quit, but until we get somewhere
598          * usefull such that we can restore our state, we will */
599         avahi_log_warn("Disconnnected from D-BUS, terminating...");
600         
601         raise(SIGQUIT); /* The signal handler will catch this and terminate the process cleanly*/
602         
603         return DBUS_HANDLER_RESULT_HANDLED;
604         
605     } else if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameAcquired")) {
606         char *name;
607
608         if (!dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) {
609             avahi_log_warn("Error parsing NameAcquired message");
610             goto fail;
611         }
612
613 /*         avahi_log_info(__FILE__": name acquired (%s)", name); */
614         return DBUS_HANDLER_RESULT_HANDLED;
615         
616     } else if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
617         char *name, *old, *new;
618
619         if (!dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old, DBUS_TYPE_STRING, &new, DBUS_TYPE_INVALID)) {
620             avahi_log_warn("Error parsing NameOwnerChanged message");
621             goto fail;
622         }
623
624         if (!*new) {
625             Client *client;
626
627             if ((client = client_get(name, FALSE))) {
628                 avahi_log_debug(__FILE__": client %s vanished.", name); 
629                 client_free(client);
630             }
631         }
632     }
633
634 fail:
635     if (dbus_error_is_set(&error))
636         dbus_error_free(&error);
637     
638     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
639 }
640
641 static void entry_group_callback(AvahiServer *s, AvahiSEntryGroup *g, AvahiEntryGroupState state, void* userdata) {
642     EntryGroupInfo *i = userdata;
643     DBusMessage *m;
644     int32_t t;
645     
646     assert(s);
647     assert(g);
648     assert(i);
649
650     m = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "StateChanged");
651     t = (int32_t) state;
652     dbus_message_append_args(m, DBUS_TYPE_INT32, &t, DBUS_TYPE_INVALID);
653     dbus_message_set_destination(m, i->client->name);  
654     dbus_connection_send(server->bus, m, NULL);
655     dbus_message_unref(m);
656 }
657
658 static DBusHandlerResult msg_entry_group_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
659     DBusError error;
660     EntryGroupInfo *i = userdata;
661
662     assert(c);
663     assert(m);
664     assert(i);
665     
666     dbus_error_init(&error);
667
668     avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s",
669                     dbus_message_get_interface(m),
670                     dbus_message_get_path(m),
671                     dbus_message_get_member(m));
672
673     /* Introspection */
674     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
675         return handle_introspect(c, m, "EntryGroup.introspect");
676     
677     /* Access control */
678     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
679         return respond_error(c, m, AVAHI_ERR_ACCESS_DENIED, NULL);
680     
681     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Free")) {
682
683         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
684             avahi_log_warn("Error parsing EntryGroup::Free message");
685             goto fail;
686         }
687
688         entry_group_free(i);
689         return respond_ok(c, m);
690         
691     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Commit")) {
692
693         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
694             avahi_log_warn("Error parsing EntryGroup::Commit message");
695             goto fail;
696         }
697
698         avahi_s_entry_group_commit(i->entry_group);
699         return respond_ok(c, m);
700         
701         
702     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Reset")) {
703         
704         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
705             avahi_log_warn("Error parsing EntryGroup::Reset message");
706             goto fail;
707         }
708
709         avahi_s_entry_group_reset(i->entry_group);
710         return respond_ok(c, m);
711         
712     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "IsEmpty")) {
713         DBusMessage *reply;
714         int b;
715         
716         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
717             avahi_log_warn("Error parsing EntryGroup::IsEmpty message");
718             goto fail;
719         }
720
721         b = !!avahi_s_entry_group_is_empty(i->entry_group);
722
723         reply = dbus_message_new_method_return(m);
724         dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &b, DBUS_TYPE_INVALID);
725         dbus_connection_send(c, reply, NULL);
726         dbus_message_unref(reply);
727         
728         return DBUS_HANDLER_RESULT_HANDLED;
729         
730     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "GetState")) {
731         AvahiEntryGroupState state;
732         
733         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
734             avahi_log_warn("Error parsing EntryGroup::GetState message");
735             goto fail;
736         }
737
738         state = avahi_s_entry_group_get_state(i->entry_group);
739         return respond_int32(c, m, (int32_t) state);
740         
741     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddService")) {
742         int32_t interface, protocol;
743         char *type, *name, *domain, *host;
744         uint16_t port;
745         AvahiStringList *strlst;
746         DBusMessageIter iter, sub;
747         int j;
748         
749         if (!dbus_message_get_args(
750                 m, &error,
751                 DBUS_TYPE_INT32, &interface,
752                 DBUS_TYPE_INT32, &protocol,
753                 DBUS_TYPE_STRING, &name,
754                 DBUS_TYPE_STRING, &type,
755                 DBUS_TYPE_STRING, &domain,
756                 DBUS_TYPE_STRING, &host,
757                 DBUS_TYPE_UINT16, &port, 
758                 DBUS_TYPE_INVALID) || !type || !name) {
759             avahi_log_warn("Error parsing EntryGroup::AddService message");
760             goto fail;
761         }
762
763         dbus_message_iter_init(m, &iter);
764
765         for (j = 0; j < 7; j++)
766             dbus_message_iter_next(&iter);
767         
768         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
769             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_ARRAY) {
770             avahi_log_warn("Error parsing EntryGroup::AddService message 2");
771             goto fail;
772         }
773
774         strlst = NULL;
775         dbus_message_iter_recurse(&iter, &sub);
776         
777         for (;;) {
778             DBusMessageIter sub2;
779             int at, n;
780             uint8_t *k;
781
782             if ((at = dbus_message_iter_get_arg_type(&sub)) == DBUS_TYPE_INVALID)
783                 break;
784
785             assert(at == DBUS_TYPE_ARRAY);
786             
787             if (dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_BYTE) {
788                 avahi_log_warn("Error parsing EntryGroup::AddService message");
789                 goto fail;
790             }
791
792             dbus_message_iter_recurse(&sub, &sub2);
793             dbus_message_iter_get_fixed_array(&sub2, &k, &n);
794             strlst = avahi_string_list_add_arbitrary(strlst, k, n);
795             
796             dbus_message_iter_next(&sub);
797         }
798
799         if (i->n_entries >= MAX_ENTRIES_PER_ENTRY_GROUP) {
800             avahi_string_list_free(strlst);
801             avahi_log_warn("Too many entries per entry group, client request failed.");
802             return respond_error(c, m, AVAHI_ERR_TOO_MANY_ENTRIES, NULL);
803         }
804
805         if (domain && !*domain)
806             domain = NULL;
807
808         if (host && !*host)
809             host = NULL;
810
811         if (avahi_server_add_service_strlst(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, type, domain, host, port, strlst) < 0) {
812             avahi_string_list_free(strlst);
813             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
814         } else
815             i->n_entries ++;
816         
817         avahi_string_list_free(strlst);
818         
819         return respond_ok(c, m);
820         
821     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddAddress")) {
822         int32_t interface, protocol;
823         char *name, *address;
824         AvahiAddress a;
825         
826         if (!dbus_message_get_args(
827                 m, &error,
828                 DBUS_TYPE_INT32, &interface,
829                 DBUS_TYPE_INT32, &protocol,
830                 DBUS_TYPE_STRING, &name,
831                 DBUS_TYPE_STRING, &address,
832                 DBUS_TYPE_INVALID) || !name || !address) {
833             avahi_log_warn("Error parsing EntryGroup::AddAddress message");
834             goto fail;
835         }
836
837         if (i->n_entries >= MAX_ENTRIES_PER_ENTRY_GROUP) {
838             avahi_log_warn("Too many entries per entry group, client request failed.");
839             return respond_error(c, m, AVAHI_ERR_TOO_MANY_ENTRIES, NULL);
840         }
841         
842         if (!(avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a))) {
843             return respond_error(c, m, AVAHI_ERR_INVALID_ADDRESS, NULL);
844         }
845
846         if (avahi_server_add_address(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, 0, name, &a) < 0)
847             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
848         else
849             i->n_entries ++;
850         
851         return respond_ok(c, m);
852     }
853     
854     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
855
856 fail:
857     if (dbus_error_is_set(&error))
858         dbus_error_free(&error);
859     
860     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
861 }
862
863 static void sync_host_name_resolver_callback(AvahiSHostNameResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *host_name, const AvahiAddress *a, void* userdata) {
864     SyncHostNameResolverInfo *i = userdata;
865     
866     assert(r);
867     assert(host_name);
868     assert(i);
869
870     if (event == AVAHI_RESOLVER_FOUND) {
871         char t[256], *pt = t;
872         int32_t i_interface, i_protocol, i_aprotocol;
873         DBusMessage *reply;
874
875         assert(a);
876         avahi_address_snprint(t, sizeof(t), a);
877
878         i_interface = (int32_t) interface;
879         i_protocol = (int32_t) protocol;
880         i_aprotocol = (int32_t) a->proto;
881         
882         reply = dbus_message_new_method_return(i->message);
883         dbus_message_append_args(
884             reply,
885             DBUS_TYPE_INT32, &i_interface,
886             DBUS_TYPE_INT32, &i_protocol,
887             DBUS_TYPE_STRING, &host_name,
888             DBUS_TYPE_INT32, &i_aprotocol,
889             DBUS_TYPE_STRING, &pt,
890             DBUS_TYPE_INVALID);
891
892         dbus_connection_send(server->bus, reply, NULL);
893         dbus_message_unref(reply);
894     } else {
895         assert(event == AVAHI_RESOLVER_TIMEOUT);
896
897         respond_error(server->bus, i->message, AVAHI_ERR_TIMEOUT, NULL);
898     }
899
900     sync_host_name_resolver_free(i);
901 }
902
903 static void sync_address_resolver_callback(AvahiSAddressResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const AvahiAddress *address, const char *host_name, void* userdata) {
904     SyncAddressResolverInfo *i = userdata;
905     
906     assert(r);
907     assert(address);
908     assert(i);
909
910     if (event == AVAHI_RESOLVER_FOUND) {
911         char t[256], *pt = t;
912         int32_t i_interface, i_protocol, i_aprotocol;
913         DBusMessage *reply;
914
915         assert(host_name);
916         avahi_address_snprint(t, sizeof(t), address);
917
918         i_interface = (int32_t) interface;
919         i_protocol = (int32_t) protocol;
920         i_aprotocol = (int32_t) address->proto;
921         
922         reply = dbus_message_new_method_return(i->message);
923         dbus_message_append_args(
924             reply,
925             DBUS_TYPE_INT32, &i_interface,
926             DBUS_TYPE_INT32, &i_protocol,
927             DBUS_TYPE_INT32, &i_aprotocol,
928             DBUS_TYPE_STRING, &pt,
929             DBUS_TYPE_STRING, &host_name,
930             DBUS_TYPE_INVALID);
931
932         dbus_connection_send(server->bus, reply, NULL);
933         dbus_message_unref(reply);
934     } else {
935         assert(event == AVAHI_RESOLVER_TIMEOUT);
936         respond_error(server->bus, i->message, AVAHI_ERR_TIMEOUT, NULL);
937     }
938
939     sync_address_resolver_free(i);
940 }
941
942 static DBusHandlerResult msg_domain_browser_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
943     DBusError error;
944     DomainBrowserInfo *i = userdata;
945
946     assert(c);
947     assert(m);
948     assert(i);
949     
950     dbus_error_init(&error);
951
952     avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s",
953                     dbus_message_get_interface(m),
954                     dbus_message_get_path(m),
955                     dbus_message_get_member(m));
956
957     /* Introspection */
958     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
959         return handle_introspect(c, m, "DomainBrowser.introspect");
960     
961     /* Access control */
962     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
963         return respond_error(c, m, AVAHI_ERR_ACCESS_DENIED, NULL);
964     
965     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "Free")) {
966
967         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
968             avahi_log_warn("Error parsing DomainBrowser::Free message");
969             goto fail;
970         }
971
972         domain_browser_free(i);
973         return respond_ok(c, m);
974         
975     }
976     
977     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
978
979 fail:
980     if (dbus_error_is_set(&error))
981         dbus_error_free(&error);
982     
983     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
984 }
985
986 static void domain_browser_callback(AvahiSDomainBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *domain, void* userdata) {
987     DomainBrowserInfo *i = userdata;
988     DBusMessage *m;
989     int32_t i_interface, i_protocol;
990     
991     assert(b);
992     assert(domain);
993     assert(i);
994
995     i_interface = (int32_t) interface;
996     i_protocol = (int32_t) protocol;
997
998     m = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, event == AVAHI_BROWSER_NEW ? "ItemNew" : "ItemRemove");
999     dbus_message_append_args(
1000         m,
1001         DBUS_TYPE_INT32, &i_interface,
1002         DBUS_TYPE_INT32, &i_protocol,
1003         DBUS_TYPE_STRING, &domain,
1004         DBUS_TYPE_INVALID);
1005     dbus_message_set_destination(m, i->client->name);   
1006     dbus_connection_send(server->bus, m, NULL);
1007     dbus_message_unref(m);
1008 }
1009
1010 static DBusHandlerResult msg_service_type_browser_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
1011     DBusError error;
1012     ServiceTypeBrowserInfo *i = userdata;
1013
1014     assert(c);
1015     assert(m);
1016     assert(i);
1017     
1018     dbus_error_init(&error);
1019
1020     avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s",
1021                     dbus_message_get_interface(m),
1022                     dbus_message_get_path(m),
1023                     dbus_message_get_member(m));
1024
1025     /* Introspection */
1026     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
1027         return handle_introspect(c, m, "ServiceTypeBrowser.introspect");
1028     
1029     /* Access control */
1030     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
1031         return respond_error(c, m, AVAHI_ERR_ACCESS_DENIED, NULL);
1032     
1033     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "Free")) {
1034
1035         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
1036             avahi_log_warn("Error parsing ServiceTypeBrowser::Free message");
1037             goto fail;
1038         }
1039
1040         service_type_browser_free(i);
1041         return respond_ok(c, m);
1042         
1043     }
1044     
1045     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
1046
1047 fail:
1048     if (dbus_error_is_set(&error))
1049         dbus_error_free(&error);
1050     
1051     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1052 }
1053
1054 static void service_type_browser_callback(AvahiSServiceTypeBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *type, const char *domain, void* userdata) {
1055     ServiceTypeBrowserInfo *i = userdata;
1056     DBusMessage *m;
1057     int32_t i_interface, i_protocol;
1058     
1059     assert(b);
1060     assert(type);
1061     assert(domain);
1062     assert(i);
1063
1064     i_interface = (int32_t) interface;
1065     i_protocol = (int32_t) protocol;
1066
1067     m = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, event == AVAHI_BROWSER_NEW ? "ItemNew" : "ItemRemove");
1068     dbus_message_append_args(
1069         m,
1070         DBUS_TYPE_INT32, &i_interface,
1071         DBUS_TYPE_INT32, &i_protocol,
1072         DBUS_TYPE_STRING, &type,
1073         DBUS_TYPE_STRING, &domain,
1074         DBUS_TYPE_INVALID);
1075     dbus_message_set_destination(m, i->client->name);   
1076     dbus_connection_send(server->bus, m, NULL);
1077     dbus_message_unref(m);
1078 }
1079
1080 static DBusHandlerResult msg_service_browser_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
1081     DBusError error;
1082     ServiceBrowserInfo *i = userdata;
1083
1084     assert(c);
1085     assert(m);
1086     assert(i);
1087     
1088     dbus_error_init(&error);
1089
1090     avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s",
1091                     dbus_message_get_interface(m),
1092                     dbus_message_get_path(m),
1093                     dbus_message_get_member(m));
1094
1095     /* Introspection */
1096     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
1097         return handle_introspect(c, m, "ServiceBrowser.Introspect");
1098     
1099     /* Access control */
1100     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
1101         return respond_error(c, m, AVAHI_ERR_ACCESS_DENIED, NULL);
1102     
1103     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "Free")) {
1104
1105         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
1106             avahi_log_warn("Error parsing ServiceBrowser::Free message");
1107             goto fail;
1108         }
1109
1110         service_browser_free(i);
1111         return respond_ok(c, m);
1112         
1113     }
1114     
1115     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
1116
1117 fail:
1118     if (dbus_error_is_set(&error))
1119         dbus_error_free(&error);
1120     
1121     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1122 }
1123
1124 static void service_browser_callback(AvahiSServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, void* userdata) {
1125     ServiceBrowserInfo *i = userdata;
1126     DBusMessage *m;
1127     int32_t i_interface, i_protocol;
1128     
1129     assert(b);
1130     assert(name);
1131     assert(type);
1132     assert(domain);
1133     assert(i);
1134
1135     i_interface = (int32_t) interface;
1136     i_protocol = (int32_t) protocol;
1137
1138     m = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, event == AVAHI_BROWSER_NEW ? "ItemNew" : "ItemRemove");
1139     dbus_message_append_args(
1140         m,
1141         DBUS_TYPE_INT32, &i_interface,
1142         DBUS_TYPE_INT32, &i_protocol,
1143         DBUS_TYPE_STRING, &name,
1144         DBUS_TYPE_STRING, &type,
1145         DBUS_TYPE_STRING, &domain,
1146         DBUS_TYPE_INVALID);
1147     dbus_message_set_destination(m, i->client->name);   
1148     dbus_connection_send(server->bus, m, NULL);
1149     dbus_message_unref(m);
1150 }
1151
1152 static void append_string_list(DBusMessage *reply, AvahiStringList *txt) {
1153     AvahiStringList *p;
1154     DBusMessageIter iter, sub;
1155     
1156     assert(reply);
1157
1158     dbus_message_iter_init_append(reply, &iter);
1159     dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "ay", &sub);
1160     
1161     for (p = txt; p; p = p->next) {
1162         DBusMessageIter sub2;
1163         const uint8_t *data = p->text;
1164         
1165         dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "y", &sub2);
1166         dbus_message_iter_append_fixed_array(&sub2, DBUS_TYPE_BYTE, &data, p->size); 
1167         dbus_message_iter_close_container(&sub, &sub2);
1168         
1169     }
1170     dbus_message_iter_close_container(&iter, &sub);
1171 }
1172
1173 static void sync_service_resolver_callback(
1174     AvahiSServiceResolver *r,
1175     AvahiIfIndex interface,
1176     AvahiProtocol protocol,
1177     AvahiResolverEvent event,
1178     const char *name,
1179     const char *type,
1180     const char *domain,
1181     const char *host_name,
1182     const AvahiAddress *a,
1183     uint16_t port,
1184     AvahiStringList *txt,
1185     void* userdata) {
1186     
1187     SyncServiceResolverInfo *i = userdata;
1188     
1189     assert(r);
1190     assert(i);
1191
1192     if (event == AVAHI_RESOLVER_FOUND) {
1193         char t[256], *pt = t;
1194         int32_t i_interface, i_protocol, i_aprotocol;
1195         DBusMessage *reply;
1196     
1197         assert(host_name);
1198         
1199         assert(a);
1200         avahi_address_snprint(t, sizeof(t), a);
1201
1202         i_interface = (int32_t) interface;
1203         i_protocol = (int32_t) protocol;
1204         i_aprotocol = (int32_t) a->proto;
1205
1206         reply = dbus_message_new_method_return(i->message);
1207         dbus_message_append_args(
1208             reply,
1209             DBUS_TYPE_INT32, &i_interface,
1210             DBUS_TYPE_INT32, &i_protocol,
1211             DBUS_TYPE_STRING, &name,
1212             DBUS_TYPE_STRING, &type,
1213             DBUS_TYPE_STRING, &domain,
1214             DBUS_TYPE_STRING, &host_name,
1215             DBUS_TYPE_INT32, &i_aprotocol,
1216             DBUS_TYPE_STRING, &pt,
1217             DBUS_TYPE_UINT16, &port,
1218             DBUS_TYPE_INVALID);
1219
1220         append_string_list(reply, txt);
1221                 
1222         dbus_connection_send(server->bus, reply, NULL);
1223         dbus_message_unref(reply);
1224     } else {
1225         assert(event == AVAHI_RESOLVER_TIMEOUT);
1226
1227         respond_error(server->bus, i->message, AVAHI_ERR_TIMEOUT, NULL);
1228     }
1229
1230     sync_service_resolver_free(i);
1231 }
1232
1233 static void async_address_resolver_callback(AvahiSAddressResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const AvahiAddress *address, const char *host_name, void* userdata) {
1234     AsyncAddressResolverInfo *i = userdata;
1235     DBusMessage *reply;
1236     
1237     assert(r);
1238     assert(address);
1239     assert(i);
1240
1241     if (event == AVAHI_RESOLVER_FOUND) {
1242         char t[256], *pt = t;
1243         int32_t i_interface, i_protocol, i_aprotocol;
1244
1245         assert(host_name);
1246         avahi_address_snprint(t, sizeof(t), address);
1247
1248         i_interface = (int32_t) interface;
1249         i_protocol = (int32_t) protocol;
1250         i_aprotocol = (int32_t) address->proto;
1251         
1252         reply = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_ADDRESS_RESOLVER, "Found");
1253         dbus_message_append_args(
1254             reply,
1255             DBUS_TYPE_INT32, &i_interface,
1256             DBUS_TYPE_INT32, &i_protocol,
1257             DBUS_TYPE_INT32, &i_aprotocol,
1258             DBUS_TYPE_STRING, &pt,
1259             DBUS_TYPE_STRING, &host_name,
1260             DBUS_TYPE_INVALID);
1261
1262     } else {
1263         assert(event == AVAHI_RESOLVER_TIMEOUT);
1264
1265         reply = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_ADDRESS_RESOLVER, "Timeout");
1266     }
1267
1268     dbus_message_set_destination(reply, i->client->name);  
1269     dbus_connection_send(server->bus, reply, NULL);
1270     dbus_message_unref(reply);
1271 }
1272
1273 static DBusHandlerResult msg_async_address_resolver_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
1274     DBusError error;
1275     AsyncAddressResolverInfo *i = userdata;
1276
1277     assert(c);
1278     assert(m);
1279     assert(i);
1280     
1281     dbus_error_init(&error);
1282
1283     avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s",
1284                     dbus_message_get_interface(m),
1285                     dbus_message_get_path(m),
1286                     dbus_message_get_member(m));
1287
1288     /* Introspection */
1289     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
1290         return handle_introspect(c, m, "AddressResolver.Introspect");
1291     
1292     /* Access control */
1293     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
1294         return respond_error(c, m, AVAHI_ERR_ACCESS_DENIED, NULL);
1295     
1296     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ADDRESS_RESOLVER, "Free")) {
1297
1298         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
1299             avahi_log_warn("Error parsing AddressResolver::Free message");
1300             goto fail;
1301         }
1302
1303         async_address_resolver_free(i);
1304         return respond_ok(c, m);
1305         
1306     }
1307     
1308     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
1309
1310 fail:
1311     if (dbus_error_is_set(&error))
1312         dbus_error_free(&error);
1313     
1314     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1315 }
1316
1317 static void async_host_name_resolver_callback(AvahiSHostNameResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *host_name, const AvahiAddress *a, void* userdata) {
1318     AsyncHostNameResolverInfo *i = userdata;
1319     DBusMessage *reply;
1320     
1321     assert(r);
1322     assert(host_name);
1323     assert(i);
1324
1325     if (event == AVAHI_RESOLVER_FOUND) {
1326         char t[256], *pt = t;
1327         int32_t i_interface, i_protocol, i_aprotocol;
1328
1329         assert(a);
1330         avahi_address_snprint(t, sizeof(t), a);
1331
1332         i_interface = (int32_t) interface;
1333         i_protocol = (int32_t) protocol;
1334         i_aprotocol = (int32_t) a->proto;
1335         
1336         reply = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_HOST_NAME_RESOLVER, "Found");
1337         dbus_message_append_args(
1338             reply,
1339             DBUS_TYPE_INT32, &i_interface,
1340             DBUS_TYPE_INT32, &i_protocol,
1341             DBUS_TYPE_STRING, &host_name,
1342             DBUS_TYPE_INT32, &i_aprotocol,
1343             DBUS_TYPE_STRING, &pt,
1344             DBUS_TYPE_INVALID);
1345     } else {
1346         assert(event == AVAHI_RESOLVER_TIMEOUT);
1347
1348         reply = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_HOST_NAME_RESOLVER, "Timeout");
1349     }
1350
1351     dbus_message_set_destination(reply, i->client->name);  
1352     dbus_connection_send(server->bus, reply, NULL);
1353     dbus_message_unref(reply);
1354 }
1355
1356 static DBusHandlerResult msg_async_host_name_resolver_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
1357     DBusError error;
1358     AsyncHostNameResolverInfo *i = userdata;
1359
1360     assert(c);
1361     assert(m);
1362     assert(i);
1363     
1364     dbus_error_init(&error);
1365
1366     avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s",
1367                     dbus_message_get_interface(m),
1368                     dbus_message_get_path(m),
1369                     dbus_message_get_member(m));
1370
1371     /* Introspection */
1372     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
1373         return handle_introspect(c, m, "HostNameResolver.Introspect");
1374     
1375     /* Access control */
1376     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
1377         return respond_error(c, m, AVAHI_ERR_ACCESS_DENIED, NULL);
1378     
1379     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_HOST_NAME_RESOLVER, "Free")) {
1380
1381         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
1382             avahi_log_warn("Error parsing HostNameResolver::Free message");
1383             goto fail;
1384         }
1385
1386         async_host_name_resolver_free(i);
1387         return respond_ok(c, m);
1388     }
1389     
1390     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
1391
1392 fail:
1393     if (dbus_error_is_set(&error))
1394         dbus_error_free(&error);
1395     
1396     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1397 }
1398
1399 static void async_service_resolver_callback(
1400     AvahiSServiceResolver *r,
1401     AvahiIfIndex interface,
1402     AvahiProtocol protocol,
1403     AvahiResolverEvent event,
1404     const char *name,
1405     const char *type,
1406     const char *domain,
1407     const char *host_name,
1408     const AvahiAddress *a,
1409     uint16_t port,
1410     AvahiStringList *txt,
1411     void* userdata) {
1412
1413     AsyncServiceResolverInfo *i = userdata;
1414     DBusMessage *reply;
1415     
1416     assert(r);
1417     assert(i);
1418
1419     if (event == AVAHI_RESOLVER_FOUND) {
1420         char t[256], *pt = t;
1421         int32_t i_interface, i_protocol, i_aprotocol;
1422     
1423         assert(host_name);
1424
1425 /*         avahi_log_debug(__FILE__": [%s] Successfully resolved service <%s.%s.%s>", i->path, name, type, domain); */
1426         
1427         assert(a);
1428         avahi_address_snprint(t, sizeof(t), a);
1429
1430         i_interface = (int32_t) interface;
1431         i_protocol = (int32_t) protocol;
1432         i_aprotocol = (int32_t) a->proto;
1433
1434         reply = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_SERVICE_RESOLVER, "Found");
1435         dbus_message_append_args(
1436             reply,
1437             DBUS_TYPE_INT32, &i_interface,
1438             DBUS_TYPE_INT32, &i_protocol,
1439             DBUS_TYPE_STRING, &name,
1440             DBUS_TYPE_STRING, &type,
1441             DBUS_TYPE_STRING, &domain,
1442             DBUS_TYPE_STRING, &host_name,
1443             DBUS_TYPE_INT32, &i_aprotocol,
1444             DBUS_TYPE_STRING, &pt,
1445             DBUS_TYPE_UINT16, &port,
1446             DBUS_TYPE_INVALID);
1447
1448         append_string_list(reply, txt);
1449         
1450     } else {
1451         assert(event == AVAHI_RESOLVER_TIMEOUT);
1452
1453 /*         avahi_log_debug(__FILE__": [%s] Failed to resolve service <%s.%s.%s>", i->path, name, type, domain); */
1454         
1455         reply = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_SERVICE_RESOLVER, "Timeout");
1456     }
1457
1458     dbus_message_set_destination(reply, i->client->name);  
1459     dbus_connection_send(server->bus, reply, NULL);
1460     dbus_message_unref(reply);
1461 }
1462
1463 static DBusHandlerResult msg_async_service_resolver_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
1464     DBusError error;
1465     AsyncServiceResolverInfo *i = userdata;
1466
1467     assert(c);
1468     assert(m);
1469     assert(i);
1470     
1471     dbus_error_init(&error);
1472
1473     avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s",
1474                     dbus_message_get_interface(m),
1475                     dbus_message_get_path(m),
1476                     dbus_message_get_member(m));
1477
1478     /* Introspection */
1479     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
1480         return handle_introspect(c, m, "ServiceResolver.Introspect");
1481     
1482     /* Access control */
1483     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
1484         return respond_error(c, m, AVAHI_ERR_ACCESS_DENIED, NULL);
1485     
1486     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVICE_RESOLVER, "Free")) {
1487
1488         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
1489             avahi_log_warn("Error parsing ServiceResolver::Free message");
1490             goto fail;
1491         }
1492
1493         async_service_resolver_free(i);
1494         return respond_ok(c, m);
1495     }
1496     
1497     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
1498
1499 fail:
1500     if (dbus_error_is_set(&error))
1501         dbus_error_free(&error);
1502     
1503     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1504 }
1505
1506 static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
1507     DBusError error;
1508
1509     dbus_error_init(&error);
1510
1511     avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s",
1512                     dbus_message_get_interface(m),
1513                     dbus_message_get_path(m),
1514                     dbus_message_get_member(m));
1515
1516     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
1517         return handle_introspect(c, m, "Server.introspect");
1518         
1519     else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostName")) {
1520
1521         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
1522             avahi_log_warn("Error parsing Server::GetHostName message");
1523             goto fail;
1524         }
1525
1526         return respond_string(c, m, avahi_server_get_host_name(avahi_server));
1527         
1528     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetDomainName")) {
1529
1530         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
1531             avahi_log_warn("Error parsing Server::GetDomainName message");
1532             goto fail;
1533         }
1534
1535         return respond_string(c, m, avahi_server_get_domain_name(avahi_server));
1536
1537     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostNameFqdn")) {
1538
1539         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
1540             avahi_log_warn("Error parsing Server::GetHostNameFqdn message");
1541             goto fail;
1542         }
1543     
1544         return respond_string(c, m, avahi_server_get_host_name_fqdn(avahi_server));
1545         
1546     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetVersionString")) {
1547
1548         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
1549             avahi_log_warn("Error parsing Server::GetVersionString message");
1550             goto fail;
1551         }
1552     
1553         return respond_string(c, m, PACKAGE_STRING);
1554
1555     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetState")) {
1556         AvahiServerState state;
1557         
1558         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
1559             avahi_log_warn("Error parsing Server::GetState message");
1560             goto fail;
1561         }
1562         
1563         state = avahi_server_get_state(avahi_server);
1564         return respond_int32(c, m, (int32_t) state);
1565
1566     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetLocalServiceCookie")) {
1567
1568         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
1569             avahi_log_warn("Error parsing Server::GetLocalServiceCookie message");
1570             goto fail;
1571         }
1572         
1573         return respond_uint32(c, m, avahi_server_get_local_service_cookie(avahi_server));
1574
1575     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "IsServiceLocal")) {
1576         int32_t interface, protocol;
1577         char *name, *type, *domain;
1578         int b;
1579         
1580         if (!dbus_message_get_args(
1581                 m, &error,
1582                 DBUS_TYPE_INT32, &interface,
1583                 DBUS_TYPE_INT32, &protocol,
1584                 DBUS_TYPE_STRING, &name,
1585                 DBUS_TYPE_STRING, &type,
1586                 DBUS_TYPE_STRING, &domain,
1587                 DBUS_TYPE_INVALID) || !name || !type || !domain) {
1588             avahi_log_warn("Error parsing Server::IsServiceLocal message");
1589             goto fail;
1590         }
1591
1592         if ((b = avahi_server_is_service_local(avahi_server, interface, protocol, name, type, domain)) < 0)
1593             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);            
1594         
1595         return respond_boolean(c, m, b);
1596
1597     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetNetworkInterfaceNameByIndex")) {
1598         int32_t idx;
1599         int fd;
1600         struct ifreq ifr;
1601         
1602         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INT32, &idx, DBUS_TYPE_INVALID))) {
1603             avahi_log_warn("Error parsing Server::GetNetworkInterfaceNameByIndex message");
1604             goto fail;
1605         }
1606
1607 #ifdef VALGRIND_WORKAROUND
1608         return respond_string(c, m, "blah");
1609 #else
1610         
1611         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
1612             if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1613                 char txt[256];
1614                 snprintf(txt, sizeof(txt), "OS Error: %s", strerror(errno));
1615                 return respond_error(c, m, AVAHI_ERR_OS, txt);
1616             }
1617
1618         memset(&ifr, 0, sizeof(ifr));
1619         ifr.ifr_ifindex = idx;
1620
1621         if (ioctl(fd, SIOCGIFNAME, &ifr) < 0) {
1622             char txt[256];
1623             snprintf(txt, sizeof(txt), "OS Error: %s", strerror(errno));
1624             close(fd);
1625             return respond_error(c, m, AVAHI_ERR_OS, txt);
1626         }
1627
1628         close(fd);
1629         
1630         return respond_string(c, m, ifr.ifr_name);
1631 #endif
1632         
1633     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetNetworkInterfaceIndexByName")) {
1634         char *n;
1635         int fd;
1636         struct ifreq ifr;
1637         
1638         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n) {
1639             avahi_log_warn("Error parsing Server::GetNetworkInterfaceIndexByName message");
1640             goto fail;
1641         }
1642
1643 #ifdef VALGRIND_WORKAROUND
1644         return respond_int32(c, m, 1);
1645 #else
1646         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
1647             if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1648                 char txt[256];
1649                 snprintf(txt, sizeof(txt), "OS Error: %s", strerror(errno));
1650                 return respond_error(c, m, AVAHI_ERR_OS, txt);
1651             }
1652
1653         memset(&ifr, 0, sizeof(ifr));
1654         snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", n);
1655
1656         if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
1657             char txt[256];
1658             snprintf(txt, sizeof(txt), "OS Error: %s", strerror(errno));
1659             close(fd);
1660             return respond_error(c, m, AVAHI_ERR_OS, txt);
1661         }
1662
1663         close(fd);
1664         
1665         return respond_int32(c, m, ifr.ifr_ifindex);
1666 #endif
1667
1668     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetAlternativeHostName")) {
1669         char *n, * t;
1670         
1671         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n) {
1672             avahi_log_warn("Error parsing Server::GetAlternativeHostName message");
1673             goto fail;
1674         }
1675
1676         t = avahi_alternative_host_name(n);
1677         respond_string(c, m, t);
1678         avahi_free(t);
1679
1680         return DBUS_HANDLER_RESULT_HANDLED;
1681
1682     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetAlternativeServiceName")) {
1683         char *n, *t;
1684         
1685         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n) {
1686             avahi_log_warn("Error parsing Server::GetAlternativeServiceName message");
1687             goto fail;
1688         }
1689
1690         t = avahi_alternative_service_name(n);
1691         respond_string(c, m, t);
1692         avahi_free(t);
1693
1694         return DBUS_HANDLER_RESULT_HANDLED;
1695         
1696     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "EntryGroupNew")) {
1697         Client *client;
1698         EntryGroupInfo *i;
1699         static const DBusObjectPathVTable vtable = {
1700             NULL,
1701             msg_entry_group_impl,
1702             NULL,
1703             NULL,
1704             NULL,
1705             NULL
1706         };
1707
1708         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
1709             avahi_log_warn("Error parsing Server::EntryGroupNew message");
1710             goto fail;
1711         }
1712
1713         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1714             avahi_log_warn("Too many clients, client request failed.");
1715             return respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
1716         }
1717
1718         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1719             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1720             return respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
1721         }
1722
1723         i = avahi_new(EntryGroupInfo, 1);
1724         i->id = ++client->current_id;
1725         i->client = client;
1726         i->path = avahi_strdup_printf("/Client%u/EntryGroup%u", client->id, i->id);
1727         i->n_entries = 0;
1728         AVAHI_LLIST_PREPEND(EntryGroupInfo, entry_groups, client->entry_groups, i);
1729         client->n_objects++;
1730         
1731         if (!(i->entry_group = avahi_s_entry_group_new(avahi_server, entry_group_callback, i))) {
1732             entry_group_free(i);
1733             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
1734         }
1735
1736         dbus_connection_register_object_path(c, i->path, &vtable, i);
1737         return respond_path(c, m, i->path);
1738         
1739     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveHostName")) {
1740         Client *client;
1741         int32_t interface, protocol, aprotocol;
1742         char *name;
1743         SyncHostNameResolverInfo *i;
1744             
1745         if (!dbus_message_get_args(
1746                 m, &error,
1747                 DBUS_TYPE_INT32, &interface,
1748                 DBUS_TYPE_INT32, &protocol,
1749                 DBUS_TYPE_STRING, &name,
1750                 DBUS_TYPE_INT32, &aprotocol,
1751                 DBUS_TYPE_INVALID) || !name) {
1752             avahi_log_warn("Error parsing Server::ResolveHostName message");
1753             goto fail;
1754         }
1755
1756         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1757             avahi_log_warn("Too many clients, client request failed.");
1758             return respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
1759         }
1760
1761         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1762             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1763             return respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
1764         }
1765
1766         i = avahi_new(SyncHostNameResolverInfo, 1);
1767         i->client = client;
1768         i->message = dbus_message_ref(m);
1769         AVAHI_LLIST_PREPEND(SyncHostNameResolverInfo, sync_host_name_resolvers, client->sync_host_name_resolvers, i);
1770         client->n_objects++;
1771
1772         if (!(i->host_name_resolver = avahi_s_host_name_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, (AvahiProtocol) aprotocol, sync_host_name_resolver_callback, i))) {
1773             sync_host_name_resolver_free(i);
1774             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
1775         }
1776         
1777         return DBUS_HANDLER_RESULT_HANDLED;
1778         
1779     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveAddress")) {
1780         Client *client;
1781         int32_t interface, protocol;
1782         char *address;
1783         SyncAddressResolverInfo *i;
1784         AvahiAddress a;
1785             
1786         if (!dbus_message_get_args(
1787                 m, &error,
1788                 DBUS_TYPE_INT32, &interface,
1789                 DBUS_TYPE_INT32, &protocol,
1790                 DBUS_TYPE_STRING, &address,
1791                 DBUS_TYPE_INVALID) || !address) {
1792             avahi_log_warn("Error parsing Server::ResolveAddress message");
1793             goto fail;
1794         }
1795
1796         if (!avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a))
1797             return respond_error(c, m, AVAHI_ERR_INVALID_ADDRESS, NULL);
1798
1799         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1800             avahi_log_warn("Too many clients, client request failed.");
1801             return respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
1802         }
1803
1804         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1805             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1806             return respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
1807         }
1808
1809         i = avahi_new(SyncAddressResolverInfo, 1);
1810         i->client = client;
1811         i->message = dbus_message_ref(m);
1812         AVAHI_LLIST_PREPEND(SyncAddressResolverInfo, sync_address_resolvers, client->sync_address_resolvers, i);
1813         client->n_objects++;
1814
1815         if (!(i->address_resolver = avahi_s_address_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, &a, sync_address_resolver_callback, i))) {
1816             sync_address_resolver_free(i);
1817             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
1818         }
1819         
1820         return DBUS_HANDLER_RESULT_HANDLED;
1821         
1822     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "DomainBrowserNew")) {
1823         Client *client;
1824         DomainBrowserInfo *i;
1825         static const DBusObjectPathVTable vtable = {
1826             NULL,
1827             msg_domain_browser_impl,
1828             NULL,
1829             NULL,
1830             NULL,
1831             NULL
1832         };
1833         int32_t interface, protocol, type;
1834         char *domain;
1835         
1836         if (!dbus_message_get_args(
1837                 m, &error,
1838                 DBUS_TYPE_INT32, &interface,
1839                 DBUS_TYPE_INT32, &protocol,
1840                 DBUS_TYPE_STRING, &domain,
1841                 DBUS_TYPE_INT32, &type,
1842                 DBUS_TYPE_INVALID) || type < 0 || type >= AVAHI_DOMAIN_BROWSER_MAX) {
1843             avahi_log_warn("Error parsing Server::DomainBrowserNew message");
1844             goto fail;
1845         }
1846
1847         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1848             avahi_log_warn("Too many clients, client request failed.");
1849             return respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
1850         }
1851
1852         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1853             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1854             return respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
1855         }
1856
1857         if (!*domain)
1858             domain = NULL;
1859
1860         i = avahi_new(DomainBrowserInfo, 1);
1861         i->id = ++client->current_id;
1862         i->client = client;
1863         i->path = avahi_strdup_printf("/Client%u/DomainBrowser%u", client->id, i->id);
1864         AVAHI_LLIST_PREPEND(DomainBrowserInfo, domain_browsers, client->domain_browsers, i);
1865         client->n_objects++;
1866
1867         if (!(i->domain_browser = avahi_s_domain_browser_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, domain, (AvahiDomainBrowserType) type, domain_browser_callback, i))) {
1868             domain_browser_free(i);
1869             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
1870         }
1871         
1872         dbus_connection_register_object_path(c, i->path, &vtable, i);
1873         return respond_path(c, m, i->path);
1874
1875     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ServiceTypeBrowserNew")) {
1876         Client *client;
1877         ServiceTypeBrowserInfo *i;
1878         static const DBusObjectPathVTable vtable = {
1879             NULL,
1880             msg_service_type_browser_impl,
1881             NULL,
1882             NULL,
1883             NULL,
1884             NULL
1885         };
1886         int32_t interface, protocol;
1887         char *domain;
1888         
1889         if (!dbus_message_get_args(
1890                 m, &error,
1891                 DBUS_TYPE_INT32, &interface,
1892                 DBUS_TYPE_INT32, &protocol,
1893                 DBUS_TYPE_STRING, &domain,
1894                 DBUS_TYPE_INVALID)) {
1895             avahi_log_warn("Error parsing Server::ServiceTypeBrowserNew message");
1896             goto fail;
1897         }
1898
1899         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1900             avahi_log_warn("Too many clients, client request failed.");
1901             return respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
1902         }
1903
1904
1905         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1906             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1907             return respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
1908         }
1909
1910         if (!*domain)
1911             domain = NULL;
1912
1913         i = avahi_new(ServiceTypeBrowserInfo, 1);
1914         i->id = ++client->current_id;
1915         i->client = client;
1916         i->path = avahi_strdup_printf("/Client%u/ServiceTypeBrowser%u", client->id, i->id);
1917         AVAHI_LLIST_PREPEND(ServiceTypeBrowserInfo, service_type_browsers, client->service_type_browsers, i);
1918         client->n_objects++;
1919
1920         if (!(i->service_type_browser = avahi_s_service_type_browser_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, domain, service_type_browser_callback, i))) {
1921             service_type_browser_free(i);
1922             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
1923         }
1924         
1925         dbus_connection_register_object_path(c, i->path, &vtable, i);
1926         return respond_path(c, m, i->path);
1927         
1928     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ServiceBrowserNew")) {
1929         Client *client;
1930         ServiceBrowserInfo *i;
1931         static const DBusObjectPathVTable vtable = {
1932             NULL,
1933             msg_service_browser_impl,
1934             NULL,
1935             NULL,
1936             NULL,
1937             NULL
1938         };
1939         int32_t interface, protocol;
1940         char *domain, *type;
1941         
1942         if (!dbus_message_get_args(
1943                 m, &error,
1944                 DBUS_TYPE_INT32, &interface,
1945                 DBUS_TYPE_INT32, &protocol,
1946                 DBUS_TYPE_STRING, &type,
1947                 DBUS_TYPE_STRING, &domain,
1948                 DBUS_TYPE_INVALID) || !type) {
1949             avahi_log_warn("Error parsing Server::ServiceBrowserNew message");
1950             goto fail;
1951         }
1952
1953         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1954             avahi_log_warn("Too many clients, client request failed.");
1955             return respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
1956         }
1957
1958
1959         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1960             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1961             return respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
1962         }
1963
1964         if (!*domain)
1965             domain = NULL;
1966
1967         i = avahi_new(ServiceBrowserInfo, 1);
1968         i->id = ++client->current_id;
1969         i->client = client;
1970         i->path = avahi_strdup_printf("/Client%u/ServiceBrowser%u", client->id, i->id);
1971         AVAHI_LLIST_PREPEND(ServiceBrowserInfo, service_browsers, client->service_browsers, i);
1972         client->n_objects++;
1973
1974         if (!(i->service_browser = avahi_s_service_browser_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, type, domain, service_browser_callback, i))) {
1975             service_browser_free(i);
1976             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
1977         }
1978         
1979         dbus_connection_register_object_path(c, i->path, &vtable, i);
1980         return respond_path(c, m, i->path);
1981         
1982     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveService")) {
1983         Client *client;
1984         int32_t interface, protocol, aprotocol;
1985         char *name, *type, *domain;
1986         SyncServiceResolverInfo *i;
1987             
1988         if (!dbus_message_get_args(
1989                 m, &error,
1990                 DBUS_TYPE_INT32, &interface,
1991                 DBUS_TYPE_INT32, &protocol,
1992                 DBUS_TYPE_STRING, &name,
1993                 DBUS_TYPE_STRING, &type,
1994                 DBUS_TYPE_STRING, &domain,
1995                 DBUS_TYPE_INT32, &aprotocol,
1996                 DBUS_TYPE_INVALID) || !name || !type) {
1997             avahi_log_warn("Error parsing Server::ResolveService message");
1998             goto fail;
1999         }
2000
2001         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
2002             avahi_log_warn("Too many clients, client request failed.");
2003             return respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
2004         }
2005         
2006         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
2007             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
2008             return respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
2009         }
2010
2011         if (!*domain)
2012             domain = NULL;
2013         
2014         i = avahi_new(SyncServiceResolverInfo, 1);
2015         i->client = client;
2016         i->message = dbus_message_ref(m);
2017         AVAHI_LLIST_PREPEND(SyncServiceResolverInfo, sync_service_resolvers, client->sync_service_resolvers, i);
2018         client->n_objects++;
2019
2020         if (!(i->service_resolver = avahi_s_service_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, type, domain, (AvahiProtocol) aprotocol, sync_service_resolver_callback, i))) {
2021             sync_service_resolver_free(i);
2022             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
2023         }
2024         
2025         return DBUS_HANDLER_RESULT_HANDLED;
2026         
2027     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ServiceResolverNew")) {
2028         Client *client;
2029         int32_t interface, protocol, aprotocol;
2030         char *name, *type, *domain;
2031         AsyncServiceResolverInfo *i;
2032         static const DBusObjectPathVTable vtable = {
2033             NULL,
2034             msg_async_service_resolver_impl,
2035             NULL,
2036             NULL,
2037             NULL,
2038             NULL
2039         };
2040
2041         if (!dbus_message_get_args(
2042                 m, &error,
2043                 DBUS_TYPE_INT32, &interface,
2044                 DBUS_TYPE_INT32, &protocol,
2045                 DBUS_TYPE_STRING, &name,
2046                 DBUS_TYPE_STRING, &type,
2047                 DBUS_TYPE_STRING, &domain,
2048                 DBUS_TYPE_INT32, &aprotocol,
2049                 DBUS_TYPE_INVALID) || !name || !type) {
2050             avahi_log_warn("Error parsing Server::ServiceResolverNew message");
2051             goto fail;
2052         }
2053             
2054         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
2055             avahi_log_warn(__FILE__": Too many clients, client request failed.");
2056             return respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
2057         }
2058
2059         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
2060             avahi_log_warn(__FILE__": Too many objects for client '%s', client request failed.", client->name);
2061             return respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
2062         }
2063
2064         i = avahi_new(AsyncServiceResolverInfo, 1);
2065         i->id = ++client->current_id;
2066         i->client = client;
2067         i->path = avahi_strdup_printf("/Client%u/ServiceResolver%u", client->id, i->id);
2068         AVAHI_LLIST_PREPEND(AsyncServiceResolverInfo, async_service_resolvers, client->async_service_resolvers, i);
2069         client->n_objects++;
2070
2071         if (!(i->service_resolver = avahi_s_service_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, type, domain, (AvahiProtocol) aprotocol, async_service_resolver_callback, i))) {
2072             async_service_resolver_free(i);
2073             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
2074         }
2075
2076 /*         avahi_log_debug(__FILE__": [%s], new service resolver for <%s.%s.%s>", i->path, name, type, domain); */
2077         
2078         dbus_connection_register_object_path(c, i->path, &vtable, i);
2079         return respond_path(c, m, i->path);
2080
2081     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "HostNameResolverNew")) {
2082         Client *client;
2083         int32_t interface, protocol, aprotocol;
2084         char *name;
2085         AsyncHostNameResolverInfo *i;
2086         static const DBusObjectPathVTable vtable = {
2087             NULL,
2088             msg_async_host_name_resolver_impl,
2089             NULL,
2090             NULL,
2091             NULL,
2092             NULL
2093         };
2094             
2095         if (!dbus_message_get_args(
2096                 m, &error,
2097                 DBUS_TYPE_INT32, &interface,
2098                 DBUS_TYPE_INT32, &protocol,
2099                 DBUS_TYPE_STRING, &name,
2100                 DBUS_TYPE_INT32, &aprotocol,
2101                 DBUS_TYPE_INVALID) || !name) {
2102             avahi_log_warn("Error parsing Server::HostNameResolverNew message");
2103             goto fail;
2104         }
2105             
2106         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
2107             avahi_log_warn(__FILE__": Too many clients, client request failed.");
2108             return respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
2109         }
2110
2111         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
2112             avahi_log_warn(__FILE__": Too many objects for client '%s', client request failed.", client->name);
2113             return respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
2114         }
2115
2116         i = avahi_new(AsyncHostNameResolverInfo, 1);
2117         i->id = ++client->current_id;
2118         i->client = client;
2119         i->path = avahi_strdup_printf("/Client%u/HostNameResolver%u", client->id, i->id);
2120         AVAHI_LLIST_PREPEND(AsyncHostNameResolverInfo, async_host_name_resolvers, client->async_host_name_resolvers, i);
2121         client->n_objects++;
2122
2123         if (!(i->host_name_resolver = avahi_s_host_name_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, aprotocol, async_host_name_resolver_callback, i))) {
2124             async_host_name_resolver_free(i);
2125             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
2126         }
2127         
2128         dbus_connection_register_object_path(c, i->path, &vtable, i);
2129         return respond_path(c, m, i->path);
2130
2131     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "AddressResolverNew")) {
2132         Client *client;
2133         int32_t interface, protocol;
2134         char *address;
2135         AsyncAddressResolverInfo *i;
2136         AvahiAddress a;
2137         static const DBusObjectPathVTable vtable = {
2138             NULL,
2139             msg_async_address_resolver_impl,
2140             NULL,
2141             NULL,
2142             NULL,
2143             NULL
2144         };
2145             
2146         if (!dbus_message_get_args(
2147                 m, &error,
2148                 DBUS_TYPE_INT32, &interface,
2149                 DBUS_TYPE_INT32, &protocol,
2150                 DBUS_TYPE_STRING, &address,
2151                 DBUS_TYPE_INVALID) || !address) {
2152             avahi_log_warn("Error parsing Server::AddressResolverNew message");
2153             goto fail;
2154         }
2155
2156         if (!avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a))
2157             return respond_error(c, m, AVAHI_ERR_INVALID_ADDRESS, NULL);
2158
2159         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
2160             avahi_log_warn(__FILE__": Too many clients, client request failed.");
2161             return respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
2162         }
2163
2164         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
2165             avahi_log_warn(__FILE__": Too many objects for client '%s', client request failed.", client->name);
2166             return respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
2167         }
2168
2169         i = avahi_new(AsyncAddressResolverInfo, 1);
2170         i->id = ++client->current_id;
2171         i->client = client;
2172         i->path = avahi_strdup_printf("/Client%u/AddressResolver%u", client->id, i->id);
2173         AVAHI_LLIST_PREPEND(AsyncAddressResolverInfo, async_address_resolvers, client->async_address_resolvers, i);
2174         client->n_objects++;
2175
2176         if (!(i->address_resolver = avahi_s_address_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, &a, async_address_resolver_callback, i))) {
2177             async_address_resolver_free(i);
2178             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
2179         }
2180         
2181         dbus_connection_register_object_path(c, i->path, &vtable, i);
2182         return respond_path(c, m, i->path);
2183     }
2184
2185     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
2186
2187 fail:
2188     if (dbus_error_is_set(&error))
2189         dbus_error_free(&error);
2190     
2191     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2192 }
2193
2194 void dbus_protocol_server_state_changed(AvahiServerState state) {
2195     DBusMessage *m;
2196     int32_t t;
2197     
2198     if (!server)
2199         return;
2200
2201     m = dbus_message_new_signal(AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "StateChanged");
2202     t = (int32_t) state;
2203     dbus_message_append_args(m, DBUS_TYPE_INT32, &t, DBUS_TYPE_INVALID);
2204     dbus_connection_send(server->bus, m, NULL);
2205     dbus_message_unref(m);
2206 }
2207
2208 int dbus_protocol_setup(const AvahiPoll *poll_api) {
2209     DBusError error;
2210
2211     static const DBusObjectPathVTable server_vtable = {
2212         NULL,
2213         msg_server_impl,
2214         NULL,
2215         NULL,
2216         NULL,
2217         NULL
2218     };
2219
2220     dbus_error_init(&error);
2221
2222     server = avahi_new(Server, 1);
2223     AVAHI_LLIST_HEAD_INIT(Clients, server->clients);
2224     server->current_id = 0;
2225     server->n_clients = 0;
2226
2227     if (!(server->bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
2228         assert(dbus_error_is_set(&error));
2229         avahi_log_error("dbus_bus_get(): %s", error.message);
2230         goto fail;
2231     }
2232
2233     if (avahi_dbus_connection_glue(server->bus, poll_api) < 0) {
2234         avahi_log_error("avahi_dbus_connection_glue() failed");
2235         goto fail;
2236     }
2237
2238     if (dbus_bus_request_name(server->bus, AVAHI_DBUS_NAME, DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT, &error) != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
2239         if (dbus_error_is_set(&error)) {
2240             avahi_log_error("dbus_bus_request_name(): %s", error.message);
2241             goto fail;
2242         }
2243
2244         avahi_log_error("Failed to acquire DBUS name '"AVAHI_DBUS_NAME"'");
2245         goto fail;
2246     }
2247
2248     if (!(dbus_connection_add_filter(server->bus, msg_signal_filter_impl, (void*) poll_api, NULL))) {
2249         avahi_log_error("dbus_connection_add_filter() failed");
2250         goto fail;
2251     }
2252     
2253     dbus_bus_add_match(server->bus, "type='signal',""interface='" DBUS_INTERFACE_DBUS  "'", &error);
2254
2255     if (dbus_error_is_set(&error)) {
2256         avahi_log_error("dbus_bus_add_match(): %s", error.message);
2257         goto fail;
2258     }
2259     
2260     if (!(dbus_connection_register_object_path(server->bus, AVAHI_DBUS_PATH_SERVER, &server_vtable, NULL))) {
2261         avahi_log_error("dbus_connection_register_object_path() failed");
2262         goto fail;
2263     }
2264
2265     return 0;
2266
2267 fail:
2268     if (server->bus) {
2269         dbus_connection_disconnect(server->bus);
2270         dbus_connection_unref(server->bus);
2271     }
2272
2273     if (dbus_error_is_set(&error))
2274         dbus_error_free(&error);
2275         
2276     avahi_free(server);
2277     server = NULL;
2278     return -1;
2279 }
2280
2281 void dbus_protocol_shutdown(void) {
2282
2283     if (server) {
2284     
2285         while (server->clients)
2286             client_free(server->clients);
2287
2288         assert(server->n_clients == 0);
2289
2290         if (server->bus) {
2291             dbus_connection_disconnect(server->bus);
2292             dbus_connection_unref(server->bus);
2293         }
2294
2295         avahi_free(server);
2296         server = NULL;
2297     }
2298 }