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