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