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