]> git.meshlink.io Git - catta/blob - avahi-daemon/dbus-protocol.c
* add C examples
[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         
517     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Reset")) {
518         
519         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
520             avahi_log_warn("Error parsing EntryGroup::Reset message");
521             goto fail;
522         }
523
524         avahi_entry_group_reset(i->entry_group);
525         return respond_ok(c, m);
526         
527     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "IsEmpty")) {
528         DBusMessage *reply;
529         gboolean b;
530         
531         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
532             avahi_log_warn("Error parsing EntryGroup::IsEmpty message");
533             goto fail;
534         }
535
536         b = avahi_entry_group_is_empty(i->entry_group);
537         
538         reply = dbus_message_new_method_return(m);
539         dbus_message_append_args(m, DBUS_TYPE_BOOLEAN, &b, DBUS_TYPE_INVALID);
540         dbus_connection_send(c, reply, NULL);
541         dbus_message_unref(reply);
542         
543         return DBUS_HANDLER_RESULT_HANDLED;
544         
545     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "GetState")) {
546         DBusMessage *reply;
547         gint32 t;
548
549         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
550             avahi_log_warn("Error parsing EntryGroup::GetState message");
551             goto fail;
552         }
553
554         t = (gint32) avahi_entry_group_get_state(i->entry_group);
555         reply = dbus_message_new_method_return(m);
556         dbus_message_append_args(reply, DBUS_TYPE_INT32, &t, DBUS_TYPE_INVALID);
557         dbus_connection_send(c, reply, NULL);
558         dbus_message_unref(reply);
559         
560         return DBUS_HANDLER_RESULT_HANDLED;
561         
562     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddService")) {
563         gint32 interface, protocol;
564         gchar *type, *name, *domain, *host;
565         guint16 port;
566         gchar **txt = NULL;
567         gint txt_len;
568         AvahiStringList *strlst;
569         
570         if (!dbus_message_get_args(
571                 m, &error,
572                 DBUS_TYPE_INT32, &interface,
573                 DBUS_TYPE_INT32, &protocol,
574                 DBUS_TYPE_STRING, &name,
575                 DBUS_TYPE_STRING, &type,
576                 DBUS_TYPE_STRING, &domain,
577                 DBUS_TYPE_STRING, &host,
578                 DBUS_TYPE_UINT16, &port, 
579                 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &txt, &txt_len,
580                 DBUS_TYPE_INVALID) || !type || !*type || !name || !*name || !port) {
581             avahi_log_warn("Error parsing EntryGroup::AddService message");
582             goto fail;
583         }
584
585         if (i->n_entries >= MAX_ENTRIES_PER_ENTRY_GROUP) {
586             avahi_log_warn("Too many entries per entry group, client request failed.");
587             dbus_free_string_array(txt);
588             return respond_error(c, m, AVAHI_DBUS_ERROR_TOO_MANY_ENTRIES, NULL);
589         }
590
591         strlst = avahi_string_list_new_from_array((const gchar**) txt, txt_len);
592         dbus_free_string_array(txt);
593
594         if (domain && !*domain)
595             domain = NULL;
596
597         if (host && !*host)
598             host = NULL;
599
600         if (avahi_server_add_service_strlst(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, type, domain, host, port, strlst) < 0) {
601             avahi_log_warn("Failed to add service: %s", name);
602             avahi_string_list_free(strlst);
603             return respond_error(c, m, AVAHI_DBUS_ERROR_INVALID_SERVICE, NULL);
604         } else
605             i->n_entries ++;
606         
607         avahi_string_list_free(strlst);
608         
609         return respond_ok(c, m);
610         
611     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddAddress")) {
612         gint32 interface, protocol;
613         gchar *name, *address;
614         AvahiAddress a;
615         
616         if (!dbus_message_get_args(
617                 m, &error,
618                 DBUS_TYPE_INT32, &interface,
619                 DBUS_TYPE_INT32, &protocol,
620                 DBUS_TYPE_STRING, &name,
621                 DBUS_TYPE_STRING, &address,
622                 DBUS_TYPE_INVALID) || !name || !*name || !address || !*address) {
623             avahi_log_warn("Error parsing EntryGroup::AddAddress message");
624             goto fail;
625         }
626
627         if (i->n_entries >= MAX_ENTRIES_PER_ENTRY_GROUP) {
628             avahi_log_warn("Too many entries per entry group, client request failed.");
629             return respond_error(c, m, AVAHI_DBUS_ERROR_TOO_MANY_ENTRIES, NULL);
630         }
631         
632         if (!(avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a))) {
633             avahi_log_warn("Error parsing address data");
634             return respond_error(c, m, AVAHI_DBUS_ERROR_INVALID_ADDRESS, NULL);
635         }
636
637         if (avahi_server_add_address(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, 0, name, &a) < 0) {
638             avahi_log_warn("Failed to add service: %s", name);
639             return respond_error(c, m, AVAHI_DBUS_ERROR_INVALID_ADDRESS, NULL);
640         } else
641             i->n_entries ++;
642         
643         return respond_ok(c, m);
644     }
645     
646     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
647
648 fail:
649     if (dbus_error_is_set(&error))
650         dbus_error_free(&error);
651     
652     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
653 }
654
655 static void host_name_resolver_callback(AvahiHostNameResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const gchar *host_name, const AvahiAddress *a, gpointer userdata) {
656     HostNameResolverInfo *i = userdata;
657     DBusMessage *reply;
658     
659     g_assert(r);
660     g_assert(host_name);
661     g_assert(i);
662
663     if (event == AVAHI_RESOLVER_FOUND) {
664         char t[256], *pt = t;
665         gint32 i_interface, i_protocol, i_aprotocol;
666
667         g_assert(a);
668         avahi_address_snprint(t, sizeof(t), a);
669
670         i_interface = (gint32) interface;
671         i_protocol = (gint32) protocol;
672         i_aprotocol = (gint32) a->family;
673         
674         reply = dbus_message_new_method_return(i->message);
675         dbus_message_append_args(
676             reply,
677             DBUS_TYPE_INT32, &i_interface,
678             DBUS_TYPE_INT32, &i_protocol,
679             DBUS_TYPE_STRING, &host_name,
680             DBUS_TYPE_INT32, &i_aprotocol,
681             DBUS_TYPE_STRING, &pt,
682             DBUS_TYPE_INVALID);
683
684     } else {
685         g_assert(event == AVAHI_RESOLVER_TIMEOUT);
686         reply = dbus_message_new_error(i->message, AVAHI_DBUS_ERROR_TIMEOUT, NULL);
687     }
688
689     dbus_connection_send(server->bus, reply, NULL);
690     dbus_message_unref(reply);
691
692     host_name_resolver_free(i);
693 }
694
695 static void address_resolver_callback(AvahiAddressResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const AvahiAddress *address, const gchar *host_name, gpointer userdata) {
696     AddressResolverInfo *i = userdata;
697     DBusMessage *reply;
698     
699     g_assert(r);
700     g_assert(address);
701     g_assert(i);
702
703     if (event == AVAHI_RESOLVER_FOUND) {
704         char t[256], *pt = t;
705         gint32 i_interface, i_protocol, i_aprotocol;
706
707         g_assert(host_name);
708         avahi_address_snprint(t, sizeof(t), address);
709
710         i_interface = (gint32) interface;
711         i_protocol = (gint32) protocol;
712         i_aprotocol = (gint32) address->family;
713         
714         reply = dbus_message_new_method_return(i->message);
715         dbus_message_append_args(
716             reply,
717             DBUS_TYPE_INT32, &i_interface,
718             DBUS_TYPE_INT32, &i_protocol,
719             DBUS_TYPE_INT32, &i_aprotocol,
720             DBUS_TYPE_STRING, &pt,
721             DBUS_TYPE_STRING, &host_name,
722             DBUS_TYPE_INVALID);
723
724     } else {
725         g_assert(event == AVAHI_RESOLVER_TIMEOUT);
726         reply = dbus_message_new_error(i->message, AVAHI_DBUS_ERROR_TIMEOUT, NULL);
727     }
728
729     dbus_connection_send(server->bus, reply, NULL);
730     dbus_message_unref(reply);
731
732     address_resolver_free(i);
733 }
734
735 static DBusHandlerResult msg_domain_browser_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
736     DBusError error;
737     DomainBrowserInfo *i = userdata;
738
739     g_assert(c);
740     g_assert(m);
741     g_assert(i);
742     
743     dbus_error_init(&error);
744
745     avahi_log_debug("dbus: interface=%s, path=%s, member=%s",
746                     dbus_message_get_interface(m),
747                     dbus_message_get_path(m),
748                     dbus_message_get_member(m));
749
750     /* Introspection */
751     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
752         return handle_introspect(c, m, "DomainBrowser.introspect");
753     
754     /* Access control */
755     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
756         return respond_error(c, m, DBUS_ERROR_ACCESS_DENIED, NULL);
757     
758     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "Free")) {
759
760         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
761             avahi_log_warn("Error parsing DomainBrowser::Free message");
762             goto fail;
763         }
764
765         domain_browser_free(i);
766         return respond_ok(c, m);
767         
768     }
769     
770     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
771
772 fail:
773     if (dbus_error_is_set(&error))
774         dbus_error_free(&error);
775     
776     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
777 }
778
779 static void domain_browser_callback(AvahiDomainBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const gchar *domain, gpointer userdata) {
780     DomainBrowserInfo *i = userdata;
781     DBusMessage *m;
782     gint32 i_interface, i_protocol;
783     
784     g_assert(b);
785     g_assert(domain);
786     g_assert(i);
787
788     i_interface = (gint32) interface;
789     i_protocol = (gint32) protocol;
790
791     m = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, event == AVAHI_BROWSER_NEW ? "ItemNew" : "ItemRemove");
792     dbus_message_append_args(
793         m,
794         DBUS_TYPE_INT32, &i_interface,
795         DBUS_TYPE_INT32, &i_protocol,
796         DBUS_TYPE_STRING, &domain,
797         DBUS_TYPE_INVALID);
798     dbus_message_set_destination(m, i->client->name);   
799     dbus_connection_send(server->bus, m, NULL);
800     dbus_message_unref(m);
801 }
802
803 static DBusHandlerResult msg_service_type_browser_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
804     DBusError error;
805     ServiceTypeBrowserInfo *i = userdata;
806
807     g_assert(c);
808     g_assert(m);
809     g_assert(i);
810     
811     dbus_error_init(&error);
812
813     avahi_log_debug("dbus: interface=%s, path=%s, member=%s",
814                     dbus_message_get_interface(m),
815                     dbus_message_get_path(m),
816                     dbus_message_get_member(m));
817
818     /* Introspection */
819     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
820         return handle_introspect(c, m, "ServiceTypeBrowser.introspect");
821     
822     /* Access control */
823     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
824         return respond_error(c, m, DBUS_ERROR_ACCESS_DENIED, NULL);
825     
826     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "Free")) {
827
828         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
829             avahi_log_warn("Error parsing ServiceTypeBrowser::Free message");
830             goto fail;
831         }
832
833         service_type_browser_free(i);
834         return respond_ok(c, m);
835         
836     }
837     
838     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
839
840 fail:
841     if (dbus_error_is_set(&error))
842         dbus_error_free(&error);
843     
844     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
845 }
846
847 static void service_type_browser_callback(AvahiServiceTypeBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const gchar *type, const gchar *domain, gpointer userdata) {
848     ServiceTypeBrowserInfo *i = userdata;
849     DBusMessage *m;
850     gint32 i_interface, i_protocol;
851     
852     g_assert(b);
853     g_assert(type);
854     g_assert(domain);
855     g_assert(i);
856
857     i_interface = (gint32) interface;
858     i_protocol = (gint32) protocol;
859
860     m = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, event == AVAHI_BROWSER_NEW ? "ItemNew" : "ItemRemove");
861     dbus_message_append_args(
862         m,
863         DBUS_TYPE_INT32, &i_interface,
864         DBUS_TYPE_INT32, &i_protocol,
865         DBUS_TYPE_STRING, &type,
866         DBUS_TYPE_STRING, &domain,
867         DBUS_TYPE_INVALID);
868     dbus_message_set_destination(m, i->client->name);   
869     dbus_connection_send(server->bus, m, NULL);
870     dbus_message_unref(m);
871 }
872
873 static DBusHandlerResult msg_service_browser_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
874     DBusError error;
875     ServiceBrowserInfo *i = userdata;
876
877     g_assert(c);
878     g_assert(m);
879     g_assert(i);
880     
881     dbus_error_init(&error);
882
883     avahi_log_debug("dbus: interface=%s, path=%s, member=%s",
884                     dbus_message_get_interface(m),
885                     dbus_message_get_path(m),
886                     dbus_message_get_member(m));
887
888     /* Introspection */
889     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
890         return handle_introspect(c, m, "ServiceBrowser.introspect");
891     
892     /* Access control */
893     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
894         return respond_error(c, m, DBUS_ERROR_ACCESS_DENIED, NULL);
895     
896     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "Free")) {
897
898         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
899             avahi_log_warn("Error parsing ServiceBrowser::Free message");
900             goto fail;
901         }
902
903         service_browser_free(i);
904         return respond_ok(c, m);
905         
906     }
907     
908     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
909
910 fail:
911     if (dbus_error_is_set(&error))
912         dbus_error_free(&error);
913     
914     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
915 }
916
917 static void service_browser_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const gchar *name, const gchar *type, const gchar *domain, gpointer userdata) {
918     ServiceBrowserInfo *i = userdata;
919     DBusMessage *m;
920     gint32 i_interface, i_protocol;
921     
922     g_assert(b);
923     g_assert(name);
924     g_assert(type);
925     g_assert(domain);
926     g_assert(i);
927
928     i_interface = (gint32) interface;
929     i_protocol = (gint32) protocol;
930
931     m = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, event == AVAHI_BROWSER_NEW ? "ItemNew" : "ItemRemove");
932     dbus_message_append_args(
933         m,
934         DBUS_TYPE_INT32, &i_interface,
935         DBUS_TYPE_INT32, &i_protocol,
936         DBUS_TYPE_STRING, &name,
937         DBUS_TYPE_STRING, &type,
938         DBUS_TYPE_STRING, &domain,
939         DBUS_TYPE_INVALID);
940     dbus_message_set_destination(m, i->client->name);   
941     dbus_connection_send(server->bus, m, NULL);
942     dbus_message_unref(m);
943 }
944
945 static void service_resolver_callback(
946     AvahiServiceResolver *r,
947     AvahiIfIndex interface,
948     AvahiProtocol protocol,
949     AvahiResolverEvent event,
950     const gchar *name,
951     const gchar *type,
952     const gchar *domain,
953     const gchar *host_name,
954     const AvahiAddress *a,
955     guint16 port,
956     AvahiStringList *txt,
957     gpointer userdata) {
958     
959     ServiceResolverInfo *i = userdata;
960     DBusMessage *reply;
961     
962     g_assert(r);
963     g_assert(i);
964
965     if (event == AVAHI_RESOLVER_FOUND) {
966         char t[256], *pt = t;
967         gint32 i_interface, i_protocol, i_aprotocol;
968         gchar **array;
969         guint n, j;
970         AvahiStringList *p;
971
972         g_assert(host_name);
973         
974         g_assert(a);
975         avahi_address_snprint(t, sizeof(t), a);
976
977         i_interface = (gint32) interface;
978         i_protocol = (gint32) protocol;
979         i_aprotocol = (gint32) a->family;
980
981         array = g_new(gchar*, (n = avahi_string_list_length(txt)));
982
983         /** FIXME: DBUS doesn't support strings that include NUL bytes (?) */
984         for (p = txt, j = n-1; p; p = p->next, j--)
985             array[j] = g_strndup((gchar*) p->text, p->size);
986         
987         reply = dbus_message_new_method_return(i->message);
988         dbus_message_append_args(
989             reply,
990             DBUS_TYPE_INT32, &i_interface,
991             DBUS_TYPE_INT32, &i_protocol,
992             DBUS_TYPE_STRING, &name,
993             DBUS_TYPE_STRING, &type,
994             DBUS_TYPE_STRING, &domain,
995             DBUS_TYPE_STRING, &host_name,
996             DBUS_TYPE_INT32, &i_aprotocol,
997             DBUS_TYPE_STRING, &pt,
998             DBUS_TYPE_UINT16, &port,
999             DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &array, n,
1000             DBUS_TYPE_INVALID);
1001
1002         for (j = 0; j < n; j++)
1003             g_free(array[j]);
1004
1005     } else {
1006         g_assert(event == AVAHI_RESOLVER_TIMEOUT);
1007         reply = dbus_message_new_error(i->message, AVAHI_DBUS_ERROR_TIMEOUT, NULL);
1008     }
1009
1010     dbus_connection_send(server->bus, reply, NULL);
1011     dbus_message_unref(reply);
1012
1013     service_resolver_free(i);
1014 }
1015
1016
1017 static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
1018     DBusError error;
1019
1020     dbus_error_init(&error);
1021
1022     avahi_log_debug("dbus: interface=%s, path=%s, member=%s",
1023                     dbus_message_get_interface(m),
1024                     dbus_message_get_path(m),
1025                     dbus_message_get_member(m));
1026
1027     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
1028         return handle_introspect(c, m, "Server.introspect");
1029         
1030     else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostName")) {
1031
1032         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
1033             avahi_log_warn("Error parsing Server::GetHostName message");
1034             goto fail;
1035         }
1036
1037         return respond_string(c, m, avahi_server_get_host_name(avahi_server));
1038         
1039     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetDomainName")) {
1040
1041         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
1042             avahi_log_warn("Error parsing Server::GetDomainName message");
1043             goto fail;
1044         }
1045
1046         return respond_string(c, m, avahi_server_get_domain_name(avahi_server));
1047
1048     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostNameFqdn")) {
1049
1050         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
1051             avahi_log_warn("Error parsing Server::GetHostNameFqdn message");
1052             goto fail;
1053         }
1054     
1055         return respond_string(c, m, avahi_server_get_host_name_fqdn(avahi_server));
1056         
1057     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetVersionString")) {
1058
1059         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
1060             avahi_log_warn("Error parsing Server::GetVersionString message");
1061             goto fail;
1062         }
1063     
1064         return respond_string(c, m, PACKAGE_STRING);
1065
1066     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetState")) {
1067         DBusMessage *reply;
1068         gint32 s;
1069             
1070         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
1071             avahi_log_warn("Error parsing Server::GetState message");
1072             goto fail;
1073         }
1074
1075         s = (gint32) avahi_server_get_state(avahi_server);
1076         
1077         reply = dbus_message_new_method_return(m);
1078         dbus_message_append_args(reply, DBUS_TYPE_INT32, &s, DBUS_TYPE_INVALID);
1079         dbus_connection_send(c, reply, NULL);
1080         dbus_message_unref(reply);
1081         
1082         return DBUS_HANDLER_RESULT_HANDLED;
1083
1084     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetAlternativeHostName")) {
1085         gchar *n, * t;
1086         
1087         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n || !*n) {
1088             avahi_log_warn("Error parsing Server::GetAlternativeHostName message");
1089             goto fail;
1090         }
1091
1092         t = avahi_alternative_host_name(n);
1093         respond_string(c, m, t);
1094         g_free(t);
1095
1096         return DBUS_HANDLER_RESULT_HANDLED;
1097
1098     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetAlternativeServiceName")) {
1099         gchar *n, *t;
1100         
1101         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n || !*n) {
1102             avahi_log_warn("Error parsing Server::GetAlternativeServiceName message");
1103             goto fail;
1104         }
1105
1106         t = avahi_alternative_service_name(n);
1107         respond_string(c, m, t);
1108         g_free(t);
1109
1110         return DBUS_HANDLER_RESULT_HANDLED;
1111         
1112     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "EntryGroupNew")) {
1113         Client *client;
1114         EntryGroupInfo *i;
1115         static const DBusObjectPathVTable vtable = {
1116             NULL,
1117             msg_entry_group_impl,
1118             NULL,
1119             NULL,
1120             NULL,
1121             NULL
1122         };
1123
1124         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
1125             avahi_log_warn("Error parsing Server::EntryGroupNew message");
1126             goto fail;
1127         }
1128
1129         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1130             avahi_log_warn("Too many clients, client request failed.");
1131             return respond_error(c, m, AVAHI_DBUS_ERROR_TOO_MANY_CLIENTS, NULL);
1132         }
1133
1134         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1135             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1136             return respond_error(c, m, AVAHI_DBUS_ERROR_TOO_MANY_OBJECTS, NULL);
1137         }
1138
1139         i = g_new(EntryGroupInfo, 1);
1140         i->id = ++client->current_id;
1141         i->client = client;
1142         i->path = g_strdup_printf("/Client%u/EntryGroup%u", client->id, i->id);
1143         i->n_entries = 0;
1144         AVAHI_LLIST_PREPEND(EntryGroupInfo, entry_groups, client->entry_groups, i);
1145         client->n_objects++;
1146         
1147         if (!(i->entry_group = avahi_entry_group_new(avahi_server, entry_group_callback, i))) {
1148             avahi_log_warn("Failed to create entry group");
1149             entry_group_free(i);
1150             goto fail;
1151         }
1152
1153         dbus_connection_register_object_path(c, i->path, &vtable, i);
1154         return respond_path(c, m, i->path);
1155         
1156     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveHostName")) {
1157         Client *client;
1158         gint32 interface, protocol, aprotocol;
1159         gchar *name;
1160         HostNameResolverInfo *i;
1161             
1162         if (!dbus_message_get_args(
1163                 m, &error,
1164                 DBUS_TYPE_INT32, &interface,
1165                 DBUS_TYPE_INT32, &protocol,
1166                 DBUS_TYPE_STRING, &name,
1167                 DBUS_TYPE_INT32, &aprotocol,
1168                 DBUS_TYPE_INVALID) || !name || !*name) {
1169             avahi_log_warn("Error parsing Server::ResolveHostName message");
1170             goto fail;
1171         }
1172
1173         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1174             avahi_log_warn("Too many clients, client request failed.");
1175             return respond_error(c, m, AVAHI_DBUS_ERROR_TOO_MANY_CLIENTS, NULL);
1176         }
1177
1178         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1179             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1180             return respond_error(c, m, AVAHI_DBUS_ERROR_TOO_MANY_OBJECTS, NULL);
1181         }
1182
1183         i = g_new(HostNameResolverInfo, 1);
1184         i->client = client;
1185         i->message = dbus_message_ref(m);
1186         AVAHI_LLIST_PREPEND(HostNameResolverInfo, host_name_resolvers, client->host_name_resolvers, i);
1187         client->n_objects++;
1188
1189         if (!(i->host_name_resolver = avahi_host_name_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, (AvahiProtocol) aprotocol, host_name_resolver_callback, i))) {
1190             host_name_resolver_free(i);
1191             avahi_log_warn("Failed to create host name resolver");
1192             goto fail;
1193         }
1194         
1195         return DBUS_HANDLER_RESULT_HANDLED;
1196         
1197     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveAddress")) {
1198         Client *client;
1199         gint32 interface, protocol;
1200         gchar *address;
1201         AddressResolverInfo *i;
1202         AvahiAddress a;
1203             
1204         if (!dbus_message_get_args(
1205                 m, &error,
1206                 DBUS_TYPE_INT32, &interface,
1207                 DBUS_TYPE_INT32, &protocol,
1208                 DBUS_TYPE_STRING, &address,
1209                 DBUS_TYPE_INVALID) || !address || !*address) {
1210             avahi_log_warn("Error parsing Server::ResolveAddress message");
1211             goto fail;
1212         }
1213
1214         if (!avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a)) {
1215             avahi_log_warn("Error parsing address data");
1216             return respond_error(c, m, AVAHI_DBUS_ERROR_INVALID_ADDRESS, NULL);
1217         }
1218
1219         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1220             avahi_log_warn("Too many clients, client request failed.");
1221             return respond_error(c, m, AVAHI_DBUS_ERROR_TOO_MANY_CLIENTS, NULL);
1222         }
1223
1224         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1225             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1226             return respond_error(c, m, AVAHI_DBUS_ERROR_TOO_MANY_OBJECTS, NULL);
1227         }
1228
1229         i = g_new(AddressResolverInfo, 1);
1230         i->client = client;
1231         i->message = dbus_message_ref(m);
1232         AVAHI_LLIST_PREPEND(AddressResolverInfo, address_resolvers, client->address_resolvers, i);
1233         client->n_objects++;
1234
1235         if (!(i->address_resolver = avahi_address_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, &a, address_resolver_callback, i))) {
1236             address_resolver_free(i);
1237             avahi_log_warn("Failed to create address resolver");
1238             goto fail;
1239         }
1240         
1241         return DBUS_HANDLER_RESULT_HANDLED;
1242         
1243     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "DomainBrowserNew")) {
1244         Client *client;
1245         DomainBrowserInfo *i;
1246         static const DBusObjectPathVTable vtable = {
1247             NULL,
1248             msg_domain_browser_impl,
1249             NULL,
1250             NULL,
1251             NULL,
1252             NULL
1253         };
1254         gint32 interface, protocol, type;
1255         gchar *domain;
1256         
1257
1258         if (!dbus_message_get_args(
1259                 m, &error,
1260                 DBUS_TYPE_INT32, &interface,
1261                 DBUS_TYPE_INT32, &protocol,
1262                 DBUS_TYPE_STRING, &domain,
1263                 DBUS_TYPE_INT32, &type,
1264                 DBUS_TYPE_INVALID) || type < 0 || type >= AVAHI_DOMAIN_BROWSER_MAX) {
1265             avahi_log_warn("Error parsing Server::DomainBrowserNew message");
1266             goto fail;
1267         }
1268
1269         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1270             avahi_log_warn("Too many clients, client request failed.");
1271             return respond_error(c, m, AVAHI_DBUS_ERROR_TOO_MANY_CLIENTS, NULL);
1272         }
1273
1274         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1275             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1276             return respond_error(c, m, AVAHI_DBUS_ERROR_TOO_MANY_OBJECTS, NULL);
1277         }
1278
1279         if (!*domain)
1280             domain = NULL;
1281
1282         i = g_new(DomainBrowserInfo, 1);
1283         i->id = ++client->current_id;
1284         i->client = client;
1285         i->path = g_strdup_printf("/Client%u/DomainBrowser%u", client->id, i->id);
1286         AVAHI_LLIST_PREPEND(DomainBrowserInfo, domain_browsers, client->domain_browsers, i);
1287         client->n_objects++;
1288
1289         if (!(i->domain_browser = avahi_domain_browser_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, domain, (AvahiDomainBrowserType) type, domain_browser_callback, i))) {
1290             avahi_log_warn("Failed to create domain browser");
1291             domain_browser_free(i);
1292             goto fail;
1293         }
1294         
1295         dbus_connection_register_object_path(c, i->path, &vtable, i);
1296         return respond_path(c, m, i->path);
1297
1298     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ServiceTypeBrowserNew")) {
1299         Client *client;
1300         ServiceTypeBrowserInfo *i;
1301         static const DBusObjectPathVTable vtable = {
1302             NULL,
1303             msg_service_type_browser_impl,
1304             NULL,
1305             NULL,
1306             NULL,
1307             NULL
1308         };
1309         gint32 interface, protocol;
1310         gchar *domain;
1311         
1312         if (!dbus_message_get_args(
1313                 m, &error,
1314                 DBUS_TYPE_INT32, &interface,
1315                 DBUS_TYPE_INT32, &protocol,
1316                 DBUS_TYPE_STRING, &domain,
1317                 DBUS_TYPE_INVALID)) {
1318             avahi_log_warn("Error parsing Server::ServiceTypeBrowserNew message");
1319             goto fail;
1320         }
1321
1322         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1323             avahi_log_warn("Too many clients, client request failed.");
1324             return respond_error(c, m, AVAHI_DBUS_ERROR_TOO_MANY_CLIENTS, NULL);
1325         }
1326
1327
1328         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1329             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1330             return respond_error(c, m, AVAHI_DBUS_ERROR_TOO_MANY_OBJECTS, NULL);
1331         }
1332
1333         if (!*domain)
1334             domain = NULL;
1335
1336         i = g_new(ServiceTypeBrowserInfo, 1);
1337         i->id = ++client->current_id;
1338         i->client = client;
1339         i->path = g_strdup_printf("/Client%u/ServiceTypeBrowser%u", client->id, i->id);
1340         AVAHI_LLIST_PREPEND(ServiceTypeBrowserInfo, service_type_browsers, client->service_type_browsers, i);
1341         client->n_objects++;
1342
1343         if (!(i->service_type_browser = avahi_service_type_browser_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, domain, service_type_browser_callback, i))) {
1344             avahi_log_warn("Failed to create service type browser");
1345             service_type_browser_free(i);
1346             goto fail;
1347         }
1348         
1349         dbus_connection_register_object_path(c, i->path, &vtable, i);
1350         return respond_path(c, m, i->path);
1351         
1352      } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ServiceBrowserNew")) {
1353         Client *client;
1354         ServiceBrowserInfo *i;
1355         static const DBusObjectPathVTable vtable = {
1356             NULL,
1357             msg_service_browser_impl,
1358             NULL,
1359             NULL,
1360             NULL,
1361             NULL
1362         };
1363         gint32 interface, protocol;
1364         gchar *domain, *type;
1365         
1366         if (!dbus_message_get_args(
1367                 m, &error,
1368                 DBUS_TYPE_INT32, &interface,
1369                 DBUS_TYPE_INT32, &protocol,
1370                 DBUS_TYPE_STRING, &type,
1371                 DBUS_TYPE_STRING, &domain,
1372                 DBUS_TYPE_INVALID) || !type || !*type) {
1373             avahi_log_warn("Error parsing Server::ServiceBrowserNew message");
1374             goto fail;
1375         }
1376
1377         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1378             avahi_log_warn("Too many clients, client request failed.");
1379             return respond_error(c, m, AVAHI_DBUS_ERROR_TOO_MANY_CLIENTS, NULL);
1380         }
1381
1382
1383         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1384             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1385             return respond_error(c, m, AVAHI_DBUS_ERROR_TOO_MANY_OBJECTS, NULL);
1386         }
1387
1388         if (!*domain)
1389             domain = NULL;
1390
1391         i = g_new(ServiceBrowserInfo, 1);
1392         i->id = ++client->current_id;
1393         i->client = client;
1394         i->path = g_strdup_printf("/Client%u/ServiceBrowser%u", client->id, i->id);
1395         AVAHI_LLIST_PREPEND(ServiceBrowserInfo, service_browsers, client->service_browsers, i);
1396         client->n_objects++;
1397
1398         if (!(i->service_browser = avahi_service_browser_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, type, domain, service_browser_callback, i))) {
1399             avahi_log_warn("Failed to create service browser");
1400             service_browser_free(i);
1401             goto fail;
1402         }
1403         
1404         dbus_connection_register_object_path(c, i->path, &vtable, i);
1405         return respond_path(c, m, i->path);
1406         
1407     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveService")) {
1408         Client *client;
1409         gint32 interface, protocol, aprotocol;
1410         gchar *name, *type, *domain;
1411         ServiceResolverInfo *i;
1412             
1413         if (!dbus_message_get_args(
1414                 m, &error,
1415                 DBUS_TYPE_INT32, &interface,
1416                 DBUS_TYPE_INT32, &protocol,
1417                 DBUS_TYPE_STRING, &name,
1418                 DBUS_TYPE_STRING, &type,
1419                 DBUS_TYPE_STRING, &domain,
1420                 DBUS_TYPE_INT32, &aprotocol,
1421                 DBUS_TYPE_INVALID) || !name || !*name || !type || !*type) {
1422             avahi_log_warn("Error parsing Server::ResolveService message");
1423             goto fail;
1424         }
1425
1426         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
1427             avahi_log_warn("Too many clients, client request failed.");
1428             return respond_error(c, m, AVAHI_DBUS_ERROR_TOO_MANY_CLIENTS, NULL);
1429         }
1430         
1431         if (client->n_objects >= MAX_OBJECTS_PER_CLIENT) {
1432             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
1433             return respond_error(c, m, AVAHI_DBUS_ERROR_TOO_MANY_OBJECTS, NULL);
1434         }
1435
1436         if (!*domain)
1437             domain = NULL;
1438         
1439         i = g_new(ServiceResolverInfo, 1);
1440         i->client = client;
1441         i->message = dbus_message_ref(m);
1442         AVAHI_LLIST_PREPEND(ServiceResolverInfo, service_resolvers, client->service_resolvers, i);
1443         client->n_objects++;
1444
1445         if (!(i->service_resolver = avahi_service_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, type, domain, (AvahiProtocol) aprotocol, service_resolver_callback, i))) {
1446             service_resolver_free(i);
1447             avahi_log_warn("Failed to create service resolver");
1448             goto fail;
1449         }
1450         
1451         return DBUS_HANDLER_RESULT_HANDLED;
1452      }
1453
1454     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
1455
1456 fail:
1457     if (dbus_error_is_set(&error))
1458         dbus_error_free(&error);
1459     
1460     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1461 }
1462
1463 void dbus_protocol_server_state_changed(AvahiServerState state) {
1464     DBusMessage *m;
1465     gint32 t;
1466     
1467     if (!server)
1468         return;
1469
1470     m = dbus_message_new_signal(AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "StateChanged");
1471     t = (gint32) state;
1472     dbus_message_append_args(m, DBUS_TYPE_INT32, &t, DBUS_TYPE_INVALID);
1473     dbus_connection_send(server->bus, m, NULL);
1474     dbus_message_unref(m);
1475 }
1476
1477 int dbus_protocol_setup(GMainLoop *loop) {
1478     DBusError error;
1479
1480     static const DBusObjectPathVTable server_vtable = {
1481         NULL,
1482         msg_server_impl,
1483         NULL,
1484         NULL,
1485         NULL,
1486         NULL
1487     };
1488
1489     dbus_error_init(&error);
1490
1491     server = g_malloc(sizeof(Server));
1492     server->clients = NULL;
1493     server->current_id = 0;
1494     server->n_clients = 0;
1495
1496     server->bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
1497     if (dbus_error_is_set(&error)) {
1498         avahi_log_warn("dbus_bus_get(): %s", error.message);
1499         goto fail;
1500     }
1501
1502     dbus_connection_setup_with_g_main(server->bus, NULL);
1503     dbus_connection_set_exit_on_disconnect(server->bus, FALSE);
1504
1505     dbus_bus_request_name(server->bus, AVAHI_DBUS_NAME, 0, &error);
1506     if (dbus_error_is_set(&error)) {
1507         avahi_log_warn("dbus_bus_request_name(): %s", error.message);
1508         goto fail;
1509     }
1510
1511     dbus_bus_add_match(server->bus, "type='signal',""interface='" DBUS_INTERFACE_DBUS  "'", &error);
1512
1513     dbus_connection_add_filter(server->bus, msg_signal_filter_impl, loop, NULL);
1514     dbus_connection_register_object_path(server->bus, AVAHI_DBUS_PATH_SERVER, &server_vtable, NULL);
1515
1516     return 0;
1517
1518 fail:
1519     if (server->bus) {
1520         dbus_connection_disconnect(server->bus);
1521         dbus_connection_unref(server->bus);
1522     }
1523     
1524     dbus_error_free (&error);
1525     g_free(server);
1526     server = NULL;
1527     return -1;
1528 }
1529
1530 void dbus_protocol_shutdown(void) {
1531
1532     if (server) {
1533     
1534         while (server->clients)
1535             client_free(server->clients);
1536
1537         g_assert(server->n_clients == 0);
1538
1539         if (server->bus) {
1540             dbus_connection_disconnect(server->bus);
1541             dbus_connection_unref(server->bus);
1542         }
1543
1544         g_free(server);
1545         server = NULL;
1546     }
1547 }