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