]> git.meshlink.io Git - catta/blob - avahi-daemon/dbus-protocol.c
022187be5b07646d132938672aab3e5b6048cd48
[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 HostNameResolverInfo HostNameResolverInfo;
56 typedef struct AddressResolverInfo AddressResolverInfo;
57 typedef struct DomainBrowserInfo DomainBrowserInfo;
58 typedef struct ServiceTypeBrowserInfo ServiceTypeBrowserInfo;
59 typedef struct ServiceBrowserInfo ServiceBrowserInfo;
60 typedef struct ServiceResolverInfo ServiceResolverInfo;
61
62 #define MAX_CLIENTS 20
63 #define MAX_OBJECTS_PER_CLIENT 50
64 #define MAX_ENTRIES_PER_ENTRY_GROUP 20
65
66 /* #define VALGRIND_WORKAROUND */
67
68 struct EntryGroupInfo {
69     unsigned id;
70     Client *client;
71     AvahiSEntryGroup *entry_group;
72     char *path;
73
74     int n_entries;
75     
76     AVAHI_LLIST_FIELDS(EntryGroupInfo, entry_groups);
77 };
78
79 struct HostNameResolverInfo {
80     Client *client;
81     AvahiSHostNameResolver *host_name_resolver;
82     DBusMessage *message;
83
84     AVAHI_LLIST_FIELDS(HostNameResolverInfo, host_name_resolvers);
85 };
86
87 struct AddressResolverInfo {
88     Client *client;
89     AvahiSAddressResolver *address_resolver;
90     DBusMessage *message;
91
92     AVAHI_LLIST_FIELDS(AddressResolverInfo, address_resolvers);
93 };
94
95 struct DomainBrowserInfo {
96     unsigned id;
97     Client *client;
98     AvahiSDomainBrowser *domain_browser;
99     char *path;
100
101     AVAHI_LLIST_FIELDS(DomainBrowserInfo, domain_browsers);
102 };
103
104 struct ServiceTypeBrowserInfo {
105     unsigned id;
106     Client *client;
107     AvahiSServiceTypeBrowser *service_type_browser;
108     char *path;
109
110     AVAHI_LLIST_FIELDS(ServiceTypeBrowserInfo, service_type_browsers);
111 };
112
113 struct ServiceBrowserInfo {
114     unsigned id;
115     Client *client;
116     AvahiSServiceBrowser *service_browser;
117     char *path;
118
119     AVAHI_LLIST_FIELDS(ServiceBrowserInfo, service_browsers);
120 };
121
122 struct ServiceResolverInfo {
123     Client *client;
124     AvahiSServiceResolver *service_resolver;
125     DBusMessage *message;
126
127     AVAHI_LLIST_FIELDS(ServiceResolverInfo, service_resolvers);
128 };
129
130 struct Client {
131     unsigned id;
132     char *name;
133     unsigned current_id;
134     int n_objects;
135     
136     AVAHI_LLIST_FIELDS(Client, clients);
137     AVAHI_LLIST_HEAD(EntryGroupInfo, entry_groups);
138     AVAHI_LLIST_HEAD(HostNameResolverInfo, host_name_resolvers);
139     AVAHI_LLIST_HEAD(AddressResolverInfo, address_resolvers);
140     AVAHI_LLIST_HEAD(DomainBrowserInfo, domain_browsers);
141     AVAHI_LLIST_HEAD(ServiceTypeBrowserInfo, service_type_browsers);
142     AVAHI_LLIST_HEAD(ServiceBrowserInfo, service_browsers);
143     AVAHI_LLIST_HEAD(ServiceResolverInfo, service_resolvers);
144 };
145
146 struct Server {
147     DBusConnection *bus;
148     AVAHI_LLIST_HEAD(Client, clients);
149     int n_clients;
150     unsigned current_id;
151 };
152
153 static Server *server = NULL;
154
155 static void entry_group_free(EntryGroupInfo *i) {
156     assert(i);
157
158     if (i->entry_group)
159         avahi_s_entry_group_free(i->entry_group);
160     dbus_connection_unregister_object_path(server->bus, i->path);
161     avahi_free(i->path);
162     AVAHI_LLIST_REMOVE(EntryGroupInfo, entry_groups, i->client->entry_groups, i);
163
164     i->client->n_objects--;
165     assert(i->client->n_objects >= 0);
166     
167     avahi_free(i);
168  }
169
170 static void host_name_resolver_free(HostNameResolverInfo *i) {
171     assert(i);
172
173     if (i->host_name_resolver)
174         avahi_s_host_name_resolver_free(i->host_name_resolver);
175     dbus_message_unref(i->message);
176     AVAHI_LLIST_REMOVE(HostNameResolverInfo, host_name_resolvers, i->client->host_name_resolvers, i);
177
178     i->client->n_objects--;
179     assert(i->client->n_objects >= 0);
180
181     avahi_free(i);
182 }
183
184 static void address_resolver_free(AddressResolverInfo *i) {
185     assert(i);
186
187     if (i->address_resolver)
188         avahi_s_address_resolver_free(i->address_resolver);
189     dbus_message_unref(i->message);
190     AVAHI_LLIST_REMOVE(AddressResolverInfo, address_resolvers, i->client->address_resolvers, i);
191
192     i->client->n_objects--;
193     assert(i->client->n_objects >= 0);
194
195     avahi_free(i);
196 }
197
198 static void domain_browser_free(DomainBrowserInfo *i) {
199     assert(i);
200
201     if (i->domain_browser)
202         avahi_s_domain_browser_free(i->domain_browser);
203     dbus_connection_unregister_object_path(server->bus, i->path);
204     avahi_free(i->path);
205     AVAHI_LLIST_REMOVE(DomainBrowserInfo, domain_browsers, i->client->domain_browsers, i);
206
207     i->client->n_objects--;
208     assert(i->client->n_objects >= 0);
209
210     avahi_free(i);
211 }
212
213 static void service_type_browser_free(ServiceTypeBrowserInfo *i) {
214     assert(i);
215
216     if (i->service_type_browser)
217         avahi_s_service_type_browser_free(i->service_type_browser);
218     dbus_connection_unregister_object_path(server->bus, i->path);
219     avahi_free(i->path);
220     AVAHI_LLIST_REMOVE(ServiceTypeBrowserInfo, service_type_browsers, i->client->service_type_browsers, i);
221
222     i->client->n_objects--;
223     assert(i->client->n_objects >= 0);
224
225     avahi_free(i);
226 }
227
228 static void service_browser_free(ServiceBrowserInfo *i) {
229     assert(i);
230
231     if (i->service_browser)
232         avahi_s_service_browser_free(i->service_browser);
233     dbus_connection_unregister_object_path(server->bus, i->path);
234     avahi_free(i->path);
235     AVAHI_LLIST_REMOVE(ServiceBrowserInfo, service_browsers, i->client->service_browsers, i);
236
237     i->client->n_objects--;
238     assert(i->client->n_objects >= 0);
239
240     avahi_free(i);
241 }
242
243 static void service_resolver_free(ServiceResolverInfo *i) {
244     assert(i);
245
246     if (i->service_resolver)
247         avahi_s_service_resolver_free(i->service_resolver);
248     dbus_message_unref(i->message);
249     AVAHI_LLIST_REMOVE(ServiceResolverInfo, service_resolvers, i->client->service_resolvers, i);
250
251     i->client->n_objects--;
252     assert(i->client->n_objects >= 0);
253
254     avahi_free(i);
255 }
256
257 static void client_free(Client *c) {
258     
259     assert(server);
260     assert(c);
261
262     while (c->entry_groups)
263         entry_group_free(c->entry_groups);
264
265     while (c->host_name_resolvers)
266         host_name_resolver_free(c->host_name_resolvers);
267
268     while (c->address_resolvers)
269         address_resolver_free(c->address_resolvers);
270
271     while (c->domain_browsers)
272         domain_browser_free(c->domain_browsers);
273
274     while (c->service_type_browsers)
275         service_type_browser_free(c->service_type_browsers);
276
277     while (c->service_browsers)
278         service_browser_free(c->service_browsers);
279
280     while (c->service_resolvers)
281         service_resolver_free(c->service_resolvers);
282
283     assert(c->n_objects == 0);
284     
285     avahi_free(c->name);
286     AVAHI_LLIST_REMOVE(Client, clients, server->clients, c);
287     avahi_free(c);
288
289     server->n_clients --;
290     assert(server->n_clients >= 0);
291 }
292
293 static Client *client_get(const char *name, int create) {
294     Client *client;
295
296     assert(server);
297     assert(name);
298
299     for (client = server->clients; client; client = client->clients_next)
300         if (!strcmp(name, client->name))
301             return client;
302
303     if (!create)
304         return NULL;
305
306     if (server->n_clients >= MAX_CLIENTS)
307         return NULL;
308     
309     /* If not existant yet, create a new entry */
310     client = avahi_new(Client, 1);
311     client->id = server->current_id++;
312     client->name = avahi_strdup(name);
313     client->current_id = 0;
314     client->n_objects = 0;
315     AVAHI_LLIST_HEAD_INIT(EntryGroupInfo, client->entry_groups);
316     AVAHI_LLIST_HEAD_INIT(HostNameResolverInfo, client->host_name_resolvers);
317     AVAHI_LLIST_HEAD_INIT(AddressResolverInfo, client->address_resolvers);
318     AVAHI_LLIST_HEAD_INIT(DomainBrowserInfo, client->domain_browsers);
319     AVAHI_LLIST_HEAD_INIT(ServiceTypeBrowserInfo, client->service_type_browsers);
320     AVAHI_LLIST_HEAD_INIT(ServiceBrowserInfo, client->service_browsers);
321     AVAHI_LLIST_HEAD_INIT(ServiceResolverInfo, client->service_resolvers);
322
323     AVAHI_LLIST_PREPEND(Client, clients, server->clients, client);
324
325     server->n_clients++;
326     assert(server->n_clients > 0);
327     
328     return client;
329 }
330
331 static DBusHandlerResult respond_error(DBusConnection *c, DBusMessage *m, int error, const char *text) {
332     DBusMessage *reply;
333
334     assert(-error > -AVAHI_OK);
335     assert(-error < -AVAHI_ERR_MAX);
336     
337     reply = dbus_message_new_error(m, avahi_error_number_to_dbus (error), text ? text : avahi_strerror(error));
338     dbus_connection_send(c, reply, NULL);
339     dbus_message_unref(reply);
340     
341     return DBUS_HANDLER_RESULT_HANDLED;
342 }
343
344 static DBusHandlerResult respond_string(DBusConnection *c, DBusMessage *m, const char *text) {
345     DBusMessage *reply;
346
347     reply = dbus_message_new_method_return(m);
348     dbus_message_append_args(reply, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID);
349     dbus_connection_send(c, reply, NULL);
350     dbus_message_unref(reply);
351     
352     return DBUS_HANDLER_RESULT_HANDLED;
353 }
354
355 static DBusHandlerResult respond_int32(DBusConnection *c, DBusMessage *m, int32_t i) {
356     DBusMessage *reply;
357
358     reply = dbus_message_new_method_return(m);
359     dbus_message_append_args(reply, DBUS_TYPE_INT32, &i, DBUS_TYPE_INVALID);
360     dbus_connection_send(c, reply, NULL);
361     dbus_message_unref(reply);
362     
363     return DBUS_HANDLER_RESULT_HANDLED;
364 }
365
366 static DBusHandlerResult respond_ok(DBusConnection *c, DBusMessage *m) {
367     DBusMessage *reply;
368
369     reply = dbus_message_new_method_return(m);
370     dbus_connection_send(c, reply, NULL);
371     dbus_message_unref(reply);
372     
373     return DBUS_HANDLER_RESULT_HANDLED;
374 }
375
376 static DBusHandlerResult respond_path(DBusConnection *c, DBusMessage *m, const char *path) {
377     DBusMessage *reply;
378
379     reply = dbus_message_new_method_return(m);
380     dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
381     dbus_connection_send(c, reply, NULL);
382     dbus_message_unref(reply);
383     
384     return DBUS_HANDLER_RESULT_HANDLED;
385 }
386
387 static char *file_get_contents(char *fname) {
388     int fd = -1;
389     struct stat st;
390     ssize_t size;
391     char *buf = NULL;
392     
393     assert(fname);
394
395     if (!(fd = open(fname, O_RDONLY))) {
396         avahi_log_error("Failed to open %s: %s", fname, strerror(errno));
397         goto fail;
398     }
399
400     if (fstat(fd, &st) < 0) {
401         avahi_log_error("stat(%s) failed: %s", fname, strerror(errno));
402         goto fail;
403     }
404
405     if (!(S_ISREG(st.st_mode))) {
406         avahi_log_error("Invalid file %s", fname);
407         goto fail;
408     }
409
410     if (st.st_size > 1024*1024) { /** 1MB */
411         avahi_log_error("File too large %s", fname);
412         goto fail;
413     }
414
415     buf = avahi_new(char, st.st_size+1);
416
417     if ((size = read(fd, buf, st.st_size)) < 0) {
418         avahi_log_error("read() failed: %s\n", strerror(errno));
419         goto fail;
420     }
421
422     buf[size] = 0;
423
424     close(fd);
425     return buf;
426     
427 fail:
428     if (fd >= 0)
429         close(fd);
430
431     if (buf)
432         avahi_free(buf);
433
434     return NULL;
435         
436 }
437
438 static DBusHandlerResult handle_introspect(DBusConnection *c, DBusMessage *m, const char *fname) {
439     char *path, *contents;
440     DBusError error;
441     
442     assert(c);
443     assert(m);
444     assert(fname);
445
446     dbus_error_init(&error);
447
448     if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
449         avahi_log_error("Error parsing Introspect message: %s", error.message);
450         goto fail;
451     }
452     
453     path = avahi_strdup_printf("%s/%s", AVAHI_DBUS_INTROSPECTION_DIR, fname);
454     contents = file_get_contents(path);
455     avahi_free(path);
456     
457     if (!contents) {
458         avahi_log_error("Failed to load introspection data.");
459         goto fail;
460     }
461     
462     respond_string(c, m, contents);
463     avahi_free(contents);
464     
465     return DBUS_HANDLER_RESULT_HANDLED;
466
467 fail:
468     if (dbus_error_is_set(&error))
469         dbus_error_free(&error);
470     
471     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
472
473 }
474
475 static DBusHandlerResult msg_signal_filter_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
476     DBusError error;
477
478     dbus_error_init(&error);
479
480 /*     avahi_log_debug("dbus: interface=%s, path=%s, member=%s", */
481 /*                     dbus_message_get_interface(m), */
482 /*                     dbus_message_get_path(m), */
483 /*                     dbus_message_get_member(m)); */
484
485     if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) {
486         /* No, we shouldn't quit, but until we get somewhere
487          * usefull such that we can restore our state, we will */
488         avahi_log_warn("Disconnnected from d-bus, terminating...");
489         
490         raise(SIGQUIT); /* The signal handler will catch this and terminate the process cleanly*/
491         
492         return DBUS_HANDLER_RESULT_HANDLED;
493         
494     } else if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameAcquired")) {
495         char *name;
496
497         if (!dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) {
498             avahi_log_warn("Error parsing NameAcquired message");
499             goto fail;
500         }
501
502 /*         avahi_log_info("dbus: name acquired (%s)", name); */
503         return DBUS_HANDLER_RESULT_HANDLED;
504         
505     } else if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
506         char *name, *old, *new;
507
508         if (!dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old, DBUS_TYPE_STRING, &new, DBUS_TYPE_INVALID)) {
509             avahi_log_warn("Error parsing NameOwnerChanged message");
510             goto fail;
511         }
512
513         if (!*new) {
514             Client *client;
515
516             if ((client = client_get(name, FALSE))) {
517 /*                 avahi_log_info("dbus: client %s vanished", name); */
518                 client_free(client);
519             }
520         }
521     }
522
523 fail:
524     if (dbus_error_is_set(&error))
525         dbus_error_free(&error);
526     
527     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
528 }
529
530 static void entry_group_callback(AvahiServer *s, AvahiSEntryGroup *g, AvahiEntryGroupState state, void* userdata) {
531     EntryGroupInfo *i = userdata;
532     DBusMessage *m;
533     int32_t t;
534     
535     assert(s);
536     assert(g);
537     assert(i);
538
539     m = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "StateChanged");
540     t = (int32_t) state;
541     dbus_message_append_args(m, DBUS_TYPE_INT32, &t, DBUS_TYPE_INVALID);
542     dbus_message_set_destination(m, i->client->name);  
543     dbus_connection_send(server->bus, m, NULL);
544     dbus_message_unref(m);
545 }
546
547 static DBusHandlerResult msg_entry_group_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
548     DBusError error;
549     EntryGroupInfo *i = userdata;
550
551     assert(c);
552     assert(m);
553     assert(i);
554     
555     dbus_error_init(&error);
556
557     avahi_log_debug("dbus: interface=%s, path=%s, member=%s",
558                     dbus_message_get_interface(m),
559                     dbus_message_get_path(m),
560                     dbus_message_get_member(m));
561
562     /* Introspection */
563     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
564         return handle_introspect(c, m, "EntryGroup.introspect");
565     
566     /* Access control */
567     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
568         return respond_error(c, m, AVAHI_ERR_ACCESS_DENIED, NULL);
569     
570     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Free")) {
571
572         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
573             avahi_log_warn("Error parsing EntryGroup::Free message");
574             goto fail;
575         }
576
577         entry_group_free(i);
578         return respond_ok(c, m);
579         
580     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Commit")) {
581
582         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
583             avahi_log_warn("Error parsing EntryGroup::Commit message");
584             goto fail;
585         }
586
587         avahi_s_entry_group_commit(i->entry_group);
588         return respond_ok(c, m);
589         
590         
591     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Reset")) {
592         
593         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
594             avahi_log_warn("Error parsing EntryGroup::Reset message");
595             goto fail;
596         }
597
598         avahi_s_entry_group_reset(i->entry_group);
599         return respond_ok(c, m);
600         
601     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "IsEmpty")) {
602         DBusMessage *reply;
603         int b;
604         
605         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
606             avahi_log_warn("Error parsing EntryGroup::IsEmpty message");
607             goto fail;
608         }
609
610         b = !!avahi_s_entry_group_is_empty(i->entry_group);
611
612         reply = dbus_message_new_method_return(m);
613         dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &b, DBUS_TYPE_INVALID);
614         dbus_connection_send(c, reply, NULL);
615         dbus_message_unref(reply);
616         
617         return DBUS_HANDLER_RESULT_HANDLED;
618         
619     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "GetState")) {
620         AvahiEntryGroupState state;
621         
622         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
623             avahi_log_warn("Error parsing EntryGroup::GetState message");
624             goto fail;
625         }
626
627         state = avahi_s_entry_group_get_state(i->entry_group);
628         return respond_int32(c, m, (int32_t) state);
629         
630     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddService")) {
631         int32_t interface, protocol;
632         char *type, *name, *domain, *host;
633         uint16_t port;
634         AvahiStringList *strlst;
635         DBusMessageIter iter, sub;
636         int j;
637         
638         if (!dbus_message_get_args(
639                 m, &error,
640                 DBUS_TYPE_INT32, &interface,
641                 DBUS_TYPE_INT32, &protocol,
642                 DBUS_TYPE_STRING, &name,
643                 DBUS_TYPE_STRING, &type,
644                 DBUS_TYPE_STRING, &domain,
645                 DBUS_TYPE_STRING, &host,
646                 DBUS_TYPE_UINT16, &port, 
647                 DBUS_TYPE_INVALID) || !type || !name) {
648             avahi_log_warn("Error parsing EntryGroup::AddService message");
649             goto fail;
650         }
651
652         dbus_message_iter_init(m, &iter);
653
654         for (j = 0; j < 7; j++)
655             dbus_message_iter_next(&iter);
656         
657         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
658             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_ARRAY) {
659             avahi_log_warn("Error parsing EntryGroup::AddService message 2");
660             goto fail;
661         }
662
663         strlst = NULL;
664         dbus_message_iter_recurse(&iter, &sub);
665         
666         for (;;) {
667             DBusMessageIter sub2;
668             int at, n;
669             uint8_t *k;
670
671             if ((at = dbus_message_iter_get_arg_type(&sub)) == DBUS_TYPE_INVALID)
672                 break;
673
674             assert(at == DBUS_TYPE_ARRAY);
675             
676             if (dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_BYTE) {
677                 avahi_log_warn("Error parsing EntryGroup::AddService message");
678                 goto fail;
679             }
680
681             dbus_message_iter_recurse(&sub, &sub2);
682             dbus_message_iter_get_fixed_array(&sub2, &k, &n);
683             strlst = avahi_string_list_add_arbitrary(strlst, k, n);
684             
685             dbus_message_iter_next(&sub);
686         }
687
688         if (i->n_entries >= MAX_ENTRIES_PER_ENTRY_GROUP) {
689             avahi_string_list_free(strlst);
690             avahi_log_warn("Too many entries per entry group, client request failed.");
691             return respond_error(c, m, AVAHI_ERR_TOO_MANY_ENTRIES, NULL);
692         }
693
694         if (domain && !*domain)
695             domain = NULL;
696
697         if (host && !*host)
698             host = NULL;
699
700         if (avahi_server_add_service_strlst(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, type, domain, host, port, strlst) < 0) {
701             avahi_string_list_free(strlst);
702             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
703         } else
704             i->n_entries ++;
705         
706         avahi_string_list_free(strlst);
707         
708         return respond_ok(c, m);
709         
710     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddAddress")) {
711         int32_t interface, protocol;
712         char *name, *address;
713         AvahiAddress a;
714         
715         if (!dbus_message_get_args(
716                 m, &error,
717                 DBUS_TYPE_INT32, &interface,
718                 DBUS_TYPE_INT32, &protocol,
719                 DBUS_TYPE_STRING, &name,
720                 DBUS_TYPE_STRING, &address,
721                 DBUS_TYPE_INVALID) || !name || !address) {
722             avahi_log_warn("Error parsing EntryGroup::AddAddress message");
723             goto fail;
724         }
725
726         if (i->n_entries >= MAX_ENTRIES_PER_ENTRY_GROUP) {
727             avahi_log_warn("Too many entries per entry group, client request failed.");
728             return respond_error(c, m, AVAHI_ERR_TOO_MANY_ENTRIES, NULL);
729         }
730         
731         if (!(avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a))) {
732             return respond_error(c, m, AVAHI_ERR_INVALID_ADDRESS, NULL);
733         }
734
735         if (avahi_server_add_address(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, 0, name, &a) < 0)
736             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
737         else
738             i->n_entries ++;
739         
740         return respond_ok(c, m);
741     }
742     
743     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
744
745 fail:
746     if (dbus_error_is_set(&error))
747         dbus_error_free(&error);
748     
749     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
750 }
751
752 static void host_name_resolver_callback(AvahiSHostNameResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *host_name, const AvahiAddress *a, void* userdata) {
753     HostNameResolverInfo *i = userdata;
754     
755     assert(r);
756     assert(host_name);
757     assert(i);
758
759     if (event == AVAHI_RESOLVER_FOUND) {
760         char t[256], *pt = t;
761         int32_t i_interface, i_protocol, i_aprotocol;
762         DBusMessage *reply;
763
764         assert(a);
765         avahi_address_snprint(t, sizeof(t), a);
766
767         i_interface = (int32_t) interface;
768         i_protocol = (int32_t) protocol;
769         i_aprotocol = (int32_t) a->family;
770         
771         reply = dbus_message_new_method_return(i->message);
772         dbus_message_append_args(
773             reply,
774             DBUS_TYPE_INT32, &i_interface,
775             DBUS_TYPE_INT32, &i_protocol,
776             DBUS_TYPE_STRING, &host_name,
777             DBUS_TYPE_INT32, &i_aprotocol,
778             DBUS_TYPE_STRING, &pt,
779             DBUS_TYPE_INVALID);
780
781         dbus_connection_send(server->bus, reply, NULL);
782         dbus_message_unref(reply);
783     } else {
784         assert(event == AVAHI_RESOLVER_TIMEOUT);
785
786         respond_error(server->bus, i->message, AVAHI_ERR_TIMEOUT, NULL);
787     }
788
789     host_name_resolver_free(i);
790 }
791
792 static void address_resolver_callback(AvahiSAddressResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const AvahiAddress *address, const char *host_name, void* userdata) {
793     AddressResolverInfo *i = userdata;
794     
795     assert(r);
796     assert(address);
797     assert(i);
798
799     if (event == AVAHI_RESOLVER_FOUND) {
800         char t[256], *pt = t;
801         int32_t i_interface, i_protocol, i_aprotocol;
802         DBusMessage *reply;
803
804         assert(host_name);
805         avahi_address_snprint(t, sizeof(t), address);
806
807         i_interface = (int32_t) interface;
808         i_protocol = (int32_t) protocol;
809         i_aprotocol = (int32_t) address->family;
810         
811         reply = dbus_message_new_method_return(i->message);
812         dbus_message_append_args(
813             reply,
814             DBUS_TYPE_INT32, &i_interface,
815             DBUS_TYPE_INT32, &i_protocol,
816             DBUS_TYPE_INT32, &i_aprotocol,
817             DBUS_TYPE_STRING, &pt,
818             DBUS_TYPE_STRING, &host_name,
819             DBUS_TYPE_INVALID);
820
821         dbus_connection_send(server->bus, reply, NULL);
822         dbus_message_unref(reply);
823     } else {
824         assert(event == AVAHI_RESOLVER_TIMEOUT);
825         respond_error(server->bus, i->message, AVAHI_ERR_TIMEOUT, NULL);
826     }
827
828     address_resolver_free(i);
829 }
830
831 static DBusHandlerResult msg_domain_browser_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
832     DBusError error;
833     DomainBrowserInfo *i = userdata;
834
835     assert(c);
836     assert(m);
837     assert(i);
838     
839     dbus_error_init(&error);
840
841     avahi_log_debug("dbus: interface=%s, path=%s, member=%s",
842                     dbus_message_get_interface(m),
843                     dbus_message_get_path(m),
844                     dbus_message_get_member(m));
845
846     /* Introspection */
847     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
848         return handle_introspect(c, m, "DomainBrowser.introspect");
849     
850     /* Access control */
851     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
852         return respond_error(c, m, AVAHI_ERR_ACCESS_DENIED, NULL);
853     
854     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "Free")) {
855
856         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
857             avahi_log_warn("Error parsing DomainBrowser::Free message");
858             goto fail;
859         }
860
861         domain_browser_free(i);
862         return respond_ok(c, m);
863         
864     }
865     
866     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
867
868 fail:
869     if (dbus_error_is_set(&error))
870         dbus_error_free(&error);
871     
872     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
873 }
874
875 static void domain_browser_callback(AvahiSDomainBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *domain, void* userdata) {
876     DomainBrowserInfo *i = userdata;
877     DBusMessage *m;
878     int32_t i_interface, i_protocol;
879     
880     assert(b);
881     assert(domain);
882     assert(i);
883
884     i_interface = (int32_t) interface;
885     i_protocol = (int32_t) protocol;
886
887     m = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, event == AVAHI_BROWSER_NEW ? "ItemNew" : "ItemRemove");
888     dbus_message_append_args(
889         m,
890         DBUS_TYPE_INT32, &i_interface,
891         DBUS_TYPE_INT32, &i_protocol,
892         DBUS_TYPE_STRING, &domain,
893         DBUS_TYPE_INVALID);
894     dbus_message_set_destination(m, i->client->name);   
895     dbus_connection_send(server->bus, m, NULL);
896     dbus_message_unref(m);
897 }
898
899 static DBusHandlerResult msg_service_type_browser_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
900     DBusError error;
901     ServiceTypeBrowserInfo *i = userdata;
902
903     assert(c);
904     assert(m);
905     assert(i);
906     
907     dbus_error_init(&error);
908
909     avahi_log_debug("dbus: interface=%s, path=%s, member=%s",
910                     dbus_message_get_interface(m),
911                     dbus_message_get_path(m),
912                     dbus_message_get_member(m));
913
914     /* Introspection */
915     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
916         return handle_introspect(c, m, "ServiceTypeBrowser.introspect");
917     
918     /* Access control */
919     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
920         return respond_error(c, m, AVAHI_ERR_ACCESS_DENIED, NULL);
921     
922     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "Free")) {
923
924         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
925             avahi_log_warn("Error parsing ServiceTypeBrowser::Free message");
926             goto fail;
927         }
928
929         service_type_browser_free(i);
930         return respond_ok(c, m);
931         
932     }
933     
934     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
935
936 fail:
937     if (dbus_error_is_set(&error))
938         dbus_error_free(&error);
939     
940     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
941 }
942
943 static void service_type_browser_callback(AvahiSServiceTypeBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *type, const char *domain, void* userdata) {
944     ServiceTypeBrowserInfo *i = userdata;
945     DBusMessage *m;
946     int32_t i_interface, i_protocol;
947     
948     assert(b);
949     assert(type);
950     assert(domain);
951     assert(i);
952
953     i_interface = (int32_t) interface;
954     i_protocol = (int32_t) protocol;
955
956     m = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, event == AVAHI_BROWSER_NEW ? "ItemNew" : "ItemRemove");
957     dbus_message_append_args(
958         m,
959         DBUS_TYPE_INT32, &i_interface,
960         DBUS_TYPE_INT32, &i_protocol,
961         DBUS_TYPE_STRING, &type,
962         DBUS_TYPE_STRING, &domain,
963         DBUS_TYPE_INVALID);
964     dbus_message_set_destination(m, i->client->name);   
965     dbus_connection_send(server->bus, m, NULL);
966     dbus_message_unref(m);
967 }
968
969 static DBusHandlerResult msg_service_browser_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
970     DBusError error;
971     ServiceBrowserInfo *i = userdata;
972
973     assert(c);
974     assert(m);
975     assert(i);
976     
977     dbus_error_init(&error);
978
979     avahi_log_debug("dbus: interface=%s, path=%s, member=%s",
980                     dbus_message_get_interface(m),
981                     dbus_message_get_path(m),
982                     dbus_message_get_member(m));
983
984     /* Introspection */
985     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
986         return handle_introspect(c, m, "ServiceBrowser.Introspect");
987     
988     /* Access control */
989     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
990         return respond_error(c, m, AVAHI_ERR_ACCESS_DENIED, NULL);
991     
992     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "Free")) {
993
994         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
995             avahi_log_warn("Error parsing ServiceBrowser::Free message");
996             goto fail;
997         }
998
999         service_browser_free(i);
1000         return respond_ok(c, m);
1001         
1002     }
1003     
1004     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
1005
1006 fail:
1007     if (dbus_error_is_set(&error))
1008         dbus_error_free(&error);
1009     
1010     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1011 }
1012
1013 static void service_browser_callback(AvahiSServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, void* userdata) {
1014     ServiceBrowserInfo *i = userdata;
1015     DBusMessage *m;
1016     int32_t i_interface, i_protocol;
1017     
1018     assert(b);
1019     assert(name);
1020     assert(type);
1021     assert(domain);
1022     assert(i);
1023
1024     i_interface = (int32_t) interface;
1025     i_protocol = (int32_t) protocol;
1026
1027     m = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, event == AVAHI_BROWSER_NEW ? "ItemNew" : "ItemRemove");
1028     dbus_message_append_args(
1029         m,
1030         DBUS_TYPE_INT32, &i_interface,
1031         DBUS_TYPE_INT32, &i_protocol,
1032         DBUS_TYPE_STRING, &name,
1033         DBUS_TYPE_STRING, &type,
1034         DBUS_TYPE_STRING, &domain,
1035         DBUS_TYPE_INVALID);
1036     dbus_message_set_destination(m, i->client->name);   
1037     dbus_connection_send(server->bus, m, NULL);
1038     dbus_message_unref(m);
1039 }
1040
1041 static void service_resolver_callback(
1042     AvahiSServiceResolver *r,
1043     AvahiIfIndex interface,
1044     AvahiProtocol protocol,
1045     AvahiResolverEvent event,
1046     const char *name,
1047     const char *type,
1048     const char *domain,
1049     const char *host_name,
1050     const AvahiAddress *a,
1051     uint16_t port,
1052     AvahiStringList *txt,
1053     void* userdata) {
1054     
1055     ServiceResolverInfo *i = userdata;
1056     
1057     assert(r);
1058     assert(i);
1059
1060     if (event == AVAHI_RESOLVER_FOUND) {
1061         char t[256], *pt = t;
1062         int32_t i_interface, i_protocol, i_aprotocol;
1063         unsigned n, j;
1064         AvahiStringList *p;
1065         DBusMessage *reply;
1066         DBusMessageIter iter, sub;
1067
1068         assert(host_name);
1069         
1070         assert(a);
1071         avahi_address_snprint(t, sizeof(t), a);
1072
1073         i_interface = (int32_t) interface;
1074         i_protocol = (int32_t) protocol;
1075         i_aprotocol = (int32_t) a->family;
1076
1077         reply = dbus_message_new_method_return(i->message);
1078         dbus_message_append_args(
1079             reply,
1080             DBUS_TYPE_INT32, &i_interface,
1081             DBUS_TYPE_INT32, &i_protocol,
1082             DBUS_TYPE_STRING, &name,
1083             DBUS_TYPE_STRING, &type,
1084             DBUS_TYPE_STRING, &domain,
1085             DBUS_TYPE_STRING, &host_name,
1086             DBUS_TYPE_INT32, &i_aprotocol,
1087             DBUS_TYPE_STRING, &pt,
1088             DBUS_TYPE_UINT16, &port,
1089             DBUS_TYPE_INVALID);
1090
1091         dbus_message_iter_init_append(reply, &iter);
1092         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "ay", &sub);
1093
1094         for (p = txt, j = n-1; p; p = p->next, j--) {
1095             DBusMessageIter sub2;
1096             const uint8_t *data = p->text;
1097             
1098             dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "y", &sub2);
1099             dbus_message_iter_append_fixed_array(&sub2, DBUS_TYPE_BYTE, &data, p->size); 
1100             dbus_message_iter_close_container(&sub, &sub2);
1101
1102         }
1103         dbus_message_iter_close_container(&iter, &sub);
1104                 
1105         dbus_connection_send(server->bus, reply, NULL);
1106         dbus_message_unref(reply);
1107     } else {
1108         assert(event == AVAHI_RESOLVER_TIMEOUT);
1109
1110         respond_error(server->bus, i->message, AVAHI_ERR_TIMEOUT, NULL);
1111     }
1112
1113     service_resolver_free(i);
1114 }
1115
1116 static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
1117     DBusError error;
1118
1119     dbus_error_init(&error);
1120
1121     avahi_log_debug("dbus: interface=%s, path=%s, member=%s",
1122                     dbus_message_get_interface(m),
1123                     dbus_message_get_path(m),
1124                     dbus_message_get_member(m));
1125
1126     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
1127         return handle_introspect(c, m, "Server.introspect");
1128         
1129     else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostName")) {
1130
1131         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
1132             avahi_log_warn("Error parsing Server::GetHostName message");
1133             goto fail;
1134         }
1135
1136         return respond_string(c, m, avahi_server_get_host_name(avahi_server));
1137         
1138     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetDomainName")) {
1139
1140         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
1141             avahi_log_warn("Error parsing Server::GetDomainName message");
1142             goto fail;
1143         }
1144
1145         return respond_string(c, m, avahi_server_get_domain_name(avahi_server));
1146
1147     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostNameFqdn")) {
1148
1149         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
1150             avahi_log_warn("Error parsing Server::GetHostNameFqdn message");
1151             goto fail;
1152         }
1153     
1154         return respond_string(c, m, avahi_server_get_host_name_fqdn(avahi_server));
1155         
1156     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetVersionString")) {
1157
1158         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
1159             avahi_log_warn("Error parsing Server::GetVersionString message");
1160             goto fail;
1161         }
1162     
1163         return respond_string(c, m, PACKAGE_STRING);
1164
1165     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetState")) {
1166         AvahiServerState state;
1167         
1168         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
1169             avahi_log_warn("Error parsing Server::GetState message");
1170             goto fail;
1171         }
1172         
1173         state = avahi_server_get_state(avahi_server);
1174         return respond_int32(c, m, (int32_t) state);
1175
1176     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetNetworkInterfaceNameByIndex")) {
1177         int32_t idx;
1178         int fd;
1179         struct ifreq ifr;
1180         
1181         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INT32, &idx, DBUS_TYPE_INVALID))) {
1182             avahi_log_warn("Error parsing Server::GetNetworkInterfaceNameByIndex message");
1183             goto fail;
1184         }
1185
1186 #ifdef VALGRIND_WORKAROUND
1187         return respond_string(c, m, "blah");
1188 #else
1189         
1190         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1191             char txt[256];
1192             snprintf(txt, sizeof(txt), "OS Error: %s", strerror(errno));
1193             return respond_error(c, m, AVAHI_ERR_OS, txt);
1194         }
1195
1196         memset(&ifr, 0, sizeof(ifr));
1197         ifr.ifr_ifindex = idx;
1198
1199         if (ioctl(fd, SIOCGIFNAME, &ifr) < 0) {
1200             char txt[256];
1201             snprintf(txt, sizeof(txt), "OS Error: %s", strerror(errno));
1202             close(fd);
1203             return respond_error(c, m, AVAHI_ERR_OS, txt);
1204         }
1205
1206         close(fd);
1207         
1208         return respond_string(c, m, ifr.ifr_name);
1209 #endif
1210         
1211     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetNetworkInterfaceIndexByName")) {
1212         char *n;
1213         int fd;
1214         struct ifreq ifr;
1215         
1216         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n) {
1217             avahi_log_warn("Error parsing Server::GetNetworkInterfaceIndexByName message");
1218             goto fail;
1219         }
1220
1221 #ifdef VALGRIND_WORKAROUND
1222         return respond_int32(c, m, 1);
1223 #else
1224         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1225             char txt[256];
1226             snprintf(txt, sizeof(txt), "OS Error: %s", strerror(errno));
1227             return respond_error(c, m, AVAHI_ERR_OS, txt);
1228         }
1229
1230         memset(&ifr, 0, sizeof(ifr));
1231         snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", n);
1232
1233         if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
1234             char txt[256];
1235             snprintf(txt, sizeof(txt), "OS Error: %s", strerror(errno));
1236             close(fd);
1237             return respond_error(c, m, AVAHI_ERR_OS, txt);
1238         }
1239
1240         close(fd);
1241         
1242         return respond_int32(c, m, ifr.ifr_ifindex);
1243 #endif
1244
1245     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetAlternativeHostName")) {
1246         char *n, * t;
1247         
1248         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n) {
1249             avahi_log_warn("Error parsing Server::GetAlternativeHostName message");
1250             goto fail;
1251         }
1252
1253         t = avahi_alternative_host_name(n);
1254         respond_string(c, m, t);
1255         avahi_free(t);
1256
1257         return DBUS_HANDLER_RESULT_HANDLED;
1258
1259     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetAlternativeServiceName")) {
1260         char *n, *t;
1261         
1262         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n) {
1263             avahi_log_warn("Error parsing Server::GetAlternativeServiceName message");
1264             goto fail;
1265         }
1266
1267         t = avahi_alternative_service_name(n);
1268         respond_string(c, m, t);
1269         avahi_free(t);
1270
1271         return DBUS_HANDLER_RESULT_HANDLED;
1272         
1273     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "EntryGroupNew")) {
1274         Client *client;
1275         EntryGroupInfo *i;
1276         static const DBusObjectPathVTable vtable = {
1277             NULL,
1278             msg_entry_group_impl,
1279             NULL,
1280             NULL,
1281             NULL,
1282             NULL
1283         };
1284
1285         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
1286             avahi_log_warn("Error parsing Server::EntryGroupNew message");
1287             goto fail;
1288         }
1289
1290         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1291             avahi_log_warn("Too many clients, client request failed.");
1292             return respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
1293         }
1294
1295         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1296             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1297             return respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
1298         }
1299
1300         i = avahi_new(EntryGroupInfo, 1);
1301         i->id = ++client->current_id;
1302         i->client = client;
1303         i->path = avahi_strdup_printf("/Client%u/EntryGroup%u", client->id, i->id);
1304         i->n_entries = 0;
1305         AVAHI_LLIST_PREPEND(EntryGroupInfo, entry_groups, client->entry_groups, i);
1306         client->n_objects++;
1307         
1308         if (!(i->entry_group = avahi_s_entry_group_new(avahi_server, entry_group_callback, i))) {
1309             entry_group_free(i);
1310             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
1311         }
1312
1313         dbus_connection_register_object_path(c, i->path, &vtable, i);
1314         return respond_path(c, m, i->path);
1315         
1316     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveHostName")) {
1317         Client *client;
1318         int32_t interface, protocol, aprotocol;
1319         char *name;
1320         HostNameResolverInfo *i;
1321             
1322         if (!dbus_message_get_args(
1323                 m, &error,
1324                 DBUS_TYPE_INT32, &interface,
1325                 DBUS_TYPE_INT32, &protocol,
1326                 DBUS_TYPE_STRING, &name,
1327                 DBUS_TYPE_INT32, &aprotocol,
1328                 DBUS_TYPE_INVALID) || !name) {
1329             avahi_log_warn("Error parsing Server::ResolveHostName message");
1330             goto fail;
1331         }
1332
1333         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1334             avahi_log_warn("Too many clients, client request failed.");
1335             return respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
1336         }
1337
1338         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1339             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1340             return respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
1341         }
1342
1343         i = avahi_new(HostNameResolverInfo, 1);
1344         i->client = client;
1345         i->message = dbus_message_ref(m);
1346         AVAHI_LLIST_PREPEND(HostNameResolverInfo, host_name_resolvers, client->host_name_resolvers, i);
1347         client->n_objects++;
1348
1349         if (!(i->host_name_resolver = avahi_s_host_name_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, (AvahiProtocol) aprotocol, host_name_resolver_callback, i))) {
1350             host_name_resolver_free(i);
1351             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
1352         }
1353         
1354         return DBUS_HANDLER_RESULT_HANDLED;
1355         
1356     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveAddress")) {
1357         Client *client;
1358         int32_t interface, protocol;
1359         char *address;
1360         AddressResolverInfo *i;
1361         AvahiAddress a;
1362             
1363         if (!dbus_message_get_args(
1364                 m, &error,
1365                 DBUS_TYPE_INT32, &interface,
1366                 DBUS_TYPE_INT32, &protocol,
1367                 DBUS_TYPE_STRING, &address,
1368                 DBUS_TYPE_INVALID) || !address) {
1369             avahi_log_warn("Error parsing Server::ResolveAddress message");
1370             goto fail;
1371         }
1372
1373         if (!avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a))
1374             return respond_error(c, m, AVAHI_ERR_INVALID_ADDRESS, NULL);
1375
1376         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1377             avahi_log_warn("Too many clients, client request failed.");
1378             return respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
1379         }
1380
1381         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1382             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1383             return respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
1384         }
1385
1386         i = avahi_new(AddressResolverInfo, 1);
1387         i->client = client;
1388         i->message = dbus_message_ref(m);
1389         AVAHI_LLIST_PREPEND(AddressResolverInfo, address_resolvers, client->address_resolvers, i);
1390         client->n_objects++;
1391
1392         if (!(i->address_resolver = avahi_s_address_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, &a, address_resolver_callback, i))) {
1393             address_resolver_free(i);
1394             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
1395         }
1396         
1397         return DBUS_HANDLER_RESULT_HANDLED;
1398         
1399     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "DomainBrowserNew")) {
1400         Client *client;
1401         DomainBrowserInfo *i;
1402         static const DBusObjectPathVTable vtable = {
1403             NULL,
1404             msg_domain_browser_impl,
1405             NULL,
1406             NULL,
1407             NULL,
1408             NULL
1409         };
1410         int32_t interface, protocol, type;
1411         char *domain;
1412         
1413
1414         if (!dbus_message_get_args(
1415                 m, &error,
1416                 DBUS_TYPE_INT32, &interface,
1417                 DBUS_TYPE_INT32, &protocol,
1418                 DBUS_TYPE_STRING, &domain,
1419                 DBUS_TYPE_INT32, &type,
1420                 DBUS_TYPE_INVALID) || type < 0 || type >= AVAHI_DOMAIN_BROWSER_MAX) {
1421             avahi_log_warn("Error parsing Server::DomainBrowserNew message");
1422             goto fail;
1423         }
1424
1425         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1426             avahi_log_warn("Too many clients, client request failed.");
1427             return respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
1428         }
1429
1430         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1431             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1432             return respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
1433         }
1434
1435         if (!*domain)
1436             domain = NULL;
1437
1438         i = avahi_new(DomainBrowserInfo, 1);
1439         i->id = ++client->current_id;
1440         i->client = client;
1441         i->path = avahi_strdup_printf("/Client%u/DomainBrowser%u", client->id, i->id);
1442         AVAHI_LLIST_PREPEND(DomainBrowserInfo, domain_browsers, client->domain_browsers, i);
1443         client->n_objects++;
1444
1445         if (!(i->domain_browser = avahi_s_domain_browser_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, domain, (AvahiDomainBrowserType) type, domain_browser_callback, i))) {
1446             domain_browser_free(i);
1447             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
1448         }
1449         
1450         dbus_connection_register_object_path(c, i->path, &vtable, i);
1451         return respond_path(c, m, i->path);
1452
1453     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ServiceTypeBrowserNew")) {
1454         Client *client;
1455         ServiceTypeBrowserInfo *i;
1456         static const DBusObjectPathVTable vtable = {
1457             NULL,
1458             msg_service_type_browser_impl,
1459             NULL,
1460             NULL,
1461             NULL,
1462             NULL
1463         };
1464         int32_t interface, protocol;
1465         char *domain;
1466         
1467         if (!dbus_message_get_args(
1468                 m, &error,
1469                 DBUS_TYPE_INT32, &interface,
1470                 DBUS_TYPE_INT32, &protocol,
1471                 DBUS_TYPE_STRING, &domain,
1472                 DBUS_TYPE_INVALID)) {
1473             avahi_log_warn("Error parsing Server::ServiceTypeBrowserNew message");
1474             goto fail;
1475         }
1476
1477         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1478             avahi_log_warn("Too many clients, client request failed.");
1479             return respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
1480         }
1481
1482
1483         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1484             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1485             return respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
1486         }
1487
1488         if (!*domain)
1489             domain = NULL;
1490
1491         i = avahi_new(ServiceTypeBrowserInfo, 1);
1492         i->id = ++client->current_id;
1493         i->client = client;
1494         i->path = avahi_strdup_printf("/Client%u/ServiceTypeBrowser%u", client->id, i->id);
1495         AVAHI_LLIST_PREPEND(ServiceTypeBrowserInfo, service_type_browsers, client->service_type_browsers, i);
1496         client->n_objects++;
1497
1498         if (!(i->service_type_browser = avahi_s_service_type_browser_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, domain, service_type_browser_callback, i))) {
1499             service_type_browser_free(i);
1500             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
1501         }
1502         
1503         dbus_connection_register_object_path(c, i->path, &vtable, i);
1504         return respond_path(c, m, i->path);
1505         
1506      } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ServiceBrowserNew")) {
1507         Client *client;
1508         ServiceBrowserInfo *i;
1509         static const DBusObjectPathVTable vtable = {
1510             NULL,
1511             msg_service_browser_impl,
1512             NULL,
1513             NULL,
1514             NULL,
1515             NULL
1516         };
1517         int32_t interface, protocol;
1518         char *domain, *type;
1519         
1520         if (!dbus_message_get_args(
1521                 m, &error,
1522                 DBUS_TYPE_INT32, &interface,
1523                 DBUS_TYPE_INT32, &protocol,
1524                 DBUS_TYPE_STRING, &type,
1525                 DBUS_TYPE_STRING, &domain,
1526                 DBUS_TYPE_INVALID) || !type) {
1527             avahi_log_warn("Error parsing Server::ServiceBrowserNew message");
1528             goto fail;
1529         }
1530
1531         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1532             avahi_log_warn("Too many clients, client request failed.");
1533             return respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
1534         }
1535
1536
1537         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1538             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1539             return respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
1540         }
1541
1542         if (!*domain)
1543             domain = NULL;
1544
1545         i = avahi_new(ServiceBrowserInfo, 1);
1546         i->id = ++client->current_id;
1547         i->client = client;
1548         i->path = avahi_strdup_printf("/Client%u/ServiceBrowser%u", client->id, i->id);
1549         AVAHI_LLIST_PREPEND(ServiceBrowserInfo, service_browsers, client->service_browsers, i);
1550         client->n_objects++;
1551
1552         if (!(i->service_browser = avahi_s_service_browser_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, type, domain, service_browser_callback, i))) {
1553             service_browser_free(i);
1554             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
1555         }
1556         
1557         dbus_connection_register_object_path(c, i->path, &vtable, i);
1558         return respond_path(c, m, i->path);
1559         
1560     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveService")) {
1561         Client *client;
1562         int32_t interface, protocol, aprotocol;
1563         char *name, *type, *domain;
1564         ServiceResolverInfo *i;
1565             
1566         if (!dbus_message_get_args(
1567                 m, &error,
1568                 DBUS_TYPE_INT32, &interface,
1569                 DBUS_TYPE_INT32, &protocol,
1570                 DBUS_TYPE_STRING, &name,
1571                 DBUS_TYPE_STRING, &type,
1572                 DBUS_TYPE_STRING, &domain,
1573                 DBUS_TYPE_INT32, &aprotocol,
1574                 DBUS_TYPE_INVALID) || !name || !type) {
1575             avahi_log_warn("Error parsing Server::ResolveService message");
1576             goto fail;
1577         }
1578
1579         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1580             avahi_log_warn("Too many clients, client request failed.");
1581             return respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
1582         }
1583         
1584         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1585             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1586             return respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
1587         }
1588
1589         if (!*domain)
1590             domain = NULL;
1591         
1592         i = avahi_new(ServiceResolverInfo, 1);
1593         i->client = client;
1594         i->message = dbus_message_ref(m);
1595         AVAHI_LLIST_PREPEND(ServiceResolverInfo, service_resolvers, client->service_resolvers, i);
1596         client->n_objects++;
1597
1598         if (!(i->service_resolver = avahi_s_service_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, type, domain, (AvahiProtocol) aprotocol, service_resolver_callback, i))) {
1599             service_resolver_free(i);
1600             return respond_error(c, m, avahi_server_errno(avahi_server), NULL);
1601         }
1602         
1603         return DBUS_HANDLER_RESULT_HANDLED;
1604      }
1605
1606     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
1607
1608 fail:
1609     if (dbus_error_is_set(&error))
1610         dbus_error_free(&error);
1611     
1612     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1613 }
1614
1615 void dbus_protocol_server_state_changed(AvahiServerState state) {
1616     DBusMessage *m;
1617     int32_t t;
1618     
1619     if (!server)
1620         return;
1621
1622     m = dbus_message_new_signal(AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "StateChanged");
1623     t = (int32_t) state;
1624     dbus_message_append_args(m, DBUS_TYPE_INT32, &t, DBUS_TYPE_INVALID);
1625     dbus_connection_send(server->bus, m, NULL);
1626     dbus_message_unref(m);
1627 }
1628
1629 int dbus_protocol_setup(const AvahiPoll *poll_api) {
1630     DBusError error;
1631
1632     static const DBusObjectPathVTable server_vtable = {
1633         NULL,
1634         msg_server_impl,
1635         NULL,
1636         NULL,
1637         NULL,
1638         NULL
1639     };
1640
1641     dbus_error_init(&error);
1642
1643     server = avahi_new(Server, 1);
1644     AVAHI_LLIST_HEAD_INIT(Clients, server->clients);
1645     server->current_id = 0;
1646     server->n_clients = 0;
1647
1648     if (!(server->bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
1649         assert(dbus_error_is_set(&error));
1650         avahi_log_error("dbus_bus_get(): %s", error.message);
1651         goto fail;
1652     }
1653
1654     if (avahi_dbus_connection_glue(server->bus, poll_api) < 0) {
1655         avahi_log_error("avahi_dbus_connection_glue() failed");
1656         goto fail;
1657     }
1658
1659     if (dbus_bus_request_name(server->bus, AVAHI_DBUS_NAME, DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT, &error) != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
1660         if (dbus_error_is_set(&error)) {
1661             avahi_log_error("dbus_bus_request_name(): %s", error.message);
1662             goto fail;
1663         }
1664
1665         avahi_log_error("Failed to acquire DBUS name '"AVAHI_DBUS_NAME"'");
1666         goto fail;
1667     }
1668
1669     if (!(dbus_connection_add_filter(server->bus, msg_signal_filter_impl, (void*) poll_api, NULL))) {
1670         avahi_log_error("dbus_connection_add_filter() failed");
1671         goto fail;
1672     }
1673     
1674     dbus_bus_add_match(server->bus, "type='signal',""interface='" DBUS_INTERFACE_DBUS  "'", &error);
1675
1676     if (dbus_error_is_set(&error)) {
1677         avahi_log_error("dbus_bus_add_match(): %s", error.message);
1678         goto fail;
1679     }
1680     
1681     if (!(dbus_connection_register_object_path(server->bus, AVAHI_DBUS_PATH_SERVER, &server_vtable, NULL))) {
1682         avahi_log_error("dbus_connection_register_object_path() failed");
1683         goto fail;
1684     }
1685
1686     return 0;
1687
1688 fail:
1689     if (server->bus) {
1690         dbus_connection_disconnect(server->bus);
1691         dbus_connection_unref(server->bus);
1692     }
1693
1694     if (dbus_error_is_set(&error))
1695         dbus_error_free(&error);
1696         
1697     avahi_free(server);
1698     server = NULL;
1699     return -1;
1700 }
1701
1702 void dbus_protocol_shutdown(void) {
1703
1704     if (server) {
1705     
1706         while (server->clients)
1707             client_free(server->clients);
1708
1709         assert(server->n_clients == 0);
1710
1711         if (server->bus) {
1712             dbus_connection_disconnect(server->bus);
1713             dbus_connection_unref(server->bus);
1714         }
1715
1716         avahi_free(server);
1717         server = NULL;
1718     }
1719 }