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