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