]> git.meshlink.io Git - catta/blob - avahi-daemon/dbus-protocol.c
* Implement client API for arbitrary record browsing
[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 <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <net/if.h>
32 #include <errno.h>
33 #include <unistd.h>
34 #include <assert.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <signal.h>
39 #include <stdlib.h>
40
41 #include <dbus/dbus.h>
42
43 #include <avahi-common/dbus.h>
44 #include <avahi-common/llist.h>
45 #include <avahi-common/malloc.h>
46 #include <avahi-common/dbus.h>
47 #include <avahi-common/dbus-watch-glue.h>
48 #include <avahi-common/alternative.h>
49 #include <avahi-common/error.h>
50 #include <avahi-common/domain.h>
51
52 #include <avahi-core/log.h>
53 #include <avahi-core/core.h>
54 #include <avahi-core/lookup.h>
55 #include <avahi-core/publish.h>
56
57 #include "dbus-protocol.h"
58 #include "dbus-util.h"
59 #include "dbus-internal.h"
60 #include "main.h"
61
62 /* #define VALGRIND_WORKAROUND 1 */
63
64 Server *server = NULL;
65
66 static int disable_user_service_publishing = 0;
67
68 static void client_free(Client *c) {
69     
70     assert(server);
71     assert(c);
72
73     while (c->entry_groups)
74         avahi_dbus_entry_group_free(c->entry_groups);
75
76     while (c->sync_host_name_resolvers)
77         avahi_dbus_sync_host_name_resolver_free(c->sync_host_name_resolvers);
78
79     while (c->async_host_name_resolvers)
80         avahi_dbus_async_host_name_resolver_free(c->async_host_name_resolvers);
81     
82     while (c->sync_address_resolvers)
83         avahi_dbus_sync_address_resolver_free(c->sync_address_resolvers);
84
85     while (c->async_address_resolvers)
86         avahi_dbus_async_address_resolver_free(c->async_address_resolvers);
87
88     while (c->domain_browsers)
89         avahi_dbus_domain_browser_free(c->domain_browsers);
90
91     while (c->service_type_browsers)
92         avahi_dbus_service_type_browser_free(c->service_type_browsers);
93
94     while (c->service_browsers)
95         avahi_dbus_service_browser_free(c->service_browsers);
96
97     while (c->sync_service_resolvers)
98         avahi_dbus_sync_service_resolver_free(c->sync_service_resolvers);
99
100     while (c->async_service_resolvers)
101         avahi_dbus_async_service_resolver_free(c->async_service_resolvers);
102
103     while (c->record_browsers)
104         avahi_dbus_record_browser_free(c->record_browsers);
105
106     assert(c->n_objects == 0);
107     
108     avahi_free(c->name);
109     AVAHI_LLIST_REMOVE(Client, clients, server->clients, c);
110     avahi_free(c);
111
112     server->n_clients --;
113     assert(server->n_clients >= 0);
114 }
115
116 static Client *client_get(const char *name, int create) {
117     Client *client;
118
119     assert(server);
120     assert(name);
121
122     for (client = server->clients; client; client = client->clients_next)
123         if (!strcmp(name, client->name))
124             return client;
125
126     if (!create)
127         return NULL;
128
129     if (server->n_clients >= CLIENTS_MAX)
130         return NULL;
131     
132     /* If not existant yet, create a new entry */
133     client = avahi_new(Client, 1);
134     client->id = server->current_id++;
135     client->name = avahi_strdup(name);
136     client->current_id = 0;
137     client->n_objects = 0;
138     
139     AVAHI_LLIST_HEAD_INIT(EntryGroupInfo, client->entry_groups);
140     AVAHI_LLIST_HEAD_INIT(SyncHostNameResolverInfo, client->sync_host_name_resolvers);
141     AVAHI_LLIST_HEAD_INIT(AsyncHostNameResolverInfo, client->async_host_name_resolvers);
142     AVAHI_LLIST_HEAD_INIT(SyncAddressResolverInfo, client->sync_address_resolvers);
143     AVAHI_LLIST_HEAD_INIT(AsyncAddressResolverInfo, client->async_address_resolvers);
144     AVAHI_LLIST_HEAD_INIT(DomainBrowserInfo, client->domain_browsers);
145     AVAHI_LLIST_HEAD_INIT(ServiceTypeBrowserInfo, client->service_type_browsers);
146     AVAHI_LLIST_HEAD_INIT(ServiceBrowserInfo, client->service_browsers);
147     AVAHI_LLIST_HEAD_INIT(SyncServiceResolverInfo, client->sync_service_resolvers);
148     AVAHI_LLIST_HEAD_INIT(AsyncServiceResolverInfo, client->async_service_resolvers);
149     AVAHI_LLIST_HEAD_INIT(RecordBrowserInfo, client->record_browsers);
150
151     AVAHI_LLIST_PREPEND(Client, clients, server->clients, client);
152
153     server->n_clients++;
154     assert(server->n_clients > 0);
155     
156     return client;
157 }
158
159
160 static DBusHandlerResult msg_signal_filter_impl(AVAHI_GCC_UNUSED DBusConnection *c, DBusMessage *m, AVAHI_GCC_UNUSED void *userdata) {
161     DBusError error;
162
163     dbus_error_init(&error);
164
165 /*     avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s", */
166 /*                     dbus_message_get_interface(m), */
167 /*                     dbus_message_get_path(m), */
168 /*                     dbus_message_get_member(m)); */
169
170     if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) {
171         /* No, we shouldn't quit, but until we get somewhere
172          * usefull such that we can restore our state, we will */
173         avahi_log_warn("Disconnnected from D-BUS, terminating...");
174         
175         raise(SIGQUIT); /* The signal handler will catch this and terminate the process cleanly*/
176         
177         return DBUS_HANDLER_RESULT_HANDLED;
178         
179     } else if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameAcquired")) {
180         char *name;
181
182         if (!dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) {
183             avahi_log_warn("Error parsing NameAcquired message");
184             goto fail;
185         }
186
187 /*         avahi_log_info(__FILE__": name acquired (%s)", name); */
188         return DBUS_HANDLER_RESULT_HANDLED;
189         
190     } else if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
191         char *name, *old, *new;
192
193         if (!dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old, DBUS_TYPE_STRING, &new, DBUS_TYPE_INVALID)) {
194             avahi_log_warn("Error parsing NameOwnerChanged message");
195             goto fail;
196         }
197
198         if (!*new) {
199             Client *client;
200
201             if ((client = client_get(name, FALSE))) {
202                 avahi_log_debug(__FILE__": client %s vanished.", name); 
203                 client_free(client);
204             }
205         }
206     }
207
208 fail:
209     if (dbus_error_is_set(&error))
210         dbus_error_free(&error);
211     
212     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
213 }
214
215 static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAHI_GCC_UNUSED void *userdata) {
216     DBusError error;
217
218     dbus_error_init(&error);
219
220     avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s",
221                     dbus_message_get_interface(m),
222                     dbus_message_get_path(m),
223                     dbus_message_get_member(m));
224
225     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
226         return avahi_dbus_handle_introspect(c, m, "Server.introspect");
227         
228     else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostName")) {
229
230         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
231             avahi_log_warn("Error parsing Server::GetHostName message");
232             goto fail;
233         }
234
235         return avahi_dbus_respond_string(c, m, avahi_server_get_host_name(avahi_server));
236         
237     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetDomainName")) {
238
239         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
240             avahi_log_warn("Error parsing Server::GetDomainName message");
241             goto fail;
242         }
243
244         return avahi_dbus_respond_string(c, m, avahi_server_get_domain_name(avahi_server));
245
246     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostNameFqdn")) {
247
248         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
249             avahi_log_warn("Error parsing Server::GetHostNameFqdn message");
250             goto fail;
251         }
252     
253         return avahi_dbus_respond_string(c, m, avahi_server_get_host_name_fqdn(avahi_server));
254         
255     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetVersionString")) {
256
257         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
258             avahi_log_warn("Error parsing Server::GetVersionString message");
259             goto fail;
260         }
261     
262         return avahi_dbus_respond_string(c, m, PACKAGE_STRING);
263
264     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetState")) {
265         AvahiServerState state;
266         
267         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
268             avahi_log_warn("Error parsing Server::GetState message");
269             goto fail;
270         }
271         
272         state = avahi_server_get_state(avahi_server);
273         return avahi_dbus_respond_int32(c, m, (int32_t) state);
274
275     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetLocalServiceCookie")) {
276
277         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
278             avahi_log_warn("Error parsing Server::GetLocalServiceCookie message");
279             goto fail;
280         }
281         
282         return avahi_dbus_respond_uint32(c, m, avahi_server_get_local_service_cookie(avahi_server));
283
284     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetNetworkInterfaceNameByIndex")) {
285         int32_t idx;
286         int fd;
287         char name[IF_NAMESIZE];
288
289         
290         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INT32, &idx, DBUS_TYPE_INVALID))) {
291             avahi_log_warn("Error parsing Server::GetNetworkInterfaceNameByIndex message");
292             goto fail;
293         }
294
295 #ifdef VALGRIND_WORKAROUND
296         return respond_string(c, m, "blah");
297 #else
298         
299         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
300             if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
301                 char txt[256];
302                 snprintf(txt, sizeof(txt), "OS Error: %s", strerror(errno));
303                 return avahi_dbus_respond_error(c, m, AVAHI_ERR_OS, txt);
304             }
305
306         if ((!if_indextoname(idx, name))) {
307             char txt[256];
308             snprintf(txt, sizeof(txt), "OS Error: %s", strerror(errno));
309             close(fd);
310             return avahi_dbus_respond_error(c, m, AVAHI_ERR_OS, txt);
311         }
312
313         close(fd);
314         
315         return avahi_dbus_respond_string(c, m, name);
316 #endif
317         
318     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetNetworkInterfaceIndexByName")) {
319         char *n;
320         int fd;
321         int32_t idx;
322         
323         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n) {
324             avahi_log_warn("Error parsing Server::GetNetworkInterfaceIndexByName message");
325             goto fail;
326         }
327
328 #ifdef VALGRIND_WORKAROUND
329         return respond_int32(c, m, 1);
330 #else
331         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
332             if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
333                 char txt[256];
334                 snprintf(txt, sizeof(txt), "OS Error: %s", strerror(errno));
335                 return avahi_dbus_respond_error(c, m, AVAHI_ERR_OS, txt);
336             }
337
338         if (!(idx = if_nametoindex(n))) {
339             char txt[256];
340             snprintf(txt, sizeof(txt), "OS Error: %s", strerror(errno));
341             close(fd);
342             return avahi_dbus_respond_error(c, m, AVAHI_ERR_OS, txt);
343         }
344
345         close(fd);
346         
347         return avahi_dbus_respond_int32(c, m, idx);
348 #endif
349
350     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetAlternativeHostName")) {
351         char *n, * t;
352         
353         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n) {
354             avahi_log_warn("Error parsing Server::GetAlternativeHostName message");
355             goto fail;
356         }
357
358         t = avahi_alternative_host_name(n);
359         avahi_dbus_respond_string(c, m, t);
360         avahi_free(t);
361
362         return DBUS_HANDLER_RESULT_HANDLED;
363
364     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetAlternativeServiceName")) {
365         char *n, *t;
366         
367         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n) {
368             avahi_log_warn("Error parsing Server::GetAlternativeServiceName message");
369             goto fail;
370         }
371
372         t = avahi_alternative_service_name(n);
373         avahi_dbus_respond_string(c, m, t);
374         avahi_free(t);
375
376         return DBUS_HANDLER_RESULT_HANDLED;
377         
378     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "EntryGroupNew")) {
379         Client *client;
380         EntryGroupInfo *i;
381         static const DBusObjectPathVTable vtable = {
382             NULL,
383             avahi_dbus_msg_entry_group_impl,
384             NULL,
385             NULL,
386             NULL,
387             NULL
388         };
389
390         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
391             avahi_log_warn("Error parsing Server::EntryGroupNew message");
392             goto fail;
393         }
394
395         if (disable_user_service_publishing)
396             return avahi_dbus_respond_error(c, m, AVAHI_ERR_NOT_PERMITTED, NULL);
397         
398         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
399             avahi_log_warn("Too many clients, client request failed.");
400             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
401         }
402
403         if (client->n_objects >= OBJECTS_PER_CLIENT_MAX) {
404             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
405             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
406         }
407
408         i = avahi_new(EntryGroupInfo, 1);
409         i->id = ++client->current_id;
410         i->client = client;
411         i->path = avahi_strdup_printf("/Client%u/EntryGroup%u", client->id, i->id);
412         i->n_entries = 0;
413         AVAHI_LLIST_PREPEND(EntryGroupInfo, entry_groups, client->entry_groups, i);
414         client->n_objects++;
415         
416         if (!(i->entry_group = avahi_s_entry_group_new(avahi_server, avahi_dbus_entry_group_callback, i))) {
417             avahi_dbus_entry_group_free(i);
418             return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
419         }
420
421         dbus_connection_register_object_path(c, i->path, &vtable, i);
422         return avahi_dbus_respond_path(c, m, i->path);
423         
424     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveHostName")) {
425         Client *client;
426         int32_t interface, protocol, aprotocol;
427         uint32_t flags;
428         char *name;
429         SyncHostNameResolverInfo *i;
430             
431         if (!dbus_message_get_args(
432                 m, &error,
433                 DBUS_TYPE_INT32, &interface,
434                 DBUS_TYPE_INT32, &protocol,
435                 DBUS_TYPE_STRING, &name,
436                 DBUS_TYPE_INT32, &aprotocol,
437                 DBUS_TYPE_UINT32, &flags,
438                 DBUS_TYPE_INVALID) || !name) {
439             avahi_log_warn("Error parsing Server::ResolveHostName message");
440             goto fail;
441         }
442
443         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
444             avahi_log_warn("Too many clients, client request failed.");
445             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
446         }
447
448         if (client->n_objects >= OBJECTS_PER_CLIENT_MAX) {
449             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
450             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
451         }
452
453         i = avahi_new(SyncHostNameResolverInfo, 1);
454         i->client = client;
455         i->message = dbus_message_ref(m);
456         AVAHI_LLIST_PREPEND(SyncHostNameResolverInfo, sync_host_name_resolvers, client->sync_host_name_resolvers, i);
457         client->n_objects++;
458
459         if (!(i->host_name_resolver = avahi_s_host_name_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, (AvahiProtocol) aprotocol, (AvahiLookupFlags) flags, avahi_dbus_sync_host_name_resolver_callback, i))) {
460             avahi_dbus_sync_host_name_resolver_free(i);
461             return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
462         }
463         
464         return DBUS_HANDLER_RESULT_HANDLED;
465         
466     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveAddress")) {
467         Client *client;
468         int32_t interface, protocol;
469         uint32_t flags;
470         char *address;
471         SyncAddressResolverInfo *i;
472         AvahiAddress a;
473             
474         if (!dbus_message_get_args(
475                 m, &error,
476                 DBUS_TYPE_INT32, &interface,
477                 DBUS_TYPE_INT32, &protocol,
478                 DBUS_TYPE_STRING, &address,
479                 DBUS_TYPE_UINT32, &flags, 
480                 DBUS_TYPE_INVALID) || !address) {
481             avahi_log_warn("Error parsing Server::ResolveAddress message");
482             goto fail;
483         }
484
485         if (!avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a))
486             return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_ADDRESS, NULL);
487
488         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
489             avahi_log_warn("Too many clients, client request failed.");
490             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
491         }
492
493         if (client->n_objects >= OBJECTS_PER_CLIENT_MAX) {
494             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
495             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
496         }
497
498         i = avahi_new(SyncAddressResolverInfo, 1);
499         i->client = client;
500         i->message = dbus_message_ref(m);
501         AVAHI_LLIST_PREPEND(SyncAddressResolverInfo, sync_address_resolvers, client->sync_address_resolvers, i);
502         client->n_objects++;
503
504         if (!(i->address_resolver = avahi_s_address_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, &a, (AvahiLookupFlags) flags, avahi_dbus_sync_address_resolver_callback, i))) {
505             avahi_dbus_sync_address_resolver_free(i);
506             return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
507         }
508         
509         return DBUS_HANDLER_RESULT_HANDLED;
510         
511     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "DomainBrowserNew")) {
512         Client *client;
513         DomainBrowserInfo *i;
514         static const DBusObjectPathVTable vtable = {
515             NULL,
516             avahi_dbus_msg_domain_browser_impl,
517             NULL,
518             NULL,
519             NULL,
520             NULL
521         };
522         int32_t interface, protocol, type;
523         uint32_t flags;
524         char *domain;
525         
526         if (!dbus_message_get_args(
527                 m, &error,
528                 DBUS_TYPE_INT32, &interface,
529                 DBUS_TYPE_INT32, &protocol,
530                 DBUS_TYPE_STRING, &domain,
531                 DBUS_TYPE_INT32, &type,
532                 DBUS_TYPE_UINT32, &flags,
533                 DBUS_TYPE_INVALID) || type < 0 || type >= AVAHI_DOMAIN_BROWSER_MAX) {
534             avahi_log_warn("Error parsing Server::DomainBrowserNew message");
535             goto fail;
536         }
537
538         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
539             avahi_log_warn("Too many clients, client request failed.");
540             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
541         }
542
543         if (client->n_objects >= OBJECTS_PER_CLIENT_MAX) {
544             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
545             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
546         }
547
548         if (!*domain)
549             domain = NULL;
550
551         i = avahi_new(DomainBrowserInfo, 1);
552         i->id = ++client->current_id;
553         i->client = client;
554         i->path = avahi_strdup_printf("/Client%u/DomainBrowser%u", client->id, i->id);
555         AVAHI_LLIST_PREPEND(DomainBrowserInfo, domain_browsers, client->domain_browsers, i);
556         client->n_objects++;
557
558         if (!(i->domain_browser = avahi_s_domain_browser_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, domain, (AvahiDomainBrowserType) type, (AvahiLookupFlags) flags, avahi_dbus_domain_browser_callback, i))) {
559             avahi_dbus_domain_browser_free(i);
560             return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
561         }
562         
563         dbus_connection_register_object_path(c, i->path, &vtable, i);
564         return avahi_dbus_respond_path(c, m, i->path);
565
566     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ServiceTypeBrowserNew")) {
567         Client *client;
568         ServiceTypeBrowserInfo *i;
569         static const DBusObjectPathVTable vtable = {
570             NULL,
571             avahi_dbus_msg_service_type_browser_impl,
572             NULL,
573             NULL,
574             NULL,
575             NULL
576         };
577         int32_t interface, protocol;
578         uint32_t flags;
579         char *domain;
580         
581         if (!dbus_message_get_args(
582                 m, &error,
583                 DBUS_TYPE_INT32, &interface,
584                 DBUS_TYPE_INT32, &protocol,
585                 DBUS_TYPE_STRING, &domain,
586                 DBUS_TYPE_UINT32, &flags,
587                 DBUS_TYPE_INVALID)) {
588             avahi_log_warn("Error parsing Server::ServiceTypeBrowserNew message");
589             goto fail;
590         }
591
592         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
593             avahi_log_warn("Too many clients, client request failed.");
594             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
595         }
596
597
598         if (client->n_objects >= OBJECTS_PER_CLIENT_MAX) {
599             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
600             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
601         }
602
603         if (!*domain)
604             domain = NULL;
605
606         i = avahi_new(ServiceTypeBrowserInfo, 1);
607         i->id = ++client->current_id;
608         i->client = client;
609         i->path = avahi_strdup_printf("/Client%u/ServiceTypeBrowser%u", client->id, i->id);
610         AVAHI_LLIST_PREPEND(ServiceTypeBrowserInfo, service_type_browsers, client->service_type_browsers, i);
611         client->n_objects++;
612
613         if (!(i->service_type_browser = avahi_s_service_type_browser_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, domain, (AvahiLookupFlags) flags, avahi_dbus_service_type_browser_callback, i))) {
614             avahi_dbus_service_type_browser_free(i);
615             return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
616         }
617         
618         dbus_connection_register_object_path(c, i->path, &vtable, i);
619         return avahi_dbus_respond_path(c, m, i->path);
620         
621     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ServiceBrowserNew")) {
622         Client *client;
623         ServiceBrowserInfo *i;
624         static const DBusObjectPathVTable vtable = {
625             NULL,
626             avahi_dbus_msg_service_browser_impl,
627             NULL,
628             NULL,
629             NULL,
630             NULL
631         };
632         int32_t interface, protocol;
633         uint32_t flags;
634         char *domain, *type;
635         
636         if (!dbus_message_get_args(
637                 m, &error,
638                 DBUS_TYPE_INT32, &interface,
639                 DBUS_TYPE_INT32, &protocol,
640                 DBUS_TYPE_STRING, &type,
641                 DBUS_TYPE_STRING, &domain,
642                 DBUS_TYPE_UINT32, &flags,
643                 DBUS_TYPE_INVALID) || !type) {
644             avahi_log_warn("Error parsing Server::ServiceBrowserNew message");
645             goto fail;
646         }
647
648         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
649             avahi_log_warn("Too many clients, client request failed.");
650             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
651         }
652
653         if (client->n_objects >= OBJECTS_PER_CLIENT_MAX) {
654             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
655             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
656         }
657
658         if (!*domain)
659             domain = NULL;
660
661         i = avahi_new(ServiceBrowserInfo, 1);
662         i->id = ++client->current_id;
663         i->client = client;
664         i->path = avahi_strdup_printf("/Client%u/ServiceBrowser%u", client->id, i->id);
665         AVAHI_LLIST_PREPEND(ServiceBrowserInfo, service_browsers, client->service_browsers, i);
666         client->n_objects++;
667
668         if (!(i->service_browser = avahi_s_service_browser_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, type, domain, (AvahiLookupFlags) flags, avahi_dbus_service_browser_callback, i))) {
669             avahi_dbus_service_browser_free(i);
670             return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
671         }
672         
673         dbus_connection_register_object_path(c, i->path, &vtable, i);
674         return avahi_dbus_respond_path(c, m, i->path);
675         
676     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveService")) {
677         Client *client;
678         int32_t interface, protocol, aprotocol;
679         uint32_t flags;
680         char *name, *type, *domain;
681         SyncServiceResolverInfo *i;
682             
683         if (!dbus_message_get_args(
684                 m, &error,
685                 DBUS_TYPE_INT32, &interface,
686                 DBUS_TYPE_INT32, &protocol,
687                 DBUS_TYPE_STRING, &name,
688                 DBUS_TYPE_STRING, &type,
689                 DBUS_TYPE_STRING, &domain,
690                 DBUS_TYPE_INT32, &aprotocol,
691                 DBUS_TYPE_UINT32, &flags,
692                 DBUS_TYPE_INVALID) || !type) {
693             avahi_log_warn("Error parsing Server::ResolveService message");
694             goto fail;
695         }
696
697         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
698             avahi_log_warn("Too many clients, client request failed.");
699             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
700         }
701         
702         if (client->n_objects >= OBJECTS_PER_CLIENT_MAX) {
703             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
704             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
705         }
706
707         if (!*domain)
708             domain = NULL;
709
710         if (!*name)
711             name = NULL;
712         
713         i = avahi_new(SyncServiceResolverInfo, 1);
714         i->client = client;
715         i->message = dbus_message_ref(m);
716         AVAHI_LLIST_PREPEND(SyncServiceResolverInfo, sync_service_resolvers, client->sync_service_resolvers, i);
717         client->n_objects++;
718
719         if (!(i->service_resolver = avahi_s_service_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, type, domain, (AvahiProtocol) aprotocol, (AvahiLookupFlags) flags, avahi_dbus_sync_service_resolver_callback, i))) {
720             avahi_dbus_sync_service_resolver_free(i);
721             return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
722         }
723         
724         return DBUS_HANDLER_RESULT_HANDLED;
725         
726     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ServiceResolverNew")) {
727         Client *client;
728         int32_t interface, protocol, aprotocol;
729         uint32_t flags;
730         char *name, *type, *domain;
731         AsyncServiceResolverInfo *i;
732         static const DBusObjectPathVTable vtable = {
733             NULL,
734             avahi_dbus_msg_async_service_resolver_impl,
735             NULL,
736             NULL,
737             NULL,
738             NULL
739         };
740
741         if (!dbus_message_get_args(
742                 m, &error,
743                 DBUS_TYPE_INT32, &interface,
744                 DBUS_TYPE_INT32, &protocol,
745                 DBUS_TYPE_STRING, &name,
746                 DBUS_TYPE_STRING, &type,
747                 DBUS_TYPE_STRING, &domain,
748                 DBUS_TYPE_INT32, &aprotocol,
749                 DBUS_TYPE_UINT32, &flags,
750                 DBUS_TYPE_INVALID) || !type) {
751             avahi_log_warn("Error parsing Server::ServiceResolverNew message");
752             goto fail;
753         }
754             
755         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
756             avahi_log_warn(__FILE__": Too many clients, client request failed.");
757             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
758         }
759
760         if (client->n_objects >= OBJECTS_PER_CLIENT_MAX) {
761             avahi_log_warn(__FILE__": Too many objects for client '%s', client request failed.", client->name);
762             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
763         }
764
765         if (!*domain)
766             domain = NULL;
767
768         if (!*name)
769             name = NULL;
770         
771         i = avahi_new(AsyncServiceResolverInfo, 1);
772         i->id = ++client->current_id;
773         i->client = client;
774         i->path = avahi_strdup_printf("/Client%u/ServiceResolver%u", client->id, i->id);
775         AVAHI_LLIST_PREPEND(AsyncServiceResolverInfo, async_service_resolvers, client->async_service_resolvers, i);
776         client->n_objects++;
777
778         if (!(i->service_resolver = avahi_s_service_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, type, domain, (AvahiProtocol) aprotocol, (AvahiLookupFlags) flags, avahi_dbus_async_service_resolver_callback, i))) {
779             avahi_dbus_async_service_resolver_free(i);
780             return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
781         }
782
783 /*         avahi_log_debug(__FILE__": [%s], new service resolver for <%s.%s.%s>", i->path, name, type, domain); */
784         
785         dbus_connection_register_object_path(c, i->path, &vtable, i);
786         return avahi_dbus_respond_path(c, m, i->path);
787
788     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "HostNameResolverNew")) {
789         Client *client;
790         int32_t interface, protocol, aprotocol;
791         uint32_t flags;
792         char *name;
793         AsyncHostNameResolverInfo *i;
794         static const DBusObjectPathVTable vtable = {
795             NULL,
796             avahi_dbus_msg_async_host_name_resolver_impl,
797             NULL,
798             NULL,
799             NULL,
800             NULL
801         };
802             
803         if (!dbus_message_get_args(
804                 m, &error,
805                 DBUS_TYPE_INT32, &interface,
806                 DBUS_TYPE_INT32, &protocol,
807                 DBUS_TYPE_STRING, &name,
808                 DBUS_TYPE_INT32, &aprotocol,
809                 DBUS_TYPE_UINT32, &flags,
810                 DBUS_TYPE_INVALID) || !name) {
811             avahi_log_warn("Error parsing Server::HostNameResolverNew message");
812             goto fail;
813         }
814             
815         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
816             avahi_log_warn(__FILE__": Too many clients, client request failed.");
817             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
818         }
819
820         if (client->n_objects >= OBJECTS_PER_CLIENT_MAX) {
821             avahi_log_warn(__FILE__": Too many objects for client '%s', client request failed.", client->name);
822             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
823         }
824
825         i = avahi_new(AsyncHostNameResolverInfo, 1);
826         i->id = ++client->current_id;
827         i->client = client;
828         i->path = avahi_strdup_printf("/Client%u/HostNameResolver%u", client->id, i->id);
829         AVAHI_LLIST_PREPEND(AsyncHostNameResolverInfo, async_host_name_resolvers, client->async_host_name_resolvers, i);
830         client->n_objects++;
831
832         if (!(i->host_name_resolver = avahi_s_host_name_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, aprotocol, (AvahiLookupFlags) flags, avahi_dbus_async_host_name_resolver_callback, i))) {
833             avahi_dbus_async_host_name_resolver_free(i);
834             return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
835         }
836         
837         dbus_connection_register_object_path(c, i->path, &vtable, i);
838         return avahi_dbus_respond_path(c, m, i->path);
839
840     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "AddressResolverNew")) {
841         Client *client;
842         int32_t interface, protocol;
843         uint32_t flags;
844         char *address;
845         AsyncAddressResolverInfo *i;
846         AvahiAddress a;
847         static const DBusObjectPathVTable vtable = {
848             NULL,
849             avahi_dbus_msg_async_address_resolver_impl,
850             NULL,
851             NULL,
852             NULL,
853             NULL
854         };
855             
856         if (!dbus_message_get_args(
857                 m, &error,
858                 DBUS_TYPE_INT32, &interface,
859                 DBUS_TYPE_INT32, &protocol,
860                 DBUS_TYPE_STRING, &address,
861                 DBUS_TYPE_UINT32, &flags,
862                 DBUS_TYPE_INVALID) || !address) {
863             avahi_log_warn("Error parsing Server::AddressResolverNew message");
864             goto fail;
865         }
866
867         if (!avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a))
868             return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_ADDRESS, NULL);
869
870         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
871             avahi_log_warn(__FILE__": Too many clients, client request failed.");
872             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
873         }
874
875         if (client->n_objects >= OBJECTS_PER_CLIENT_MAX) {
876             avahi_log_warn(__FILE__": Too many objects for client '%s', client request failed.", client->name);
877             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
878         }
879
880         i = avahi_new(AsyncAddressResolverInfo, 1);
881         i->id = ++client->current_id;
882         i->client = client;
883         i->path = avahi_strdup_printf("/Client%u/AddressResolver%u", client->id, i->id);
884         AVAHI_LLIST_PREPEND(AsyncAddressResolverInfo, async_address_resolvers, client->async_address_resolvers, i);
885         client->n_objects++;
886
887         if (!(i->address_resolver = avahi_s_address_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, &a, (AvahiLookupFlags) flags, avahi_dbus_async_address_resolver_callback, i))) {
888             avahi_dbus_async_address_resolver_free(i);
889             return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
890         }
891         
892         dbus_connection_register_object_path(c, i->path, &vtable, i);
893         return avahi_dbus_respond_path(c, m, i->path);
894         
895     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "RecordBrowserNew")) {
896         Client *client;
897         RecordBrowserInfo *i;
898         static const DBusObjectPathVTable vtable = {
899             NULL,
900             avahi_dbus_msg_record_browser_impl,
901             NULL,
902             NULL,
903             NULL,
904             NULL
905         };
906         int32_t interface, protocol;
907         uint32_t flags;
908         char *name;
909         uint16_t type, clazz;
910         AvahiKey *key;
911         
912         if (!dbus_message_get_args(
913                 m, &error,
914                 DBUS_TYPE_INT32, &interface,
915                 DBUS_TYPE_INT32, &protocol,
916                 DBUS_TYPE_STRING, &name,
917                 DBUS_TYPE_UINT16, &clazz,
918                 DBUS_TYPE_UINT16, &type,
919                 DBUS_TYPE_UINT32, &flags,
920                 DBUS_TYPE_INVALID) || !name) {
921             avahi_log_warn("Error parsing Server::RecordBrowserNew message");
922             goto fail;
923         }
924
925         if (!avahi_is_valid_domain_name(name)) 
926             return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_DOMAIN_NAME, NULL);
927
928         if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
929             avahi_log_warn("Too many clients, client request failed.");
930             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
931         }
932
933         if (client->n_objects >= OBJECTS_PER_CLIENT_MAX) {
934             avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
935             return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
936         }
937
938         i = avahi_new(RecordBrowserInfo, 1);
939         i->id = ++client->current_id;
940         i->client = client;
941         i->path = avahi_strdup_printf("/Client%u/RecordBrowser%u", client->id, i->id);
942         AVAHI_LLIST_PREPEND(RecordBrowserInfo, record_browsers, client->record_browsers, i);
943         client->n_objects++;
944
945         key = avahi_key_new(name, clazz, type);
946         assert(key);
947
948         if (!(i->record_browser = avahi_s_record_browser_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, key, (AvahiLookupFlags) flags, avahi_dbus_record_browser_callback, i))) {
949             avahi_key_unref(key);
950             avahi_dbus_record_browser_free(i);
951             return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
952         }
953
954         avahi_key_unref(key);
955         
956         dbus_connection_register_object_path(c, i->path, &vtable, i);
957         return avahi_dbus_respond_path(c, m, i->path);
958     }
959
960     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
961
962 fail:
963     if (dbus_error_is_set(&error))
964         dbus_error_free(&error);
965     
966     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
967 }
968
969 void dbus_protocol_server_state_changed(AvahiServerState state) {
970     DBusMessage *m;
971     int32_t t;
972     const char *e;
973     
974     if (!server)
975         return;
976
977     m = dbus_message_new_signal(AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "StateChanged");
978     t = (int32_t) state;
979
980     if (state == AVAHI_SERVER_COLLISION)
981         e = AVAHI_DBUS_ERR_COLLISION;
982     else if (state == AVAHI_SERVER_FAILURE)
983         e = avahi_error_number_to_dbus(avahi_server_errno(avahi_server));
984     else
985         e = AVAHI_DBUS_ERR_OK;
986     
987     dbus_message_append_args(m, DBUS_TYPE_INT32, &t, DBUS_TYPE_STRING, &e, DBUS_TYPE_INVALID);
988     dbus_connection_send(server->bus, m, NULL);
989     dbus_message_unref(m);
990 }
991
992 int dbus_protocol_setup(const AvahiPoll *poll_api, int _disable_user_service_publishing) {
993     DBusError error;
994
995     static const DBusObjectPathVTable server_vtable = {
996         NULL,
997         msg_server_impl,
998         NULL,
999         NULL,
1000         NULL,
1001         NULL
1002     };
1003
1004     dbus_error_init(&error);
1005
1006     disable_user_service_publishing = _disable_user_service_publishing;
1007
1008     server = avahi_new(Server, 1);
1009     AVAHI_LLIST_HEAD_INIT(Clients, server->clients);
1010     server->current_id = 0;
1011     server->n_clients = 0;
1012
1013     if (!(server->bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
1014         assert(dbus_error_is_set(&error));
1015         avahi_log_error("dbus_bus_get(): %s", error.message);
1016         goto fail;
1017     }
1018
1019     if (avahi_dbus_connection_glue(server->bus, poll_api) < 0) {
1020         avahi_log_error("avahi_dbus_connection_glue() failed");
1021         goto fail;
1022     }
1023
1024     if (dbus_bus_request_name(server->bus, AVAHI_DBUS_NAME, DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT, &error) != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
1025         if (dbus_error_is_set(&error)) {
1026             avahi_log_error("dbus_bus_request_name(): %s", error.message);
1027             goto fail;
1028         }
1029
1030         avahi_log_error("Failed to acquire DBUS name '"AVAHI_DBUS_NAME"'");
1031         goto fail;
1032     }
1033
1034     if (!(dbus_connection_add_filter(server->bus, msg_signal_filter_impl, (void*) poll_api, NULL))) {
1035         avahi_log_error("dbus_connection_add_filter() failed");
1036         goto fail;
1037     }
1038     
1039     dbus_bus_add_match(server->bus, "type='signal',""interface='" DBUS_INTERFACE_DBUS  "'", &error);
1040
1041     if (dbus_error_is_set(&error)) {
1042         avahi_log_error("dbus_bus_add_match(): %s", error.message);
1043         goto fail;
1044     }
1045     
1046     if (!(dbus_connection_register_object_path(server->bus, AVAHI_DBUS_PATH_SERVER, &server_vtable, NULL))) {
1047         avahi_log_error("dbus_connection_register_object_path() failed");
1048         goto fail;
1049     }
1050
1051     return 0;
1052
1053 fail:
1054     if (server->bus) {
1055         dbus_connection_disconnect(server->bus);
1056         dbus_connection_unref(server->bus);
1057     }
1058
1059     if (dbus_error_is_set(&error))
1060         dbus_error_free(&error);
1061         
1062     avahi_free(server);
1063     server = NULL;
1064     return -1;
1065 }
1066
1067 void dbus_protocol_shutdown(void) {
1068
1069     if (server) {
1070     
1071         while (server->clients)
1072             client_free(server->clients);
1073
1074         assert(server->n_clients == 0);
1075
1076         if (server->bus) {
1077             dbus_connection_disconnect(server->bus);
1078             dbus_connection_unref(server->bus);
1079         }
1080
1081         avahi_free(server);
1082         server = NULL;
1083     }
1084 }