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