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