Home | History | Annotate | Download | only in 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-client/client.h>
     31 #include <avahi-common/dbus.h>
     32 #include <avahi-common/llist.h>
     33 #include <avahi-common/error.h>
     34 #include "avahi-common/avahi-malloc.h"
     35 #include <avahi-common/domain.h>
     36 
     37 #include "client.h"
     38 #include "internal.h"
     39 #include "xdg-config.h"
     40 
     41 static void parse_environment(AvahiDomainBrowser *b) {
     42     char buf[AVAHI_DOMAIN_NAME_MAX*3], *e, *t, *p;
     43 
     44     assert(b);
     45 
     46     if (!(e = getenv("AVAHI_BROWSE_DOMAINS")))
     47         return;
     48 
     49     snprintf(buf, sizeof(buf), "%s", e);
     50 
     51     for (t = strtok_r(buf, ":", &p); t; t = strtok_r(NULL, ":", &p)) {
     52         char domain[AVAHI_DOMAIN_NAME_MAX];
     53         if (avahi_normalize_name(t, domain, sizeof(domain)))
     54             b->static_browse_domains = avahi_string_list_add(b->static_browse_domains, domain);
     55     }
     56 }
     57 
     58 static void parse_domain_file(AvahiDomainBrowser *b) {
     59     FILE *f;
     60     char buf[AVAHI_DOMAIN_NAME_MAX];
     61 
     62     assert(b);
     63 
     64     if (!(f = avahi_xdg_config_open("avahi/browse-domains")))
     65         return;
     66 
     67 
     68     while (fgets(buf, sizeof(buf)-1, f)) {
     69         char domain[AVAHI_DOMAIN_NAME_MAX];
     70         buf[strcspn(buf, "\n\r")] = 0;
     71 
     72         if (avahi_normalize_name(buf, domain, sizeof(domain)))
     73             b->static_browse_domains = avahi_string_list_add(b->static_browse_domains, domain);
     74     }
     75 }
     76 
     77 static void domain_browser_ref(AvahiDomainBrowser *db) {
     78     assert(db);
     79     assert(db->ref >= 1);
     80     db->ref++;
     81 }
     82 
     83 static void defer_timeout_callback(AvahiTimeout *t, void *userdata) {
     84     AvahiDomainBrowser *db = userdata;
     85     AvahiStringList *l;
     86     assert(t);
     87 
     88     db->client->poll_api->timeout_free(db->defer_timeout);
     89     db->defer_timeout = NULL;
     90 
     91     domain_browser_ref(db);
     92 
     93     for (l = db->static_browse_domains; l; l = l->next) {
     94 
     95         if (db->ref <= 1)
     96             break;
     97 
     98         db->callback(db, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AVAHI_BROWSER_NEW, (char*) l->text, AVAHI_LOOKUP_RESULT_STATIC, db->userdata);
     99     }
    100 
    101     avahi_domain_browser_free(db);
    102 }
    103 
    104 AvahiDomainBrowser* avahi_domain_browser_new(
    105     AvahiClient *client,
    106     AvahiIfIndex interface,
    107     AvahiProtocol protocol,
    108     const char *domain,
    109     AvahiDomainBrowserType btype,
    110     AvahiLookupFlags flags,
    111     AvahiDomainBrowserCallback callback,
    112     void *userdata) {
    113 
    114     AvahiDomainBrowser *db = NULL;
    115     DBusMessage *message = NULL, *reply = NULL;
    116     DBusError error;
    117     char *path;
    118     int32_t i_interface, i_protocol, bt;
    119     uint32_t u_flags;
    120 
    121     assert(client);
    122     assert(callback);
    123 
    124     dbus_error_init (&error);
    125 
    126     if (!avahi_client_is_connected(client)) {
    127         avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
    128         goto fail;
    129     }
    130 
    131     if (!domain)
    132         domain = "";
    133 
    134     if (!(db = avahi_new (AvahiDomainBrowser, 1))) {
    135         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    136         goto fail;
    137     }
    138 
    139     db->ref = 1;
    140     db->client = client;
    141     db->callback = callback;
    142     db->userdata = userdata;
    143     db->path = NULL;
    144     db->interface = interface;
    145     db->protocol = protocol;
    146     db->static_browse_domains = NULL;
    147     db->defer_timeout = NULL;
    148 
    149     AVAHI_LLIST_PREPEND(AvahiDomainBrowser, domain_browsers, client->domain_browsers, db);
    150 
    151     if (!(client->flags & AVAHI_CLIENT_IGNORE_USER_CONFIG)) {
    152         parse_environment(db);
    153         parse_domain_file(db);
    154     }
    155 
    156     db->static_browse_domains = avahi_string_list_reverse(db->static_browse_domains);
    157 
    158     if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "DomainBrowserNew"))) {
    159         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    160         goto fail;
    161     }
    162 
    163     i_interface = (int32_t) interface;
    164     i_protocol = (int32_t) protocol;
    165     u_flags = (uint32_t) flags;
    166     bt = btype;
    167 
    168     if (!(dbus_message_append_args(
    169               message,
    170               DBUS_TYPE_INT32, &i_interface,
    171               DBUS_TYPE_INT32, &i_protocol,
    172               DBUS_TYPE_STRING, &domain,
    173               DBUS_TYPE_INT32, &bt,
    174               DBUS_TYPE_UINT32, &u_flags,
    175               DBUS_TYPE_INVALID))) {
    176         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    177         goto fail;
    178     }
    179 
    180     if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) ||
    181         dbus_error_is_set(&error)) {
    182         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
    183         goto fail;
    184     }
    185 
    186     if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) ||
    187         dbus_error_is_set(&error) ||
    188         !path) {
    189         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
    190         goto fail;
    191     }
    192 
    193     if (!(db->path = avahi_strdup(path))) {
    194 
    195         /* FIXME: We don't remove the object on the server side */
    196 
    197         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    198         goto fail;
    199     }
    200 
    201     if (db->static_browse_domains && btype == AVAHI_DOMAIN_BROWSER_BROWSE) {
    202         struct timeval tv = { 0, 0 };
    203 
    204         if (!(db->defer_timeout = client->poll_api->timeout_new(client->poll_api, &tv, defer_timeout_callback, db))) {
    205             avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    206             goto fail;
    207         }
    208     }
    209 
    210     dbus_message_unref(message);
    211     dbus_message_unref(reply);
    212 
    213     return db;
    214 
    215 fail:
    216 
    217     if (dbus_error_is_set(&error)) {
    218         avahi_client_set_dbus_error(client, &error);
    219         dbus_error_free(&error);
    220     }
    221 
    222     if (db)
    223         avahi_domain_browser_free(db);
    224 
    225     if (message)
    226         dbus_message_unref(message);
    227 
    228     if (reply)
    229         dbus_message_unref(reply);
    230 
    231     return NULL;
    232 }
    233 
    234 AvahiClient* avahi_domain_browser_get_client (AvahiDomainBrowser *b) {
    235     assert(b);
    236     return b->client;
    237 }
    238 
    239 int avahi_domain_browser_free (AvahiDomainBrowser *b) {
    240     AvahiClient *client;
    241     int r = AVAHI_OK;
    242 
    243     assert(b);
    244     assert(b->ref >= 1);
    245 
    246     if (--(b->ref) >= 1)
    247         return AVAHI_OK;
    248 
    249     client = b->client;
    250 
    251     if (b->path && avahi_client_is_connected(b->client))
    252         r = avahi_client_simple_method_call(client, b->path, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "Free");
    253 
    254     AVAHI_LLIST_REMOVE(AvahiDomainBrowser, domain_browsers, client->domain_browsers, b);
    255 
    256     if (b->defer_timeout)
    257         b->client->poll_api->timeout_free(b->defer_timeout);
    258 
    259     avahi_string_list_free(b->static_browse_domains);
    260     avahi_free(b->path);
    261     avahi_free(b);
    262 
    263     return r;
    264 }
    265 
    266 DBusHandlerResult avahi_domain_browser_event (AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message) {
    267     AvahiDomainBrowser *db = NULL;
    268     DBusError error;
    269     const char *path;
    270     char *domain = NULL;
    271     int32_t interface, protocol;
    272     uint32_t flags = 0;
    273     AvahiStringList *l;
    274 
    275     assert(client);
    276     assert(message);
    277 
    278     dbus_error_init (&error);
    279 
    280     if (!(path = dbus_message_get_path(message)))
    281         goto fail;
    282 
    283     for (db = client->domain_browsers; db; db = db->domain_browsers_next)
    284         if (strcmp (db->path, path) == 0)
    285             break;
    286 
    287     if (!db)
    288         goto fail;
    289 
    290     interface = db->interface;
    291     protocol = db->protocol;
    292 
    293     switch (event) {
    294         case AVAHI_BROWSER_NEW:
    295         case AVAHI_BROWSER_REMOVE:
    296 
    297             if (!dbus_message_get_args(
    298                     message, &error,
    299                     DBUS_TYPE_INT32, &interface,
    300                     DBUS_TYPE_INT32, &protocol,
    301                     DBUS_TYPE_STRING, &domain,
    302                     DBUS_TYPE_UINT32, &flags,
    303                     DBUS_TYPE_INVALID) ||
    304                 dbus_error_is_set (&error)) {
    305                 fprintf(stderr, "Failed to parse browser event.\n");
    306                 goto fail;
    307             }
    308 
    309             break;
    310 
    311         case AVAHI_BROWSER_CACHE_EXHAUSTED:
    312         case AVAHI_BROWSER_ALL_FOR_NOW:
    313             break;
    314 
    315         case AVAHI_BROWSER_FAILURE: {
    316             char *etxt;
    317 
    318             if (!dbus_message_get_args(
    319                     message, &error,
    320                     DBUS_TYPE_STRING, &etxt,
    321                     DBUS_TYPE_INVALID) ||
    322                 dbus_error_is_set (&error)) {
    323                 fprintf(stderr, "Failed to parse browser event.\n");
    324                 goto fail;
    325             }
    326 
    327             avahi_client_set_errno(db->client, avahi_error_dbus_to_number(etxt));
    328             break;
    329         }
    330     }
    331 
    332     if (domain)
    333         for (l = db->static_browse_domains; l; l = l->next)
    334             if (avahi_domain_equal((char*) l->text, domain)) {
    335                 /* We had this entry already in the static entries */
    336                 return DBUS_HANDLER_RESULT_HANDLED;
    337             }
    338 
    339     db->callback(db, (AvahiIfIndex) interface, (AvahiProtocol) protocol, event, domain, (AvahiLookupResultFlags) flags, db->userdata);
    340 
    341     return DBUS_HANDLER_RESULT_HANDLED;
    342 
    343 fail:
    344     dbus_error_free (&error);
    345     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    346 }
    347 
    348 /* AvahiServiceTypeBrowser */
    349 
    350 AvahiServiceTypeBrowser* avahi_service_type_browser_new(
    351     AvahiClient *client,
    352     AvahiIfIndex interface,
    353     AvahiProtocol protocol,
    354     const char *domain,
    355     AvahiLookupFlags flags,
    356     AvahiServiceTypeBrowserCallback callback,
    357     void *userdata) {
    358 
    359     AvahiServiceTypeBrowser *b = NULL;
    360     DBusMessage *message = NULL, *reply = NULL;
    361     DBusError error;
    362     char *path;
    363     int32_t i_interface, i_protocol;
    364     uint32_t u_flags;
    365 
    366     assert(client);
    367     assert(callback);
    368 
    369     dbus_error_init(&error);
    370 
    371     if (!avahi_client_is_connected(client)) {
    372         avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
    373         goto fail;
    374     }
    375 
    376     if (!domain)
    377         domain = "";
    378 
    379     if (!(b = avahi_new(AvahiServiceTypeBrowser, 1))) {
    380         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    381         goto fail;
    382     }
    383 
    384     b->client = client;
    385     b->callback = callback;
    386     b->userdata = userdata;
    387     b->path = NULL;
    388     b->domain = NULL;
    389     b->interface = interface;
    390     b->protocol = protocol;
    391 
    392     AVAHI_LLIST_PREPEND(AvahiServiceTypeBrowser, service_type_browsers, client->service_type_browsers, b);
    393 
    394     if (domain[0])
    395         if (!(b->domain = avahi_strdup(domain))) {
    396             avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    397             goto fail;
    398         }
    399 
    400     if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "ServiceTypeBrowserNew"))) {
    401         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    402         goto fail;
    403     }
    404 
    405     i_interface = (int32_t) interface;
    406     i_protocol = (int32_t) protocol;
    407     u_flags = (uint32_t) flags;
    408 
    409     if (!dbus_message_append_args(
    410             message,
    411             DBUS_TYPE_INT32, &i_interface,
    412             DBUS_TYPE_INT32, &i_protocol,
    413             DBUS_TYPE_STRING, &domain,
    414             DBUS_TYPE_UINT32, &u_flags,
    415             DBUS_TYPE_INVALID)) {
    416         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    417         goto fail;
    418     }
    419 
    420     if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) ||
    421         dbus_error_is_set(&error)) {
    422         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
    423         goto fail;
    424     }
    425 
    426     if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) ||
    427         dbus_error_is_set(&error) ||
    428         !path) {
    429         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
    430         goto fail;
    431     }
    432 
    433     if (!(b->path = avahi_strdup(path))) {
    434 
    435         /* FIXME: We don't remove the object on the server side */
    436 
    437         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    438         goto fail;
    439     }
    440 
    441     dbus_message_unref(message);
    442     dbus_message_unref(reply);
    443 
    444     return b;
    445 
    446 fail:
    447 
    448     if (dbus_error_is_set(&error)) {
    449         avahi_client_set_dbus_error(client, &error);
    450         dbus_error_free(&error);
    451     }
    452 
    453     if (b)
    454         avahi_service_type_browser_free(b);
    455 
    456     if (message)
    457         dbus_message_unref(message);
    458 
    459     if (reply)
    460         dbus_message_unref(reply);
    461 
    462     return NULL;
    463 }
    464 
    465 AvahiClient* avahi_service_type_browser_get_client (AvahiServiceTypeBrowser *b) {
    466     assert(b);
    467     return b->client;
    468 }
    469 
    470 int avahi_service_type_browser_free (AvahiServiceTypeBrowser *b) {
    471     AvahiClient *client;
    472     int r = AVAHI_OK;
    473 
    474     assert(b);
    475     client = b->client;
    476 
    477     if (b->path && avahi_client_is_connected(b->client))
    478         r = avahi_client_simple_method_call(client, b->path, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "Free");
    479 
    480     AVAHI_LLIST_REMOVE(AvahiServiceTypeBrowser, service_type_browsers, b->client->service_type_browsers, b);
    481 
    482     avahi_free(b->path);
    483     avahi_free(b->domain);
    484     avahi_free(b);
    485     return r;
    486 }
    487 
    488 DBusHandlerResult avahi_service_type_browser_event (AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message) {
    489     AvahiServiceTypeBrowser *b = NULL;
    490     DBusError error;
    491     const char *path;
    492     char *domain, *type = NULL;
    493     int32_t interface, protocol;
    494     uint32_t flags = 0;
    495 
    496     assert(client);
    497     assert(message);
    498 
    499     dbus_error_init (&error);
    500 
    501     if (!(path = dbus_message_get_path(message)))
    502         goto fail;
    503 
    504     for (b = client->service_type_browsers; b; b = b->service_type_browsers_next)
    505         if (strcmp (b->path, path) == 0)
    506             break;
    507 
    508     if (!b)
    509         goto fail;
    510 
    511     domain = b->domain;
    512     interface = b->interface;
    513     protocol = b->protocol;
    514 
    515     switch (event) {
    516         case AVAHI_BROWSER_NEW:
    517         case AVAHI_BROWSER_REMOVE:
    518             if (!dbus_message_get_args(
    519                     message, &error,
    520                     DBUS_TYPE_INT32, &interface,
    521                     DBUS_TYPE_INT32, &protocol,
    522                     DBUS_TYPE_STRING, &type,
    523                     DBUS_TYPE_STRING, &domain,
    524                     DBUS_TYPE_UINT32, &flags,
    525                     DBUS_TYPE_INVALID) ||
    526                 dbus_error_is_set(&error)) {
    527                 fprintf(stderr, "Failed to parse browser event.\n");
    528                 goto fail;
    529             }
    530             break;
    531 
    532         case AVAHI_BROWSER_CACHE_EXHAUSTED:
    533         case AVAHI_BROWSER_ALL_FOR_NOW:
    534             break;
    535 
    536         case AVAHI_BROWSER_FAILURE: {
    537             char *etxt;
    538 
    539             if (!dbus_message_get_args(
    540                     message, &error,
    541                     DBUS_TYPE_STRING, &etxt,
    542                     DBUS_TYPE_INVALID) ||
    543                 dbus_error_is_set (&error)) {
    544                 fprintf(stderr, "Failed to parse browser event.\n");
    545                 goto fail;
    546             }
    547 
    548             avahi_client_set_errno(b->client, avahi_error_dbus_to_number(etxt));
    549             break;
    550         }
    551     }
    552 
    553     b->callback(b, (AvahiIfIndex) interface, (AvahiProtocol) protocol, event, type, domain, (AvahiLookupResultFlags) flags, b->userdata);
    554 
    555     return DBUS_HANDLER_RESULT_HANDLED;
    556 
    557 fail:
    558     dbus_error_free (&error);
    559     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    560 }
    561 
    562 /* AvahiServiceBrowser */
    563 
    564 AvahiServiceBrowser* avahi_service_browser_new(
    565     AvahiClient *client,
    566     AvahiIfIndex interface,
    567     AvahiProtocol protocol,
    568     const char *type,
    569     const char *domain,
    570     AvahiLookupFlags flags,
    571     AvahiServiceBrowserCallback callback,
    572     void *userdata) {
    573 
    574     AvahiServiceBrowser *b = NULL;
    575     DBusMessage *message = NULL, *reply = NULL;
    576     DBusError error;
    577     char *path;
    578     int32_t i_protocol, i_interface;
    579     uint32_t u_flags;
    580 
    581     assert(client);
    582     assert(type);
    583     assert(callback);
    584 
    585     dbus_error_init(&error);
    586 
    587     if (!avahi_client_is_connected(client)) {
    588         avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
    589         goto fail;
    590     }
    591 
    592     if (!domain)
    593         domain = "";
    594 
    595     if (!(b = avahi_new(AvahiServiceBrowser, 1))) {
    596         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    597         goto fail;
    598     }
    599 
    600     b->client = client;
    601     b->callback = callback;
    602     b->userdata = userdata;
    603     b->path = NULL;
    604     b->type = b->domain = NULL;
    605     b->interface = interface;
    606     b->protocol = protocol;
    607 
    608     AVAHI_LLIST_PREPEND(AvahiServiceBrowser, service_browsers, client->service_browsers, b);
    609 
    610     if (!(b->type = avahi_strdup(type))) {
    611         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    612         goto fail;
    613     }
    614 
    615     if (domain && domain[0])
    616         if (!(b->domain = avahi_strdup(domain))) {
    617             avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    618             goto fail;
    619         }
    620 
    621     if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "ServiceBrowserNew"))) {
    622         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    623         goto fail;
    624     }
    625 
    626     i_interface = (int32_t) interface;
    627     i_protocol = (int32_t) protocol;
    628     u_flags = (uint32_t) flags;
    629 
    630     if (!dbus_message_append_args(
    631             message,
    632             DBUS_TYPE_INT32, &i_interface,
    633             DBUS_TYPE_INT32, &i_protocol,
    634             DBUS_TYPE_STRING, &type,
    635             DBUS_TYPE_STRING, &domain,
    636             DBUS_TYPE_UINT32, &u_flags,
    637             DBUS_TYPE_INVALID)) {
    638         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    639         goto fail;
    640     }
    641 
    642     if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) ||
    643         dbus_error_is_set(&error)) {
    644         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
    645         goto fail;
    646     }
    647 
    648     if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) ||
    649         dbus_error_is_set(&error) ||
    650         !path) {
    651         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
    652         goto fail;
    653     }
    654 
    655     if (!(b->path = avahi_strdup(path))) {
    656 
    657         /* FIXME: We don't remove the object on the server side */
    658 
    659         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    660         goto fail;
    661     }
    662 
    663     dbus_message_unref(message);
    664     dbus_message_unref(reply);
    665 
    666     return b;
    667 
    668 fail:
    669     if (dbus_error_is_set(&error)) {
    670         avahi_client_set_dbus_error(client, &error);
    671         dbus_error_free(&error);
    672     }
    673 
    674     if (b)
    675         avahi_service_browser_free(b);
    676 
    677     if (message)
    678         dbus_message_unref(message);
    679 
    680     if (reply)
    681         dbus_message_unref(reply);
    682 
    683     return NULL;
    684 }
    685 
    686 AvahiClient* avahi_service_browser_get_client (AvahiServiceBrowser *b) {
    687     assert(b);
    688     return b->client;
    689 }
    690 
    691 int avahi_service_browser_free (AvahiServiceBrowser *b) {
    692     AvahiClient *client;
    693     int r = AVAHI_OK;
    694 
    695     assert(b);
    696     client = b->client;
    697 
    698     if (b->path && avahi_client_is_connected(b->client))
    699         r = avahi_client_simple_method_call(client, b->path, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "Free");
    700 
    701     AVAHI_LLIST_REMOVE(AvahiServiceBrowser, service_browsers, b->client->service_browsers, b);
    702 
    703     avahi_free(b->path);
    704     avahi_free(b->type);
    705     avahi_free(b->domain);
    706     avahi_free(b);
    707     return r;
    708 }
    709 
    710 DBusHandlerResult avahi_service_browser_event(AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message) {
    711     AvahiServiceBrowser *b = NULL;
    712     DBusError error;
    713     const char *path;
    714     char *name = NULL, *type, *domain;
    715     int32_t interface, protocol;
    716     uint32_t flags = 0;
    717 
    718     dbus_error_init (&error);
    719 
    720     if (!(path = dbus_message_get_path(message)))
    721         goto fail;
    722 
    723     for (b = client->service_browsers; b; b = b->service_browsers_next)
    724         if (strcmp (b->path, path) == 0)
    725             break;
    726 
    727     if (!b)
    728         goto fail;
    729 
    730     type = b->type;
    731     domain = b->domain;
    732     interface = b->interface;
    733     protocol = b->protocol;
    734 
    735     switch (event) {
    736         case AVAHI_BROWSER_NEW:
    737         case AVAHI_BROWSER_REMOVE:
    738 
    739             if (!dbus_message_get_args (
    740                     message, &error,
    741                     DBUS_TYPE_INT32, &interface,
    742                     DBUS_TYPE_INT32, &protocol,
    743                     DBUS_TYPE_STRING, &name,
    744                     DBUS_TYPE_STRING, &type,
    745                     DBUS_TYPE_STRING, &domain,
    746                     DBUS_TYPE_UINT32, &flags,
    747                     DBUS_TYPE_INVALID) ||
    748                 dbus_error_is_set(&error)) {
    749                 fprintf(stderr, "Failed to parse browser event.\n");
    750                 goto fail;
    751             }
    752             break;
    753 
    754         case AVAHI_BROWSER_CACHE_EXHAUSTED:
    755         case AVAHI_BROWSER_ALL_FOR_NOW:
    756             break;
    757 
    758         case AVAHI_BROWSER_FAILURE: {
    759             char *etxt;
    760 
    761             if (!dbus_message_get_args(
    762                     message, &error,
    763                     DBUS_TYPE_STRING, &etxt,
    764                     DBUS_TYPE_INVALID) ||
    765                 dbus_error_is_set (&error)) {
    766                 fprintf(stderr, "Failed to parse browser event.\n");
    767                 goto fail;
    768             }
    769 
    770             avahi_client_set_errno(b->client, avahi_error_dbus_to_number(etxt));
    771             break;
    772         }
    773     }
    774 
    775     b->callback(b, (AvahiIfIndex) interface, (AvahiProtocol) protocol, event, name, type, domain, (AvahiLookupResultFlags) flags, b->userdata);
    776 
    777     return DBUS_HANDLER_RESULT_HANDLED;
    778 
    779 fail:
    780     dbus_error_free (&error);
    781     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    782 }
    783 
    784 /* AvahiRecordBrowser */
    785 
    786 AvahiRecordBrowser* avahi_record_browser_new(
    787     AvahiClient *client,
    788     AvahiIfIndex interface,
    789     AvahiProtocol protocol,
    790     const char *name,
    791     uint16_t clazz,
    792     uint16_t type,
    793     AvahiLookupFlags flags,
    794     AvahiRecordBrowserCallback callback,
    795     void *userdata) {
    796 
    797     AvahiRecordBrowser *b = NULL;
    798     DBusMessage *message = NULL, *reply = NULL;
    799     DBusError error;
    800     char *path;
    801     int32_t i_protocol, i_interface;
    802     uint32_t u_flags;
    803 
    804     assert(client);
    805     assert(name);
    806     assert(callback);
    807 
    808     dbus_error_init(&error);
    809 
    810     if (!avahi_client_is_connected(client)) {
    811         avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE);
    812         goto fail;
    813     }
    814 
    815     if (!(b = avahi_new(AvahiRecordBrowser, 1))) {
    816         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    817         goto fail;
    818     }
    819 
    820     b->client = client;
    821     b->callback = callback;
    822     b->userdata = userdata;
    823     b->path = NULL;
    824     b->name = NULL;
    825     b->clazz = clazz;
    826     b->type = type;
    827     b->interface = interface;
    828     b->protocol = protocol;
    829 
    830     AVAHI_LLIST_PREPEND(AvahiRecordBrowser, record_browsers, client->record_browsers, b);
    831 
    832     if (!(b->name = avahi_strdup(name))) {
    833         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    834         goto fail;
    835     }
    836 
    837     if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "RecordBrowserNew"))) {
    838         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    839         goto fail;
    840     }
    841 
    842     i_interface = (int32_t) interface;
    843     i_protocol = (int32_t) protocol;
    844     u_flags = (uint32_t) flags;
    845 
    846     if (!dbus_message_append_args(
    847             message,
    848             DBUS_TYPE_INT32, &i_interface,
    849             DBUS_TYPE_INT32, &i_protocol,
    850             DBUS_TYPE_STRING, &name,
    851             DBUS_TYPE_UINT16, &clazz,
    852             DBUS_TYPE_UINT16, &type,
    853             DBUS_TYPE_UINT32, &u_flags,
    854             DBUS_TYPE_INVALID)) {
    855         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    856         goto fail;
    857     }
    858 
    859     if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) ||
    860         dbus_error_is_set(&error)) {
    861         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
    862         goto fail;
    863     }
    864 
    865     if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) ||
    866         dbus_error_is_set(&error) ||
    867         !path) {
    868         avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR);
    869         goto fail;
    870     }
    871 
    872     if (!(b->path = avahi_strdup(path))) {
    873 
    874         /* FIXME: We don't remove the object on the server side */
    875 
    876         avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY);
    877         goto fail;
    878     }
    879 
    880     dbus_message_unref(message);
    881     dbus_message_unref(reply);
    882 
    883     return b;
    884 
    885 fail:
    886     if (dbus_error_is_set(&error)) {
    887         avahi_client_set_dbus_error(client, &error);
    888         dbus_error_free(&error);
    889     }
    890 
    891     if (b)
    892         avahi_record_browser_free(b);
    893 
    894     if (message)
    895         dbus_message_unref(message);
    896 
    897     if (reply)
    898         dbus_message_unref(reply);
    899 
    900     return NULL;
    901 }
    902 
    903 AvahiClient* avahi_record_browser_get_client (AvahiRecordBrowser *b) {
    904     assert(b);
    905     return b->client;
    906 }
    907 
    908 int avahi_record_browser_free (AvahiRecordBrowser *b) {
    909     AvahiClient *client;
    910     int r = AVAHI_OK;
    911 
    912     assert(b);
    913     client = b->client;
    914 
    915     if (b->path && avahi_client_is_connected(b->client))
    916         r = avahi_client_simple_method_call(client, b->path, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "Free");
    917 
    918     AVAHI_LLIST_REMOVE(AvahiRecordBrowser, record_browsers, b->client->record_browsers, b);
    919 
    920     avahi_free(b->path);
    921     avahi_free(b->name);
    922     avahi_free(b);
    923     return r;
    924 }
    925 
    926 DBusHandlerResult avahi_record_browser_event(AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message) {
    927     AvahiRecordBrowser *b = NULL;
    928     DBusError error;
    929     const char *path;
    930     char *name;
    931     int32_t interface, protocol;
    932     uint32_t flags = 0;
    933     uint16_t clazz, type;
    934     void *rdata = NULL;
    935     int rdata_size = 0;
    936 
    937     dbus_error_init (&error);
    938 
    939     if (!(path = dbus_message_get_path(message)))
    940         goto fail;
    941 
    942     for (b = client->record_browsers; b; b = b->record_browsers_next)
    943         if (strcmp (b->path, path) == 0)
    944             break;
    945 
    946     if (!b)
    947         goto fail;
    948 
    949     interface = b->interface;
    950     protocol = b->protocol;
    951     clazz = b->clazz;
    952     type = b->type;
    953     name = b->name;
    954 
    955     switch (event) {
    956         case AVAHI_BROWSER_NEW:
    957         case AVAHI_BROWSER_REMOVE: {
    958             DBusMessageIter iter, sub;
    959             int j;
    960 
    961             if (!dbus_message_get_args (
    962                     message, &error,
    963                     DBUS_TYPE_INT32, &interface,
    964                     DBUS_TYPE_INT32, &protocol,
    965                     DBUS_TYPE_STRING, &name,
    966                     DBUS_TYPE_UINT16, &clazz,
    967                     DBUS_TYPE_UINT16, &type,
    968                     DBUS_TYPE_INVALID) ||
    969                 dbus_error_is_set(&error)) {
    970                 fprintf(stderr, "Failed to parse browser event.\n");
    971                 goto fail;
    972             }
    973 
    974 
    975             dbus_message_iter_init(message, &iter);
    976 
    977             for (j = 0; j < 5; j++)
    978                 dbus_message_iter_next(&iter);
    979 
    980             if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
    981                 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE)
    982                 goto fail;
    983 
    984             dbus_message_iter_recurse(&iter, &sub);
    985             dbus_message_iter_get_fixed_array(&sub, &rdata, &rdata_size);
    986 
    987             dbus_message_iter_next(&iter);
    988 
    989             if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
    990                 goto fail;
    991 
    992             dbus_message_iter_get_basic(&iter, &flags);
    993 
    994             break;
    995         }
    996 
    997         case AVAHI_BROWSER_CACHE_EXHAUSTED:
    998         case AVAHI_BROWSER_ALL_FOR_NOW:
    999             break;
   1000 
   1001         case AVAHI_BROWSER_FAILURE: {
   1002             char *etxt;
   1003 
   1004             if (!dbus_message_get_args(
   1005                     message, &error,
   1006                     DBUS_TYPE_STRING, &etxt,
   1007                     DBUS_TYPE_INVALID) ||
   1008                 dbus_error_is_set (&error)) {
   1009                 fprintf(stderr, "Failed to parse browser event.\n");
   1010                 goto fail;
   1011             }
   1012 
   1013             avahi_client_set_errno(b->client, avahi_error_dbus_to_number(etxt));
   1014             break;
   1015         }
   1016     }
   1017 
   1018     b->callback(b, (AvahiIfIndex) interface, (AvahiProtocol) protocol, event, name, clazz, type, rdata, (size_t) rdata_size, (AvahiLookupResultFlags) flags, b->userdata);
   1019 
   1020     return DBUS_HANDLER_RESULT_HANDLED;
   1021 
   1022 fail:
   1023     dbus_error_free (&error);
   1024     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
   1025 }
   1026