Home | History | Annotate | Download | only in avahi-core
      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 
     26 #include <avahi-common/domain.h>
     27 #include "avahi-common/avahi-malloc.h"
     28 #include <avahi-common/error.h>
     29 
     30 #include "browse.h"
     31 #include "log.h"
     32 
     33 struct AvahiSDomainBrowser {
     34     int ref;
     35 
     36     AvahiServer *server;
     37 
     38     AvahiSRecordBrowser *record_browser;
     39 
     40     AvahiDomainBrowserType type;
     41     AvahiSDomainBrowserCallback callback;
     42     void* userdata;
     43 
     44     AvahiTimeEvent *defer_event;
     45 
     46     int all_for_now_scheduled;
     47 
     48     AVAHI_LLIST_FIELDS(AvahiSDomainBrowser, browser);
     49 };
     50 
     51 static void inc_ref(AvahiSDomainBrowser *b) {
     52     assert(b);
     53     assert(b->ref >= 1);
     54 
     55     b->ref++;
     56 }
     57 
     58 static void record_browser_callback(
     59     AvahiSRecordBrowser*rr,
     60     AvahiIfIndex interface,
     61     AvahiProtocol protocol,
     62     AvahiBrowserEvent event,
     63     AvahiRecord *record,
     64     AvahiLookupResultFlags flags,
     65     void* userdata) {
     66 
     67     AvahiSDomainBrowser *b = userdata;
     68     char *n = NULL;
     69 
     70     assert(rr);
     71     assert(b);
     72 
     73     if (event == AVAHI_BROWSER_ALL_FOR_NOW &&
     74         b->defer_event) {
     75 
     76         b->all_for_now_scheduled = 1;
     77         return;
     78     }
     79 
     80     /* Filter flags */
     81     flags &= AVAHI_LOOKUP_RESULT_CACHED | AVAHI_LOOKUP_RESULT_MULTICAST | AVAHI_LOOKUP_RESULT_WIDE_AREA;
     82 
     83     if (record) {
     84         assert(record->key->type == AVAHI_DNS_TYPE_PTR);
     85         n = record->data.ptr.name;
     86 
     87         if (b->type == AVAHI_DOMAIN_BROWSER_BROWSE) {
     88             AvahiStringList *l;
     89 
     90             /* Filter out entries defined statically */
     91 
     92             for (l = b->server->config.browse_domains; l; l = l->next)
     93                 if (avahi_domain_equal((char*) l->text, n))
     94                     return;
     95         }
     96 
     97     }
     98 
     99     b->callback(b, interface, protocol, event, n, flags, b->userdata);
    100 }
    101 
    102 static void defer_callback(AvahiTimeEvent *e, void *userdata) {
    103     AvahiSDomainBrowser *b = userdata;
    104     AvahiStringList *l;
    105 
    106     assert(e);
    107     assert(b);
    108 
    109     assert(b->type == AVAHI_DOMAIN_BROWSER_BROWSE);
    110 
    111     avahi_time_event_free(b->defer_event);
    112     b->defer_event = NULL;
    113 
    114     /* Increase ref counter */
    115     inc_ref(b);
    116 
    117     for (l = b->server->config.browse_domains; l; l = l->next) {
    118 
    119         /* Check whether this object still exists outside our own
    120          * stack frame */
    121         if (b->ref <= 1)
    122             break;
    123 
    124         b->callback(b, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AVAHI_BROWSER_NEW, (char*) l->text, AVAHI_LOOKUP_RESULT_STATIC, b->userdata);
    125     }
    126 
    127     if (b->ref > 1) {
    128         /* If the ALL_FOR_NOW event has already been scheduled, execute it now */
    129 
    130         if (b->all_for_now_scheduled)
    131             b->callback(b, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AVAHI_BROWSER_ALL_FOR_NOW, NULL, 0, b->userdata);
    132     }
    133 
    134     /* Decrease ref counter */
    135     avahi_s_domain_browser_free(b);
    136 }
    137 
    138 AvahiSDomainBrowser *avahi_s_domain_browser_new(
    139     AvahiServer *server,
    140     AvahiIfIndex interface,
    141     AvahiProtocol protocol,
    142     const char *domain,
    143     AvahiDomainBrowserType type,
    144     AvahiLookupFlags flags,
    145     AvahiSDomainBrowserCallback callback,
    146     void* userdata) {
    147 
    148     static const char * const type_table[AVAHI_DOMAIN_BROWSER_MAX] = {
    149         "b",
    150         "db",
    151         "r",
    152         "dr",
    153         "lb"
    154     };
    155 
    156     AvahiSDomainBrowser *b;
    157     AvahiKey *k = NULL;
    158     char n[AVAHI_DOMAIN_NAME_MAX];
    159     int r;
    160 
    161     assert(server);
    162     assert(callback);
    163 
    164     AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE);
    165     AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL);
    166     AVAHI_CHECK_VALIDITY_RETURN_NULL(server, type < AVAHI_DOMAIN_BROWSER_MAX, AVAHI_ERR_INVALID_FLAGS);
    167     AVAHI_CHECK_VALIDITY_RETURN_NULL(server, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME);
    168     AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_FLAGS_VALID(flags, AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS);
    169 
    170     if (!domain)
    171         domain = server->domain_name;
    172 
    173     if ((r = avahi_service_name_join(n, sizeof(n), type_table[type], "_dns-sd._udp", domain)) < 0) {
    174         avahi_server_set_errno(server, r);
    175         return NULL;
    176     }
    177 
    178     if (!(b = avahi_new(AvahiSDomainBrowser, 1))) {
    179         avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
    180         return NULL;
    181     }
    182 
    183     b->ref = 1;
    184     b->server = server;
    185     b->callback = callback;
    186     b->userdata = userdata;
    187     b->record_browser = NULL;
    188     b->type = type;
    189     b->all_for_now_scheduled = 0;
    190     b->defer_event = NULL;
    191 
    192     AVAHI_LLIST_PREPEND(AvahiSDomainBrowser, browser, server->domain_browsers, b);
    193 
    194     if (!(k = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_PTR))) {
    195         avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
    196         goto fail;
    197     }
    198 
    199     if (!(b->record_browser = avahi_s_record_browser_new(server, interface, protocol, k, flags, record_browser_callback, b)))
    200         goto fail;
    201 
    202     avahi_key_unref(k);
    203 
    204     if (type == AVAHI_DOMAIN_BROWSER_BROWSE && b->server->config.browse_domains)
    205         b->defer_event = avahi_time_event_new(server->time_event_queue, NULL, defer_callback, b);
    206 
    207     return b;
    208 
    209 fail:
    210 
    211     if (k)
    212         avahi_key_unref(k);
    213 
    214     avahi_s_domain_browser_free(b);
    215 
    216     return NULL;
    217 }
    218 
    219 void avahi_s_domain_browser_free(AvahiSDomainBrowser *b) {
    220     assert(b);
    221 
    222     assert(b->ref >= 1);
    223     if (--b->ref > 0)
    224         return;
    225 
    226     AVAHI_LLIST_REMOVE(AvahiSDomainBrowser, browser, b->server->domain_browsers, b);
    227 
    228     if (b->record_browser)
    229         avahi_s_record_browser_free(b->record_browser);
    230 
    231     if (b->defer_event)
    232         avahi_time_event_free(b->defer_event);
    233 
    234     avahi_free(b);
    235 }
    236