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