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 <string.h> 25#include <errno.h> 26#include <stdio.h> 27 28#include <avahi-common/llist.h> 29#include <avahi-common/malloc.h> 30#include <avahi-common/error.h> 31#include <avahi-core/log.h> 32#include <avahi-core/publish.h> 33 34#include "main.h" 35#include "cnames.h" 36 37typedef struct CName CName; 38 39struct CName { 40 AvahiSEntryGroup *group; 41 int iteration; 42 43 char *cname; 44 45 int publish_proto; /*0/mDNS/LLMNR*/ 46 47 AVAHI_LLIST_FIELDS(CName, cnames); 48}; 49 50static AVAHI_LLIST_HEAD(CName, cnames) = NULL; 51static int current_iteration = 0; 52 53static void add_cname_to_server(CName *c); 54static void remove_cname_from_server(CName *c); 55 56static void entry_group_callback(AvahiServer *s, AVAHI_GCC_UNUSED AvahiSEntryGroup *eg, AvahiEntryGroupState state, void* userdata) { 57 CName *c; 58 59 assert(s); 60 assert(eg); 61 62 c = userdata; 63 64 switch (state) { 65 66 case AVAHI_ENTRY_GROUP_COLLISION: 67 avahi_log_error("Conflict for alias \"%s\", not established.", c->cname); 68 break; 69 70 case AVAHI_ENTRY_GROUP_ESTABLISHED: 71 avahi_log_notice ("Alias \"%s\" successfully established.", c->cname); 72 break; 73 74 case AVAHI_ENTRY_GROUP_FAILURE: 75 avahi_log_notice ("Failed to establish alias \"%s\": %s.", c->cname, avahi_strerror (avahi_server_errno (s))); 76 break; 77 78 case AVAHI_ENTRY_GROUP_UNCOMMITED: 79 case AVAHI_ENTRY_GROUP_REGISTERING: 80 ; 81 } 82} 83 84static CName *cname_new(void) { 85 CName *c; 86 87 c = avahi_new(CName, 1); 88 89 c->group = NULL; 90 c->cname = NULL; 91 c->iteration = current_iteration; 92 93 AVAHI_LLIST_PREPEND(CName, cnames, cnames, c); 94 95 return c; 96} 97 98static void cname_free(CName *c) { 99 assert(c); 100 101 AVAHI_LLIST_REMOVE(CName, cnames, cnames, c); 102 103 if (c->group) 104 avahi_s_entry_group_free(c->group); 105 106 avahi_free(c->cname); 107 108 avahi_free(c); 109} 110 111static CName *cname_find(const char *name) { 112 CName *c; 113 114 assert(name); 115 116 for (c = cnames; c; c = c->cnames_next) 117 if (!strcmp(c->cname, name)) 118 return c; 119 120 return NULL; 121} 122 123static void add_cname_to_server(CName *c) 124{ 125 avahi_log_error("add_cname_to_server start."); 126 if (!c->group) 127 if (!(c->group = avahi_s_entry_group_new (avahi_server, entry_group_callback, c))) { 128 avahi_log_error("avahi_s_entry_group_new() failed: %s", avahi_strerror(avahi_server_errno(avahi_server))); 129 return; 130 } 131 132 if (avahi_s_entry_group_is_empty(c->group)) { 133 int err; 134 135 c->publish_proto = AVAHI_PUBLISH_USE_MULTICAST; 136 137 if ((err = avahi_server_add_cname(avahi_server, c->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, c->publish_proto, AVAHI_DEFAULT_TTL_HOST_NAME, c->cname)) < 0) { 138 avahi_log_error ("Alias %s: avahi_server_add_cname failure: %s", c->cname, avahi_strerror(err)); 139 return; 140 } 141 142 avahi_s_entry_group_commit (c->group); 143 } 144} 145 146static void remove_cname_from_server(CName *c) 147{ 148 if (c->group) 149 avahi_s_entry_group_reset (c->group); 150} 151 152void cnames_add_to_server(void) { 153 CName *c; 154 155 for (c = cnames; c; c = c->cnames_next){ 156 avahi_log_error("cnames_add_to_server start."); 157 add_cname_to_server(c); 158 } 159} 160 161void cnames_remove_from_server(void) { 162 CName *c; 163 164 for (c = cnames; c; c = c->cnames_next) 165 remove_cname_from_server(c); 166} 167 168void cnames_register(char **aliases) { 169 CName *c, *next; 170 char **name; 171 172 current_iteration++; 173 174 for (name = aliases; name && *name; name++) { 175 if (!(c = cname_find(*name))) { 176 c = cname_new(); 177 c->cname = *name; 178 179 avahi_log_info("Loading new alias %s.", c->cname); 180 } 181 182 c->iteration = current_iteration; 183 } 184 185 for (c = cnames; c; c = next) { 186 next = c->cnames_next; 187 188 if (c->iteration != current_iteration) { 189 avahi_log_info("Alias %s vanished, removing.", c->cname); 190 cname_free(c); 191 } 192 } 193} 194 195void cnames_free_all (void) 196{ 197 while(cnames) 198 cname_free(cnames); 199} 200 201typedef struct LLMNR_CName LLMNR_CName; 202 203struct LLMNR_CName { 204 AvahiSEntryGroup *llmnr_group; 205 int iteration; 206 207 char *llmnr_cname; 208 209 int publish_proto; /*0/mDNS/LLMNR*/ 210 211 AVAHI_LLIST_FIELDS(LLMNR_CName, llmnr_cnames); 212}; 213 214static AVAHI_LLIST_HEAD(LLMNR_CName, llmnr_cnames) = NULL; 215static int llmnr_current_iteration = 0; 216 217static void add_llmnr_cname_to_server(LLMNR_CName *lc); 218static void remove_llmnr_cname_from_server(LLMNR_CName *lc); 219 220static void llmnr_entry_group_callback(AvahiServer *s, AVAHI_GCC_UNUSED AvahiSEntryGroup *eg, AvahiEntryGroupState state, void* userdata) { 221 LLMNR_CName *lc; 222 223 assert(s); 224 assert(eg); 225 226 lc = userdata; 227 228 switch (state) { 229 230 case AVAHI_ENTRY_GROUP_COLLISION: 231 avahi_log_error("Conflict for llmnr alias \"%s\", not established.", lc->llmnr_cname); 232 break; 233 234 case AVAHI_ENTRY_GROUP_ESTABLISHED: 235 avahi_log_notice ("LLMNR Alias \"%s\" successfully established.", lc->llmnr_cname); 236 break; 237 238 case AVAHI_ENTRY_GROUP_FAILURE: 239 avahi_log_notice ("Failed to establish llmnr alias \"%s\": %s.", lc->llmnr_cname, avahi_strerror (avahi_server_errno (s))); 240 break; 241 242 case AVAHI_ENTRY_GROUP_UNCOMMITED: 243 case AVAHI_ENTRY_GROUP_REGISTERING: 244 ; 245 } 246} 247 248static LLMNR_CName *llmnr_cname_new(void) { 249 LLMNR_CName *lc; 250 251 lc = avahi_new(LLMNR_CName, 1); 252 253 lc->llmnr_group = NULL; 254 lc->llmnr_cname = NULL; 255 lc->iteration = llmnr_current_iteration; 256 257 AVAHI_LLIST_PREPEND(LLMNR_CName, llmnr_cnames, llmnr_cnames, lc); 258 259 return lc; 260} 261 262static void llmnr_cname_free(LLMNR_CName *lc) { 263 assert(lc); 264 265 AVAHI_LLIST_REMOVE(LLMNR_CName, llmnr_cnames, llmnr_cnames, lc); 266 267 if (lc->llmnr_group) 268 avahi_s_entry_group_free(lc->llmnr_group); 269 270 avahi_free(lc->llmnr_cname); 271 272 avahi_free(lc); 273} 274 275static LLMNR_CName *llmnr_cname_find(const char *llmnr_name) { 276 LLMNR_CName *lc; 277 278 assert(llmnr_name); 279 280 for (lc = llmnr_cnames; lc; lc = lc->llmnr_cnames_next) 281 if (!strcmp(lc->llmnr_cname, llmnr_name)) 282 return lc; 283 284 return NULL; 285} 286 287static void add_llmnr_cname_to_server(LLMNR_CName *lc) 288{ 289 avahi_log_error("add_llmnr_cname_to_server start."); 290 if (!lc->llmnr_group) 291 if (!(lc->llmnr_group = avahi_s_entry_group_new (avahi_server, llmnr_entry_group_callback, lc))) { 292 avahi_log_error("avahi_s_llmnr_entry_group_new() failed: %s", avahi_strerror(avahi_server_errno(avahi_server))); 293 return; 294 } 295 296 if (avahi_s_entry_group_is_empty(lc->llmnr_group)) { 297 int err; 298 299 lc->publish_proto = AVAHI_PUBLISH_USE_LLMNR; 300 301 if ((err = avahi_server_add_llmnr_cname(avahi_server, lc->llmnr_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, lc->publish_proto, AVAHI_DEFAULT_TTL_HOST_NAME, lc->llmnr_cname)) < 0) { 302 avahi_log_error ("Alias %s: avahi_server_add_llmnr_cname failure: %s", lc->llmnr_cname, avahi_strerror(err)); 303 return; 304 } 305 306 avahi_s_entry_group_commit (lc->llmnr_group); 307 } 308} 309 310static void remove_llmnr_cname_from_server(LLMNR_CName *lc) 311{ 312 if (lc->llmnr_group) 313 avahi_s_entry_group_reset (lc->llmnr_group); 314} 315 316void llmnr_cnames_add_to_server(void) { 317 LLMNR_CName *lc; 318 319 for (lc = llmnr_cnames; lc; lc = lc->llmnr_cnames_next){ 320 avahi_log_error("llmnr_cnames_add_to_server start."); 321 add_llmnr_cname_to_server(lc); 322 } 323} 324 325void llmnr_cnames_remove_from_server(void) { 326 LLMNR_CName *lc; 327 328 for (lc = llmnr_cnames; lc; lc = lc->llmnr_cnames_next) 329 remove_llmnr_cname_from_server(lc); 330} 331 332void llmnr_cnames_register(char **aliases_llmnr) { 333 LLMNR_CName *lc, *llmnr_next; 334 char **llmnr_name; 335 336 llmnr_current_iteration++; 337 338 for (llmnr_name = aliases_llmnr; llmnr_name && *llmnr_name; llmnr_name++) { 339 if (!(lc = llmnr_cname_find(*llmnr_name))) { 340 lc = llmnr_cname_new(); 341 lc->llmnr_cname = *llmnr_name; 342 343 avahi_log_info("Loading new alias_llmnr %s.", lc->llmnr_cname); 344 } 345 346 lc->iteration = llmnr_current_iteration; 347 } 348 349 for (lc = llmnr_cnames; lc; lc = llmnr_next) { 350 llmnr_next = lc->llmnr_cnames_next; 351 352 if (lc->iteration != llmnr_current_iteration) { 353 avahi_log_info("Alias_llmnr %s vanished, removing.", lc->llmnr_cname); 354 llmnr_cname_free(lc); 355 } 356 } 357} 358 359void llmnr_cnames_free_all (void) 360{ 361 while(llmnr_cnames) 362 llmnr_cname_free(llmnr_cnames); 363} 364 365