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