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