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