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