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