]> git.meshlink.io Git - catta/blob - avahi-daemon/dbus-protocol.c
a1582ab86796aeafd02a4ab44174c07e4cbadc1e
[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         
203     } else if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
204         gchar *name, *old, *new;
205
206         if (!dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old, DBUS_TYPE_STRING, &new, DBUS_TYPE_INVALID)) {
207             avahi_log_warn("Error parsing NameOwnerChanged message");
208             goto fail;
209         }
210
211         if (!*new) {
212             Client *client;
213
214             if ((client = client_get(name, FALSE))) {
215                 avahi_log_info("dbus: client %s vanished", name);
216                 client_free(client);
217             }
218         }
219     }
220
221 fail:
222     if (dbus_error_is_set(&error))
223         dbus_error_free(&error);
224     
225     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
226 }
227
228 static DBusHandlerResult respond_error(DBusConnection *c, DBusMessage *m, const gchar *error, const gchar *text) {
229     DBusMessage *reply;
230
231     reply = dbus_message_new_error(m, error, text);
232     dbus_connection_send(c, reply, NULL);
233     dbus_message_unref(reply);
234     
235     return DBUS_HANDLER_RESULT_HANDLED;
236 }
237
238 static void entry_group_callback(AvahiServer *s, AvahiEntryGroup *g, AvahiEntryGroupState state, gpointer userdata) {
239     EntryGroupInfo *i = userdata;
240     DBusMessage *m;
241     gint32 t;
242     
243     g_assert(s);
244     g_assert(g);
245     g_assert(i);
246
247     m = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "StateChanged");
248     t = (gint32) state;
249     dbus_message_append_args(m, DBUS_TYPE_INT32, &t, DBUS_TYPE_INVALID);
250     dbus_message_set_destination(m, i->client->name);  
251     dbus_connection_send(server->bus, m, NULL);
252     dbus_message_unref(m);
253 }
254
255 static DBusHandlerResult respond_ok(DBusConnection *c, DBusMessage *m) {
256     DBusMessage *reply;
257
258     reply = dbus_message_new_method_return(m);
259     dbus_connection_send(c, reply, NULL);
260     dbus_message_unref(reply);
261     
262     return DBUS_HANDLER_RESULT_HANDLED;
263 }
264
265 static DBusHandlerResult msg_entry_group_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
266     DBusError error;
267     EntryGroupInfo *i = userdata;
268
269     g_assert(c);
270     g_assert(m);
271     g_assert(i);
272     
273     dbus_error_init(&error);
274
275     avahi_log_debug("dbus: interface=%s, path=%s, member=%s",
276                     dbus_message_get_interface(m),
277                     dbus_message_get_path(m),
278                     dbus_message_get_member(m));
279
280     /* Access control */
281     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
282         return respond_error(c, m, DBUS_ERROR_ACCESS_DENIED, NULL);
283     
284     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Free")) {
285
286         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
287             avahi_log_warn("Error parsing EntryGroup::Free message");
288             goto fail;
289         }
290
291         entry_group_free(i);
292         return respond_ok(c, m);
293         
294     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Commit")) {
295
296         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
297             avahi_log_warn("Error parsing EntryGroup::Commit message");
298             goto fail;
299         }
300
301         avahi_entry_group_commit(i->entry_group);
302         return respond_ok(c, m);
303         
304     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "GetState")) {
305         DBusMessage *reply;
306         gint32 t;
307
308         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
309             avahi_log_warn("Error parsing EntryGroup::GetState message");
310             goto fail;
311         }
312
313         t = (gint32) avahi_entry_group_get_state(i->entry_group);
314         reply = dbus_message_new_method_return(m);
315         dbus_message_append_args(reply, DBUS_TYPE_INT32, &t, DBUS_TYPE_INVALID);
316         dbus_connection_send(c, reply, NULL);
317         dbus_message_unref(reply);
318         
319         return DBUS_HANDLER_RESULT_HANDLED;
320         
321     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddService")) {
322         gint32 interface, protocol;
323         gchar *type, *name, *domain, *host;
324         guint16 port;
325         gchar **txt = NULL;
326         gint txt_len;
327         AvahiStringList *strlst;
328         
329         if (!dbus_message_get_args(
330                 m, &error,
331                 DBUS_TYPE_INT32, &interface,
332                 DBUS_TYPE_INT32, &protocol,
333                 DBUS_TYPE_STRING, &name,
334                 DBUS_TYPE_STRING, &type,
335                 DBUS_TYPE_STRING, &domain,
336                 DBUS_TYPE_STRING, &host,
337                 DBUS_TYPE_UINT16, &port, 
338                 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &txt, &txt_len,
339                 DBUS_TYPE_INVALID) || !type || !*type || !name || !*name || !port) {
340             avahi_log_warn("Error parsing EntryGroup::AddService message");
341             goto fail;
342         }
343
344         strlst = avahi_string_list_new_from_array((const gchar**) txt, txt_len);
345         dbus_free_string_array(txt);
346
347         if (domain && !*domain)
348             domain = NULL;
349
350         if (host && !*host)
351             host = NULL;
352
353         if (avahi_server_add_service_strlst(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, type, domain, host, port, strlst) < 0) {
354             avahi_log_warn("Failed to add service: %s", name);
355             return respond_error(c, m, "org.freedesktop.Avahi.InvalidServiceError", NULL);
356         } else
357             avahi_log_info("Successfully added service: %s", name);
358         
359         return respond_ok(c, m);
360         
361     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddAddress")) {
362         gint32 interface, protocol;
363         gchar *name, *address;
364         AvahiAddress a;
365         
366         if (!dbus_message_get_args(
367                 m, &error,
368                 DBUS_TYPE_INT32, &interface,
369                 DBUS_TYPE_INT32, &protocol,
370                 DBUS_TYPE_STRING, &name,
371                 DBUS_TYPE_STRING, &address,
372                 DBUS_TYPE_INVALID) || !name || !*name || !address || !*address) {
373             avahi_log_warn("Error parsing EntryGroup::AddAddress message");
374             goto fail;
375         }
376
377         if (!(avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a))) {
378             avahi_log_warn("Error parsing address data");
379             return respond_error(c, m, "org.freedesktop.Avahi.InvalidAddressError", NULL);
380         }
381
382         if (avahi_server_add_address(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, 0, name, &a) < 0) {
383             avahi_log_warn("Failed to add service: %s", name);
384             return respond_error(c, m, "org.freedesktop.Avahi.InvalidAddressError", NULL);
385         } else
386             avahi_log_info("Successfully added address: %s -> %s", name, address);
387         
388         return respond_ok(c, m);
389     }
390     
391     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
392
393 fail:
394     if (dbus_error_is_set(&error))
395         dbus_error_free(&error);
396     
397     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
398 }
399
400 static void host_name_resolver_callback(AvahiHostNameResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const gchar *host_name, const AvahiAddress *a, gpointer userdata) {
401     HostNameResolverInfo *i = userdata;
402     DBusMessage *reply;
403     
404     g_assert(r);
405     g_assert(host_name);
406     g_assert(i);
407
408     if (event == AVAHI_RESOLVER_FOUND) {
409         char t[256], *pt = t;
410         gint32 i_interface, i_protocol, i_aprotocol;
411
412         g_assert(a);
413         avahi_address_snprint(t, sizeof(t), a);
414
415         i_interface = (gint32) interface;
416         i_protocol = (gint32) protocol;
417         i_aprotocol = (gint32) a->family;
418         
419         reply = dbus_message_new_method_return(i->message);
420         dbus_message_append_args(
421             reply,
422             DBUS_TYPE_INT32, &i_interface,
423             DBUS_TYPE_INT32, &i_protocol,
424             DBUS_TYPE_STRING, &host_name,
425             DBUS_TYPE_INT32, &i_aprotocol,
426             DBUS_TYPE_STRING, &pt,
427             DBUS_TYPE_INVALID);
428
429     } else {
430         g_assert(event == AVAHI_RESOLVER_TIMEOUT);
431         reply = dbus_message_new_error(i->message, "org.freedesktop.Avahi.TimeoutError", NULL);
432     }
433
434     dbus_connection_send(server->bus, reply, NULL);
435     dbus_message_unref(reply);
436
437     host_name_resolver_free(i);
438 }
439
440 static void address_resolver_callback(AvahiAddressResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const AvahiAddress *address, const gchar *host_name, gpointer userdata) {
441     AddressResolverInfo *i = userdata;
442     DBusMessage *reply;
443     
444     g_assert(r);
445     g_assert(address);
446     g_assert(i);
447
448     if (event == AVAHI_RESOLVER_FOUND) {
449         char t[256], *pt = t;
450         gint32 i_interface, i_protocol, i_aprotocol;
451
452         g_assert(host_name);
453         avahi_address_snprint(t, sizeof(t), address);
454
455         i_interface = (gint32) interface;
456         i_protocol = (gint32) protocol;
457         i_aprotocol = (gint32) address->family;
458         
459         reply = dbus_message_new_method_return(i->message);
460         dbus_message_append_args(
461             reply,
462             DBUS_TYPE_INT32, &i_interface,
463             DBUS_TYPE_INT32, &i_protocol,
464             DBUS_TYPE_INT32, &i_aprotocol,
465             DBUS_TYPE_STRING, &pt,
466             DBUS_TYPE_STRING, &host_name,
467             DBUS_TYPE_INVALID);
468
469     } else {
470         g_assert(event == AVAHI_RESOLVER_TIMEOUT);
471         reply = dbus_message_new_error(i->message, "org.freedesktop.Avahi.TimeoutError", NULL);
472     }
473
474     dbus_connection_send(server->bus, reply, NULL);
475     dbus_message_unref(reply);
476
477     address_resolver_free(i);
478 }
479
480 static DBusHandlerResult respond_string(DBusConnection *c, DBusMessage *m, const gchar *text) {
481     DBusMessage *reply;
482
483     reply = dbus_message_new_method_return(m);
484     dbus_message_append_args(reply, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID);
485     dbus_connection_send(c, reply, NULL);
486     dbus_message_unref(reply);
487     
488     return DBUS_HANDLER_RESULT_HANDLED;
489 }
490
491 static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
492     DBusError error;
493
494     dbus_error_init(&error);
495
496     avahi_log_debug("dbus: interface=%s, path=%s, member=%s",
497                     dbus_message_get_interface(m),
498                     dbus_message_get_path(m),
499                     dbus_message_get_member(m));
500
501     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostName")) {
502
503         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
504             avahi_log_warn("Error parsing Server::GetHostName message");
505             goto fail;
506         }
507
508         return respond_string(c, m, avahi_server_get_host_name(avahi_server));
509         
510     } if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetDomainName")) {
511
512         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
513             avahi_log_warn("Error parsing Server::GetDomainName message");
514             goto fail;
515         }
516
517         return respond_string(c, m, avahi_server_get_domain_name(avahi_server));
518
519     } if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostNameFqdn")) {
520
521         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
522             avahi_log_warn("Error parsing Server::GetHostNameFqdn message");
523             goto fail;
524         }
525     
526         return respond_string(c, m, avahi_server_get_host_name_fqdn(avahi_server));
527         
528     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "EntryGroupNew")) {
529         Client *client;
530         EntryGroupInfo *i;
531         static const DBusObjectPathVTable vtable = {
532             NULL,
533             msg_entry_group_impl,
534             NULL,
535             NULL,
536             NULL,
537             NULL
538         };
539         DBusMessage *reply;
540
541         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
542             avahi_log_warn("Error parsing Server::EntryGroupNew message");
543             goto fail;
544         }
545
546         client = client_get(dbus_message_get_sender(m), TRUE);
547
548         i = g_new(EntryGroupInfo, 1);
549         i->id = ++client->current_id;
550         i->client = client;
551         i->entry_group = avahi_entry_group_new(avahi_server, entry_group_callback, i);
552         i->path = g_strdup_printf("/org/freedesktop/Avahi/Client%u/EntryGroup%u", client->id, i->id);
553
554         AVAHI_LLIST_PREPEND(EntryGroupInfo, entry_groups, client->entry_groups, i);
555
556         dbus_connection_register_object_path(c, i->path, &vtable, i);
557         reply = dbus_message_new_method_return(m);
558         dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &i->path, DBUS_TYPE_INVALID);
559         dbus_connection_send(c, reply, NULL);
560         dbus_message_unref(reply);
561         
562         return DBUS_HANDLER_RESULT_HANDLED;
563         
564     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveHostName")) {
565         Client *client;
566         gint32 interface, protocol, aprotocol;
567         gchar *name;
568         HostNameResolverInfo *i;
569             
570         if (!dbus_message_get_args(
571                 m, &error,
572                 DBUS_TYPE_INT32, &interface,
573                 DBUS_TYPE_INT32, &protocol,
574                 DBUS_TYPE_STRING, &name,
575                 DBUS_TYPE_INT32, &aprotocol,
576                 DBUS_TYPE_INVALID) || !name || !*name) {
577             avahi_log_warn("Error parsing EntryGroup::ResolveHostName message");
578             goto fail;
579         }
580
581         client = client_get(dbus_message_get_sender(m), TRUE);
582
583         i = g_new(HostNameResolverInfo, 1);
584         i->client = client;
585         i->message = dbus_message_ref(m);
586         i->host_name_resolver = avahi_host_name_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, (AvahiProtocol) aprotocol, host_name_resolver_callback, i);
587
588         AVAHI_LLIST_PREPEND(HostNameResolverInfo, host_name_resolvers, client->host_name_resolvers, i);
589         
590         return DBUS_HANDLER_RESULT_HANDLED;
591         
592     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveAddress")) {
593         Client *client;
594         gint32 interface, protocol;
595         gchar *address;
596         AddressResolverInfo *i;
597         AvahiAddress a;
598             
599         if (!dbus_message_get_args(
600                 m, &error,
601                 DBUS_TYPE_INT32, &interface,
602                 DBUS_TYPE_INT32, &protocol,
603                 DBUS_TYPE_STRING, &address,
604                 DBUS_TYPE_INVALID) || !address || !*address) {
605             avahi_log_warn("Error parsing EntryGroup::ResolveAddress message");
606             goto fail;
607         }
608
609         if (!avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a)) {
610             avahi_log_warn("Error parsing address data");
611             return respond_error(c, m, "org.freedesktop.Avahi.InvalidAddressError", NULL);
612         }
613         
614         client = client_get(dbus_message_get_sender(m), TRUE);
615
616         i = g_new(AddressResolverInfo, 1);
617         i->client = client;
618         i->message = dbus_message_ref(m);
619         i->address_resolver = avahi_address_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, &a, address_resolver_callback, i);
620
621         AVAHI_LLIST_PREPEND(AddressResolverInfo, address_resolvers, client->address_resolvers, i);
622         
623         return DBUS_HANDLER_RESULT_HANDLED;
624     }
625     
626     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
627
628
629 fail:
630     if (dbus_error_is_set(&error))
631         dbus_error_free(&error);
632     
633     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
634 }
635
636 void dbus_protocol_server_state_changed(AvahiServerState state) {
637     DBusMessage *m;
638     gint32 t;
639     
640     if (!server)
641         return;
642
643     m = dbus_message_new_signal(AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "StateChanged");
644     t = (gint32) state;
645     dbus_message_append_args(m, DBUS_TYPE_INT32, &t, DBUS_TYPE_INVALID);
646     dbus_connection_send(server->bus, m, NULL);
647     dbus_message_unref(m);
648 }
649
650 int dbus_protocol_setup(GMainLoop *loop) {
651     DBusError error;
652
653     static const DBusObjectPathVTable server_vtable = {
654         NULL,
655         msg_server_impl,
656         NULL,
657         NULL,
658         NULL,
659         NULL
660     };
661
662     dbus_error_init(&error);
663
664     server = g_malloc(sizeof(Server));
665     server->clients = NULL;
666     server->current_id = 0;
667
668     server->bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
669     if (dbus_error_is_set(&error)) {
670         avahi_log_warn("dbus_bus_get(): %s", error.message);
671         goto fail;
672     }
673
674     dbus_connection_setup_with_g_main(server->bus, NULL);
675     dbus_connection_set_exit_on_disconnect(server->bus, FALSE);
676
677     dbus_bus_request_name(server->bus, AVAHI_DBUS_NAME, 0, &error);
678     if (dbus_error_is_set(&error)) {
679         avahi_log_warn("dbus_bus_request_name(): %s", error.message);
680         goto fail;
681     }
682
683     dbus_bus_add_match(server->bus, "type='signal',""interface='" DBUS_INTERFACE_DBUS  "'", &error);
684
685     dbus_connection_add_filter(server->bus, msg_signal_filter_impl, loop, NULL);
686     dbus_connection_register_object_path(server->bus, AVAHI_DBUS_PATH_SERVER, &server_vtable, NULL);
687
688     return 0;
689
690 fail:
691     if (server->bus) {
692         dbus_connection_disconnect(server->bus);
693         dbus_connection_unref(server->bus);
694     }
695     
696     dbus_error_free (&error);
697     g_free(server);
698     server = NULL;
699     return -1;
700 }
701
702 void dbus_protocol_shutdown(void) {
703
704     if (server) {
705     
706         while (server->clients)
707             client_free(server->clients);
708
709         if (server->bus) {
710             dbus_connection_disconnect(server->bus);
711             dbus_connection_unref(server->bus);
712         }
713
714         g_free(server);
715         server = NULL;
716     }
717 }