]> git.meshlink.io Git - catta/blob - avahi-daemon/dbus-protocol.c
DBUS: finish introspection support
[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(host_name);
872     g_assert(i);
873
874     if (event == AVAHI_RESOLVER_FOUND) {
875         char t[256], *pt = t;
876         gint32 i_interface, i_protocol, i_aprotocol;
877         gchar **array;
878         guint n, j;
879         AvahiStringList *p;
880
881         g_assert(a);
882         avahi_address_snprint(t, sizeof(t), a);
883
884         i_interface = (gint32) interface;
885         i_protocol = (gint32) protocol;
886         i_aprotocol = (gint32) a->family;
887
888         array = g_new(gchar*, (n = avahi_string_list_length(txt)));
889
890         /** FIXME: DBUS doesn't support strings that include NUL bytes (?) */
891         for (p = txt, j = n-1; p; p = p->next, j--)
892             array[j] = g_strndup((gchar*) p->text, p->size);
893         
894         reply = dbus_message_new_method_return(i->message);
895         dbus_message_append_args(
896             reply,
897             DBUS_TYPE_INT32, &i_interface,
898             DBUS_TYPE_INT32, &i_protocol,
899             DBUS_TYPE_STRING, &name,
900             DBUS_TYPE_STRING, &type,
901             DBUS_TYPE_STRING, &domain,
902             DBUS_TYPE_STRING, &host_name,
903             DBUS_TYPE_INT32, &i_aprotocol,
904             DBUS_TYPE_STRING, &pt,
905             DBUS_TYPE_UINT16, &port,
906             DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &array, n,
907             DBUS_TYPE_INVALID);
908
909         for (j = 0; j < n; j++)
910             g_free(array[j]);
911
912     } else {
913         g_assert(event == AVAHI_RESOLVER_TIMEOUT);
914         reply = dbus_message_new_error(i->message, "org.freedesktop.Avahi.TimeoutError", NULL);
915     }
916
917     dbus_connection_send(server->bus, reply, NULL);
918     dbus_message_unref(reply);
919
920     service_resolver_free(i);
921 }
922
923
924 static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
925     DBusError error;
926
927     dbus_error_init(&error);
928
929     avahi_log_debug("dbus: interface=%s, path=%s, member=%s",
930                     dbus_message_get_interface(m),
931                     dbus_message_get_path(m),
932                     dbus_message_get_member(m));
933
934     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
935         return handle_introspect(c, m, "Server.introspect");
936         
937     else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostName")) {
938
939         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
940             avahi_log_warn("Error parsing Server::GetHostName message");
941             goto fail;
942         }
943
944         return respond_string(c, m, avahi_server_get_host_name(avahi_server));
945         
946     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetDomainName")) {
947
948         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
949             avahi_log_warn("Error parsing Server::GetDomainName message");
950             goto fail;
951         }
952
953         return respond_string(c, m, avahi_server_get_domain_name(avahi_server));
954
955     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostNameFqdn")) {
956
957         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
958             avahi_log_warn("Error parsing Server::GetHostNameFqdn message");
959             goto fail;
960         }
961     
962         return respond_string(c, m, avahi_server_get_host_name_fqdn(avahi_server));
963         
964     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetVersionString")) {
965
966         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
967             avahi_log_warn("Error parsing Server::GetVersionString message");
968             goto fail;
969         }
970     
971         return respond_string(c, m, PACKAGE_STRING);
972
973     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetState")) {
974         DBusMessage *reply;
975         gint32 s;
976             
977         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
978             avahi_log_warn("Error parsing Server::GetState message");
979             goto fail;
980         }
981
982         s = (gint32) avahi_server_get_state(avahi_server);
983         
984         reply = dbus_message_new_method_return(m);
985         dbus_message_append_args(reply, DBUS_TYPE_INT32, &s, DBUS_TYPE_INVALID);
986         dbus_connection_send(c, reply, NULL);
987         dbus_message_unref(reply);
988         
989         return DBUS_HANDLER_RESULT_HANDLED;
990
991     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetAlternativeHostName")) {
992         gchar *n, * t;
993         
994         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n || !*n) {
995             avahi_log_warn("Error parsing Server::GetAlternativeHostName message");
996             goto fail;
997         }
998
999         t = avahi_alternative_host_name(n);
1000         respond_string(c, m, t);
1001         g_free(t);
1002
1003         return DBUS_HANDLER_RESULT_HANDLED;
1004
1005     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetAlternativeServiceName")) {
1006         gchar *n, *t;
1007         
1008         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n || !*n) {
1009             avahi_log_warn("Error parsing Server::GetAlternativeServiceName message");
1010             goto fail;
1011         }
1012
1013         t = avahi_alternative_service_name(n);
1014         respond_string(c, m, t);
1015         g_free(t);
1016
1017         return DBUS_HANDLER_RESULT_HANDLED;
1018         
1019     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "EntryGroupNew")) {
1020         Client *client;
1021         EntryGroupInfo *i;
1022         static const DBusObjectPathVTable vtable = {
1023             NULL,
1024             msg_entry_group_impl,
1025             NULL,
1026             NULL,
1027             NULL,
1028             NULL
1029         };
1030
1031         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
1032             avahi_log_warn("Error parsing Server::EntryGroupNew message");
1033             goto fail;
1034         }
1035
1036         client = client_get(dbus_message_get_sender(m), TRUE);
1037
1038         i = g_new(EntryGroupInfo, 1);
1039         i->id = ++client->current_id;
1040         i->client = client;
1041         i->path = g_strdup_printf("/Client%u/EntryGroup%u", client->id, i->id);
1042         AVAHI_LLIST_PREPEND(EntryGroupInfo, entry_groups, client->entry_groups, i);
1043
1044         if (!(i->entry_group = avahi_entry_group_new(avahi_server, entry_group_callback, i))) {
1045             avahi_log_warn("Failed to create entry group");
1046             entry_group_free(i);
1047             goto fail;
1048         }
1049
1050         dbus_connection_register_object_path(c, i->path, &vtable, i);
1051         return respond_path(c, m, i->path);
1052         
1053     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveHostName")) {
1054         Client *client;
1055         gint32 interface, protocol, aprotocol;
1056         gchar *name;
1057         HostNameResolverInfo *i;
1058             
1059         if (!dbus_message_get_args(
1060                 m, &error,
1061                 DBUS_TYPE_INT32, &interface,
1062                 DBUS_TYPE_INT32, &protocol,
1063                 DBUS_TYPE_STRING, &name,
1064                 DBUS_TYPE_INT32, &aprotocol,
1065                 DBUS_TYPE_INVALID) || !name || !*name) {
1066             avahi_log_warn("Error parsing Server::ResolveHostName message");
1067             goto fail;
1068         }
1069
1070         client = client_get(dbus_message_get_sender(m), TRUE);
1071
1072         i = g_new(HostNameResolverInfo, 1);
1073         i->client = client;
1074         i->message = dbus_message_ref(m);
1075         AVAHI_LLIST_PREPEND(HostNameResolverInfo, host_name_resolvers, client->host_name_resolvers, i);
1076
1077         if (!(i->host_name_resolver = avahi_host_name_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, (AvahiProtocol) aprotocol, host_name_resolver_callback, i))) {
1078             host_name_resolver_free(i);
1079             avahi_log_warn("Failed to create host name resolver");
1080             goto fail;
1081         }
1082         
1083         return DBUS_HANDLER_RESULT_HANDLED;
1084         
1085     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveAddress")) {
1086         Client *client;
1087         gint32 interface, protocol;
1088         gchar *address;
1089         AddressResolverInfo *i;
1090         AvahiAddress a;
1091             
1092         if (!dbus_message_get_args(
1093                 m, &error,
1094                 DBUS_TYPE_INT32, &interface,
1095                 DBUS_TYPE_INT32, &protocol,
1096                 DBUS_TYPE_STRING, &address,
1097                 DBUS_TYPE_INVALID) || !address || !*address) {
1098             avahi_log_warn("Error parsing Server::ResolveAddress message");
1099             goto fail;
1100         }
1101
1102         if (!avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a)) {
1103             avahi_log_warn("Error parsing address data");
1104             return respond_error(c, m, "org.freedesktop.Avahi.InvalidAddressError", NULL);
1105         }
1106         
1107         client = client_get(dbus_message_get_sender(m), TRUE);
1108
1109         i = g_new(AddressResolverInfo, 1);
1110         i->client = client;
1111         i->message = dbus_message_ref(m);
1112
1113         AVAHI_LLIST_PREPEND(AddressResolverInfo, address_resolvers, client->address_resolvers, i);
1114
1115         if (!(i->address_resolver = avahi_address_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, &a, address_resolver_callback, i))) {
1116             address_resolver_free(i);
1117             avahi_log_warn("Failed to create address resolver");
1118             goto fail;
1119         }
1120         
1121         return DBUS_HANDLER_RESULT_HANDLED;
1122         
1123     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "DomainBrowserNew")) {
1124         Client *client;
1125         DomainBrowserInfo *i;
1126         static const DBusObjectPathVTable vtable = {
1127             NULL,
1128             msg_domain_browser_impl,
1129             NULL,
1130             NULL,
1131             NULL,
1132             NULL
1133         };
1134         gint32 interface, protocol, type;
1135         gchar *domain;
1136         
1137
1138         if (!dbus_message_get_args(
1139                 m, &error,
1140                 DBUS_TYPE_INT32, &interface,
1141                 DBUS_TYPE_INT32, &protocol,
1142                 DBUS_TYPE_STRING, &domain,
1143                 DBUS_TYPE_INT32, &type,
1144                 DBUS_TYPE_INVALID) || type < 0 || type >= AVAHI_DOMAIN_BROWSER_MAX) {
1145             avahi_log_warn("Error parsing Server::DomainBrowserNew message");
1146             goto fail;
1147         }
1148
1149         client = client_get(dbus_message_get_sender(m), TRUE);
1150
1151         if (!*domain)
1152             domain = NULL;
1153
1154         i = g_new(DomainBrowserInfo, 1);
1155         i->id = ++client->current_id;
1156         i->client = client;
1157         i->path = g_strdup_printf("/Client%u/DomainBrowser%u", client->id, i->id);
1158
1159         AVAHI_LLIST_PREPEND(DomainBrowserInfo, domain_browsers, client->domain_browsers, i);
1160
1161         if (!(i->domain_browser = avahi_domain_browser_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, domain, (AvahiDomainBrowserType) type, domain_browser_callback, i))) {
1162             avahi_log_warn("Failed to create domain browser");
1163             domain_browser_free(i);
1164             goto fail;
1165         }
1166         
1167         dbus_connection_register_object_path(c, i->path, &vtable, i);
1168         return respond_path(c, m, i->path);
1169
1170     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ServiceTypeBrowserNew")) {
1171         Client *client;
1172         ServiceTypeBrowserInfo *i;
1173         static const DBusObjectPathVTable vtable = {
1174             NULL,
1175             msg_service_type_browser_impl,
1176             NULL,
1177             NULL,
1178             NULL,
1179             NULL
1180         };
1181         gint32 interface, protocol;
1182         gchar *domain;
1183         
1184         if (!dbus_message_get_args(
1185                 m, &error,
1186                 DBUS_TYPE_INT32, &interface,
1187                 DBUS_TYPE_INT32, &protocol,
1188                 DBUS_TYPE_STRING, &domain,
1189                 DBUS_TYPE_INVALID)) {
1190             avahi_log_warn("Error parsing Server::ServiceTypeBrowserNew message");
1191             goto fail;
1192         }
1193
1194         client = client_get(dbus_message_get_sender(m), TRUE);
1195
1196         if (!*domain)
1197             domain = NULL;
1198
1199         i = g_new(ServiceTypeBrowserInfo, 1);
1200         i->id = ++client->current_id;
1201         i->client = client;
1202         i->path = g_strdup_printf("/Client%u/ServiceTypeBrowser%u", client->id, i->id);
1203
1204         AVAHI_LLIST_PREPEND(ServiceTypeBrowserInfo, service_type_browsers, client->service_type_browsers, i);
1205
1206         if (!(i->service_type_browser = avahi_service_type_browser_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, domain, service_type_browser_callback, i))) {
1207             avahi_log_warn("Failed to create service type browser");
1208             service_type_browser_free(i);
1209             goto fail;
1210         }
1211         
1212         dbus_connection_register_object_path(c, i->path, &vtable, i);
1213         return respond_path(c, m, i->path);
1214         
1215      } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ServiceBrowserNew")) {
1216         Client *client;
1217         ServiceBrowserInfo *i;
1218         static const DBusObjectPathVTable vtable = {
1219             NULL,
1220             msg_service_browser_impl,
1221             NULL,
1222             NULL,
1223             NULL,
1224             NULL
1225         };
1226         gint32 interface, protocol;
1227         gchar *domain, *type;
1228         
1229         if (!dbus_message_get_args(
1230                 m, &error,
1231                 DBUS_TYPE_INT32, &interface,
1232                 DBUS_TYPE_INT32, &protocol,
1233                 DBUS_TYPE_STRING, &type,
1234                 DBUS_TYPE_STRING, &domain,
1235                 DBUS_TYPE_INVALID) || !type || !*type) {
1236             avahi_log_warn("Error parsing Server::ServiceBrowserNew message");
1237             goto fail;
1238         }
1239
1240         client = client_get(dbus_message_get_sender(m), TRUE);
1241
1242         if (!*domain)
1243             domain = NULL;
1244
1245         i = g_new(ServiceBrowserInfo, 1);
1246         i->id = ++client->current_id;
1247         i->client = client;
1248         i->path = g_strdup_printf("/Client%u/ServiceBrowser%u", client->id, i->id);
1249
1250         AVAHI_LLIST_PREPEND(ServiceBrowserInfo, service_browsers, client->service_browsers, i);
1251
1252         if (!(i->service_browser = avahi_service_browser_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, type, domain, service_browser_callback, i))) {
1253             avahi_log_warn("Failed to create service browser");
1254             service_browser_free(i);
1255             goto fail;
1256         }
1257         
1258         dbus_connection_register_object_path(c, i->path, &vtable, i);
1259         return respond_path(c, m, i->path);
1260         
1261     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveService")) {
1262         Client *client;
1263         gint32 interface, protocol, aprotocol;
1264         gchar *name, *type, *domain;
1265         ServiceResolverInfo *i;
1266             
1267         if (!dbus_message_get_args(
1268                 m, &error,
1269                 DBUS_TYPE_INT32, &interface,
1270                 DBUS_TYPE_INT32, &protocol,
1271                 DBUS_TYPE_STRING, &name,
1272                 DBUS_TYPE_STRING, &type,
1273                 DBUS_TYPE_STRING, &domain,
1274                 DBUS_TYPE_INT32, &aprotocol,
1275                 DBUS_TYPE_INVALID) || !name || !*name || !type || !*type) {
1276             avahi_log_warn("Error parsing Server::ResolveService message");
1277             goto fail;
1278         }
1279
1280         client = client_get(dbus_message_get_sender(m), TRUE);
1281
1282         if (!*domain)
1283             domain = NULL;
1284         
1285         i = g_new(ServiceResolverInfo, 1);
1286         i->client = client;
1287         i->message = dbus_message_ref(m);
1288         AVAHI_LLIST_PREPEND(ServiceResolverInfo, service_resolvers, client->service_resolvers, i);
1289
1290         if (!(i->service_resolver = avahi_service_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, type, domain, (AvahiProtocol) aprotocol, service_resolver_callback, i))) {
1291             service_resolver_free(i);
1292             avahi_log_warn("Failed to create service resolver");
1293             goto fail;
1294         }
1295         
1296         return DBUS_HANDLER_RESULT_HANDLED;
1297      }
1298
1299     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
1300
1301 fail:
1302     if (dbus_error_is_set(&error))
1303         dbus_error_free(&error);
1304     
1305     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1306 }
1307
1308 void dbus_protocol_server_state_changed(AvahiServerState state) {
1309     DBusMessage *m;
1310     gint32 t;
1311     
1312     if (!server)
1313         return;
1314
1315     m = dbus_message_new_signal(AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "StateChanged");
1316     t = (gint32) state;
1317     dbus_message_append_args(m, DBUS_TYPE_INT32, &t, DBUS_TYPE_INVALID);
1318     dbus_connection_send(server->bus, m, NULL);
1319     dbus_message_unref(m);
1320 }
1321
1322 int dbus_protocol_setup(GMainLoop *loop) {
1323     DBusError error;
1324
1325     static const DBusObjectPathVTable server_vtable = {
1326         NULL,
1327         msg_server_impl,
1328         NULL,
1329         NULL,
1330         NULL,
1331         NULL
1332     };
1333
1334     dbus_error_init(&error);
1335
1336     server = g_malloc(sizeof(Server));
1337     server->clients = NULL;
1338     server->current_id = 0;
1339
1340     server->bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
1341     if (dbus_error_is_set(&error)) {
1342         avahi_log_warn("dbus_bus_get(): %s", error.message);
1343         goto fail;
1344     }
1345
1346     dbus_connection_setup_with_g_main(server->bus, NULL);
1347     dbus_connection_set_exit_on_disconnect(server->bus, FALSE);
1348
1349     dbus_bus_request_name(server->bus, AVAHI_DBUS_NAME, 0, &error);
1350     if (dbus_error_is_set(&error)) {
1351         avahi_log_warn("dbus_bus_request_name(): %s", error.message);
1352         goto fail;
1353     }
1354
1355     dbus_bus_add_match(server->bus, "type='signal',""interface='" DBUS_INTERFACE_DBUS  "'", &error);
1356
1357     dbus_connection_add_filter(server->bus, msg_signal_filter_impl, loop, NULL);
1358     dbus_connection_register_object_path(server->bus, AVAHI_DBUS_PATH_SERVER, &server_vtable, NULL);
1359
1360     return 0;
1361
1362 fail:
1363     if (server->bus) {
1364         dbus_connection_disconnect(server->bus);
1365         dbus_connection_unref(server->bus);
1366     }
1367     
1368     dbus_error_free (&error);
1369     g_free(server);
1370     server = NULL;
1371     return -1;
1372 }
1373
1374 void dbus_protocol_shutdown(void) {
1375
1376     if (server) {
1377     
1378         while (server->clients)
1379             client_free(server->clients);
1380
1381         if (server->bus) {
1382             dbus_connection_disconnect(server->bus);
1383             dbus_connection_unref(server->bus);
1384         }
1385
1386         g_free(server);
1387         server = NULL;
1388     }
1389 }