• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/avahi-0.6.31/avahi-client/
1/***
2  This file is part of avahi.
3
4  avahi is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Lesser General Public License as
6  published by the Free Software Foundation; either version 2.1 of the
7  License, or (at your option) any later version.
8
9  avahi is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12  Public License for more details.
13
14  You should have received a copy of the GNU Lesser General Public
15  License along with avahi; if not, write to the Free Software
16  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17  USA.
18***/
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24#include <stdlib.h>
25#include <stdio.h>
26#include <string.h>
27
28#include <dbus/dbus.h>
29
30#include <avahi-common/dbus.h>
31#include <avahi-common/llist.h>
32#include <avahi-common/error.h>
33#include <avahi-common/dbus.h>
34#include <avahi-common/malloc.h>
35#include <avahi-common/dbus-watch-glue.h>
36#include <avahi-common/i18n.h>
37
38#include "client.h"
39#include "internal.h"
40
41#define AVAHI_CLIENT_DBUS_API_SUPPORTED ((uint32_t) 0x0201)
42
43static int init_server(AvahiClient *client, int *ret_error);
44
45int avahi_client_set_errno (AvahiClient *client, int error) {
46    assert(client);
47
48    return client->error = error;
49}
50
51int avahi_client_set_dbus_error(AvahiClient *client, DBusError *error) {
52    assert(client);
53    assert(error);
54
55    return avahi_client_set_errno(client, avahi_error_dbus_to_number(error->name));
56}
57
58static void client_set_state(AvahiClient *client, AvahiClientState state) {
59    assert(client);
60
61    if (client->state == state)
62        return;
63
64    client->state = state;
65
66    switch (client->state) {
67        case AVAHI_CLIENT_FAILURE:
68            if (client->bus) {
69#ifdef HAVE_DBUS_CONNECTION_CLOSE
70                dbus_connection_close(client->bus);
71#else
72                dbus_connection_disconnect(client->bus);
73#endif
74                dbus_connection_unref(client->bus);
75                client->bus = NULL;
76            }
77
78            /* Fall through */
79
80        case AVAHI_CLIENT_S_COLLISION:
81        case AVAHI_CLIENT_S_REGISTERING:
82
83            /* Clear cached strings */
84            avahi_free(client->host_name);
85            avahi_free(client->host_name_fqdn);
86            avahi_free(client->domain_name);
87
88            client->host_name =  NULL;
89            client->host_name_fqdn = NULL;
90            client->domain_name = NULL;
91            break;
92
93        case AVAHI_CLIENT_S_RUNNING:
94        case AVAHI_CLIENT_CONNECTING:
95            break;
96
97    }
98
99    if (client->callback)
100        client->callback (client, state, client->userdata);
101}
102
103static DBusHandlerResult filter_func(DBusConnection *bus, DBusMessage *message, void *userdata) {
104    AvahiClient *client = userdata;
105    DBusError error;
106
107    assert(bus);
108    assert(message);
109
110    dbus_error_init(&error);
111
112/*     fprintf(stderr, "dbus: interface=%s, path=%s, member=%s\n", */
113/*             dbus_message_get_interface (message), */
114/*             dbus_message_get_path (message), */
115/*             dbus_message_get_member (message)); */
116
117    if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
118
119        /* The DBUS server died or kicked us */
120        avahi_client_set_errno(client, AVAHI_ERR_DISCONNECTED);
121        goto fail;
122
123    } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameAcquired")) {
124
125        /* Ignore this message */
126
127    } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
128        char *name, *old, *new;
129
130        if (!dbus_message_get_args(
131                  message, &error,
132                  DBUS_TYPE_STRING, &name,
133                  DBUS_TYPE_STRING, &old,
134                  DBUS_TYPE_STRING, &new,
135                  DBUS_TYPE_INVALID) || dbus_error_is_set(&error)) {
136
137            fprintf(stderr, "WARNING: Failed to parse NameOwnerChanged signal: %s\n", error.message);
138            avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
139            goto fail;
140        }
141
142        if (strcmp(name, AVAHI_DBUS_NAME) == 0) {
143
144            if (old[0] &&
145                avahi_client_is_connected(client)) {
146
147                /* Regardless if the server lost its name or
148                 * if the name was transfered: our services are no longer
149                 * available, so we disconnect ourselves */
150                avahi_client_set_errno(client, AVAHI_ERR_DISCONNECTED);
151                goto fail;
152
153            } else if (client->state == AVAHI_CLIENT_CONNECTING && (!old || *old == 0)) {
154                int ret;
155
156                /* Server appeared */
157
158                if ((ret = init_server(client, NULL)) < 0) {
159                    avahi_client_set_errno(client, ret);
160                    goto fail;
161                }
162            }
163        }
164
165    } else if (!avahi_client_is_connected(client)) {
166
167        /* Ignore messages we get in unconnected state */
168
169    } else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_SERVER, "StateChanged")) {
170        int32_t state;
171        char *e = NULL;
172        int c;
173
174        if (!dbus_message_get_args(
175                  message, &error,
176                  DBUS_TYPE_INT32, &state,
177                  DBUS_TYPE_STRING, &e,
178                  DBUS_TYPE_INVALID) || dbus_error_is_set (&error)) {
179
180            fprintf(stderr, "WARNING: Failed to parse Server.StateChanged signal: %s\n", error.message);
181            avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
182            goto fail;
183        }
184
185        if ((c = avahi_error_dbus_to_number(e)) != AVAHI_OK)
186            avahi_client_set_errno(client, c);
187
188        client_set_state(client, (AvahiClientState) state);
189
190    } else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "StateChanged")) {
191        const char *path;
192        AvahiEntryGroup *g;
193        path = dbus_message_get_path(message);
194
195        for (g = client->groups; g; g = g->groups_next)
196            if (strcmp(g->path, path) == 0)
197                break;
198
199        if (g) {
200            int32_t state;
201            char *e;
202            int c;
203
204            if (!dbus_message_get_args(
205                      message, &error,
206                      DBUS_TYPE_INT32, &state,
207                      DBUS_TYPE_STRING, &e,
208                      DBUS_TYPE_INVALID) ||
209                dbus_error_is_set(&error)) {
210
211                fprintf(stderr, "WARNING: Failed to parse EntryGroup.StateChanged signal: %s\n", error.message);
212                avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
213                goto fail;
214            }
215
216            if ((c = avahi_error_dbus_to_number(e)) != AVAHI_OK)
217                avahi_client_set_errno(client, c);
218
219            avahi_entry_group_set_state(g, state);
220        }
221
222    } else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "ItemNew"))
223        return avahi_domain_browser_event(client, AVAHI_BROWSER_NEW, message);
224    else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "ItemRemove"))
225        return avahi_domain_browser_event(client, AVAHI_BROWSER_REMOVE, message);
226    else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "CacheExhausted"))
227        return avahi_domain_browser_event(client, AVAHI_BROWSER_CACHE_EXHAUSTED, message);
228    else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "AllForNow"))
229        return avahi_domain_browser_event(client, AVAHI_BROWSER_ALL_FOR_NOW, message);
230    else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "Failure"))
231        return avahi_domain_browser_event(client, AVAHI_BROWSER_FAILURE, message);
232
233    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "ItemNew"))
234        return avahi_service_type_browser_event (client, AVAHI_BROWSER_NEW, message);
235    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "ItemRemove"))
236        return avahi_service_type_browser_event (client, AVAHI_BROWSER_REMOVE, message);
237    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "CacheExhausted"))
238        return avahi_service_type_browser_event (client, AVAHI_BROWSER_CACHE_EXHAUSTED, message);
239    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "AllForNow"))
240        return avahi_service_type_browser_event (client, AVAHI_BROWSER_ALL_FOR_NOW, message);
241    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "Failure"))
242        return avahi_service_type_browser_event (client, AVAHI_BROWSER_FAILURE, message);
243
244    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "ItemNew"))
245        return avahi_service_browser_event (client, AVAHI_BROWSER_NEW, message);
246    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "ItemRemove"))
247        return avahi_service_browser_event (client, AVAHI_BROWSER_REMOVE, message);
248    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "CacheExhausted"))
249        return avahi_service_browser_event (client, AVAHI_BROWSER_CACHE_EXHAUSTED, message);
250    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "AllForNow"))
251        return avahi_service_browser_event (client, AVAHI_BROWSER_ALL_FOR_NOW, message);
252    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "Failure"))
253        return avahi_service_browser_event (client, AVAHI_BROWSER_FAILURE, message);
254
255    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_RESOLVER, "Found"))
256        return avahi_service_resolver_event (client, AVAHI_RESOLVER_FOUND, message);
257    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_RESOLVER, "Failure"))
258        return avahi_service_resolver_event (client, AVAHI_RESOLVER_FAILURE, message);
259
260    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_HOST_NAME_RESOLVER, "Found"))
261        return avahi_host_name_resolver_event (client, AVAHI_RESOLVER_FOUND, message);
262    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_HOST_NAME_RESOLVER, "Failure"))
263        return avahi_host_name_resolver_event (client, AVAHI_RESOLVER_FAILURE, message);
264
265    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_ADDRESS_RESOLVER, "Found"))
266        return avahi_address_resolver_event (client, AVAHI_RESOLVER_FOUND, message);
267    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_ADDRESS_RESOLVER, "Failure"))
268        return avahi_address_resolver_event (client, AVAHI_RESOLVER_FAILURE, message);
269
270    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "ItemNew"))
271        return avahi_record_browser_event (client, AVAHI_BROWSER_NEW, message);
272    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "ItemRemove"))
273        return avahi_record_browser_event (client, AVAHI_BROWSER_REMOVE, message);
274    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "CacheExhausted"))
275        return avahi_record_browser_event (client, AVAHI_BROWSER_CACHE_EXHAUSTED, message);
276    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "AllForNow"))
277        return avahi_record_browser_event (client, AVAHI_BROWSER_ALL_FOR_NOW, message);
278    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "Failure"))
279        return avahi_record_browser_event (client, AVAHI_BROWSER_FAILURE, message);
280
281    else {
282
283        fprintf(stderr, "WARNING: Unhandled message: interface=%s, path=%s, member=%s\n",
284               dbus_message_get_interface(message),
285               dbus_message_get_path(message),
286               dbus_message_get_member(message));
287
288        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
289    }
290
291    return DBUS_HANDLER_RESULT_HANDLED;
292
293fail:
294
295    if (dbus_error_is_set(&error)) {
296        avahi_client_set_errno(client, avahi_error_dbus_to_number(error.name));
297        dbus_error_free(&error);
298    }
299
300    client_set_state(client, AVAHI_CLIENT_FAILURE);
301
302    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
303}
304
305static int get_server_state(AvahiClient *client, int *ret_error) {
306    DBusMessage *message = NULL, *reply = NULL;
307    DBusError error;
308    int32_t state;
309    int e = AVAHI_ERR_NO_MEMORY;
310
311    assert(client);
312
313    dbus_error_init(&error);
314
315    if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "GetState")))
316        goto fail;
317
318    reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error);
319
320    if (!reply || dbus_error_is_set (&error))
321        goto fail;
322
323    if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INT32, &state, DBUS_TYPE_INVALID) ||
324        dbus_error_is_set (&error))
325        goto fail;
326
327    client_set_state(client, (AvahiClientState) state);
328
329    dbus_message_unref(message);
330    dbus_message_unref(reply);
331
332    return AVAHI_OK;
333
334fail:
335    if (dbus_error_is_set(&error)) {
336        e = avahi_error_dbus_to_number (error.name);
337        dbus_error_free(&error);
338    }
339
340    if (ret_error)
341        *ret_error = e;
342
343    if (message)
344        dbus_message_unref(message);
345    if (reply)
346        dbus_message_unref(reply);
347
348    return e;
349}
350
351static int check_version(AvahiClient *client, int *ret_error) {
352    DBusMessage *message = NULL, *reply  = NULL;
353    DBusError error;
354    uint32_t version;
355    int e = AVAHI_ERR_NO_MEMORY;
356
357    assert(client);
358
359    dbus_error_init(&error);
360
361    if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "GetAPIVersion")))
362        goto fail;
363
364    reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error);
365
366    if (!reply || dbus_error_is_set (&error)) {
367        char *version_str;
368
369        if (!dbus_error_is_set(&error) || strcmp(error.name, DBUS_ERROR_UNKNOWN_METHOD))
370            goto fail;
371
372        /* If the method GetAPIVersion is not known, we look if
373         * GetVersionString matches "avahi 0.6" which is the only
374         * version we support which doesn't have GetAPIVersion() .*/
375
376        dbus_message_unref(message);
377        if (reply) dbus_message_unref(reply);
378        dbus_error_free(&error);
379
380        if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "GetVersionString")))
381            goto fail;
382
383        reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error);
384
385        if (!reply || dbus_error_is_set (&error))
386            goto fail;
387
388        if (!dbus_message_get_args (reply, &error, DBUS_TYPE_STRING, &version_str, DBUS_TYPE_INVALID) ||
389            dbus_error_is_set (&error))
390            goto fail;
391
392        version = strcmp(version_str, "avahi 0.6") == 0 ? 0x0201 : 0x0000;
393
394    } else {
395
396        if (!dbus_message_get_args (reply, &error, DBUS_TYPE_UINT32, &version, DBUS_TYPE_INVALID) ||
397            dbus_error_is_set(&error))
398            goto fail;
399    }
400
401    /*fprintf(stderr, "API Version 0x%04x\n", version);*/
402
403    if ((version & 0xFF00) != (AVAHI_CLIENT_DBUS_API_SUPPORTED & 0xFF00) ||
404        (version & 0x00FF) < (AVAHI_CLIENT_DBUS_API_SUPPORTED & 0x00FF)) {
405        e = AVAHI_ERR_VERSION_MISMATCH;
406        goto fail;
407    }
408
409    dbus_message_unref(message);
410    dbus_message_unref(reply);
411
412    return AVAHI_OK;
413
414fail:
415    if (dbus_error_is_set(&error)) {
416        e = avahi_error_dbus_to_number (error.name);
417        dbus_error_free(&error);
418    }
419
420    if (ret_error)
421        *ret_error = e;
422
423    if (message)
424        dbus_message_unref(message);
425    if (reply)
426        dbus_message_unref(reply);
427
428    return e;
429}
430
431static int init_server(AvahiClient *client, int *ret_error) {
432    int r;
433
434    if ((r = check_version(client, ret_error)) < 0)
435        return r;
436
437    if ((r = get_server_state(client, ret_error)) < 0)
438        return r;
439
440    return AVAHI_OK;
441}
442
443/* This function acts like dbus_bus_get but creates a private
444 * connection instead.  */
445static DBusConnection* avahi_dbus_bus_get(DBusError *error) {
446    DBusConnection *c;
447
448#ifdef HAVE_DBUS_BUS_GET_PRIVATE
449    if (!(c = dbus_bus_get_private(DBUS_BUS_SYSTEM, error)))
450        return NULL;
451
452    dbus_connection_set_exit_on_disconnect(c, FALSE);
453#else
454    const char *a;
455
456    if (!(a = getenv("DBUS_SYSTEM_BUS_ADDRESS")) || !*a)
457        a = DBUS_SYSTEM_BUS_DEFAULT_ADDRESS;
458
459    if (!(c = dbus_connection_open_private(a, error)))
460        return NULL;
461
462    dbus_connection_set_exit_on_disconnect(c, FALSE);
463
464    if (!dbus_bus_register(c, error)) {
465#ifdef HAVE_DBUS_CONNECTION_CLOSE
466        dbus_connection_close(c);
467#else
468        dbus_connection_disconnect(c);
469#endif
470        dbus_connection_unref(c);
471        return NULL;
472    }
473#endif
474
475    return c;
476}
477
478AvahiClient *avahi_client_new(const AvahiPoll *poll_api, AvahiClientFlags flags, AvahiClientCallback callback, void *userdata, int *ret_error) {
479    AvahiClient *client = NULL;
480    DBusError error;
481    DBusMessage *message = NULL, *reply = NULL;
482
483    avahi_init_i18n();
484
485    dbus_error_init(&error);
486
487    if (!(client = avahi_new(AvahiClient, 1))) {
488        if (ret_error)
489            *ret_error = AVAHI_ERR_NO_MEMORY;
490        goto fail;
491    }
492
493    client->poll_api = poll_api;
494    client->error = AVAHI_OK;
495    client->callback = callback;
496    client->userdata = userdata;
497    client->state = (AvahiClientState) -1;
498    client->flags = flags;
499
500    client->host_name = NULL;
501    client->host_name_fqdn = NULL;
502    client->domain_name = NULL;
503    client->version_string = NULL;
504    client->local_service_cookie_valid = 0;
505
506    AVAHI_LLIST_HEAD_INIT(AvahiEntryGroup, client->groups);
507    AVAHI_LLIST_HEAD_INIT(AvahiDomainBrowser, client->domain_browsers);
508    AVAHI_LLIST_HEAD_INIT(AvahiServiceBrowser, client->service_browsers);
509    AVAHI_LLIST_HEAD_INIT(AvahiServiceTypeBrowser, client->service_type_browsers);
510    AVAHI_LLIST_HEAD_INIT(AvahiServiceResolver, client->service_resolvers);
511    AVAHI_LLIST_HEAD_INIT(AvahiHostNameResolver, client->host_name_resolvers);
512    AVAHI_LLIST_HEAD_INIT(AvahiAddressResolver, client->address_resolvers);
513    AVAHI_LLIST_HEAD_INIT(AvahiRecordBrowser, client->record_browsers);
514
515    if (!(client->bus = avahi_dbus_bus_get(&error)) || dbus_error_is_set(&error)) {
516        if (ret_error)
517            *ret_error = AVAHI_ERR_DBUS_ERROR;
518        goto fail;
519    }
520
521    if (avahi_dbus_connection_glue(client->bus, poll_api) < 0) {
522        if (ret_error)
523            *ret_error = AVAHI_ERR_NO_MEMORY; /* Not optimal */
524        goto fail;
525    }
526
527    if (!dbus_connection_add_filter(client->bus, filter_func, client, NULL)) {
528        if (ret_error)
529            *ret_error = AVAHI_ERR_NO_MEMORY;
530        goto fail;
531    }
532
533    dbus_bus_add_match(
534        client->bus,
535        "type='signal', "
536        "interface='" AVAHI_DBUS_INTERFACE_SERVER "', "
537        "sender='" AVAHI_DBUS_NAME "', "
538        "path='" AVAHI_DBUS_PATH_SERVER "'",
539        &error);
540
541    if (dbus_error_is_set(&error))
542        goto fail;
543
544    dbus_bus_add_match (
545        client->bus,
546        "type='signal', "
547        "interface='" DBUS_INTERFACE_DBUS "', "
548        "sender='" DBUS_SERVICE_DBUS "', "
549        "path='" DBUS_PATH_DBUS "'",
550        &error);
551
552    if (dbus_error_is_set(&error))
553        goto fail;
554
555    dbus_bus_add_match(
556        client->bus,
557        "type='signal', "
558        "interface='" DBUS_INTERFACE_LOCAL "'",
559        &error);
560
561    if (dbus_error_is_set(&error))
562        goto fail;
563
564    if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, "org.freedesktop.DBus.Peer", "Ping")))
565        goto fail;
566
567    reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error);
568
569    if (!reply || dbus_error_is_set (&error)) {
570        /* We free the error so its not set, that way the fail target
571         * will return the NO_DAEMON error rather than a DBUS error */
572        dbus_error_free(&error);
573
574        if (!(flags & AVAHI_CLIENT_NO_FAIL)) {
575
576            if (ret_error)
577                *ret_error = AVAHI_ERR_NO_DAEMON;
578
579            goto fail;
580        }
581
582        /* The user doesn't want this call to fail if the daemon is not
583         * available, so let's return succesfully */
584        client_set_state(client, AVAHI_CLIENT_CONNECTING);
585
586    } else {
587
588        if (init_server(client, ret_error) < 0)
589            goto fail;
590    }
591
592    dbus_message_unref(message);
593
594    if (reply)
595        dbus_message_unref(reply);
596
597    return client;
598
599fail:
600
601    if (message)
602        dbus_message_unref(message);
603    if (reply)
604        dbus_message_unref(reply);
605
606    if (client)
607        avahi_client_free(client);
608
609    if (dbus_error_is_set(&error)) {
610
611        if (ret_error) {
612            if (strcmp(error.name, DBUS_ERROR_FILE_NOT_FOUND) == 0)
613                /* DBUS returns this error when the DBUS daemon is not running */
614                *ret_error = AVAHI_ERR_NO_DAEMON;
615            else
616                *ret_error = avahi_error_dbus_to_number(error.name);
617        }
618
619        dbus_error_free(&error);
620    }
621
622    return NULL;
623}
624
625void avahi_client_free(AvahiClient *client) {
626    assert(client);
627
628    if (client->bus)
629        /* Disconnect in advance, so that the free() functions won't
630         * issue needless server calls */
631#ifdef HAVE_DBUS_CONNECTION_CLOSE
632        dbus_connection_close(client->bus);
633#else
634        dbus_connection_disconnect(client->bus);
635#endif
636
637    while (client->groups)
638        avahi_entry_group_free(client->groups);
639
640    while (client->domain_browsers)
641        avahi_domain_browser_free(client->domain_browsers);
642
643    while (client->service_browsers)
644        avahi_service_browser_free(client->service_browsers);
645
646    while (client->service_type_browsers)
647        avahi_service_type_browser_free(client->service_type_browsers);
648
649    while (client->service_resolvers)
650        avahi_service_resolver_free(client->service_resolvers);
651
652    while (client->host_name_resolvers)
653        avahi_host_name_resolver_free(client->host_name_resolvers);
654
655    while (client->address_resolvers)
656        avahi_address_resolver_free(client->address_resolvers);
657
658    while (client->record_browsers)
659        avahi_record_browser_free(client->record_browsers);
660
661    if (client->bus)
662        dbus_connection_unref(client->bus);
663
664    avahi_free(client->version_string);
665    avahi_free(client->host_name);
666    avahi_free(client->host_name_fqdn);
667    avahi_free(client->domain_name);
668
669    avahi_free(client);
670}
671
672static char* avahi_client_get_string_reply_and_block (AvahiClient *client, const char *method, const char *param) {
673    DBusMessage *message = NULL, *reply = NULL;
674    DBusError error;
675    char *ret, *n;
676
677    assert(client);
678    assert(method);
679
680    dbus_error_init (&error);
681
682    if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, method))) {
683        avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
684        goto fail;
685    }
686
687    if (param) {
688        if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &param, DBUS_TYPE_INVALID)) {
689            avahi_client_set_errno (client, AVAHI_ERR_NO_MEMORY);
690            goto fail;
691        }
692    }
693
694    reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error);
695
696    if (!reply || dbus_error_is_set (&error))
697        goto fail;
698
699    if (!dbus_message_get_args (reply, &error, DBUS_TYPE_STRING, &ret, DBUS_TYPE_INVALID) ||
700        dbus_error_is_set (&error))
701        goto fail;
702
703    if (!(n = avahi_strdup(ret))) {
704        avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
705        goto fail;
706    }
707
708    dbus_message_unref(message);
709    dbus_message_unref(reply);
710
711    return n;
712
713fail:
714
715    if (message)
716        dbus_message_unref(message);
717    if (reply)
718        dbus_message_unref(reply);
719
720    if (dbus_error_is_set(&error)) {
721        avahi_client_set_dbus_error(client, &error);
722        dbus_error_free(&error);
723    }
724
725    return NULL;
726}
727
728const char* avahi_client_get_version_string(AvahiClient *client) {
729    assert(client);
730
731    if (!avahi_client_is_connected(client)) {
732        avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
733        return NULL;
734    }
735
736    if (!client->version_string)
737        client->version_string = avahi_client_get_string_reply_and_block(client, "GetVersionString", NULL);
738
739    return client->version_string;
740}
741
742const char* avahi_client_get_domain_name(AvahiClient *client) {
743    assert(client);
744
745    if (!avahi_client_is_connected(client)) {
746        avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
747        return NULL;
748    }
749
750    if (!client->domain_name)
751        client->domain_name = avahi_client_get_string_reply_and_block(client, "GetDomainName", NULL);
752
753    return client->domain_name;
754}
755
756const char* avahi_client_get_host_name(AvahiClient *client) {
757    assert(client);
758
759    if (!avahi_client_is_connected(client)) {
760        avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
761        return NULL;
762    }
763
764    if (!client->host_name)
765        client->host_name = avahi_client_get_string_reply_and_block(client, "GetHostName", NULL);
766
767    return client->host_name;
768}
769
770const char* avahi_client_get_host_name_fqdn (AvahiClient *client) {
771    assert(client);
772
773    if (!avahi_client_is_connected(client)) {
774        avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
775        return NULL;
776    }
777
778    if (!client->host_name_fqdn)
779        client->host_name_fqdn = avahi_client_get_string_reply_and_block(client, "GetHostNameFqdn", NULL);
780
781    return client->host_name_fqdn;
782}
783
784AvahiClientState avahi_client_get_state(AvahiClient *client) {
785    assert(client);
786
787    return client->state;
788}
789
790int avahi_client_errno(AvahiClient *client) {
791    assert(client);
792
793    return client->error;
794}
795
796/* Just for internal use */
797int avahi_client_simple_method_call(AvahiClient *client, const char *path, const char *interface, const char *method) {
798    DBusMessage *message = NULL, *reply = NULL;
799    DBusError error;
800    int r = AVAHI_OK;
801
802    dbus_error_init(&error);
803
804    assert(client);
805    assert(path);
806    assert(interface);
807    assert(method);
808
809    if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, path, interface, method))) {
810        r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
811        goto fail;
812    }
813
814    if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) ||
815        dbus_error_is_set (&error)) {
816        r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
817        goto fail;
818    }
819
820    if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) ||
821        dbus_error_is_set (&error)) {
822        r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
823        goto fail;
824    }
825
826    dbus_message_unref(message);
827    dbus_message_unref(reply);
828
829    return AVAHI_OK;
830
831fail:
832    if (dbus_error_is_set(&error)) {
833        r = avahi_client_set_dbus_error(client, &error);
834        dbus_error_free(&error);
835    }
836
837    if (message)
838        dbus_message_unref(message);
839
840    if (reply)
841        dbus_message_unref(reply);
842
843    return r;
844}
845
846uint32_t avahi_client_get_local_service_cookie(AvahiClient *client) {
847    DBusMessage *message = NULL, *reply = NULL;
848    DBusError error;
849    assert(client);
850
851    if (!avahi_client_is_connected(client)) {
852        avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
853        return AVAHI_SERVICE_COOKIE_INVALID;
854    }
855
856    if (client->local_service_cookie_valid)
857        return client->local_service_cookie;
858
859    dbus_error_init (&error);
860
861    if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "GetLocalServiceCookie"))) {
862        avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
863        goto fail;
864    }
865
866    reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error);
867
868    if (!reply || dbus_error_is_set (&error))
869        goto fail;
870
871    if (!dbus_message_get_args (reply, &error, DBUS_TYPE_UINT32, &client->local_service_cookie, DBUS_TYPE_INVALID) ||
872        dbus_error_is_set (&error))
873        goto fail;
874
875    dbus_message_unref(message);
876    dbus_message_unref(reply);
877
878    client->local_service_cookie_valid = 1;
879    return client->local_service_cookie;
880
881fail:
882
883    if (message)
884        dbus_message_unref(message);
885    if (reply)
886        dbus_message_unref(reply);
887
888    if (dbus_error_is_set(&error)) {
889        avahi_client_set_dbus_error(client, &error);
890        dbus_error_free(&error);
891    }
892
893    return AVAHI_SERVICE_COOKIE_INVALID;
894}
895
896int avahi_client_is_connected(AvahiClient *client) {
897    assert(client);
898
899    return
900        client->bus &&
901        dbus_connection_get_is_connected(client->bus) &&
902        (client->state == AVAHI_CLIENT_S_RUNNING || client->state == AVAHI_CLIENT_S_REGISTERING || client->state == AVAHI_CLIENT_S_COLLISION);
903}
904
905int avahi_client_set_host_name(AvahiClient* client, const char *name) {
906    DBusMessage *message = NULL, *reply = NULL;
907    DBusError error;
908
909    assert(client);
910
911    if (!avahi_client_is_connected(client))
912        return avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
913
914    dbus_error_init (&error);
915
916    if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "SetHostName"))) {
917        avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
918        goto fail;
919    }
920
921    if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) {
922        avahi_client_set_errno (client, AVAHI_ERR_NO_MEMORY);
923        goto fail;
924    }
925
926    reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error);
927
928    if (!reply || dbus_error_is_set (&error))
929        goto fail;
930
931    if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) ||
932        dbus_error_is_set (&error))
933        goto fail;
934
935    dbus_message_unref(message);
936    dbus_message_unref(reply);
937
938    avahi_free(client->host_name);
939    client->host_name = NULL;
940    avahi_free(client->host_name_fqdn);
941    client->host_name_fqdn = NULL;
942
943    return 0;
944
945fail:
946
947    if (message)
948        dbus_message_unref(message);
949    if (reply)
950        dbus_message_unref(reply);
951
952    if (dbus_error_is_set(&error)) {
953        avahi_client_set_dbus_error(client, &error);
954        dbus_error_free(&error);
955    }
956
957    return client->error;
958}
959