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