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/avahi-malloc.h"
44 #include <avahi-common/dbus-watch-glue.h>
45 #include <avahi-common/alternative.h>
46 #include <avahi-common/error.h>
47 #include <avahi-common/domain.h>
48 #include <avahi-common/timeval.h>
49 
50 #include <avahi-core/log.h>
51 #include <avahi-core/core.h>
52 #include <avahi-core/lookup.h>
53 #include <avahi-core/publish.h>
54 
55 #include "dbus-protocol.h"
56 #include "dbus-util.h"
57 #include "dbus-internal.h"
58 #include "main.h"
59 
60 /* #define VALGRIND_WORKAROUND 1 */
61 
62 #define RECONNECT_MSEC 3000
63 
64 Server *server = NULL;
65 
66 static int dbus_connect(void);
67 static void dbus_disconnect(void);
68 
client_free(Client * c)69 static 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 
client_get(const char * name,int create)117 static 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 
reconnect_callback(AvahiTimeout * t,AVAHI_GCC_UNUSED void * userdata)160 static 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 
msg_signal_filter_impl(AVAHI_GCC_UNUSED DBusConnection * c,DBusMessage * m,AVAHI_GCC_UNUSED void * userdata)174 static 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 
234 fail:
235     if (dbus_error_is_set(&error))
236         dbus_error_free(&error);
237 
238     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
239 }
240 
msg_server_impl(DBusConnection * c,DBusMessage * m,AVAHI_GCC_UNUSED void * userdata)241 static 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 
1004 fail:
1005     if (dbus_error_is_set(&error))
1006         dbus_error_free(&error);
1007 
1008     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1009 }
1010 
dbus_protocol_server_state_changed(AvahiServerState state)1011 void 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 
dbus_connect(void)1040 static 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;
1127 fail:
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 
dbus_disconnect(void)1145 static 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 
dbus_protocol_setup(const AvahiPoll * poll_api,int _disable_user_service_publishing,int _n_clients_max,int _n_objects_per_client_max,int _n_entries_per_entry_group_max,int force)1164 int 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 
1199 fail:
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 
dbus_protocol_shutdown(void)1215 void 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