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