browse-dns-server.c revision af548e38c2c282132ddac2a75a76218ff3be3175
1/* $Id$ */ 2 3/*** 4 This file is part of avahi. 5 6 avahi is free software; you can redistribute it and/or modify it 7 under the terms of the GNU Lesser General Public License as 8 published by the Free Software Foundation; either version 2.1 of the 9 License, or (at your option) any later version. 10 11 avahi is distributed in the hope that it will be useful, but WITHOUT 12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 14 Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with avahi; if not, write to the Free Software 18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 19 USA. 20***/ 21 22#ifdef HAVE_CONFIG_H 23#include <config.h> 24#endif 25 26#include <string.h> 27 28#include <avahi-common/domain.h> 29#include <avahi-common/malloc.h> 30#include <avahi-common/error.h> 31 32#include "browse.h" 33#include "log.h" 34#include "rr.h" 35 36typedef struct AvahiDNSServerInfo AvahiDNSServerInfo; 37 38struct AvahiDNSServerInfo { 39 AvahiSDNSServerBrowser *browser; 40 41 AvahiIfIndex interface; 42 AvahiProtocol protocol; 43 AvahiRecord *srv_record; 44 AvahiSHostNameResolver *host_name_resolver; 45 AvahiAddress address; 46 47 AVAHI_LLIST_FIELDS(AvahiDNSServerInfo, info); 48}; 49 50struct AvahiSDNSServerBrowser { 51 AvahiServer *server; 52 char *domain_name; 53 54 AvahiSRecordBrowser *record_browser; 55 AvahiSDNSServerBrowserCallback callback; 56 void* userdata; 57 AvahiProtocol aprotocol; 58 59 unsigned n_info; 60 61 AVAHI_LLIST_FIELDS(AvahiSDNSServerBrowser, browser); 62 AVAHI_LLIST_HEAD(AvahiDNSServerInfo, info); 63}; 64 65static AvahiDNSServerInfo* get_server_info(AvahiSDNSServerBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiRecord *r) { 66 AvahiDNSServerInfo *i; 67 68 assert(b); 69 assert(r); 70 71 for (i = b->info; i; i = i->info_next) 72 if (i->interface == interface && 73 i->protocol == protocol && 74 avahi_record_equal_no_ttl(r, i->srv_record)) 75 return i; 76 77 return NULL; 78} 79 80static void server_info_free(AvahiSDNSServerBrowser *b, AvahiDNSServerInfo *i) { 81 assert(b); 82 assert(i); 83 84 avahi_record_unref(i->srv_record); 85 if (i->host_name_resolver) 86 avahi_s_host_name_resolver_free(i->host_name_resolver); 87 88 AVAHI_LLIST_REMOVE(AvahiDNSServerInfo, info, b->info, i); 89 90 assert(b->n_info >= 1); 91 b->n_info--; 92 93 avahi_free(i); 94} 95 96static void host_name_resolver_callback(AvahiSHostNameResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *host_name, const AvahiAddress *a, void* userdata) { 97 AvahiDNSServerInfo *i = userdata; 98 99 assert(r); 100 assert(host_name); 101 assert(i); 102 103 if (event == AVAHI_RESOLVER_FOUND) { 104 i->address = *a; 105 106 i->browser->callback(i->browser, i->interface, i->protocol, AVAHI_BROWSER_NEW, i->srv_record->data.srv.name, &i->address, i->srv_record->data.srv.port, i->browser->userdata); 107 } 108 109 avahi_s_host_name_resolver_free(i->host_name_resolver); 110 i->host_name_resolver = NULL; 111} 112 113static void record_browser_callback(AvahiSRecordBrowser*rr, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, AvahiRecord *record, void* userdata) { 114 AvahiSDNSServerBrowser *b = userdata; 115 116 assert(rr); 117 assert(record); 118 assert(b); 119 120 assert(record->key->type == AVAHI_DNS_TYPE_SRV); 121 122 if (event == AVAHI_BROWSER_NEW) { 123 AvahiDNSServerInfo *i; 124 125 if (get_server_info(b, interface, protocol, record)) 126 return; 127 128 if (b->n_info >= 10) 129 return; 130 131 if (!(i = avahi_new(AvahiDNSServerInfo, 1))) 132 return; /* OOM */ 133 134 i->browser = b; 135 i->interface = interface; 136 i->protocol = protocol; 137 i->srv_record = avahi_record_ref(record); 138 i->host_name_resolver = avahi_s_host_name_resolver_new(b->server, interface, protocol, record->data.srv.name, b->aprotocol, host_name_resolver_callback, i); 139 140 AVAHI_LLIST_PREPEND(AvahiDNSServerInfo, info, b->info, i); 141 142 b->n_info++; 143 } else if (event == AVAHI_BROWSER_REMOVE) { 144 AvahiDNSServerInfo *i; 145 146 if (!(i = get_server_info(b, interface, protocol, record))) 147 return; 148 149 if (!i->host_name_resolver) 150 b->callback(b, interface, protocol, event, i->srv_record->data.srv.name, &i->address, i->srv_record->data.srv.port, b->userdata); 151 152 server_info_free(b, i); 153 } 154} 155 156AvahiSDNSServerBrowser *avahi_s_dns_server_browser_new(AvahiServer *server, AvahiIfIndex interface, AvahiProtocol protocol, const char *domain, AvahiDNSServerType type, AvahiProtocol aprotocol, AvahiSDNSServerBrowserCallback callback, void* userdata) { 157 AvahiSDNSServerBrowser *b; 158 AvahiKey *k; 159 char *n = NULL; 160 161 assert(server); 162 assert(callback); 163 assert(type == AVAHI_DNS_SERVER_RESOLVE || type == AVAHI_DNS_SERVER_UPDATE); 164 165 if (domain && !avahi_is_valid_domain_name(domain)) { 166 avahi_server_set_errno(server, AVAHI_ERR_INVALID_DOMAIN_NAME); 167 return NULL; 168 } 169 170 if (!(b = avahi_new(AvahiSDNSServerBrowser, 1))) { 171 avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY); 172 return NULL; 173 } 174 175 b->server = server; 176 b->domain_name = avahi_normalize_name(domain ? domain : "local"); 177 b->callback = callback; 178 b->userdata = userdata; 179 b->aprotocol = aprotocol; 180 b->n_info = 0; 181 182 AVAHI_LLIST_HEAD_INIT(AvahiDNSServerInfo, b->info); 183 AVAHI_LLIST_PREPEND(AvahiSDNSServerBrowser, browser, server->dns_server_browsers, b); 184 185 n = avahi_strdup_printf("%s.%s",type == AVAHI_DNS_SERVER_RESOLVE ? "_domain._udp" : "_dns-update._udp", b->domain_name); 186 k = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV); 187 avahi_free(n); 188 189 b->record_browser = avahi_s_record_browser_new(server, interface, protocol, k, record_browser_callback, b); 190 avahi_key_unref(k); 191 192 if (!b->record_browser) { 193 avahi_s_dns_server_browser_free(b); 194 return NULL; 195 } 196 197 return b; 198} 199 200void avahi_s_dns_server_browser_free(AvahiSDNSServerBrowser *b) { 201 assert(b); 202 203 while (b->info) 204 server_info_free(b, b->info); 205 206 AVAHI_LLIST_REMOVE(AvahiSDNSServerBrowser, browser, b->server->dns_server_browsers, b); 207 208 if (b->record_browser) 209 avahi_s_record_browser_free(b->record_browser); 210 avahi_free(b->domain_name); 211 avahi_free(b); 212} 213 214