browse-dns-server.c revision 0632e854728e8e64552ae08f90852d4a2658539e
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 "browse.h" 29#include "util.h" 30#include "log.h" 31#include "rr.h" 32 33typedef struct AvahiDNSServerInfo AvahiDNSServerInfo; 34 35struct AvahiDNSServerInfo { 36 AvahiDNSServerBrowser *browser; 37 38 AvahiIfIndex interface; 39 AvahiProtocol protocol; 40 AvahiRecord *srv_record; 41 AvahiHostNameResolver *host_name_resolver; 42 AvahiAddress address; 43 44 AVAHI_LLIST_FIELDS(AvahiDNSServerInfo, info); 45}; 46 47struct AvahiDNSServerBrowser { 48 AvahiServer *server; 49 gchar *domain_name; 50 51 AvahiRecordBrowser *record_browser; 52 AvahiDNSServerBrowserCallback callback; 53 gpointer userdata; 54 AvahiProtocol aprotocol; 55 56 guint n_info; 57 58 AVAHI_LLIST_FIELDS(AvahiDNSServerBrowser, browser); 59 AVAHI_LLIST_HEAD(AvahiDNSServerInfo, info); 60}; 61 62static AvahiDNSServerInfo* get_server_info(AvahiDNSServerBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiRecord *r) { 63 AvahiDNSServerInfo *i; 64 65 g_assert(b); 66 g_assert(r); 67 68 for (i = b->info; i; i = i->info_next) 69 if (i->interface == interface && 70 i->protocol == protocol && 71 avahi_record_equal_no_ttl(r, i->srv_record)) 72 return i; 73 74 return NULL; 75} 76 77static void server_info_free(AvahiDNSServerBrowser *b, AvahiDNSServerInfo *i) { 78 g_assert(b); 79 g_assert(i); 80 81 avahi_record_unref(i->srv_record); 82 if (i->host_name_resolver) 83 avahi_host_name_resolver_free(i->host_name_resolver); 84 85 AVAHI_LLIST_REMOVE(AvahiDNSServerInfo, info, b->info, i); 86 87 g_assert(b->n_info >= 1); 88 b->n_info--; 89 90 g_free(i); 91} 92 93static void host_name_resolver_callback(AvahiHostNameResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const gchar *host_name, const AvahiAddress *a, gpointer userdata) { 94 AvahiDNSServerInfo *i = userdata; 95 96 g_assert(r); 97 g_assert(host_name); 98 g_assert(i); 99 100 if (event == AVAHI_RESOLVER_FOUND) { 101 i->address = *a; 102 103 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); 104 } 105 106 avahi_host_name_resolver_free(i->host_name_resolver); 107 i->host_name_resolver = NULL; 108} 109 110static void record_browser_callback(AvahiRecordBrowser*rr, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, AvahiRecord *record, gpointer userdata) { 111 AvahiDNSServerBrowser *b = userdata; 112 113 g_assert(rr); 114 g_assert(record); 115 g_assert(b); 116 117 g_assert(record->key->type == AVAHI_DNS_TYPE_SRV); 118 119 if (event == AVAHI_BROWSER_NEW) { 120 AvahiDNSServerInfo *i; 121 122 if (get_server_info(b, interface, protocol, record)) 123 return; 124 125 if (b->n_info >= 10) 126 return; 127 128 i = g_new(AvahiDNSServerInfo, 1); 129 i->browser = b; 130 i->interface = interface; 131 i->protocol = protocol; 132 i->srv_record = avahi_record_ref(record); 133 i->host_name_resolver = avahi_host_name_resolver_new(b->server, interface, protocol, record->data.srv.name, b->aprotocol, host_name_resolver_callback, i); 134 135 AVAHI_LLIST_PREPEND(AvahiDNSServerInfo, info, b->info, i); 136 137 b->n_info++; 138 } else if (event == AVAHI_BROWSER_REMOVE) { 139 AvahiDNSServerInfo *i; 140 141 if (!(i = get_server_info(b, interface, protocol, record))) 142 return; 143 144 if (!i->host_name_resolver) 145 b->callback(b, interface, protocol, event, i->srv_record->data.srv.name, &i->address, i->srv_record->data.srv.port, b->userdata); 146 147 server_info_free(b, i); 148 } 149} 150 151AvahiDNSServerBrowser *avahi_dns_server_browser_new(AvahiServer *server, AvahiIfIndex interface, AvahiProtocol protocol, const gchar *domain, AvahiDNSServerType type, AvahiProtocol aprotocol, AvahiDNSServerBrowserCallback callback, gpointer userdata) { 152 AvahiDNSServerBrowser *b; 153 AvahiKey *k; 154 gchar *n = NULL; 155 156 g_assert(server); 157 g_assert(callback); 158 g_assert(type == AVAHI_DNS_SERVER_RESOLVE || type == AVAHI_DNS_SERVER_UPDATE); 159 160 if (domain && !avahi_valid_domain_name(domain)) { 161 avahi_server_set_errno(server, AVAHI_ERR_INVALID_DOMAIN_NAME); 162 return NULL; 163 } 164 165 b = g_new(AvahiDNSServerBrowser, 1); 166 b->server = server; 167 b->domain_name = avahi_normalize_name(domain ? domain : "local"); 168 b->callback = callback; 169 b->userdata = userdata; 170 b->aprotocol = aprotocol; 171 b->n_info = 0; 172 173 AVAHI_LLIST_HEAD_INIT(AvahiDNSServerInfo, b->info); 174 AVAHI_LLIST_PREPEND(AvahiDNSServerBrowser, browser, server->dns_server_browsers, b); 175 176 n = g_strdup_printf("%s.%s",type == AVAHI_DNS_SERVER_RESOLVE ? "_domain._udp" : "_dns-update._udp", b->domain_name); 177 k = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV); 178 g_free(n); 179 180 b->record_browser = avahi_record_browser_new(server, interface, protocol, k, record_browser_callback, b); 181 avahi_key_unref(k); 182 183 if (!b->record_browser) { 184 avahi_dns_server_browser_free(b); 185 return NULL; 186 } 187 188 return b; 189} 190 191void avahi_dns_server_browser_free(AvahiDNSServerBrowser *b) { 192 g_assert(b); 193 194 while (b->info) 195 server_info_free(b, b->info); 196 197 AVAHI_LLIST_REMOVE(AvahiDNSServerBrowser, browser, b->server->dns_server_browsers, b); 198 199 if (b->record_browser) 200 avahi_record_browser_free(b->record_browser); 201 g_free(b->domain_name); 202 g_free(b); 203} 204 205