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