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