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