]> git.meshlink.io Git - catta/blob - avahi-client/client.c
* add new flags parameter to avahi_client_new()
[catta] / avahi-client / client.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 <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #include <dbus/dbus.h>
31
32 #include <avahi-common/dbus.h>
33 #include <avahi-common/llist.h>
34 #include <avahi-common/error.h>
35 #include <avahi-common/dbus.h>
36 #include <avahi-common/malloc.h>
37 #include <avahi-common/dbus-watch-glue.h>
38
39 #include "client.h"
40 #include "internal.h"
41
42 static int init_server(AvahiClient *client, int *ret_error);
43
44 int avahi_client_set_errno (AvahiClient *client, int error) {
45     assert(client);
46
47     return client->error = error;
48 }
49
50 int avahi_client_set_dbus_error(AvahiClient *client, DBusError *error) {
51     assert(client);
52     assert(error);
53
54     return avahi_client_set_errno(client, avahi_error_dbus_to_number(error->name));
55 }
56
57 static void client_set_state (AvahiClient *client, AvahiServerState state) {
58     assert(client);
59
60     if (client->state == state)
61         return;
62
63     client->state = state;
64
65     switch (client->state) {
66         case AVAHI_CLIENT_FAILURE:
67             if (client->bus) {
68                 dbus_connection_disconnect(client->bus);
69                 dbus_connection_unref(client->bus);
70                 client->bus = NULL;
71             }
72             
73             /* Fall through */
74             
75         case AVAHI_CLIENT_S_COLLISION:
76         case AVAHI_CLIENT_S_REGISTERING:
77
78             /* Clear cached strings */
79             avahi_free(client->host_name);
80             avahi_free(client->host_name_fqdn);
81             avahi_free(client->domain_name);
82
83             client->host_name =  NULL;
84             client->host_name_fqdn = NULL;
85             client->domain_name = NULL;
86             break;
87
88         case AVAHI_CLIENT_S_RUNNING:
89         case AVAHI_CLIENT_CONNECTING:
90             break;
91             
92     }
93     
94     if (client->callback)
95         client->callback (client, state, client->userdata);
96 }
97
98 static DBusHandlerResult filter_func(DBusConnection *bus, DBusMessage *message, void *userdata) {
99     AvahiClient *client = userdata;
100     DBusError error;
101
102     assert(bus);
103     assert(message);
104     
105     dbus_error_init(&error);
106
107 /*     fprintf(stderr, "dbus: interface=%s, path=%s, member=%s\n", */
108 /*             dbus_message_get_interface (message), */
109 /*             dbus_message_get_path (message), */
110 /*             dbus_message_get_member (message)); */
111
112     if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
113
114         /* The DBUS server died or kicked us */
115         avahi_client_set_errno(client, AVAHI_ERR_DISCONNECTED);
116         goto fail;
117
118     } if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
119         char *name, *old, *new;
120         
121         if (!dbus_message_get_args(
122                   message, &error,
123                   DBUS_TYPE_STRING, &name,
124                   DBUS_TYPE_STRING, &old,
125                   DBUS_TYPE_STRING, &new,
126                   DBUS_TYPE_INVALID) || dbus_error_is_set(&error)) {
127
128             fprintf(stderr, "WARNING: Failed to parse NameOwnerChanged signal: %s\n", error.message);
129             avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
130             goto fail;
131         }
132
133         if (strcmp(name, AVAHI_DBUS_NAME) == 0) {
134
135             if (avahi_client_is_connected(client)) {
136
137                 /* Regardless if the server lost or acquired its name or
138                  * if the name was transfered: our services are no longer
139                  * available, so we disconnect ourselves */
140                 avahi_client_set_errno(client, AVAHI_ERR_DISCONNECTED);
141                 goto fail;
142                 
143             } else if (client->state == AVAHI_CLIENT_CONNECTING && (!old || *old == 0)) {
144                 int ret;
145                 
146                 /* Server appeared */
147                 
148                 if ((ret = init_server(client, NULL)) < 0) {
149                     avahi_client_set_errno(client, ret);
150                     goto fail;
151                 }
152             }
153         }
154
155     } else if (!avahi_client_is_connected(client)) {
156         
157         /* Ignore messages, we get in unconnected state */
158         
159     } else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_SERVER, "StateChanged")) {
160         int32_t state;
161         char *e = NULL;
162         int c;
163         
164         if (!dbus_message_get_args(
165                   message, &error,
166                   DBUS_TYPE_INT32, &state,
167                   DBUS_TYPE_STRING, &e,
168                   DBUS_TYPE_INVALID) || dbus_error_is_set (&error)) {
169
170             fprintf(stderr, "WARNING: Failed to parse Server.StateChanged signal: %s\n", error.message);
171             avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
172             goto fail;
173         }
174
175         if ((c = avahi_error_dbus_to_number(e)) != AVAHI_OK)
176             avahi_client_set_errno(client, c);
177         
178         client_set_state(client, (AvahiClientState) state);
179
180     } else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "StateChanged")) {
181         const char *path;
182         AvahiEntryGroup *g;
183         path = dbus_message_get_path(message);
184
185         for (g = client->groups; g; g = g->groups_next)
186             if (strcmp(g->path, path) == 0)
187                 break;
188         
189         if (g) {
190             int32_t state;
191             char *e;
192             int c;
193             
194             if (!dbus_message_get_args(
195                       message, &error,
196                       DBUS_TYPE_INT32, &state,
197                       DBUS_TYPE_STRING, &e,
198                       DBUS_TYPE_INVALID) ||
199                 dbus_error_is_set(&error)) {
200
201                 fprintf(stderr, "WARNING: Failed to parse EntryGroup.StateChanged signal: %s\n", error.message);
202                 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
203                 goto fail;
204             }
205
206             if ((c = avahi_error_dbus_to_number(e)) != AVAHI_OK)
207                 avahi_client_set_errno(client, c);
208             
209             avahi_entry_group_set_state(g, state);
210         }
211         
212     } else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "ItemNew"))
213         return avahi_domain_browser_event(client, AVAHI_BROWSER_NEW, message);
214     else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "ItemRemove")) 
215         return avahi_domain_browser_event(client, AVAHI_BROWSER_REMOVE, message);
216     else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "CacheExhausted")) 
217         return avahi_domain_browser_event(client, AVAHI_BROWSER_CACHE_EXHAUSTED, message);
218     else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "AllForNow")) 
219         return avahi_domain_browser_event(client, AVAHI_BROWSER_ALL_FOR_NOW, message);
220     else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "Failure")) 
221         return avahi_domain_browser_event(client, AVAHI_BROWSER_FAILURE, message);
222
223     else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "ItemNew")) 
224         return avahi_service_type_browser_event (client, AVAHI_BROWSER_NEW, message);
225     else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "ItemRemove")) 
226         return avahi_service_type_browser_event (client, AVAHI_BROWSER_REMOVE, message);
227     else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "CacheExhausted")) 
228         return avahi_service_type_browser_event (client, AVAHI_BROWSER_CACHE_EXHAUSTED, message);
229     else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "AllForNow")) 
230         return avahi_service_type_browser_event (client, AVAHI_BROWSER_ALL_FOR_NOW, message);
231     else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "Failure")) 
232         return avahi_service_type_browser_event (client, AVAHI_BROWSER_FAILURE, message);
233
234     else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "ItemNew")) 
235         return avahi_service_browser_event (client, AVAHI_BROWSER_NEW, message);
236     else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "ItemRemove")) 
237         return avahi_service_browser_event (client, AVAHI_BROWSER_REMOVE, message);
238     else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "CacheExhausted")) 
239         return avahi_service_browser_event (client, AVAHI_BROWSER_CACHE_EXHAUSTED, message);
240     else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "AllForNow")) 
241         return avahi_service_browser_event (client, AVAHI_BROWSER_ALL_FOR_NOW, message);
242     else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "Failure")) 
243         return avahi_service_browser_event (client, AVAHI_BROWSER_FAILURE, message);
244
245     else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_RESOLVER, "Found")) 
246         return avahi_service_resolver_event (client, AVAHI_RESOLVER_FOUND, message);
247     else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_RESOLVER, "Failure")) 
248         return avahi_service_resolver_event (client, AVAHI_RESOLVER_FAILURE, message);
249
250     else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_HOST_NAME_RESOLVER, "Found")) 
251         return avahi_host_name_resolver_event (client, AVAHI_RESOLVER_FOUND, message);
252     else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_HOST_NAME_RESOLVER, "Failure")) 
253         return avahi_host_name_resolver_event (client, AVAHI_RESOLVER_FAILURE, message);
254
255     else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_ADDRESS_RESOLVER, "Found")) 
256         return avahi_address_resolver_event (client, AVAHI_RESOLVER_FOUND, message);
257     else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_ADDRESS_RESOLVER, "Failure")) 
258         return avahi_address_resolver_event (client, AVAHI_RESOLVER_FAILURE, message);
259     else {
260
261         fprintf(stderr, "WARNING: Unhandled message: interface=%s, path=%s, member=%s\n",
262                dbus_message_get_interface(message), 
263                dbus_message_get_path(message),
264                dbus_message_get_member(message));
265         
266         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
267     }
268     
269     return DBUS_HANDLER_RESULT_HANDLED;
270
271 fail:
272
273     if (dbus_error_is_set(&error)) {
274         avahi_client_set_errno(client, avahi_error_dbus_to_number(error.name));
275         dbus_error_free(&error);
276     }
277
278     client_set_state(client, AVAHI_CLIENT_FAILURE);
279     
280     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
281 }
282
283 static int get_server_state(AvahiClient *client, int *ret_error) {
284     DBusMessage *message = NULL, *reply = NULL;
285     DBusError error;
286     int32_t state;
287     int e = AVAHI_ERR_NO_MEMORY;
288     
289     assert(client);
290
291     dbus_error_init(&error);
292
293     if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "GetState")))
294         goto fail;
295
296     reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error);
297
298     if (!reply || dbus_error_is_set (&error))
299         goto fail;
300
301     if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INT32, &state, DBUS_TYPE_INVALID) ||
302         dbus_error_is_set (&error))
303         goto fail;
304
305     client_set_state(client, (AvahiServerState) state);
306
307     dbus_message_unref(message);
308     dbus_message_unref(reply);
309     
310     return AVAHI_OK;
311
312 fail:
313     if (dbus_error_is_set(&error)) {
314         e = avahi_error_dbus_to_number (error.name);
315         dbus_error_free(&error);
316     } 
317     
318     if (ret_error)
319         *ret_error = e;
320
321     if (message)
322         dbus_message_unref(message);
323     if (reply)
324         dbus_message_unref(reply);
325     
326     return e;
327 }
328
329 static int check_version(AvahiClient *client, int *ret_error) {
330     DBusMessage *message = NULL, *reply  = NULL;
331     DBusError error;
332     char *version;
333     int e = AVAHI_ERR_NO_MEMORY;
334     
335     assert(client);
336
337     dbus_error_init(&error);
338
339     if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "GetVersionString")))
340         goto fail;
341
342     reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error);
343
344     if (!reply || dbus_error_is_set (&error))
345         goto fail;
346
347     if (!dbus_message_get_args (reply, &error, DBUS_TYPE_STRING, &version, DBUS_TYPE_INVALID) ||
348         dbus_error_is_set (&error))
349         goto fail;
350
351     if (strcmp(version, PACKAGE_STRING) != 0) {
352         e = AVAHI_ERR_VERSION_MISMATCH;
353         goto fail;
354     }
355
356     dbus_message_unref(message);
357     dbus_message_unref(reply);
358                
359     return AVAHI_OK;
360
361 fail:
362     if (dbus_error_is_set(&error)) {
363         e = avahi_error_dbus_to_number (error.name);
364         dbus_error_free(&error);
365     } 
366
367     if (ret_error)
368         *ret_error = e;
369
370     if (message)
371         dbus_message_unref(message);
372     if (reply)
373         dbus_message_unref(reply);
374     
375     return e;
376 }
377
378 static int init_server(AvahiClient *client, int *ret_error) {
379     int r;
380     
381     if ((r = check_version(client, ret_error)) < 0)
382         return r;
383
384     if ((r = get_server_state(client, ret_error)) < 0)
385         return r;
386
387     return AVAHI_OK;
388 }
389
390 /* This function acts like dbus_bus_get but creates a private
391  * connection instead */
392 static DBusConnection* avahi_dbus_bus_get(DBusError *error) {
393     DBusConnection *c;
394     const char *a;
395
396     if (!(a = getenv("DBUS_SYSTEM_BUS_ADDRESS")) || !*a)
397         a = DBUS_SYSTEM_BUS_DEFAULT_ADDRESS;
398     
399     if (!(c = dbus_connection_open_private(a, error)))
400         return NULL;
401
402     dbus_connection_set_exit_on_disconnect(c, FALSE);
403
404     if (!dbus_bus_register(c, error)) {
405         dbus_connection_close(c);
406         dbus_connection_unref(c);
407         return NULL;
408     }
409
410     return c;
411 }
412
413 AvahiClient *avahi_client_new(const AvahiPoll *poll_api, AvahiClientFlags flags, AvahiClientCallback callback, void *userdata, int *ret_error) {
414     AvahiClient *client = NULL;
415     DBusError error;
416
417     dbus_error_init(&error);
418
419     if (!(client = avahi_new(AvahiClient, 1))) {
420         if (ret_error)
421             *ret_error = AVAHI_ERR_NO_MEMORY;
422         goto fail;
423     }
424
425     client->poll_api = poll_api;
426     client->error = AVAHI_OK;
427     client->callback = callback;
428     client->userdata = userdata;
429     client->state = (AvahiClientState) -1;
430     client->flags = flags;
431     
432     client->host_name = NULL;
433     client->host_name_fqdn = NULL;
434     client->domain_name = NULL;
435     client->version_string = NULL;
436     client->local_service_cookie_valid = 0;
437     
438     AVAHI_LLIST_HEAD_INIT(AvahiEntryGroup, client->groups);
439     AVAHI_LLIST_HEAD_INIT(AvahiDomainBrowser, client->domain_browsers);
440     AVAHI_LLIST_HEAD_INIT(AvahiServiceBrowser, client->service_browsers);
441     AVAHI_LLIST_HEAD_INIT(AvahiServiceTypeBrowser, client->service_type_browsers);
442     AVAHI_LLIST_HEAD_INIT(AvahiServiceResolver, client->service_resolvers);
443     AVAHI_LLIST_HEAD_INIT(AvahiHostNameResolver, client->host_name_resolvers);
444     AVAHI_LLIST_HEAD_INIT(AvahiAddressResolver, client->address_resolvers);
445
446     if (!(client->bus = avahi_dbus_bus_get(&error)) || dbus_error_is_set(&error)) {
447         if (ret_error)
448             *ret_error = AVAHI_ERR_DBUS_ERROR;
449         goto fail;
450     }
451
452     if (avahi_dbus_connection_glue(client->bus, poll_api) < 0) {
453         if (ret_error)
454             *ret_error = AVAHI_ERR_NO_MEMORY; /* Not optimal */
455         goto fail;
456     }
457
458     if (!dbus_connection_add_filter (client->bus, filter_func, client, NULL)) {
459         if (ret_error)
460             *ret_error = AVAHI_ERR_NO_MEMORY; 
461         goto fail;
462     }
463         
464     dbus_bus_add_match(
465         client->bus,
466         "type='signal', "
467         "interface='" AVAHI_DBUS_INTERFACE_SERVER "', "
468         "sender='" AVAHI_DBUS_NAME "', "
469         "path='" AVAHI_DBUS_PATH_SERVER "'",
470         &error);
471
472     if (dbus_error_is_set(&error))
473         goto fail;
474
475     dbus_bus_add_match (
476         client->bus,
477         "type='signal', "
478         "interface='" DBUS_INTERFACE_DBUS "', "
479         "sender='" DBUS_SERVICE_DBUS "', "
480         "path='" DBUS_PATH_DBUS "'",
481         &error);
482
483     if (dbus_error_is_set(&error))
484         goto fail;
485
486     dbus_bus_add_match (
487         client->bus,
488         "type='signal', "
489         "interface='" DBUS_INTERFACE_LOCAL "'",
490         &error);
491
492     if (dbus_error_is_set(&error))
493         goto fail;
494
495
496     if (!(dbus_bus_name_has_owner(client->bus, AVAHI_DBUS_NAME, &error)) ||
497         dbus_error_is_set(&error)) {
498
499         /* We free the error so its not set, that way the fail target
500          * will return the NO_DAEMON error rather than a DBUS error */
501         dbus_error_free(&error);
502
503         if (!(flags & AVAHI_CLIENT_NO_FAIL)) {
504             
505             if (ret_error)
506                 *ret_error = AVAHI_ERR_NO_DAEMON;
507         
508             goto fail;
509         }
510
511         /* The user doesn't want this call to fail if the daemon is not
512          * available, so let's return succesfully */
513         client_set_state(client, AVAHI_CLIENT_CONNECTING);
514         
515     } else {
516
517         if (init_server(client, ret_error) < 0)
518             goto fail;
519     }
520
521     return client;
522
523 fail:
524
525     if (client)
526         avahi_client_free(client);
527
528     if (dbus_error_is_set(&error)) {
529
530         if (ret_error)
531             *ret_error = avahi_error_dbus_to_number(error.name);
532         
533         dbus_error_free(&error);
534     }
535         
536     return NULL;
537 }
538
539 void avahi_client_free(AvahiClient *client) {
540     assert(client);
541
542     while (client->groups)
543         avahi_entry_group_free(client->groups);
544
545     while (client->domain_browsers)
546         avahi_domain_browser_free(client->domain_browsers);
547
548     while (client->service_browsers)
549         avahi_service_browser_free(client->service_browsers);
550
551     while (client->service_type_browsers)
552         avahi_service_type_browser_free(client->service_type_browsers);
553
554     while (client->service_resolvers)
555         avahi_service_resolver_free(client->service_resolvers);
556
557     if (client->bus) {
558         dbus_connection_disconnect(client->bus);
559         dbus_connection_unref(client->bus);
560     }
561
562     avahi_free(client->version_string);
563     avahi_free(client->host_name);
564     avahi_free(client->host_name_fqdn);
565     avahi_free(client->domain_name);
566     
567     avahi_free(client);
568 }
569
570 static char* avahi_client_get_string_reply_and_block (AvahiClient *client, const char *method, const char *param) {
571     DBusMessage *message = NULL, *reply = NULL;
572     DBusError error;
573     char *ret, *n;
574
575     assert(client);
576     assert(method);
577
578     dbus_error_init (&error);
579
580     if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, method))) {
581         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
582         goto fail;
583     }
584
585     if (param) {
586         if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &param, DBUS_TYPE_INVALID)) {
587             avahi_client_set_errno (client, AVAHI_ERR_NO_MEMORY);
588             goto fail;
589         }
590     }
591     
592     reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error);
593
594     if (!reply || dbus_error_is_set (&error))
595         goto fail;
596
597     if (!dbus_message_get_args (reply, &error, DBUS_TYPE_STRING, &ret, DBUS_TYPE_INVALID) ||
598         dbus_error_is_set (&error))
599         goto fail;
600     
601     if (!(n = avahi_strdup(ret))) {
602         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
603         goto fail;
604     }
605
606     dbus_message_unref(message);
607     dbus_message_unref(reply);
608     
609     return n;
610
611 fail:
612
613     if (message)
614         dbus_message_unref(message);
615     if (reply)
616         dbus_message_unref(reply);
617     
618     if (dbus_error_is_set(&error)) {
619         avahi_client_set_dbus_error(client, &error);
620         dbus_error_free(&error);
621     }
622
623     return NULL;
624 }
625
626 const char* avahi_client_get_version_string(AvahiClient *client) {
627     assert(client);
628
629     if (!avahi_client_is_connected(client)) {
630         avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
631         return NULL;
632     }
633
634     if (!client->version_string)
635         client->version_string = avahi_client_get_string_reply_and_block(client, "GetVersionString", NULL);
636
637     return client->version_string;
638 }
639
640 const char* avahi_client_get_domain_name(AvahiClient *client) {
641     assert(client);
642
643     if (!avahi_client_is_connected(client)) {
644         avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
645         return NULL;
646     }
647
648     if (!client->domain_name)
649         client->domain_name = avahi_client_get_string_reply_and_block(client, "GetDomainName", NULL);
650     
651     return client->domain_name;
652 }
653
654 const char* avahi_client_get_host_name(AvahiClient *client) {
655     assert(client);
656     
657     if (!avahi_client_is_connected(client)) {
658         avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
659         return NULL;
660     }
661
662     if (!client->host_name)
663         client->host_name = avahi_client_get_string_reply_and_block(client, "GetHostName", NULL);
664     
665     return client->host_name;
666 }
667
668 const char* avahi_client_get_host_name_fqdn (AvahiClient *client) {
669     assert(client);
670
671     if (!avahi_client_is_connected(client)) {
672         avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
673         return NULL;
674     }
675     
676     if (!client->host_name_fqdn)
677         client->host_name_fqdn = avahi_client_get_string_reply_and_block(client, "GetHostNameFqdn", NULL);
678
679     return client->host_name_fqdn;
680 }
681
682 AvahiClientState avahi_client_get_state(AvahiClient *client) {
683     assert(client);
684
685     return client->state;
686 }
687
688 int avahi_client_errno(AvahiClient *client) {
689     assert(client);
690     
691     return client->error;
692 }
693
694 /* Just for internal use */
695 int avahi_client_simple_method_call(AvahiClient *client, const char *path, const char *interface, const char *method) {
696     DBusMessage *message = NULL, *reply = NULL;
697     DBusError error;
698     int r = AVAHI_OK;
699     
700     dbus_error_init(&error);
701
702     assert(client);
703     assert(path);
704     assert(interface);
705     assert(method);
706     
707     if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, path, interface, method))) {
708         r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
709         goto fail;
710     }
711         
712     if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
713         dbus_error_is_set (&error)) {
714         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
715         goto fail;
716     }
717     
718     if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) ||
719         dbus_error_is_set (&error)) {
720         r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
721         goto fail;
722     }
723
724     dbus_message_unref(message);
725     dbus_message_unref(reply);
726
727     return AVAHI_OK;
728     
729 fail:
730     if (dbus_error_is_set(&error)) {
731         r = avahi_client_set_dbus_error(client, &error);
732         dbus_error_free(&error);
733     }
734
735     if (message)
736         dbus_message_unref(message);
737
738     if (reply)
739         dbus_message_unref(reply);
740
741     return r;
742 }
743
744 uint32_t avahi_client_get_local_service_cookie(AvahiClient *client) {
745     DBusMessage *message = NULL, *reply = NULL;
746     DBusError error;
747     assert(client);
748
749     if (!avahi_client_is_connected(client)) {
750         avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
751         return AVAHI_SERVICE_COOKIE_INVALID;
752     }
753
754     if (client->local_service_cookie_valid)
755         return client->local_service_cookie;
756
757     dbus_error_init (&error);
758
759     if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "GetLocalServiceCookie"))) {
760         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
761         goto fail;
762     }
763
764     reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error);
765
766     if (!reply || dbus_error_is_set (&error))
767         goto fail;
768
769     if (!dbus_message_get_args (reply, &error, DBUS_TYPE_UINT32, &client->local_service_cookie, DBUS_TYPE_INVALID) ||
770         dbus_error_is_set (&error))
771         goto fail;
772     
773     dbus_message_unref(message);
774     dbus_message_unref(reply);
775
776     client->local_service_cookie_valid = 1;
777     return client->local_service_cookie;
778
779 fail:
780
781     if (message)
782         dbus_message_unref(message);
783     if (reply)
784         dbus_message_unref(reply);
785     
786     if (dbus_error_is_set(&error)) {
787         avahi_client_set_dbus_error(client, &error);
788         dbus_error_free(&error);
789     }
790
791     return AVAHI_SERVICE_COOKIE_INVALID;
792 }
793
794 int avahi_client_is_connected(AvahiClient *client) {
795     assert(client);
796
797     return client->state == AVAHI_CLIENT_S_RUNNING || client->state == AVAHI_CLIENT_S_REGISTERING || client->state == AVAHI_CLIENT_S_COLLISION;
798 }