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