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