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