]> git.meshlink.io Git - catta/blob - avahi-daemon/dbus-protocol.c
* DBUS: implement org.freedesktop.Avahi.GetVersionString()
[catta] / avahi-daemon / dbus-protocol.c
1 /* $Id$ */
2
3 /***
4   This file is part of avahi.
5  
6   avahi is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10  
11   avahi is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14   Public License for more details.
15  
16   You should have received a copy of the GNU Lesser General Public
17   License along with avahi; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <glib.h>
27 #include <string.h>
28
29 #define DBUS_API_SUBJECT_TO_CHANGE
30 #include <dbus/dbus.h>
31 #include <dbus/dbus-glib-lowlevel.h>
32
33 #include <avahi-core/llist.h>
34 #include <avahi-core/log.h>
35 #include <avahi-core/core.h>
36
37 #include "dbus-protocol.h"
38 #include "main.h"
39
40 #define AVAHI_DBUS_NAME "org.freedesktop.Avahi"
41 #define AVAHI_DBUS_INTERFACE_SERVER AVAHI_DBUS_NAME".Server"
42 #define AVAHI_DBUS_PATH_SERVER "/org/freedesktop/Avahi/Server"
43 #define AVAHI_DBUS_INTERFACE_ENTRY_GROUP AVAHI_DBUS_NAME".EntryGroup"
44 #define AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER AVAHI_DBUS_NAME".DomainBrowser"
45 #define AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER AVAHI_DBUS_NAME".ServiceTypeBrowser"
46 #define AVAHI_DBUS_INTERFACE_SERVICE_BROWSER AVAHI_DBUS_NAME".ServiceBrowser"
47
48 /* Needs wrapping:
49    - AvahiServiceResolver
50    - AvahiDomainBrowser
51    - AvahiServiceTypeBrowser
52    - AvahiServiceBrowser */
53
54 typedef struct Server Server;
55 typedef struct Client Client;
56 typedef struct EntryGroupInfo EntryGroupInfo;
57 typedef struct HostNameResolverInfo HostNameResolverInfo;
58 typedef struct AddressResolverInfo AddressResolverInfo;
59 typedef struct DomainBrowserInfo DomainBrowserInfo;
60 typedef struct ServiceTypeBrowserInfo ServiceTypeBrowserInfo;
61 typedef struct ServiceBrowserInfo ServiceBrowserInfo;
62 typedef struct ServiceResolverInfo ServiceResolverInfo;
63
64 struct EntryGroupInfo {
65     guint id;
66     Client *client;
67     AvahiEntryGroup *entry_group;
68     gchar *path;
69     
70     AVAHI_LLIST_FIELDS(EntryGroupInfo, entry_groups);
71 };
72
73 struct HostNameResolverInfo {
74     Client *client;
75     AvahiHostNameResolver *host_name_resolver;
76     DBusMessage *message;
77
78     AVAHI_LLIST_FIELDS(HostNameResolverInfo, host_name_resolvers);
79 };
80
81 struct AddressResolverInfo {
82     Client *client;
83     AvahiAddressResolver *address_resolver;
84     DBusMessage *message;
85
86     AVAHI_LLIST_FIELDS(AddressResolverInfo, address_resolvers);
87 };
88
89 struct DomainBrowserInfo {
90     guint id;
91     Client *client;
92     AvahiDomainBrowser *domain_browser;
93     gchar *path;
94
95     AVAHI_LLIST_FIELDS(DomainBrowserInfo, domain_browsers);
96 };
97
98 struct ServiceTypeBrowserInfo {
99     guint id;
100     Client *client;
101     AvahiServiceTypeBrowser *service_type_browser;
102     gchar *path;
103
104     AVAHI_LLIST_FIELDS(ServiceTypeBrowserInfo, service_type_browsers);
105 };
106
107 struct ServiceBrowserInfo {
108     guint id;
109     Client *client;
110     AvahiServiceBrowser *service_browser;
111     gchar *path;
112
113     AVAHI_LLIST_FIELDS(ServiceBrowserInfo, service_browsers);
114 };
115
116 struct ServiceResolverInfo {
117     Client *client;
118     AvahiServiceResolver *service_resolver;
119     DBusMessage *message;
120
121     AVAHI_LLIST_FIELDS(ServiceResolverInfo, service_resolvers);
122 };
123
124 struct Client {
125     guint id;
126     gchar *name;
127     guint current_id;
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     guint current_id;
143 };
144
145 static Server *server = NULL;
146
147 static void entry_group_free(EntryGroupInfo *i) {
148     g_assert(i);
149
150     if (i->entry_group)
151         avahi_entry_group_free(i->entry_group);
152     dbus_connection_unregister_object_path(server->bus, i->path);
153     g_free(i->path);
154     AVAHI_LLIST_REMOVE(EntryGroupInfo, entry_groups, i->client->entry_groups, i);
155     g_free(i);
156  }
157
158 static void host_name_resolver_free(HostNameResolverInfo *i) {
159     g_assert(i);
160
161     if (i->host_name_resolver)
162         avahi_host_name_resolver_free(i->host_name_resolver);
163     dbus_message_unref(i->message);
164     AVAHI_LLIST_REMOVE(HostNameResolverInfo, host_name_resolvers, i->client->host_name_resolvers, i);
165     g_free(i);
166 }
167
168 static void address_resolver_free(AddressResolverInfo *i) {
169     g_assert(i);
170
171     if (i->address_resolver)
172         avahi_address_resolver_free(i->address_resolver);
173     dbus_message_unref(i->message);
174     AVAHI_LLIST_REMOVE(AddressResolverInfo, address_resolvers, i->client->address_resolvers, i);
175     g_free(i);
176 }
177
178 static void domain_browser_free(DomainBrowserInfo *i) {
179     g_assert(i);
180
181     if (i->domain_browser)
182         avahi_domain_browser_free(i->domain_browser);
183     dbus_connection_unregister_object_path(server->bus, i->path);
184     g_free(i->path);
185     AVAHI_LLIST_REMOVE(DomainBrowserInfo, domain_browsers, i->client->domain_browsers, i);
186     g_free(i);
187 }
188
189 static void service_type_browser_free(ServiceTypeBrowserInfo *i) {
190     g_assert(i);
191
192     if (i->service_type_browser)
193         avahi_service_type_browser_free(i->service_type_browser);
194     dbus_connection_unregister_object_path(server->bus, i->path);
195     g_free(i->path);
196     AVAHI_LLIST_REMOVE(ServiceTypeBrowserInfo, service_type_browsers, i->client->service_type_browsers, i);
197     g_free(i);
198 }
199
200 static void service_browser_free(ServiceBrowserInfo *i) {
201     g_assert(i);
202
203     if (i->service_browser)
204         avahi_service_browser_free(i->service_browser);
205     dbus_connection_unregister_object_path(server->bus, i->path);
206     g_free(i->path);
207     AVAHI_LLIST_REMOVE(ServiceBrowserInfo, service_browsers, i->client->service_browsers, i);
208     g_free(i);
209 }
210
211 static void service_resolver_free(ServiceResolverInfo *i) {
212     g_assert(i);
213
214     if (i->service_resolver)
215         avahi_service_resolver_free(i->service_resolver);
216     dbus_message_unref(i->message);
217     AVAHI_LLIST_REMOVE(ServiceResolverInfo, service_resolvers, i->client->service_resolvers, i);
218     g_free(i);
219 }
220
221 static void client_free(Client *c) {
222     
223     g_assert(server);
224     g_assert(c);
225
226     while (c->entry_groups)
227         entry_group_free(c->entry_groups);
228
229     while (c->host_name_resolvers)
230         host_name_resolver_free(c->host_name_resolvers);
231
232     while (c->address_resolvers)
233         address_resolver_free(c->address_resolvers);
234
235     while (c->domain_browsers)
236         domain_browser_free(c->domain_browsers);
237
238     while (c->service_type_browsers)
239         service_type_browser_free(c->service_type_browsers);
240
241     while (c->service_browsers)
242         service_browser_free(c->service_browsers);
243
244     while (c->service_resolvers)
245         service_resolver_free(c->service_resolvers);
246
247     g_free(c->name);
248     AVAHI_LLIST_REMOVE(Client, clients, server->clients, c);
249     g_free(c);
250 }
251
252 static Client *client_get(const gchar *name, gboolean create) {
253     Client *client;
254
255     g_assert(server);
256     g_assert(name);
257
258     for (client = server->clients; client; client = client->clients_next)
259         if (!strcmp(name, client->name))
260             return client;
261
262     if (!create)
263         return NULL;
264
265     /* If not existant yet, create a new entry */
266     client = g_new(Client, 1);
267     client->id = server->current_id++;
268     client->name = g_strdup(name);
269     client->current_id = 0;
270     AVAHI_LLIST_HEAD_INIT(EntryGroupInfo, client->entry_groups);
271     AVAHI_LLIST_HEAD_INIT(HostNameResolverInfo, client->host_name_resolvers);
272     AVAHI_LLIST_HEAD_INIT(AddressResolverInfo, client->address_resolvers);
273     AVAHI_LLIST_HEAD_INIT(DomainBrowserInfo, client->domain_browsers);
274     AVAHI_LLIST_HEAD_INIT(ServiceTypeBrowserInfo, client->service_type_browsers);
275     AVAHI_LLIST_HEAD_INIT(ServiceBrowserInfo, client->service_browsers);
276     AVAHI_LLIST_HEAD_INIT(ServiceResolverInfo, client->service_resolvers);
277
278     AVAHI_LLIST_PREPEND(Client, clients, server->clients, client);
279     return client;
280 }
281
282 static DBusHandlerResult respond_error(DBusConnection *c, DBusMessage *m, const gchar *error, const gchar *text) {
283     DBusMessage *reply;
284
285     reply = dbus_message_new_error(m, error, text);
286     dbus_connection_send(c, reply, NULL);
287     dbus_message_unref(reply);
288     
289     return DBUS_HANDLER_RESULT_HANDLED;
290 }
291
292 static DBusHandlerResult respond_string(DBusConnection *c, DBusMessage *m, const gchar *text) {
293     DBusMessage *reply;
294
295     reply = dbus_message_new_method_return(m);
296     dbus_message_append_args(reply, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID);
297     dbus_connection_send(c, reply, NULL);
298     dbus_message_unref(reply);
299     
300     return DBUS_HANDLER_RESULT_HANDLED;
301 }
302
303 static DBusHandlerResult respond_ok(DBusConnection *c, DBusMessage *m) {
304     DBusMessage *reply;
305
306     reply = dbus_message_new_method_return(m);
307     dbus_connection_send(c, reply, NULL);
308     dbus_message_unref(reply);
309     
310     return DBUS_HANDLER_RESULT_HANDLED;
311 }
312
313 static DBusHandlerResult msg_signal_filter_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
314     GMainLoop *loop = userdata;
315     DBusError error;
316
317     dbus_error_init(&error);
318
319 /*     avahi_log_debug("dbus: interface=%s, path=%s, member=%s", */
320 /*                     dbus_message_get_interface(m), */
321 /*                     dbus_message_get_path(m), */
322 /*                     dbus_message_get_member(m)); */
323
324     if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) {
325         /* No, we shouldn't quit, but until we get somewhere
326          * usefull such that we can restore our state, we will */
327         avahi_log_warn("Disconnnected from d-bus, terminating...");
328         g_main_loop_quit (loop);
329         return DBUS_HANDLER_RESULT_HANDLED;
330         
331     } else if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameAcquired")) {
332         gchar *name;
333
334         if (!dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) {
335             avahi_log_warn("Error parsing NameAcquired message");
336             goto fail;
337         }
338
339 /*         avahi_log_info("dbus: name acquired (%s)", name); */
340         return DBUS_HANDLER_RESULT_HANDLED;
341         
342     } else if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
343         gchar *name, *old, *new;
344
345         if (!dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old, DBUS_TYPE_STRING, &new, DBUS_TYPE_INVALID)) {
346             avahi_log_warn("Error parsing NameOwnerChanged message");
347             goto fail;
348         }
349
350         if (!*new) {
351             Client *client;
352
353             if ((client = client_get(name, FALSE))) {
354 /*                 avahi_log_info("dbus: client %s vanished", name); */
355                 client_free(client);
356             }
357         }
358     }
359
360 fail:
361     if (dbus_error_is_set(&error))
362         dbus_error_free(&error);
363     
364     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
365 }
366
367
368 static void entry_group_callback(AvahiServer *s, AvahiEntryGroup *g, AvahiEntryGroupState state, gpointer userdata) {
369     EntryGroupInfo *i = userdata;
370     DBusMessage *m;
371     gint32 t;
372     
373     g_assert(s);
374     g_assert(g);
375     g_assert(i);
376
377     m = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "StateChanged");
378     t = (gint32) state;
379     dbus_message_append_args(m, DBUS_TYPE_INT32, &t, DBUS_TYPE_INVALID);
380     dbus_message_set_destination(m, i->client->name);  
381     dbus_connection_send(server->bus, m, NULL);
382     dbus_message_unref(m);
383 }
384
385 static DBusHandlerResult msg_entry_group_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
386     DBusError error;
387     EntryGroupInfo *i = userdata;
388
389     g_assert(c);
390     g_assert(m);
391     g_assert(i);
392     
393     dbus_error_init(&error);
394
395     avahi_log_debug("dbus: interface=%s, path=%s, member=%s",
396                     dbus_message_get_interface(m),
397                     dbus_message_get_path(m),
398                     dbus_message_get_member(m));
399
400     /* Access control */
401     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
402         return respond_error(c, m, DBUS_ERROR_ACCESS_DENIED, NULL);
403     
404     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Free")) {
405
406         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
407             avahi_log_warn("Error parsing EntryGroup::Free message");
408             goto fail;
409         }
410
411         entry_group_free(i);
412         return respond_ok(c, m);
413         
414     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Commit")) {
415
416         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
417             avahi_log_warn("Error parsing EntryGroup::Commit message");
418             goto fail;
419         }
420
421         avahi_entry_group_commit(i->entry_group);
422         return respond_ok(c, m);
423         
424     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "GetState")) {
425         DBusMessage *reply;
426         gint32 t;
427
428         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
429             avahi_log_warn("Error parsing EntryGroup::GetState message");
430             goto fail;
431         }
432
433         t = (gint32) avahi_entry_group_get_state(i->entry_group);
434         reply = dbus_message_new_method_return(m);
435         dbus_message_append_args(reply, DBUS_TYPE_INT32, &t, DBUS_TYPE_INVALID);
436         dbus_connection_send(c, reply, NULL);
437         dbus_message_unref(reply);
438         
439         return DBUS_HANDLER_RESULT_HANDLED;
440         
441     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddService")) {
442         gint32 interface, protocol;
443         gchar *type, *name, *domain, *host;
444         guint16 port;
445         gchar **txt = NULL;
446         gint txt_len;
447         AvahiStringList *strlst;
448         
449         if (!dbus_message_get_args(
450                 m, &error,
451                 DBUS_TYPE_INT32, &interface,
452                 DBUS_TYPE_INT32, &protocol,
453                 DBUS_TYPE_STRING, &name,
454                 DBUS_TYPE_STRING, &type,
455                 DBUS_TYPE_STRING, &domain,
456                 DBUS_TYPE_STRING, &host,
457                 DBUS_TYPE_UINT16, &port, 
458                 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &txt, &txt_len,
459                 DBUS_TYPE_INVALID) || !type || !*type || !name || !*name || !port) {
460             avahi_log_warn("Error parsing EntryGroup::AddService message");
461             goto fail;
462         }
463
464         strlst = avahi_string_list_new_from_array((const gchar**) txt, txt_len);
465         dbus_free_string_array(txt);
466
467         if (domain && !*domain)
468             domain = NULL;
469
470         if (host && !*host)
471             host = NULL;
472
473         if (avahi_server_add_service_strlst(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, type, domain, host, port, strlst) < 0) {
474             avahi_log_warn("Failed to add service: %s", name);
475             return respond_error(c, m, "org.freedesktop.Avahi.InvalidServiceError", NULL);
476         } /* else */
477 /*             avahi_log_info("Successfully added service: %s", name); */
478         
479         return respond_ok(c, m);
480         
481     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddAddress")) {
482         gint32 interface, protocol;
483         gchar *name, *address;
484         AvahiAddress a;
485         
486         if (!dbus_message_get_args(
487                 m, &error,
488                 DBUS_TYPE_INT32, &interface,
489                 DBUS_TYPE_INT32, &protocol,
490                 DBUS_TYPE_STRING, &name,
491                 DBUS_TYPE_STRING, &address,
492                 DBUS_TYPE_INVALID) || !name || !*name || !address || !*address) {
493             avahi_log_warn("Error parsing EntryGroup::AddAddress message");
494             goto fail;
495         }
496
497         if (!(avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a))) {
498             avahi_log_warn("Error parsing address data");
499             return respond_error(c, m, "org.freedesktop.Avahi.InvalidAddressError", NULL);
500         }
501
502         if (avahi_server_add_address(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, 0, name, &a) < 0) {
503             avahi_log_warn("Failed to add service: %s", name);
504             return respond_error(c, m, "org.freedesktop.Avahi.InvalidAddressError", NULL);
505         }/*  else */
506 /*             avahi_log_info("Successfully added address: %s -> %s", name, address); */
507         
508         return respond_ok(c, m);
509     }
510     
511     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
512
513 fail:
514     if (dbus_error_is_set(&error))
515         dbus_error_free(&error);
516     
517     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
518 }
519
520 static void host_name_resolver_callback(AvahiHostNameResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const gchar *host_name, const AvahiAddress *a, gpointer userdata) {
521     HostNameResolverInfo *i = userdata;
522     DBusMessage *reply;
523     
524     g_assert(r);
525     g_assert(host_name);
526     g_assert(i);
527
528     if (event == AVAHI_RESOLVER_FOUND) {
529         char t[256], *pt = t;
530         gint32 i_interface, i_protocol, i_aprotocol;
531
532         g_assert(a);
533         avahi_address_snprint(t, sizeof(t), a);
534
535         i_interface = (gint32) interface;
536         i_protocol = (gint32) protocol;
537         i_aprotocol = (gint32) a->family;
538         
539         reply = dbus_message_new_method_return(i->message);
540         dbus_message_append_args(
541             reply,
542             DBUS_TYPE_INT32, &i_interface,
543             DBUS_TYPE_INT32, &i_protocol,
544             DBUS_TYPE_STRING, &host_name,
545             DBUS_TYPE_INT32, &i_aprotocol,
546             DBUS_TYPE_STRING, &pt,
547             DBUS_TYPE_INVALID);
548
549     } else {
550         g_assert(event == AVAHI_RESOLVER_TIMEOUT);
551         reply = dbus_message_new_error(i->message, "org.freedesktop.Avahi.TimeoutError", NULL);
552     }
553
554     dbus_connection_send(server->bus, reply, NULL);
555     dbus_message_unref(reply);
556
557     host_name_resolver_free(i);
558 }
559
560 static void address_resolver_callback(AvahiAddressResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const AvahiAddress *address, const gchar *host_name, gpointer userdata) {
561     AddressResolverInfo *i = userdata;
562     DBusMessage *reply;
563     
564     g_assert(r);
565     g_assert(address);
566     g_assert(i);
567
568     if (event == AVAHI_RESOLVER_FOUND) {
569         char t[256], *pt = t;
570         gint32 i_interface, i_protocol, i_aprotocol;
571
572         g_assert(host_name);
573         avahi_address_snprint(t, sizeof(t), address);
574
575         i_interface = (gint32) interface;
576         i_protocol = (gint32) protocol;
577         i_aprotocol = (gint32) address->family;
578         
579         reply = dbus_message_new_method_return(i->message);
580         dbus_message_append_args(
581             reply,
582             DBUS_TYPE_INT32, &i_interface,
583             DBUS_TYPE_INT32, &i_protocol,
584             DBUS_TYPE_INT32, &i_aprotocol,
585             DBUS_TYPE_STRING, &pt,
586             DBUS_TYPE_STRING, &host_name,
587             DBUS_TYPE_INVALID);
588
589     } else {
590         g_assert(event == AVAHI_RESOLVER_TIMEOUT);
591         reply = dbus_message_new_error(i->message, "org.freedesktop.Avahi.TimeoutError", NULL);
592     }
593
594     dbus_connection_send(server->bus, reply, NULL);
595     dbus_message_unref(reply);
596
597     address_resolver_free(i);
598 }
599
600 static DBusHandlerResult msg_domain_browser_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
601     DBusError error;
602     DomainBrowserInfo *i = userdata;
603
604     g_assert(c);
605     g_assert(m);
606     g_assert(i);
607     
608     dbus_error_init(&error);
609
610     avahi_log_debug("dbus: interface=%s, path=%s, member=%s",
611                     dbus_message_get_interface(m),
612                     dbus_message_get_path(m),
613                     dbus_message_get_member(m));
614
615     /* Access control */
616     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
617         return respond_error(c, m, DBUS_ERROR_ACCESS_DENIED, NULL);
618     
619     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "Free")) {
620
621         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
622             avahi_log_warn("Error parsing DomainBrowser::Free message");
623             goto fail;
624         }
625
626         domain_browser_free(i);
627         return respond_ok(c, m);
628         
629     }
630     
631     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
632
633 fail:
634     if (dbus_error_is_set(&error))
635         dbus_error_free(&error);
636     
637     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
638 }
639
640 static void domain_browser_callback(AvahiDomainBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const gchar *domain, gpointer userdata) {
641     DomainBrowserInfo *i = userdata;
642     DBusMessage *m;
643     gint32 i_interface, i_protocol;
644     
645     g_assert(b);
646     g_assert(domain);
647     g_assert(i);
648
649     i_interface = (gint32) interface;
650     i_protocol = (gint32) protocol;
651
652     m = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, event == AVAHI_BROWSER_NEW ? "ItemNew" : "ItemRemove");
653     dbus_message_append_args(
654         m,
655         DBUS_TYPE_INT32, &i_interface,
656         DBUS_TYPE_INT32, &i_protocol,
657         DBUS_TYPE_STRING, &domain,
658         DBUS_TYPE_INVALID);
659     dbus_message_set_destination(m, i->client->name);   
660     dbus_connection_send(server->bus, m, NULL);
661     dbus_message_unref(m);
662 }
663
664 static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
665     DBusError error;
666
667     dbus_error_init(&error);
668
669     avahi_log_debug("dbus: interface=%s, path=%s, member=%s",
670                     dbus_message_get_interface(m),
671                     dbus_message_get_path(m),
672                     dbus_message_get_member(m));
673
674     if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostName")) {
675
676         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
677             avahi_log_warn("Error parsing Server::GetHostName message");
678             goto fail;
679         }
680
681         return respond_string(c, m, avahi_server_get_host_name(avahi_server));
682         
683     } if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetDomainName")) {
684
685         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
686             avahi_log_warn("Error parsing Server::GetDomainName message");
687             goto fail;
688         }
689
690         return respond_string(c, m, avahi_server_get_domain_name(avahi_server));
691
692     } if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostNameFqdn")) {
693
694         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
695             avahi_log_warn("Error parsing Server::GetHostNameFqdn message");
696             goto fail;
697         }
698     
699         return respond_string(c, m, avahi_server_get_host_name_fqdn(avahi_server));
700         
701     } if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetVersionString")) {
702
703         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
704             avahi_log_warn("Error parsing Server::GetVersionString message");
705             goto fail;
706         }
707     
708         return respond_string(c, m, PACKAGE_STRING);
709         
710     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "EntryGroupNew")) {
711         Client *client;
712         EntryGroupInfo *i;
713         static const DBusObjectPathVTable vtable = {
714             NULL,
715             msg_entry_group_impl,
716             NULL,
717             NULL,
718             NULL,
719             NULL
720         };
721         DBusMessage *reply;
722
723         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
724             avahi_log_warn("Error parsing Server::EntryGroupNew message");
725             goto fail;
726         }
727
728         client = client_get(dbus_message_get_sender(m), TRUE);
729
730         i = g_new(EntryGroupInfo, 1);
731         i->id = ++client->current_id;
732         i->client = client;
733         i->path = g_strdup_printf("/org/freedesktop/Avahi/Client%u/EntryGroup%u", client->id, i->id);
734         AVAHI_LLIST_PREPEND(EntryGroupInfo, entry_groups, client->entry_groups, i);
735
736         if (!(i->entry_group = avahi_entry_group_new(avahi_server, entry_group_callback, i))) {
737             avahi_log_warn("Failed to create entry group");
738             entry_group_free(i);
739             goto fail;
740         }
741
742         dbus_connection_register_object_path(c, i->path, &vtable, i);
743         reply = dbus_message_new_method_return(m);
744         dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &i->path, DBUS_TYPE_INVALID);
745         dbus_connection_send(c, reply, NULL);
746         dbus_message_unref(reply);
747         
748         return DBUS_HANDLER_RESULT_HANDLED;
749         
750     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveHostName")) {
751         Client *client;
752         gint32 interface, protocol, aprotocol;
753         gchar *name;
754         HostNameResolverInfo *i;
755             
756         if (!dbus_message_get_args(
757                 m, &error,
758                 DBUS_TYPE_INT32, &interface,
759                 DBUS_TYPE_INT32, &protocol,
760                 DBUS_TYPE_STRING, &name,
761                 DBUS_TYPE_INT32, &aprotocol,
762                 DBUS_TYPE_INVALID) || !name || !*name) {
763             avahi_log_warn("Error parsing Server::ResolveHostName message");
764             goto fail;
765         }
766
767         client = client_get(dbus_message_get_sender(m), TRUE);
768
769         i = g_new(HostNameResolverInfo, 1);
770         i->client = client;
771         i->message = dbus_message_ref(m);
772         AVAHI_LLIST_PREPEND(HostNameResolverInfo, host_name_resolvers, client->host_name_resolvers, i);
773
774         if (!(i->host_name_resolver = avahi_host_name_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, (AvahiProtocol) aprotocol, host_name_resolver_callback, i))) {
775             host_name_resolver_free(i);
776             avahi_log_warn("Failed to create host name resolver");
777             goto fail;
778         }
779         
780         return DBUS_HANDLER_RESULT_HANDLED;
781         
782     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveAddress")) {
783         Client *client;
784         gint32 interface, protocol;
785         gchar *address;
786         AddressResolverInfo *i;
787         AvahiAddress a;
788             
789         if (!dbus_message_get_args(
790                 m, &error,
791                 DBUS_TYPE_INT32, &interface,
792                 DBUS_TYPE_INT32, &protocol,
793                 DBUS_TYPE_STRING, &address,
794                 DBUS_TYPE_INVALID) || !address || !*address) {
795             avahi_log_warn("Error parsing Server::ResolveAddress message");
796             goto fail;
797         }
798
799         if (!avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a)) {
800             avahi_log_warn("Error parsing address data");
801             return respond_error(c, m, "org.freedesktop.Avahi.InvalidAddressError", NULL);
802         }
803         
804         client = client_get(dbus_message_get_sender(m), TRUE);
805
806         i = g_new(AddressResolverInfo, 1);
807         i->client = client;
808         i->message = dbus_message_ref(m);
809
810         AVAHI_LLIST_PREPEND(AddressResolverInfo, address_resolvers, client->address_resolvers, i);
811
812         if (!(i->address_resolver = avahi_address_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, &a, address_resolver_callback, i))) {
813             address_resolver_free(i);
814             avahi_log_warn("Failed to create address resolver");
815             goto fail;
816         }
817         
818         return DBUS_HANDLER_RESULT_HANDLED;
819         
820      } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "DomainBrowserNew")) {
821         Client *client;
822         DomainBrowserInfo *i;
823         static const DBusObjectPathVTable vtable = {
824             NULL,
825             msg_domain_browser_impl,
826             NULL,
827             NULL,
828             NULL,
829             NULL
830         };
831         DBusMessage *reply;
832         gint32 interface, protocol, type;
833         gchar *domain;
834         
835
836         if (!dbus_message_get_args(
837                 m, &error,
838                 DBUS_TYPE_INT32, &interface,
839                 DBUS_TYPE_INT32, &protocol,
840                 DBUS_TYPE_STRING, &domain,
841                 DBUS_TYPE_INT32, &type,
842                 DBUS_TYPE_INVALID) || type < 0 || type >= AVAHI_DOMAIN_BROWSER_MAX) {
843             avahi_log_warn("Error parsing Server::DomainBrowserNew message");
844             goto fail;
845         }
846
847         client = client_get(dbus_message_get_sender(m), TRUE);
848
849         if (!*domain)
850             domain = NULL;
851
852         i = g_new(DomainBrowserInfo, 1);
853         i->id = ++client->current_id;
854         i->client = client;
855         i->path = g_strdup_printf("/org/freedesktop/Avahi/Client%u/DomainBrowser%u", client->id, i->id);
856
857         AVAHI_LLIST_PREPEND(DomainBrowserInfo, domain_browsers, client->domain_browsers, i);
858
859         if (!(i->domain_browser = avahi_domain_browser_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, domain, (AvahiDomainBrowserType) type, domain_browser_callback, i))) {
860             avahi_log_warn("Failed to create domain browser");
861             domain_browser_free(i);
862             goto fail;
863         }
864         
865         dbus_connection_register_object_path(c, i->path, &vtable, i);
866         reply = dbus_message_new_method_return(m);
867         dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &i->path, DBUS_TYPE_INVALID);
868         dbus_connection_send(c, reply, NULL);
869         dbus_message_unref(reply);
870         
871         return DBUS_HANDLER_RESULT_HANDLED;
872     }
873     
874     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
875
876
877 fail:
878     if (dbus_error_is_set(&error))
879         dbus_error_free(&error);
880     
881     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
882 }
883
884 void dbus_protocol_server_state_changed(AvahiServerState state) {
885     DBusMessage *m;
886     gint32 t;
887     
888     if (!server)
889         return;
890
891     m = dbus_message_new_signal(AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "StateChanged");
892     t = (gint32) state;
893     dbus_message_append_args(m, DBUS_TYPE_INT32, &t, DBUS_TYPE_INVALID);
894     dbus_connection_send(server->bus, m, NULL);
895     dbus_message_unref(m);
896 }
897
898 int dbus_protocol_setup(GMainLoop *loop) {
899     DBusError error;
900
901     static const DBusObjectPathVTable server_vtable = {
902         NULL,
903         msg_server_impl,
904         NULL,
905         NULL,
906         NULL,
907         NULL
908     };
909
910     dbus_error_init(&error);
911
912     server = g_malloc(sizeof(Server));
913     server->clients = NULL;
914     server->current_id = 0;
915
916     server->bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
917     if (dbus_error_is_set(&error)) {
918         avahi_log_warn("dbus_bus_get(): %s", error.message);
919         goto fail;
920     }
921
922     dbus_connection_setup_with_g_main(server->bus, NULL);
923     dbus_connection_set_exit_on_disconnect(server->bus, FALSE);
924
925     dbus_bus_request_name(server->bus, AVAHI_DBUS_NAME, 0, &error);
926     if (dbus_error_is_set(&error)) {
927         avahi_log_warn("dbus_bus_request_name(): %s", error.message);
928         goto fail;
929     }
930
931     dbus_bus_add_match(server->bus, "type='signal',""interface='" DBUS_INTERFACE_DBUS  "'", &error);
932
933     dbus_connection_add_filter(server->bus, msg_signal_filter_impl, loop, NULL);
934     dbus_connection_register_object_path(server->bus, AVAHI_DBUS_PATH_SERVER, &server_vtable, NULL);
935
936     return 0;
937
938 fail:
939     if (server->bus) {
940         dbus_connection_disconnect(server->bus);
941         dbus_connection_unref(server->bus);
942     }
943     
944     dbus_error_free (&error);
945     g_free(server);
946     server = NULL;
947     return -1;
948 }
949
950 void dbus_protocol_shutdown(void) {
951
952     if (server) {
953     
954         while (server->clients)
955             client_free(server->clients);
956
957         if (server->bus) {
958             dbus_connection_disconnect(server->bus);
959             dbus_connection_unref(server->bus);
960         }
961
962         g_free(server);
963         server = NULL;
964     }
965 }