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
66Server *server = NULL;
67
68static int disable_user_service_publishing = 0;
69
70static int dbus_connect(void);
71static void dbus_disconnect(void);
72
73static 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
121static 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 existent 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
164static 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
178static 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("Disconnected 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("Disconnected 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
238fail:
239    if (dbus_error_is_set(&error))
240        dbus_error_free(&error);
241
242    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
243}
244
245static 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
1008fail:
1009    if (dbus_error_is_set(&error))
1010        dbus_error_free(&error);
1011
1012    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1013}
1014
1015void 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
1038static 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;
1125fail:
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
1143static 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
1162int 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
1189fail:
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
1205void 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}
1217