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