]> git.meshlink.io Git - catta/blob - avahi-daemon/dbus-protocol.c
7be5ee0049dce43b4a4b1f292f6539734118e7e1
[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
45 /* Needs wrapping:
46    - AvahiServiceResolver
47    - AvahiDomainBrowser
48    - AvahiServiceTypeBrowser
49    - AvahiServiceBrowser */
50
51 typedef struct Server Server;
52 typedef struct Client Client;
53 typedef struct EntryGroupInfo EntryGroupInfo;
54 typedef struct HostNameResolverInfo HostNameResolverInfo;
55 typedef struct AddressResolverInfo AddressResolverInfo;
56
57 struct EntryGroupInfo {
58     guint id;
59     Client *client;
60     AvahiEntryGroup *entry_group;
61     gchar *path;
62     
63     AVAHI_LLIST_FIELDS(EntryGroupInfo, entry_groups);
64 };
65
66 struct HostNameResolverInfo {
67     Client *client;
68     AvahiHostNameResolver *host_name_resolver;
69     DBusMessage *message;
70
71     AVAHI_LLIST_FIELDS(HostNameResolverInfo, host_name_resolvers);
72 };
73
74 struct AddressResolverInfo {
75     Client *client;
76     AvahiAddressResolver *address_resolver;
77     DBusMessage *message;
78
79     AVAHI_LLIST_FIELDS(AddressResolverInfo, address_resolvers);
80 };
81
82 struct Client {
83     guint id;
84     gchar *name;
85     guint current_id;
86     
87     AVAHI_LLIST_FIELDS(Client, clients);
88     AVAHI_LLIST_HEAD(EntryGroupInfo, entry_groups);
89     AVAHI_LLIST_HEAD(HostNameResolverInfo, host_name_resolvers);
90     AVAHI_LLIST_HEAD(AddressResolverInfo, address_resolvers);
91 };
92
93 struct Server {
94     DBusConnection *bus;
95     AVAHI_LLIST_HEAD(Client, clients);
96     guint current_id;
97 };
98
99 static Server *server = NULL;
100
101 static void entry_group_free(EntryGroupInfo *i) {
102     g_assert(i);
103     
104     avahi_entry_group_free(i->entry_group);
105     dbus_connection_unregister_object_path(server->bus, i->path);
106     g_free(i->path);
107     AVAHI_LLIST_REMOVE(EntryGroupInfo, entry_groups, i->client->entry_groups, i);
108     g_free(i);
109  }
110
111 static void host_name_resolver_free(HostNameResolverInfo *i) {
112     g_assert(i);
113
114     avahi_host_name_resolver_free(i->host_name_resolver);
115     dbus_message_unref(i->message);
116     AVAHI_LLIST_REMOVE(HostNameResolverInfo, host_name_resolvers, i->client->host_name_resolvers, i);
117     g_free(i);
118 }
119
120 static void address_resolver_free(AddressResolverInfo *i) {
121     g_assert(i);
122
123     avahi_address_resolver_free(i->address_resolver);
124     dbus_message_unref(i->message);
125     AVAHI_LLIST_REMOVE(AddressResolverInfo, address_resolvers, i->client->address_resolvers, i);
126     g_free(i);
127 }
128
129 static void client_free(Client *c) {
130     
131     g_assert(server);
132     g_assert(c);
133
134     while (c->entry_groups)
135         entry_group_free(c->entry_groups);
136
137     while (c->host_name_resolvers)
138         host_name_resolver_free(c->host_name_resolvers);
139
140     while (c->address_resolvers)
141         address_resolver_free(c->address_resolvers);
142     
143     g_free(c->name);
144     AVAHI_LLIST_REMOVE(Client, clients, server->clients, c);
145     g_free(c);
146 }
147
148 static Client *client_get(const gchar *name, gboolean create) {
149     Client *client;
150
151     g_assert(server);
152     g_assert(name);
153
154     for (client = server->clients; client; client = client->clients_next)
155         if (!strcmp(name, client->name))
156             return client;
157
158     if (!create)
159         return NULL;
160
161     /* If not existant yet, create a new entry */
162     client = g_new(Client, 1);
163     client->id = server->current_id++;
164     client->name = g_strdup(name);
165     client->current_id = 0;
166     AVAHI_LLIST_HEAD_INIT(EntryGroupInfo, client->entry_groups);
167     AVAHI_LLIST_HEAD_INIT(HostNameResolverInfo, client->host_name_resolvers);
168     AVAHI_LLIST_HEAD_INIT(AddressResolverInfo, client->address_resolvers);
169
170     AVAHI_LLIST_PREPEND(Client, clients, server->clients, client);
171     return client;
172 }
173
174 static DBusHandlerResult msg_signal_filter_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
175     GMainLoop *loop = userdata;
176     DBusError error;
177
178     dbus_error_init(&error);
179
180 /*     avahi_log_debug("dbus: interface=%s, path=%s, member=%s", */
181 /*                     dbus_message_get_interface(m), */
182 /*                     dbus_message_get_path(m), */
183 /*                     dbus_message_get_member(m)); */
184
185     if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) {
186         /* No, we shouldn't quit, but until we get somewhere
187          * usefull such that we can restore our state, we will */
188         avahi_log_warn("Disconnnected from d-bus, terminating...");
189         g_main_loop_quit (loop);
190         return DBUS_HANDLER_RESULT_HANDLED;
191         
192     } else if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameAcquired")) {
193         gchar *name;
194
195         if (!dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) {
196             avahi_log_warn("Error parsing NameAcquired message");
197             goto fail;
198         }
199
200         avahi_log_info("dbus: name acquired (%s)", name);
201         return DBUS_HANDLER_RESULT_HANDLED;
202     } else if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
203         gchar *name, *old, *new;
204
205         if (!dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old, DBUS_TYPE_STRING, &new, DBUS_TYPE_INVALID)) {
206             avahi_log_warn("Error parsing NameOwnerChanged message");
207             goto fail;
208         }
209
210         if (!*new) {
211             Client *client;
212
213             if ((client = client_get(name, FALSE))) {
214                 avahi_log_info("dbus: client %s vanished", name);
215                 client_free(client);
216             }
217         }
218     }
219
220 fail:
221     if (dbus_error_is_set(&error))
222         dbus_error_free(&error);
223     
224     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
225 }
226
227 static DBusHandlerResult respond_error(DBusConnection *c, DBusMessage *m, const gchar *error, const gchar *text) {
228     DBusMessage *reply;
229
230     reply = dbus_message_new_error(m, error, text);
231     dbus_connection_send(c, reply, NULL);
232     dbus_message_unref(reply);
233     
234     return DBUS_HANDLER_RESULT_HANDLED;
235 }
236
237 static void entry_group_callback(AvahiServer *s, AvahiEntryGroup *g, AvahiEntryGroupState state, gpointer userdata) {
238     EntryGroupInfo *i = userdata;
239     DBusMessage *m;
240     gint32 t;
241     
242     g_assert(s);
243     g_assert(g);
244     g_assert(i);
245
246     m = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "StateChanged");
247     t = (gint32) state;
248     dbus_message_append_args(m, DBUS_TYPE_INT32, &t, DBUS_TYPE_INVALID);
249     dbus_message_set_destination(m, i->client->name);  
250     dbus_connection_send(server->bus, m, NULL);
251     dbus_message_unref(m);
252 }
253
254 static DBusHandlerResult respond_ok(DBusConnection *c, DBusMessage *m) {
255     DBusMessage *reply;
256
257     reply = dbus_message_new_method_return(m);
258     dbus_connection_send(c, reply, NULL);
259     dbus_message_unref(reply);
260     
261     return DBUS_HANDLER_RESULT_HANDLED;
262 }
263
264 static DBusHandlerResult msg_entry_group_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
265     DBusError error;
266     EntryGroupInfo *i = userdata;
267
268     g_assert(c);
269     g_assert(m);
270     g_assert(i);
271     
272     dbus_error_init(&error);
273
274     avahi_log_debug("dbus: interface=%s, path=%s, member=%s",
275                     dbus_message_get_interface(m),
276                     dbus_message_get_path(m),
277                     dbus_message_get_member(m));
278
279     /* Access control */
280     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
281         return respond_error(c, m, DBUS_ERROR_ACCESS_DENIED, NULL);
282     
283     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Free")) {
284
285         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
286             avahi_log_warn("Error parsing EntryGroup::Free message");
287             goto fail;
288         }
289
290         entry_group_free(i);
291         return respond_ok(c, m);
292     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Commit")) {
293
294         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
295             avahi_log_warn("Error parsing EntryGroup::Commit message");
296             goto fail;
297         }
298
299         avahi_entry_group_commit(i->entry_group);
300         return respond_ok(c, m);
301     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "GetState")) {
302         DBusMessage *reply;
303         gint32 t;
304
305         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
306             avahi_log_warn("Error parsing EntryGroup::GetState message");
307             goto fail;
308         }
309
310         t = (gint32) avahi_entry_group_get_state(i->entry_group);
311         reply = dbus_message_new_method_return(m);
312         dbus_message_append_args(reply, DBUS_TYPE_INT32, &t, DBUS_TYPE_INVALID);
313         dbus_connection_send(c, reply, NULL);
314         dbus_message_unref(reply);
315         
316         return DBUS_HANDLER_RESULT_HANDLED;
317     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddService")) {
318         gint32 interface, protocol;
319         gchar *type, *name, *domain, *host;
320         guint16 port;
321         gchar **txt = NULL;
322         gint txt_len;
323         AvahiStringList *strlst;
324         
325         if (!dbus_message_get_args(
326                 m, &error,
327                 DBUS_TYPE_INT32, &interface,
328                 DBUS_TYPE_INT32, &protocol,
329                 DBUS_TYPE_STRING, &name,
330                 DBUS_TYPE_STRING, &type,
331                 DBUS_TYPE_STRING, &domain,
332                 DBUS_TYPE_STRING, &host,
333                 DBUS_TYPE_UINT16, &port, 
334                 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &txt, &txt_len,
335                 DBUS_TYPE_INVALID) || !type || !*type || !name || !*name || !port) {
336             avahi_log_warn("Error parsing EntryGroup::AddService message");
337             goto fail;
338         }
339
340         strlst = avahi_string_list_new_from_array((const gchar**) txt, txt_len);
341         dbus_free_string_array(txt);
342
343         if (domain && !*domain)
344             domain = NULL;
345
346         if (host && !*host)
347             host = NULL;
348
349         if (avahi_server_add_service_strlst(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, type, domain, host, port, strlst) < 0) {
350             avahi_log_warn("Failed to add service: %s", name);
351             return respond_error(c, m, "org.freedesktop.Avahi.InvalidServiceError", NULL);
352         } else
353             avahi_log_info("Successfully added service: %s", name);
354         
355         return respond_ok(c, m);
356     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddAddress")) {
357         gint32 interface, protocol;
358         gchar *name, *address;
359         AvahiAddress a;
360         
361         if (!dbus_message_get_args(
362                 m, &error,
363                 DBUS_TYPE_INT32, &interface,
364                 DBUS_TYPE_INT32, &protocol,
365                 DBUS_TYPE_STRING, &name,
366                 DBUS_TYPE_STRING, &address,
367                 DBUS_TYPE_INVALID) || !name || !*name || !address || !*address) {
368             avahi_log_warn("Error parsing EntryGroup::AddAddress message");
369             goto fail;
370         }
371
372         if (!(avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a))) {
373             avahi_log_warn("Error parsing address data");
374             return respond_error(c, m, "org.freedesktop.Avahi.InvalidAddressError", NULL);
375         }
376
377         if (avahi_server_add_address(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, 0, name, &a) < 0) {
378             avahi_log_warn("Failed to add service: %s", name);
379             return respond_error(c, m, "org.freedesktop.Avahi.InvalidAddressError", NULL);
380         } else
381             avahi_log_info("Successfully added address: %s -> %s", name, address);
382         
383         return respond_ok(c, m);
384     }
385     
386     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
387
388 fail:
389     if (dbus_error_is_set(&error))
390         dbus_error_free(&error);
391     
392     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
393 }
394
395 static void host_name_resolver_callback(AvahiHostNameResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const gchar *host_name, const AvahiAddress *a, gpointer userdata) {
396     HostNameResolverInfo *i = userdata;
397     DBusMessage *reply;
398     
399     g_assert(r);
400     g_assert(host_name);
401     g_assert(i);
402
403     if (event == AVAHI_RESOLVER_FOUND) {
404         char t[256], *pt = t;
405         gint32 i_interface, i_protocol, i_aprotocol;
406
407         g_assert(a);
408         avahi_address_snprint(t, sizeof(t), a);
409
410         i_interface = (gint32) interface;
411         i_protocol = (gint32) protocol;
412         i_aprotocol = (gint32) a->family;
413         
414         reply = dbus_message_new_method_return(i->message);
415         dbus_message_append_args(
416             reply,
417             DBUS_TYPE_INT32, &i_interface,
418             DBUS_TYPE_INT32, &i_protocol,
419             DBUS_TYPE_STRING, &host_name,
420             DBUS_TYPE_INT32, &i_aprotocol,
421             DBUS_TYPE_STRING, &pt,
422             DBUS_TYPE_INVALID);
423
424     } else {
425         g_assert(event == AVAHI_RESOLVER_TIMEOUT);
426         reply = dbus_message_new_error(i->message, "org.freedesktop.Avahi.TimeoutError", NULL);
427     }
428
429     dbus_connection_send(server->bus, reply, NULL);
430     dbus_message_unref(reply);
431
432     host_name_resolver_free(i);
433 }
434
435 static void address_resolver_callback(AvahiAddressResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const AvahiAddress *address, const gchar *host_name, gpointer userdata) {
436     AddressResolverInfo *i = userdata;
437     DBusMessage *reply;
438     
439     g_assert(r);
440     g_assert(address);
441     g_assert(i);
442
443     if (event == AVAHI_RESOLVER_FOUND) {
444         char t[256], *pt = t;
445         gint32 i_interface, i_protocol, i_aprotocol;
446
447         g_assert(host_name);
448         avahi_address_snprint(t, sizeof(t), address);
449
450         i_interface = (gint32) interface;
451         i_protocol = (gint32) protocol;
452         i_aprotocol = (gint32) address->family;
453         
454         reply = dbus_message_new_method_return(i->message);
455         dbus_message_append_args(
456             reply,
457             DBUS_TYPE_INT32, &i_interface,
458             DBUS_TYPE_INT32, &i_protocol,
459             DBUS_TYPE_INT32, &i_aprotocol,
460             DBUS_TYPE_STRING, &pt,
461             DBUS_TYPE_STRING, &host_name,
462             DBUS_TYPE_INVALID);
463
464     } else {
465         g_assert(event == AVAHI_RESOLVER_TIMEOUT);
466         reply = dbus_message_new_error(i->message, "org.freedesktop.Avahi.TimeoutError", NULL);
467     }
468
469     dbus_connection_send(server->bus, reply, NULL);
470     dbus_message_unref(reply);
471
472     address_resolver_free(i);
473 }
474
475 static DBusHandlerResult respond_string(DBusConnection *c, DBusMessage *m, const gchar *text) {
476     DBusMessage *reply;
477
478     reply = dbus_message_new_method_return(m);
479     dbus_message_append_args(reply, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID);
480     dbus_connection_send(c, reply, NULL);
481     dbus_message_unref(reply);
482     
483     return DBUS_HANDLER_RESULT_HANDLED;
484 }
485
486 static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
487     DBusError error;
488
489     dbus_error_init(&error);
490
491     avahi_log_debug("dbus: interface=%s, path=%s, member=%s",
492                     dbus_message_get_interface(m),
493                     dbus_message_get_path(m),
494                     dbus_message_get_member(m));
495
496     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostName")) {
497
498         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
499             avahi_log_warn("Error parsing Server::GetHostName message");
500             goto fail;
501         }
502
503         return respond_string(c, m, avahi_server_get_host_name(avahi_server));
504         
505     } if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetDomainName")) {
506
507         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
508             avahi_log_warn("Error parsing Server::GetDomainName message");
509             goto fail;
510         }
511
512         return respond_string(c, m, avahi_server_get_domain_name(avahi_server));
513
514     } if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostNameFqdn")) {
515
516         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
517             avahi_log_warn("Error parsing Server::GetHostNameFqdn message");
518             goto fail;
519         }
520     
521         return respond_string(c, m, avahi_server_get_host_name_fqdn(avahi_server));
522         
523     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "EntryGroupNew")) {
524         Client *client;
525         EntryGroupInfo *i;
526         static const DBusObjectPathVTable vtable = {
527             NULL,
528             msg_entry_group_impl,
529             NULL,
530             NULL,
531             NULL,
532             NULL
533         };
534         DBusMessage *reply;
535
536         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
537             avahi_log_warn("Error parsing Server::EntryGroupNew message");
538             goto fail;
539         }
540
541         client = client_get(dbus_message_get_sender(m), TRUE);
542
543         i = g_new(EntryGroupInfo, 1);
544         i->id = ++client->current_id;
545         i->client = client;
546         i->entry_group = avahi_entry_group_new(avahi_server, entry_group_callback, i);
547         i->path = g_strdup_printf("/org/freedesktop/Avahi/Client%u/EntryGroup%u", client->id, i->id);
548
549         AVAHI_LLIST_PREPEND(EntryGroupInfo, entry_groups, client->entry_groups, i);
550
551         dbus_connection_register_object_path(c, i->path, &vtable, i);
552         reply = dbus_message_new_method_return(m);
553         dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &i->path, DBUS_TYPE_INVALID);
554         dbus_connection_send(c, reply, NULL);
555         dbus_message_unref(reply);
556         
557         return DBUS_HANDLER_RESULT_HANDLED;
558         
559     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveHostName")) {
560         Client *client;
561         gint32 interface, protocol, aprotocol;
562         gchar *name;
563         HostNameResolverInfo *i;
564             
565         if (!dbus_message_get_args(
566                 m, &error,
567                 DBUS_TYPE_INT32, &interface,
568                 DBUS_TYPE_INT32, &protocol,
569                 DBUS_TYPE_STRING, &name,
570                 DBUS_TYPE_INT32, &aprotocol,
571                 DBUS_TYPE_INVALID) || !name || !*name) {
572             avahi_log_warn("Error parsing EntryGroup::ResolveHostName message");
573             goto fail;
574         }
575
576         client = client_get(dbus_message_get_sender(m), TRUE);
577
578         i = g_new(HostNameResolverInfo, 1);
579         i->client = client;
580         i->message = dbus_message_ref(m);
581         i->host_name_resolver = avahi_host_name_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, (AvahiProtocol) aprotocol, host_name_resolver_callback, i);
582
583         AVAHI_LLIST_PREPEND(HostNameResolverInfo, host_name_resolvers, client->host_name_resolvers, i);
584         
585         return DBUS_HANDLER_RESULT_HANDLED;
586         
587     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveAddress")) {
588         Client *client;
589         gint32 interface, protocol;
590         gchar *address;
591         AddressResolverInfo *i;
592         AvahiAddress a;
593             
594         if (!dbus_message_get_args(
595                 m, &error,
596                 DBUS_TYPE_INT32, &interface,
597                 DBUS_TYPE_INT32, &protocol,
598                 DBUS_TYPE_STRING, &address,
599                 DBUS_TYPE_INVALID) || !address || !*address) {
600             avahi_log_warn("Error parsing EntryGroup::ResolveAddress message");
601             goto fail;
602         }
603
604         if (!avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a)) {
605             avahi_log_warn("Error parsing address data");
606             return respond_error(c, m, "org.freedesktop.Avahi.InvalidAddressError", NULL);
607         }
608         
609         client = client_get(dbus_message_get_sender(m), TRUE);
610
611         i = g_new(AddressResolverInfo, 1);
612         i->client = client;
613         i->message = dbus_message_ref(m);
614         i->address_resolver = avahi_address_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, &a, address_resolver_callback, i);
615
616         AVAHI_LLIST_PREPEND(AddressResolverInfo, address_resolvers, client->address_resolvers, i);
617         
618         return DBUS_HANDLER_RESULT_HANDLED;
619     }
620     
621     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
622
623
624 fail:
625     if (dbus_error_is_set(&error))
626         dbus_error_free(&error);
627     
628     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
629 }
630
631 void dbus_protocol_server_state_changed(AvahiServerState state) {
632     DBusMessage *m;
633     gint32 t;
634     
635     if (!server)
636         return;
637
638     m = dbus_message_new_signal(AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "StateChanged");
639     t = (gint32) state;
640     dbus_message_append_args(m, DBUS_TYPE_INT32, &t, DBUS_TYPE_INVALID);
641     dbus_connection_send(server->bus, m, NULL);
642     dbus_message_unref(m);
643 }
644
645 int dbus_protocol_setup(GMainLoop *loop) {
646     DBusError error;
647
648     static const DBusObjectPathVTable server_vtable = {
649         NULL,
650         msg_server_impl,
651         NULL,
652         NULL,
653         NULL,
654         NULL
655     };
656
657     dbus_error_init(&error);
658
659     server = g_malloc(sizeof(Server));
660     server->clients = NULL;
661     server->current_id = 0;
662
663     server->bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
664     if (dbus_error_is_set(&error)) {
665         avahi_log_warn("dbus_bus_get(): %s", error.message);
666         goto fail;
667     }
668
669     dbus_connection_setup_with_g_main(server->bus, NULL);
670     dbus_connection_set_exit_on_disconnect(server->bus, FALSE);
671
672     dbus_bus_request_name(server->bus, AVAHI_DBUS_NAME, 0, &error);
673     if (dbus_error_is_set(&error)) {
674         avahi_log_warn("dbus_bus_request_name(): %s", error.message);
675         goto fail;
676     }
677
678     dbus_bus_add_match(server->bus, "type='signal',""interface='" DBUS_INTERFACE_DBUS  "'", &error);
679
680     dbus_connection_add_filter(server->bus, msg_signal_filter_impl, loop, NULL);
681     dbus_connection_register_object_path(server->bus, AVAHI_DBUS_PATH_SERVER, &server_vtable, NULL);
682
683     return 0;
684
685 fail:
686     if (server->bus) {
687         dbus_connection_disconnect(server->bus);
688         dbus_connection_unref(server->bus);
689     }
690     
691     dbus_error_free (&error);
692     g_free(server);
693     server = NULL;
694     return -1;
695 }
696
697 void dbus_protocol_shutdown(void) {
698
699     if (server) {
700     
701         while (server->clients)
702             client_free(server->clients);
703
704         if (server->bus) {
705             dbus_connection_disconnect(server->bus);
706             dbus_connection_unref(server->bus);
707         }
708
709         g_free(server);
710         server = NULL;
711     }
712 }