1 /***
2 This file is part of avahi.
3
4 avahi is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 avahi is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12 Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with avahi; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17 USA.
18 ***/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <string.h>
25 #include <sys/ioctl.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <net/if.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <assert.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <stdio.h>
36 #include <signal.h>
37 #include <stdlib.h>
38
39 #include <dbus/dbus.h>
40
41 #include <avahi-common/dbus.h>
42 #include <avahi-common/llist.h>
43 #include <avahi-common/malloc.h>
44 #include <avahi-common/dbus-watch-glue.h>
45 #include <avahi-common/alternative.h>
46 #include <avahi-common/error.h>
47 #include <avahi-common/domain.h>
48 #include <avahi-common/timeval.h>
49
50 #include <avahi-core/log.h>
51 #include <avahi-core/core.h>
52 #include <avahi-core/lookup.h>
53 #include <avahi-core/publish.h>
54
55 #include "dbus-protocol.h"
56 #include "dbus-util.h"
57 #include "dbus-internal.h"
58 #include "main.h"
59
60 /* #define VALGRIND_WORKAROUND 1 */
61
62 #define RECONNECT_MSEC 3000
63
64 Server *server = NULL;
65
66 static int 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
dbus_parsing_error(const char * txt,DBusError * error)174 static DBusHandlerResult dbus_parsing_error(const char *txt, DBusError *error) {
175 avahi_log_warn("%s",txt);
176 if (dbus_error_is_set(error))
177 dbus_error_free(error);
178
179 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
180 }
181
msg_signal_filter_impl(AVAHI_GCC_UNUSED DBusConnection * c,DBusMessage * m,AVAHI_GCC_UNUSED void * userdata)182 static DBusHandlerResult msg_signal_filter_impl(AVAHI_GCC_UNUSED DBusConnection *c, DBusMessage *m, AVAHI_GCC_UNUSED void *userdata) {
183 DBusError error;
184
185 dbus_error_init(&error);
186
187 /* avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s", */
188 /* dbus_message_get_interface(m), */
189 /* dbus_message_get_path(m), */
190 /* dbus_message_get_member(m)); */
191
192 if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) {
193 struct timeval tv;
194
195 if (server->reconnect) {
196 avahi_log_warn("Disconnected from D-Bus, trying to reconnect in %ims...", RECONNECT_MSEC);
197
198 dbus_disconnect();
199
200 avahi_elapse_time(&tv, RECONNECT_MSEC, 0);
201
202 if (server->reconnect_timeout)
203 server->poll_api->timeout_update(server->reconnect_timeout, &tv);
204 else
205 server->reconnect_timeout = server->poll_api->timeout_new(server->poll_api, &tv, reconnect_callback, NULL);
206 } else {
207 avahi_log_warn("Disconnected from D-Bus, exiting.");
208 raise(SIGTERM);
209 }
210
211 return DBUS_HANDLER_RESULT_HANDLED;
212
213 } else if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameAcquired")) {
214 char *name;
215
216 if (!dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) {
217 return dbus_parsing_error("Error parsing NameAcquired message", &error);
218 }
219
220 /* avahi_log_info(__FILE__": name acquired (%s)", name); */
221 return DBUS_HANDLER_RESULT_HANDLED;
222
223 } else if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
224 char *name, *old, *new;
225
226 if (!dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old, DBUS_TYPE_STRING, &new, DBUS_TYPE_INVALID)) {
227 return dbus_parsing_error("Error parsing NameOwnerChanged message", &error);
228 }
229
230 if (!*new) {
231 Client *client;
232
233 if ((client = client_get(name, FALSE))) {
234 avahi_log_debug(__FILE__": client %s vanished.", name);
235 client_free(client);
236 }
237 }
238 }
239
240 if (dbus_error_is_set(&error))
241 dbus_error_free(&error);
242
243 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
244 }
245
dbus_get_host_name(DBusConnection * c,DBusMessage * m,DBusError * error)246 static DBusHandlerResult dbus_get_host_name(DBusConnection *c, DBusMessage *m, DBusError *error) {
247 if (!dbus_message_get_args(m, error, DBUS_TYPE_INVALID)) {
248 return dbus_parsing_error("Error parsing Server::GetHostName message", error);
249 }
250
251 return avahi_dbus_respond_string(c, m, avahi_server_get_host_name(avahi_server));
252 }
253
dbus_set_host_name(DBusConnection * c,DBusMessage * m,DBusError * error)254 static DBusHandlerResult dbus_set_host_name(DBusConnection *c, DBusMessage *m, DBusError *error) {
255 char *name;
256
257 if (!dbus_message_get_args(m, error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) {
258 return dbus_parsing_error("Error parsing Server::SetHostName message", error);
259 }
260
261 if (avahi_server_set_host_name(avahi_server, name) < 0)
262 return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
263
264 avahi_log_info("Changing host name to '%s'.", name);
265
266 return avahi_dbus_respond_ok(c, m);
267 }
268
dbus_get_domain_name(DBusConnection * c,DBusMessage * m,DBusError * error)269 static DBusHandlerResult dbus_get_domain_name(DBusConnection *c, DBusMessage *m, DBusError *error) {
270 if (!dbus_message_get_args(m, error, DBUS_TYPE_INVALID)) {
271 return dbus_parsing_error("Error parsing Server::GetDomainName message", error);
272 }
273
274 return avahi_dbus_respond_string(c, m, avahi_server_get_domain_name(avahi_server));
275 }
276
dbus_get_host_name_fqdn(DBusConnection * c,DBusMessage * m,DBusError * error)277 static DBusHandlerResult dbus_get_host_name_fqdn(DBusConnection *c, DBusMessage *m, DBusError *error) {
278 if (!(dbus_message_get_args(m, error, DBUS_TYPE_INVALID))) {
279 return dbus_parsing_error("Error parsing Server::GetHostNameFqdn message", error);
280 }
281
282 return avahi_dbus_respond_string(c, m, avahi_server_get_host_name_fqdn(avahi_server));
283 }
284
dbus_is_ns_support_available(DBusConnection * c,DBusMessage * m,DBusError * error)285 static DBusHandlerResult dbus_is_ns_support_available(DBusConnection *c, DBusMessage *m, DBusError *error) {
286 if (!(dbus_message_get_args(m, error, DBUS_TYPE_INVALID))) {
287 return dbus_parsing_error("Error parsing Server::IsNSSSupportAvailable message", error);
288 }
289
290 return avahi_dbus_respond_boolean(c, m, nss_support);
291 }
292
dbus_get_version_string(DBusConnection * c,DBusMessage * m,DBusError * error)293 static DBusHandlerResult dbus_get_version_string(DBusConnection *c, DBusMessage *m, DBusError *error) {
294 if (!(dbus_message_get_args(m, error, DBUS_TYPE_INVALID))) {
295 return dbus_parsing_error("Error parsing Server::GetVersionString message", error);
296 }
297
298 return avahi_dbus_respond_string(c, m, PACKAGE_STRING);
299 }
300
dbus_get_api_version(DBusConnection * c,DBusMessage * m,DBusError * error)301 static DBusHandlerResult dbus_get_api_version(DBusConnection *c, DBusMessage *m, DBusError *error) {
302 if (!(dbus_message_get_args(m, error, DBUS_TYPE_INVALID))) {
303 return dbus_parsing_error("Error parsing Server::GetAPIVersion message", error);
304 }
305
306 return avahi_dbus_respond_uint32(c, m, AVAHI_DBUS_API_VERSION);
307 }
308
dbus_get_state(DBusConnection * c,DBusMessage * m,DBusError * error)309 static DBusHandlerResult dbus_get_state(DBusConnection *c, DBusMessage *m, DBusError *error) {
310 AvahiServerState state;
311
312 if (!(dbus_message_get_args(m, error, DBUS_TYPE_INVALID))) {
313 return dbus_parsing_error("Error parsing Server::GetState message", error);
314 }
315
316 state = avahi_server_get_state(avahi_server);
317 return avahi_dbus_respond_int32(c, m, (int32_t) state);
318 }
319
dbus_get_local_service_cookie(DBusConnection * c,DBusMessage * m,DBusError * error)320 static DBusHandlerResult dbus_get_local_service_cookie(DBusConnection *c, DBusMessage *m, DBusError *error) {
321 if (!(dbus_message_get_args(m, error, DBUS_TYPE_INVALID))) {
322 return dbus_parsing_error("Error parsing Server::GetLocalServiceCookie message", error);
323 }
324
325 return avahi_dbus_respond_uint32(c, m, avahi_server_get_local_service_cookie(avahi_server));
326 }
327
dbus_get_net_if_by_index(DBusConnection * c,DBusMessage * m,DBusError * error)328 static DBusHandlerResult dbus_get_net_if_by_index(DBusConnection *c, DBusMessage *m, DBusError *error) {
329 int32_t idx;
330 char name[IF_NAMESIZE];
331
332 if (!(dbus_message_get_args(m, error, DBUS_TYPE_INT32, &idx, DBUS_TYPE_INVALID))) {
333 return dbus_parsing_error("Error parsing Server::GetNetworkInterfaceNameByIndex message", error);
334 }
335
336 #ifdef VALGRIND_WORKAROUND
337 return respond_string(c, m, "blah");
338 #else
339 if ((!if_indextoname(idx, name))) {
340 char txt[256];
341 snprintf(txt, sizeof(txt), "OS Error: %s", strerror(errno));
342 return avahi_dbus_respond_error(c, m, AVAHI_ERR_OS, txt);
343 }
344
345 return avahi_dbus_respond_string(c, m, name);
346 #endif
347 }
348
dbus_get_net_if_by_name(DBusConnection * c,DBusMessage * m,DBusError * error)349 static DBusHandlerResult dbus_get_net_if_by_name(DBusConnection *c, DBusMessage *m, DBusError *error) {
350 char *n;
351 int32_t idx;
352
353 if (!(dbus_message_get_args(m, error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n) {
354 return dbus_parsing_error("Error parsing Server::GetNetworkInterfaceIndexByName message", error);
355 }
356
357 #ifdef VALGRIND_WORKAROUND
358 return respond_int32(c, m, 1);
359 #else
360 if (!(idx = if_nametoindex(n))) {
361 char txt[256];
362 snprintf(txt, sizeof(txt), "OS Error: %s", strerror(errno));
363 return avahi_dbus_respond_error(c, m, AVAHI_ERR_OS, txt);
364 }
365
366 return avahi_dbus_respond_int32(c, m, idx);
367 #endif
368 }
369
dbus_get_alternative_host_name(DBusConnection * c,DBusMessage * m,DBusError * error)370 static DBusHandlerResult dbus_get_alternative_host_name(DBusConnection *c, DBusMessage *m, DBusError *error) {
371 char *n, * t;
372
373 if (!(dbus_message_get_args(m, error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n) {
374 return dbus_parsing_error("Error parsing Server::GetAlternativeHostName message", error);
375 }
376
377 t = avahi_alternative_host_name(n);
378 avahi_dbus_respond_string(c, m, t);
379 avahi_free(t);
380
381 return DBUS_HANDLER_RESULT_HANDLED;
382 }
383
dbus_get_alternative_service_name(DBusConnection * c,DBusMessage * m,DBusError * error)384 static DBusHandlerResult dbus_get_alternative_service_name(DBusConnection *c, DBusMessage *m, DBusError *error) {
385 char *n, *t;
386
387 if (!(dbus_message_get_args(m, error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n) {
388 return dbus_parsing_error("Error parsing Server::GetAlternativeServiceName message", error);
389 }
390
391 t = avahi_alternative_service_name(n);
392 avahi_dbus_respond_string(c, m, t);
393 avahi_free(t);
394
395 return DBUS_HANDLER_RESULT_HANDLED;
396 }
397
dbus_create_new_entry_group(DBusConnection * c,DBusMessage * m,DBusError * error)398 static DBusHandlerResult dbus_create_new_entry_group(DBusConnection *c, DBusMessage *m, DBusError *error) {
399 Client *client;
400 EntryGroupInfo *i;
401 static const DBusObjectPathVTable vtable = {
402 NULL,
403 avahi_dbus_msg_entry_group_impl,
404 NULL,
405 NULL,
406 NULL,
407 NULL
408 };
409
410 if (!dbus_message_get_args(m, error, DBUS_TYPE_INVALID)) {
411 return dbus_parsing_error("Error parsing Server::EntryGroupNew message", error);
412 }
413
414 if (server->disable_user_service_publishing)
415 return avahi_dbus_respond_error(c, m, AVAHI_ERR_NOT_PERMITTED, NULL);
416
417 if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
418 avahi_log_warn("Too many clients, client request failed.");
419 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
420 }
421
422 if (client->n_objects >= server->n_objects_per_client_max) {
423 avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
424 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
425 }
426
427 i = avahi_new(EntryGroupInfo, 1);
428 i->id = ++client->current_id;
429 i->client = client;
430 i->path = NULL;
431 i->n_entries = 0;
432 AVAHI_LLIST_PREPEND(EntryGroupInfo, entry_groups, client->entry_groups, i);
433 client->n_objects++;
434
435 if (!(i->entry_group = avahi_s_entry_group_new(avahi_server, avahi_dbus_entry_group_callback, i))) {
436 avahi_dbus_entry_group_free(i);
437 return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
438 }
439
440 i->path = avahi_strdup_printf("/Client%u/EntryGroup%u", client->id, i->id);
441 dbus_connection_register_object_path(c, i->path, &vtable, i);
442 return avahi_dbus_respond_path(c, m, i->path);
443 }
444
dbus_prepare_domain_browser_object(DomainBrowserInfo ** dbi,DBusConnection * c,DBusMessage * m,DBusError * error)445 static DBusHandlerResult dbus_prepare_domain_browser_object(DomainBrowserInfo **dbi, DBusConnection *c, DBusMessage *m, DBusError *error) {
446 Client *client;
447 DomainBrowserInfo *i;
448 static const DBusObjectPathVTable vtable = {
449 NULL,
450 avahi_dbus_msg_domain_browser_impl,
451 NULL,
452 NULL,
453 NULL,
454 NULL
455 };
456 int32_t interface, protocol, type;
457 uint32_t flags;
458 char *domain;
459
460 if (!dbus_message_get_args(
461 m, error,
462 DBUS_TYPE_INT32, &interface,
463 DBUS_TYPE_INT32, &protocol,
464 DBUS_TYPE_STRING, &domain,
465 DBUS_TYPE_INT32, &type,
466 DBUS_TYPE_UINT32, &flags,
467 DBUS_TYPE_INVALID) || type < 0 || type >= AVAHI_DOMAIN_BROWSER_MAX) {
468 return dbus_parsing_error("Error parsing Server::DomainBrowserNew message", error);
469 }
470
471 if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
472 avahi_log_warn("Too many clients, client request failed.");
473 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
474 }
475
476 if (client->n_objects >= server->n_objects_per_client_max) {
477 avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
478 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
479 }
480
481 if (!*domain)
482 domain = NULL;
483
484 i = avahi_new(DomainBrowserInfo, 1);
485 i->id = ++client->current_id;
486 i->client = client;
487 i->path = NULL;
488 i->delay_timeout = NULL;
489 AVAHI_LLIST_PREPEND(DomainBrowserInfo, domain_browsers, client->domain_browsers, i);
490 client->n_objects++;
491
492 if (!(i->domain_browser = avahi_s_domain_browser_prepare(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, domain, (AvahiDomainBrowserType) type, (AvahiLookupFlags) flags, avahi_dbus_domain_browser_callback, i))) {
493 avahi_dbus_domain_browser_free(i);
494 return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
495 }
496
497 i->path = avahi_strdup_printf("/Client%u/DomainBrowser%u", client->id, i->id);
498 dbus_connection_register_object_path(c, i->path, &vtable, i);
499 *dbi = i;
500 return avahi_dbus_respond_path(c, m, i->path);
501 }
502
503
dbus_prepare_service_type_browser_object(ServiceTypeBrowserInfo ** stbi,DBusConnection * c,DBusMessage * m,DBusError * error)504 static DBusHandlerResult dbus_prepare_service_type_browser_object(ServiceTypeBrowserInfo **stbi, DBusConnection *c, DBusMessage *m, DBusError *error) {
505 Client *client;
506 ServiceTypeBrowserInfo *i;
507 static const DBusObjectPathVTable vtable = {
508 NULL,
509 avahi_dbus_msg_service_type_browser_impl,
510 NULL,
511 NULL,
512 NULL,
513 NULL
514 };
515 int32_t interface, protocol;
516 uint32_t flags;
517 char *domain;
518
519 if (!dbus_message_get_args(
520 m, error,
521 DBUS_TYPE_INT32, &interface,
522 DBUS_TYPE_INT32, &protocol,
523 DBUS_TYPE_STRING, &domain,
524 DBUS_TYPE_UINT32, &flags,
525 DBUS_TYPE_INVALID)) {
526 return dbus_parsing_error("Error parsing Server::ServiceTypeBrowserNew message", error);
527 }
528
529 if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
530 avahi_log_warn("Too many clients, client request failed.");
531 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
532 }
533
534 if (client->n_objects >= server->n_objects_per_client_max) {
535 avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
536 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
537 }
538
539 if (!*domain)
540 domain = NULL;
541
542 i = avahi_new(ServiceTypeBrowserInfo, 1);
543 i->id = ++client->current_id;
544 i->client = client;
545 i->path = NULL;
546 i->delay_timeout = NULL;
547 AVAHI_LLIST_PREPEND(ServiceTypeBrowserInfo, service_type_browsers, client->service_type_browsers, i);
548 client->n_objects++;
549
550 if (!(i->service_type_browser = avahi_s_service_type_browser_prepare(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, domain, (AvahiLookupFlags) flags, avahi_dbus_service_type_browser_callback, i))) {
551 avahi_dbus_service_type_browser_free(i);
552 return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
553 }
554
555 i->path = avahi_strdup_printf("/Client%u/ServiceTypeBrowser%u", client->id, i->id);
556 dbus_connection_register_object_path(c, i->path, &vtable, i);
557 *stbi = i;
558 return avahi_dbus_respond_path(c, m, i->path);
559 }
560
561
dbus_prepare_service_browser_object(ServiceBrowserInfo ** sbi,DBusConnection * c,DBusMessage * m,DBusError * error)562 static DBusHandlerResult dbus_prepare_service_browser_object(ServiceBrowserInfo **sbi, DBusConnection *c, DBusMessage *m, DBusError *error) {
563 Client *client;
564 ServiceBrowserInfo *i;
565 static const DBusObjectPathVTable vtable = {
566 NULL,
567 avahi_dbus_msg_service_browser_impl,
568 NULL,
569 NULL,
570 NULL,
571 NULL
572 };
573 int32_t interface, protocol;
574 uint32_t flags;
575 char *domain, *type;
576
577 if (!dbus_message_get_args(
578 m, error,
579 DBUS_TYPE_INT32, &interface,
580 DBUS_TYPE_INT32, &protocol,
581 DBUS_TYPE_STRING, &type,
582 DBUS_TYPE_STRING, &domain,
583 DBUS_TYPE_UINT32, &flags,
584 DBUS_TYPE_INVALID) || !type) {
585 return dbus_parsing_error("Error parsing Server::ServiceBrowserNew message", error);
586 }
587
588 if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
589 avahi_log_warn("Too many clients, client request failed.");
590 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
591 }
592
593 if (client->n_objects >= server->n_objects_per_client_max) {
594 avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
595 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
596 }
597
598 if (!*domain)
599 domain = NULL;
600
601 i = avahi_new(ServiceBrowserInfo, 1);
602 i->id = ++client->current_id;
603 i->client = client;
604 i->path = NULL;
605 i->delay_timeout = NULL;
606 AVAHI_LLIST_PREPEND(ServiceBrowserInfo, service_browsers, client->service_browsers, i);
607 client->n_objects++;
608
609 if (!(i->service_browser = avahi_s_service_browser_prepare(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, type, domain, (AvahiLookupFlags) flags, avahi_dbus_service_browser_callback, i))) {
610 avahi_dbus_service_browser_free(i);
611 return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
612 }
613
614 i->path = avahi_strdup_printf("/Client%u/ServiceBrowser%u", client->id, i->id);
615 dbus_connection_register_object_path(c, i->path, &vtable, i);
616 *sbi = i;
617 return avahi_dbus_respond_path(c, m, i->path);
618 }
619
dbus_create_sync_service_resolver_object(DBusConnection * c,DBusMessage * m,DBusError * error)620 static DBusHandlerResult dbus_create_sync_service_resolver_object(DBusConnection *c, DBusMessage *m, DBusError *error) {
621 Client *client;
622 int32_t interface, protocol, aprotocol;
623 uint32_t flags;
624 char *name, *type, *domain;
625 SyncServiceResolverInfo *i;
626
627 if (!dbus_message_get_args(
628 m, error,
629 DBUS_TYPE_INT32, &interface,
630 DBUS_TYPE_INT32, &protocol,
631 DBUS_TYPE_STRING, &name,
632 DBUS_TYPE_STRING, &type,
633 DBUS_TYPE_STRING, &domain,
634 DBUS_TYPE_INT32, &aprotocol,
635 DBUS_TYPE_UINT32, &flags,
636 DBUS_TYPE_INVALID) || !type) {
637 return dbus_parsing_error("Error parsing Server::ResolveService message", error);
638 }
639
640 if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
641 avahi_log_warn("Too many clients, client request failed.");
642 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
643 }
644
645 if (client->n_objects >= server->n_objects_per_client_max) {
646 avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
647 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
648 }
649
650 if (!*domain)
651 domain = NULL;
652
653 if (!*name)
654 name = NULL;
655
656 i = avahi_new(SyncServiceResolverInfo, 1);
657 i->client = client;
658 i->message = dbus_message_ref(m);
659 AVAHI_LLIST_PREPEND(SyncServiceResolverInfo, sync_service_resolvers, client->sync_service_resolvers, i);
660 client->n_objects++;
661
662 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))) {
663 avahi_dbus_sync_service_resolver_free(i);
664 return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
665 }
666
667 return DBUS_HANDLER_RESULT_HANDLED;
668 }
669
dbus_prepare_async_service_resolver_object(AsyncServiceResolverInfo ** sri,DBusConnection * c,DBusMessage * m,DBusError * error)670 static DBusHandlerResult dbus_prepare_async_service_resolver_object(AsyncServiceResolverInfo **sri, DBusConnection *c, DBusMessage *m, DBusError *error) {
671 Client *client;
672 int32_t interface, protocol, aprotocol;
673 uint32_t flags;
674 char *name, *type, *domain;
675 AsyncServiceResolverInfo *i;
676 static const DBusObjectPathVTable vtable = {
677 NULL,
678 avahi_dbus_msg_async_service_resolver_impl,
679 NULL,
680 NULL,
681 NULL,
682 NULL
683 };
684
685 if (!dbus_message_get_args(
686 m, error,
687 DBUS_TYPE_INT32, &interface,
688 DBUS_TYPE_INT32, &protocol,
689 DBUS_TYPE_STRING, &name,
690 DBUS_TYPE_STRING, &type,
691 DBUS_TYPE_STRING, &domain,
692 DBUS_TYPE_INT32, &aprotocol,
693 DBUS_TYPE_UINT32, &flags,
694 DBUS_TYPE_INVALID) || !type) {
695 return dbus_parsing_error("Error parsing Server::ServiceResolverNew message", error);
696 }
697
698 if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
699 avahi_log_warn(__FILE__": Too many clients, client request failed.");
700 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
701 }
702
703 if (client->n_objects >= server->n_objects_per_client_max) {
704 avahi_log_warn(__FILE__": Too many objects for client '%s', client request failed.", client->name);
705 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
706 }
707
708 if (!*domain)
709 domain = NULL;
710
711 if (!*name)
712 name = NULL;
713
714 i = avahi_new(AsyncServiceResolverInfo, 1);
715 i->id = ++client->current_id;
716 i->client = client;
717 i->path = NULL;
718 i->delay_timeout = NULL;
719 AVAHI_LLIST_PREPEND(AsyncServiceResolverInfo, async_service_resolvers, client->async_service_resolvers, i);
720 client->n_objects++;
721
722 if (!(i->service_resolver = avahi_s_service_resolver_prepare(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, type, domain, (AvahiProtocol) aprotocol, (AvahiLookupFlags) flags, avahi_dbus_async_service_resolver_callback, i))) {
723 avahi_dbus_async_service_resolver_free(i);
724 return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
725 }
726
727 /* avahi_log_debug(__FILE__": [%s], new service resolver for <%s.%s.%s>", i->path, name, type, domain); */
728
729 i->path = avahi_strdup_printf("/Client%u/ServiceResolver%u", client->id, i->id);
730 dbus_connection_register_object_path(c, i->path, &vtable, i);
731 *sri = i;
732 return avahi_dbus_respond_path(c, m, i->path);
733 }
734
dbus_create_sync_host_name_resolver_object(DBusConnection * c,DBusMessage * m,DBusError * error)735 static DBusHandlerResult dbus_create_sync_host_name_resolver_object(DBusConnection *c, DBusMessage *m, DBusError *error) {
736 Client *client;
737 int32_t interface, protocol, aprotocol;
738 uint32_t flags;
739 char *name;
740 SyncHostNameResolverInfo *i;
741
742 if (!dbus_message_get_args(
743 m, error,
744 DBUS_TYPE_INT32, &interface,
745 DBUS_TYPE_INT32, &protocol,
746 DBUS_TYPE_STRING, &name,
747 DBUS_TYPE_INT32, &aprotocol,
748 DBUS_TYPE_UINT32, &flags,
749 DBUS_TYPE_INVALID) || !name) {
750 return dbus_parsing_error("Error parsing Server::ResolveHostName message", error);
751 }
752
753 if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
754 avahi_log_warn("Too many clients, client request failed.");
755 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
756 }
757
758 if (client->n_objects >= server->n_objects_per_client_max) {
759 avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
760 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
761 }
762
763 i = avahi_new(SyncHostNameResolverInfo, 1);
764 i->client = client;
765 i->message = dbus_message_ref(m);
766 AVAHI_LLIST_PREPEND(SyncHostNameResolverInfo, sync_host_name_resolvers, client->sync_host_name_resolvers, i);
767 client->n_objects++;
768
769 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))) {
770 avahi_dbus_sync_host_name_resolver_free(i);
771 return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
772 }
773
774 return DBUS_HANDLER_RESULT_HANDLED;
775 }
776
dbus_prepare_async_host_name_resolver_object(AsyncHostNameResolverInfo ** hri,DBusConnection * c,DBusMessage * m,DBusError * error)777 static DBusHandlerResult dbus_prepare_async_host_name_resolver_object(AsyncHostNameResolverInfo **hri, DBusConnection *c, DBusMessage *m, DBusError *error) {
778 Client *client;
779 int32_t interface, protocol, aprotocol;
780 uint32_t flags;
781 char *name;
782 AsyncHostNameResolverInfo *i;
783 static const DBusObjectPathVTable vtable = {
784 NULL,
785 avahi_dbus_msg_async_host_name_resolver_impl,
786 NULL,
787 NULL,
788 NULL,
789 NULL
790 };
791
792 if (!dbus_message_get_args(
793 m, error,
794 DBUS_TYPE_INT32, &interface,
795 DBUS_TYPE_INT32, &protocol,
796 DBUS_TYPE_STRING, &name,
797 DBUS_TYPE_INT32, &aprotocol,
798 DBUS_TYPE_UINT32, &flags,
799 DBUS_TYPE_INVALID) || !name) {
800 return dbus_parsing_error("Error parsing Server::HostNameResolverNew message", error);
801 }
802
803 if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
804 avahi_log_warn(__FILE__": Too many clients, client request failed.");
805 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
806 }
807
808 if (client->n_objects >= server->n_objects_per_client_max) {
809 avahi_log_warn(__FILE__": Too many objects for client '%s', client request failed.", client->name);
810 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
811 }
812
813 i = avahi_new(AsyncHostNameResolverInfo, 1);
814 i->id = ++client->current_id;
815 i->client = client;
816 i->path = NULL;
817 i->delay_timeout = NULL;
818 AVAHI_LLIST_PREPEND(AsyncHostNameResolverInfo, async_host_name_resolvers, client->async_host_name_resolvers, i);
819 client->n_objects++;
820
821 if (!(i->host_name_resolver = avahi_s_host_name_resolver_prepare(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, aprotocol, (AvahiLookupFlags) flags, avahi_dbus_async_host_name_resolver_callback, i))) {
822 avahi_dbus_async_host_name_resolver_free(i);
823 return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
824 }
825
826 i->path = avahi_strdup_printf("/Client%u/HostNameResolver%u", client->id, i->id);
827 dbus_connection_register_object_path(c, i->path, &vtable, i);
828 *hri = i;
829 return avahi_dbus_respond_path(c, m, i->path);
830 }
831
dbus_create_sync_address_resolver_object(DBusConnection * c,DBusMessage * m,DBusError * error)832 static DBusHandlerResult dbus_create_sync_address_resolver_object(DBusConnection *c, DBusMessage *m, DBusError *error) {
833 Client *client;
834 int32_t interface, protocol;
835 uint32_t flags;
836 char *address;
837 SyncAddressResolverInfo *i;
838 AvahiAddress a;
839
840 if (!dbus_message_get_args(
841 m, error,
842 DBUS_TYPE_INT32, &interface,
843 DBUS_TYPE_INT32, &protocol,
844 DBUS_TYPE_STRING, &address,
845 DBUS_TYPE_UINT32, &flags,
846 DBUS_TYPE_INVALID) || !address) {
847 return dbus_parsing_error("Error parsing Server::ResolveAddress message", error);
848 }
849
850 if (!avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a))
851 return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_ADDRESS, NULL);
852
853 if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
854 avahi_log_warn("Too many clients, client request failed.");
855 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
856 }
857
858 if (client->n_objects >= server->n_objects_per_client_max) {
859 avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
860 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
861 }
862
863 i = avahi_new(SyncAddressResolverInfo, 1);
864 i->client = client;
865 i->message = dbus_message_ref(m);
866 AVAHI_LLIST_PREPEND(SyncAddressResolverInfo, sync_address_resolvers, client->sync_address_resolvers, i);
867 client->n_objects++;
868
869 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))) {
870 avahi_dbus_sync_address_resolver_free(i);
871 return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
872 }
873
874 return DBUS_HANDLER_RESULT_HANDLED;
875 }
876
dbus_prepare_async_address_resolver_object(AsyncAddressResolverInfo ** ari,DBusConnection * c,DBusMessage * m,DBusError * error)877 static DBusHandlerResult dbus_prepare_async_address_resolver_object(AsyncAddressResolverInfo **ari, DBusConnection *c, DBusMessage *m, DBusError *error) {
878 Client *client;
879 int32_t interface, protocol;
880 uint32_t flags;
881 char *address;
882 AsyncAddressResolverInfo *i;
883 AvahiAddress a;
884 static const DBusObjectPathVTable vtable = {
885 NULL,
886 avahi_dbus_msg_async_address_resolver_impl,
887 NULL,
888 NULL,
889 NULL,
890 NULL
891 };
892
893 if (!dbus_message_get_args(
894 m, error,
895 DBUS_TYPE_INT32, &interface,
896 DBUS_TYPE_INT32, &protocol,
897 DBUS_TYPE_STRING, &address,
898 DBUS_TYPE_UINT32, &flags,
899 DBUS_TYPE_INVALID) || !address) {
900 return dbus_parsing_error("Error parsing Server::AddressResolverNew message", error);
901 }
902
903 if (!avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a))
904 return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_ADDRESS, NULL);
905
906 if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
907 avahi_log_warn(__FILE__": Too many clients, client request failed.");
908 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
909 }
910
911 if (client->n_objects >= server->n_objects_per_client_max) {
912 avahi_log_warn(__FILE__": Too many objects for client '%s', client request failed.", client->name);
913 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
914 }
915
916 i = avahi_new(AsyncAddressResolverInfo, 1);
917 i->id = ++client->current_id;
918 i->client = client;
919 i->path = NULL;
920 i->delay_timeout = NULL;
921 AVAHI_LLIST_PREPEND(AsyncAddressResolverInfo, async_address_resolvers, client->async_address_resolvers, i);
922 client->n_objects++;
923
924 if (!(i->address_resolver = avahi_s_address_resolver_prepare(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, &a, (AvahiLookupFlags) flags, avahi_dbus_async_address_resolver_callback, i))) {
925 avahi_dbus_async_address_resolver_free(i);
926 return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
927 }
928
929 i->path = avahi_strdup_printf("/Client%u/AddressResolver%u", client->id, i->id);
930 dbus_connection_register_object_path(c, i->path, &vtable, i);
931 *ari = i;
932 return avahi_dbus_respond_path(c, m, i->path);
933 }
934
dbus_prepare_record_browser_object(RecordBrowserInfo ** rbi,DBusConnection * c,DBusMessage * m,DBusError * error)935 static DBusHandlerResult dbus_prepare_record_browser_object(RecordBrowserInfo **rbi, DBusConnection *c, DBusMessage *m, DBusError *error) {
936 Client *client;
937 RecordBrowserInfo *i;
938 static const DBusObjectPathVTable vtable = {
939 NULL,
940 avahi_dbus_msg_record_browser_impl,
941 NULL,
942 NULL,
943 NULL,
944 NULL
945 };
946 int32_t interface, protocol;
947 uint32_t flags;
948 char *name;
949 uint16_t type, clazz;
950 AvahiKey *key;
951
952 if (!dbus_message_get_args(
953 m, error,
954 DBUS_TYPE_INT32, &interface,
955 DBUS_TYPE_INT32, &protocol,
956 DBUS_TYPE_STRING, &name,
957 DBUS_TYPE_UINT16, &clazz,
958 DBUS_TYPE_UINT16, &type,
959 DBUS_TYPE_UINT32, &flags,
960 DBUS_TYPE_INVALID) || !name) {
961 return dbus_parsing_error("Error parsing Server::RecordBrowserNew message", error);
962 }
963
964 if (!avahi_is_valid_domain_name(name))
965 return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_DOMAIN_NAME, NULL);
966
967 if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
968 avahi_log_warn("Too many clients, client request failed.");
969 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
970 }
971
972 if (client->n_objects >= server->n_objects_per_client_max) {
973 avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
974 return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
975 }
976
977 i = avahi_new(RecordBrowserInfo, 1);
978 i->id = ++client->current_id;
979 i->client = client;
980 i->path = NULL;
981 i->delay_timeout = NULL;
982 AVAHI_LLIST_PREPEND(RecordBrowserInfo, record_browsers, client->record_browsers, i);
983 client->n_objects++;
984
985 key = avahi_key_new(name, clazz, type);
986 assert(key);
987
988 if (!(i->record_browser = avahi_s_record_browser_prepare(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, key, (AvahiLookupFlags) flags, avahi_dbus_record_browser_callback, i))) {
989 avahi_key_unref(key);
990 avahi_dbus_record_browser_free(i);
991 return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
992 }
993
994 avahi_key_unref(key);
995
996 i->path = avahi_strdup_printf("/Client%u/RecordBrowser%u", client->id, i->id);
997 dbus_connection_register_object_path(c, i->path, &vtable, i);
998 *rbi = i;
999 return avahi_dbus_respond_path(c, m, i->path);
1000 }
1001
dbus_select_common_methods(DBusConnection * c,DBusMessage * m,AVAHI_GCC_UNUSED void * userdata,const char * iface,DBusError * error)1002 static DBusHandlerResult dbus_select_common_methods(DBusConnection *c, DBusMessage *m, AVAHI_GCC_UNUSED void *userdata, const char *iface, DBusError *error) {
1003 if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
1004 return avahi_dbus_handle_introspect(c, m, "org.freedesktop.Avahi.Server.xml");
1005
1006 else if (dbus_message_is_method_call(m, iface, "GetHostName")) {
1007 return dbus_get_host_name(c, m, error);
1008
1009 } else if (dbus_message_is_method_call(m, iface, "SetHostName")) {
1010 return dbus_set_host_name(c, m, error);
1011
1012 } else if (dbus_message_is_method_call(m, iface, "GetDomainName")) {
1013 return dbus_get_domain_name(c, m, error);
1014
1015 } else if (dbus_message_is_method_call(m, iface, "GetHostNameFqdn")) {
1016 return dbus_get_host_name_fqdn(c, m, error);
1017
1018 } else if (dbus_message_is_method_call(m, iface, "IsNSSSupportAvailable")) {
1019 return dbus_is_ns_support_available(c, m, error);
1020
1021 } else if (dbus_message_is_method_call(m, iface, "GetVersionString")) {
1022 return dbus_get_version_string(c, m, error);
1023
1024 } else if (dbus_message_is_method_call(m, iface, "GetAPIVersion")) {
1025 return dbus_get_api_version(c, m, error);
1026
1027 } else if (dbus_message_is_method_call(m, iface, "GetState")) {
1028 return dbus_get_state(c, m, error);
1029
1030 } else if (dbus_message_is_method_call(m, iface, "GetLocalServiceCookie")) {
1031 return dbus_get_local_service_cookie(c, m, error);
1032
1033 } else if (dbus_message_is_method_call(m, iface, "GetNetworkInterfaceNameByIndex")) {
1034 return dbus_get_net_if_by_index(c, m, error);
1035
1036 } else if (dbus_message_is_method_call(m, iface, "GetNetworkInterfaceIndexByName")) {
1037 return dbus_get_net_if_by_name(c, m, error);
1038
1039 } else if (dbus_message_is_method_call(m, iface, "GetAlternativeHostName")) {
1040 return dbus_get_alternative_host_name(c, m, error);
1041
1042 } else if (dbus_message_is_method_call(m, iface, "GetAlternativeServiceName")) {
1043 return dbus_get_alternative_service_name(c, m, error);
1044
1045 } else if (dbus_message_is_method_call(m, iface, "EntryGroupNew")) {
1046 return dbus_create_new_entry_group(c, m, error);
1047
1048 } else if (dbus_message_is_method_call(m, iface, "ResolveHostName")) {
1049 return dbus_create_sync_host_name_resolver_object(c, m, error);
1050
1051 } else if (dbus_message_is_method_call(m, iface, "ResolveAddress")) {
1052 return dbus_create_sync_address_resolver_object(c, m, error);
1053
1054 } else if (dbus_message_is_method_call(m, iface, "ResolveService")) {
1055 return dbus_create_sync_service_resolver_object(c, m, error);
1056 }
1057
1058 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1059 }
1060
CREATE_DBUS_DELAY_FUNC(DomainBrowserInfo,domain_browser,avahi_s_domain_browser_start)1061 CREATE_DBUS_DELAY_FUNC(DomainBrowserInfo, domain_browser, avahi_s_domain_browser_start)
1062 CREATE_DBUS_DELAY_FUNC(ServiceTypeBrowserInfo, service_type_browser, avahi_s_service_type_browser_start)
1063 CREATE_DBUS_DELAY_FUNC(ServiceBrowserInfo, service_browser, avahi_s_service_browser_start)
1064 CREATE_DBUS_DELAY_FUNC(AsyncServiceResolverInfo, service_resolver, avahi_s_service_resolver_start)
1065 CREATE_DBUS_DELAY_FUNC(AsyncHostNameResolverInfo, host_name_resolver, avahi_s_host_name_resolver_start)
1066 CREATE_DBUS_DELAY_FUNC(AsyncAddressResolverInfo, address_resolver, avahi_s_address_resolver_start)
1067 CREATE_DBUS_DELAY_FUNC(RecordBrowserInfo, record_browser, avahi_s_record_browser_start_query)
1068
1069 static DBusHandlerResult dbus_select_browser(DBusConnection *c, DBusMessage *m, AVAHI_GCC_UNUSED void *userdata, const char *iface, DBusError *error) {
1070 DBusHandlerResult r;
1071 const AvahiPoll *poll_api = NULL;
1072 struct timeval tv;
1073
1074 poll_api = avahi_simple_poll_get(simple_poll_api);
1075 avahi_elapse_time(&tv, DEFAULT_START_DELAY_MS, 0);
1076
1077 if (dbus_message_is_method_call(m, iface, "DomainBrowserNew")) {
1078 DomainBrowserInfo *db = NULL;
1079 r = dbus_prepare_domain_browser_object(&db, c, m, error);
1080 if (db)
1081 db->delay_timeout = poll_api->timeout_new(poll_api, &tv, GET_DBUS_DELAY_FUNC(DomainBrowserInfo, domain_browser), db);
1082 return r;
1083
1084 } else if (dbus_message_is_method_call(m, iface, "ServiceTypeBrowserNew")) {
1085 ServiceTypeBrowserInfo *stbi = NULL;
1086 r = dbus_prepare_service_type_browser_object(&stbi, c, m, error);
1087 if (stbi)
1088 stbi->delay_timeout = poll_api->timeout_new(poll_api, &tv, GET_DBUS_DELAY_FUNC(ServiceTypeBrowserInfo, service_type_browser), stbi);
1089 return r;
1090
1091 } else if (dbus_message_is_method_call(m, iface, "ServiceBrowserNew")) {
1092 ServiceBrowserInfo *sbi = NULL;
1093 r = dbus_prepare_service_browser_object(&sbi, c, m, error);
1094 if (sbi)
1095 sbi->delay_timeout = poll_api->timeout_new(poll_api, &tv, GET_DBUS_DELAY_FUNC(ServiceBrowserInfo, service_browser), sbi);
1096 return r;
1097
1098 } else if (dbus_message_is_method_call(m, iface, "ServiceResolverNew")) {
1099 AsyncServiceResolverInfo *sri = NULL;
1100 r = dbus_prepare_async_service_resolver_object(&sri, c, m, error);
1101 if (sri)
1102 sri->delay_timeout = poll_api->timeout_new(poll_api, &tv, GET_DBUS_DELAY_FUNC(AsyncServiceResolverInfo, service_resolver), sri);
1103 return r;
1104
1105 } else if (dbus_message_is_method_call(m, iface, "HostNameResolverNew")) {
1106 AsyncHostNameResolverInfo *hri = NULL;
1107 r = dbus_prepare_async_host_name_resolver_object(&hri, c, m, error);
1108 if (hri)
1109 hri->delay_timeout = poll_api->timeout_new(poll_api, &tv, GET_DBUS_DELAY_FUNC(AsyncHostNameResolverInfo, host_name_resolver), hri);
1110 return r;
1111
1112 } else if (dbus_message_is_method_call(m, iface, "AddressResolverNew")) {
1113 AsyncAddressResolverInfo *ari = NULL;
1114 r = dbus_prepare_async_address_resolver_object(&ari, c, m, error);
1115 if (ari)
1116 ari->delay_timeout = poll_api->timeout_new(poll_api, &tv, GET_DBUS_DELAY_FUNC(AsyncAddressResolverInfo, address_resolver), ari);
1117 return r;
1118
1119 } else if (dbus_message_is_method_call(m, iface, "RecordBrowserNew")) {
1120 RecordBrowserInfo *rbi = NULL;
1121 r = dbus_prepare_record_browser_object(&rbi, c, m, error);
1122 if (rbi)
1123 rbi->delay_timeout = poll_api->timeout_new(poll_api, &tv, GET_DBUS_DELAY_FUNC(RecordBrowserInfo, record_browser), rbi);
1124 return r;
1125 }
1126
1127 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1128 }
1129
dbus_select_prepare_browser(DBusConnection * c,DBusMessage * m,AVAHI_GCC_UNUSED void * userdata,const char * iface,DBusError * error)1130 static DBusHandlerResult dbus_select_prepare_browser(DBusConnection *c, DBusMessage *m, AVAHI_GCC_UNUSED void *userdata, const char *iface, DBusError *error) {
1131 DBusHandlerResult r;
1132
1133 if (dbus_message_is_method_call(m, iface, "DomainBrowserPrepare")) {
1134 DomainBrowserInfo *db = NULL;
1135 r = dbus_prepare_domain_browser_object(&db, c, m, error);
1136 return r;
1137
1138 } else if (dbus_message_is_method_call(m, iface, "ServiceTypeBrowserPrepare")) {
1139 ServiceTypeBrowserInfo *stbi = NULL;
1140 r = dbus_prepare_service_type_browser_object(&stbi, c, m, error);
1141 return r;
1142
1143 } else if (dbus_message_is_method_call(m, iface, "ServiceBrowserPrepare")) {
1144 ServiceBrowserInfo *sbi = NULL;
1145 r = dbus_prepare_service_browser_object(&sbi, c, m, error);
1146 return r;
1147
1148 } else if (dbus_message_is_method_call(m, iface, "ServiceResolverPrepare")) {
1149 AsyncServiceResolverInfo *sri = NULL;
1150 r = dbus_prepare_async_service_resolver_object(&sri, c, m, error);
1151 return r;
1152
1153 } else if (dbus_message_is_method_call(m, iface, "HostNameResolverPrepare")) {
1154 AsyncHostNameResolverInfo *hri = NULL;
1155 r = dbus_prepare_async_host_name_resolver_object(&hri, c, m, error);
1156 return r;
1157
1158 } else if (dbus_message_is_method_call(m, iface, "AddressResolverPrepare")) {
1159 AsyncAddressResolverInfo *ari = NULL;
1160 r = dbus_prepare_async_address_resolver_object(&ari, c, m, error);
1161 return r;
1162
1163 } else if (dbus_message_is_method_call(m, iface, "RecordBrowserPrepare")) {
1164 RecordBrowserInfo *rbi = NULL;
1165 r = dbus_prepare_record_browser_object(&rbi, c, m, error);
1166 return r;
1167 }
1168
1169 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1170 }
1171
msg_server_impl(DBusConnection * c,DBusMessage * m,AVAHI_GCC_UNUSED void * userdata)1172 static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAHI_GCC_UNUSED void *userdata) {
1173 DBusHandlerResult r;
1174 DBusError error;
1175
1176 dbus_error_init(&error);
1177
1178 avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s",
1179 dbus_message_get_interface(m),
1180 dbus_message_get_path(m),
1181 dbus_message_get_member(m));
1182
1183 r = dbus_select_common_methods(c,m,userdata, AVAHI_DBUS_INTERFACE_SERVER, &error);
1184 if( r != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
1185 return r;
1186
1187 r = dbus_select_browser(c,m,userdata, AVAHI_DBUS_INTERFACE_SERVER, &error);
1188 if( r != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
1189 return r;
1190
1191 r = dbus_select_common_methods(c,m,userdata, AVAHI_DBUS_INTERFACE_SERVER2, &error);
1192 if( r != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
1193 return r;
1194
1195 r = dbus_select_browser(c,m,userdata, AVAHI_DBUS_INTERFACE_SERVER2, &error);
1196 if( r != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
1197 return r;
1198
1199 r = dbus_select_prepare_browser(c,m,userdata, AVAHI_DBUS_INTERFACE_SERVER2, &error);
1200 if( r != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
1201 return r;
1202
1203
1204 avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
1205 if (dbus_error_is_set(&error))
1206 dbus_error_free(&error);
1207
1208 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1209 }
1210
dbus_protocol_server_state_changed(AvahiServerState state)1211 void dbus_protocol_server_state_changed(AvahiServerState state) {
1212 DBusMessage *m;
1213 int32_t t;
1214 const char *e;
1215
1216 if (!server || !server->bus)
1217 return;
1218
1219 m = dbus_message_new_signal(AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "StateChanged");
1220
1221 if (!m) {
1222 avahi_log_error("Failed allocate message");
1223 return;
1224 }
1225
1226 t = (int32_t) state;
1227
1228 if (state == AVAHI_SERVER_COLLISION)
1229 e = AVAHI_DBUS_ERR_COLLISION;
1230 else if (state == AVAHI_SERVER_FAILURE)
1231 e = avahi_error_number_to_dbus(avahi_server_errno(avahi_server));
1232 else
1233 e = AVAHI_DBUS_ERR_OK;
1234
1235 dbus_message_append_args(m, DBUS_TYPE_INT32, &t, DBUS_TYPE_STRING, &e, DBUS_TYPE_INVALID);
1236 dbus_connection_send(server->bus, m, NULL);
1237 dbus_message_unref(m);
1238 }
1239
dbus_connect(void)1240 static int dbus_connect(void) {
1241 DBusError error;
1242
1243 static const DBusObjectPathVTable server_vtable = {
1244 NULL,
1245 msg_server_impl,
1246 NULL,
1247 NULL,
1248 NULL,
1249 NULL
1250 };
1251
1252 assert(server);
1253 assert(!server->bus);
1254
1255 dbus_error_init(&error);
1256
1257 #ifdef HAVE_DBUS_BUS_GET_PRIVATE
1258 if (!(server->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error))) {
1259 assert(dbus_error_is_set(&error));
1260 avahi_log_error("dbus_bus_get_private(): %s", error.message);
1261 goto fail;
1262 }
1263 #else
1264 {
1265 const char *a;
1266
1267 if (!(a = getenv("DBUS_SYSTEM_BUS_ADDRESS")) || !*a)
1268 a = DBUS_SYSTEM_BUS_DEFAULT_ADDRESS;
1269
1270 if (!(server->bus = dbus_connection_open_private(a, &error))) {
1271 assert(dbus_error_is_set(&error));
1272 avahi_log_error("dbus_bus_open_private(): %s", error.message);
1273 goto fail;
1274 }
1275
1276 if (!dbus_bus_register(server->bus, &error)) {
1277 assert(dbus_error_is_set(&error));
1278 avahi_log_error("dbus_bus_register(): %s", error.message);
1279 goto fail;
1280 }
1281 }
1282 #endif
1283
1284 if (avahi_dbus_connection_glue(server->bus, server->poll_api) < 0) {
1285 avahi_log_error("avahi_dbus_connection_glue() failed");
1286 goto fail;
1287 }
1288
1289 dbus_connection_set_exit_on_disconnect(server->bus, FALSE);
1290
1291 if (dbus_bus_request_name(
1292 server->bus,
1293 AVAHI_DBUS_NAME,
1294 #if (DBUS_VERSION_MAJOR == 0) && (DBUS_VERSION_MINOR < 60)
1295 DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT,
1296 #else
1297 DBUS_NAME_FLAG_DO_NOT_QUEUE,
1298 #endif
1299 &error) != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
1300 if (dbus_error_is_set(&error)) {
1301 avahi_log_error("dbus_bus_request_name(): %s", error.message);
1302 goto fail;
1303 }
1304
1305 avahi_log_error("Failed to acquire D-Bus name '"AVAHI_DBUS_NAME"'");
1306 goto fail;
1307 }
1308
1309 if (!(dbus_connection_add_filter(server->bus, msg_signal_filter_impl, (void*) server->poll_api, NULL))) {
1310 avahi_log_error("dbus_connection_add_filter() failed");
1311 goto fail;
1312 }
1313
1314 dbus_bus_add_match(server->bus, "type='signal',""interface='" DBUS_INTERFACE_DBUS "'", &error);
1315
1316 if (dbus_error_is_set(&error)) {
1317 avahi_log_error("dbus_bus_add_match(): %s", error.message);
1318 goto fail;
1319 }
1320
1321 if (!(dbus_connection_register_object_path(server->bus, AVAHI_DBUS_PATH_SERVER, &server_vtable, NULL))) {
1322 avahi_log_error("dbus_connection_register_object_path() failed");
1323 goto fail;
1324 }
1325
1326 return 0;
1327 fail:
1328
1329 if (dbus_error_is_set(&error))
1330 dbus_error_free(&error);
1331
1332 if (server->bus) {
1333 #ifdef HAVE_DBUS_CONNECTION_CLOSE
1334 dbus_connection_close(server->bus);
1335 #else
1336 dbus_connection_disconnect(server->bus);
1337 #endif
1338 dbus_connection_unref(server->bus);
1339 server->bus = NULL;
1340 }
1341
1342 return -1;
1343 }
1344
dbus_disconnect(void)1345 static void dbus_disconnect(void) {
1346 assert(server);
1347
1348 while (server->clients)
1349 client_free(server->clients);
1350
1351 assert(server->n_clients == 0);
1352
1353 if (server->bus) {
1354 #ifdef HAVE_DBUS_CONNECTION_CLOSE
1355 dbus_connection_close(server->bus);
1356 #else
1357 dbus_connection_disconnect(server->bus);
1358 #endif
1359 dbus_connection_unref(server->bus);
1360 server->bus = NULL;
1361 }
1362 }
1363
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)1364 int dbus_protocol_setup(const AvahiPoll *poll_api,
1365 int _disable_user_service_publishing,
1366 int _n_clients_max,
1367 int _n_objects_per_client_max,
1368 int _n_entries_per_entry_group_max,
1369 int force) {
1370
1371
1372 server = avahi_new(Server, 1);
1373 AVAHI_LLIST_HEAD_INIT(Clients, server->clients);
1374 server->current_id = 0;
1375 server->n_clients = 0;
1376 server->bus = NULL;
1377 server->poll_api = poll_api;
1378 server->reconnect_timeout = NULL;
1379 server->reconnect = force;
1380 server->disable_user_service_publishing = _disable_user_service_publishing;
1381 server->n_clients_max = _n_clients_max > 0 ? _n_clients_max : DEFAULT_CLIENTS_MAX;
1382 server->n_objects_per_client_max = _n_objects_per_client_max > 0 ? _n_objects_per_client_max : DEFAULT_OBJECTS_PER_CLIENT_MAX;
1383 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;
1384
1385 if (dbus_connect() < 0) {
1386 struct timeval tv;
1387
1388 if (!force)
1389 goto fail;
1390
1391 avahi_log_warn("WARNING: Failed to contact D-Bus daemon, retrying in %ims.", RECONNECT_MSEC);
1392
1393 avahi_elapse_time(&tv, RECONNECT_MSEC, 0);
1394 server->reconnect_timeout = server->poll_api->timeout_new(server->poll_api, &tv, reconnect_callback, NULL);
1395 }
1396
1397 return 0;
1398
1399 fail:
1400 if (server->bus) {
1401 #ifdef HAVE_DBUS_CONNECTION_CLOSE
1402 dbus_connection_close(server->bus);
1403 #else
1404 dbus_connection_disconnect(server->bus);
1405 #endif
1406
1407 dbus_connection_unref(server->bus);
1408 }
1409
1410 avahi_free(server);
1411 server = NULL;
1412 return -1;
1413 }
1414
dbus_protocol_shutdown(void)1415 void dbus_protocol_shutdown(void) {
1416
1417 if (server) {
1418 dbus_disconnect();
1419
1420 if (server->reconnect_timeout)
1421 server->poll_api->timeout_free(server->reconnect_timeout);
1422
1423 avahi_free(server);
1424 server = NULL;
1425 }
1426 }
1427