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 <assert.h> 27 28#include <sys/types.h> 29#include <sys/socket.h> 30#include <netinet/in.h> 31#include <arpa/inet.h> 32 33#include "avahi-common/avahi-malloc.h" 34#include <avahi-common/simple-watch.h> 35#include <avahi-common/alternative.h> 36#include <avahi-common/timeval.h> 37 38#include <avahi-core/core.h> 39#include <avahi-core/log.h> 40#include <avahi-core/publish.h> 41#include <avahi-core/lookup.h> 42#include <avahi-core/dns-srv-rr.h> 43 44static AvahiSEntryGroup *group = NULL; 45static AvahiServer *server = NULL; 46static char *service_name = NULL; 47 48static const AvahiPoll *poll_api; 49 50static void quit_timeout_callback(AVAHI_GCC_UNUSED AvahiTimeout *timeout, void* userdata) { 51 AvahiSimplePoll *simple_poll = userdata; 52 53 avahi_simple_poll_quit(simple_poll); 54} 55 56static void dump_line(const char *text, AVAHI_GCC_UNUSED void* userdata) { 57 printf("%s\n", text); 58} 59 60static void dump_timeout_callback(AvahiTimeout *timeout, void* userdata) { 61 struct timeval tv; 62 63 AvahiServer *avahi = userdata; 64 avahi_server_dump(avahi, dump_line, NULL); 65 66 avahi_elapse_time(&tv, 5000, 0); 67 poll_api->timeout_update(timeout, &tv); 68} 69 70static const char *browser_event_to_string(AvahiBrowserEvent event) { 71 switch (event) { 72 case AVAHI_BROWSER_NEW : return "NEW"; 73 case AVAHI_BROWSER_REMOVE : return "REMOVE"; 74 case AVAHI_BROWSER_CACHE_EXHAUSTED : return "CACHE_EXHAUSTED"; 75 case AVAHI_BROWSER_ALL_FOR_NOW : return "ALL_FOR_NOW"; 76 case AVAHI_BROWSER_FAILURE : return "FAILURE"; 77 } 78 79 abort(); 80} 81 82static const char *resolver_event_to_string(AvahiResolverEvent event) { 83 switch (event) { 84 case AVAHI_RESOLVER_FOUND: return "FOUND"; 85 case AVAHI_RESOLVER_FAILURE: return "FAILURE"; 86 } 87 abort(); 88} 89 90static void record_browser_callback( 91 AvahiSRecordBrowser *r, 92 AvahiIfIndex interface, 93 AvahiProtocol protocol, 94 AvahiBrowserEvent event, 95 AvahiRecord *record, 96 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, 97 AVAHI_GCC_UNUSED void* userdata) { 98 char *t; 99 100 assert(r); 101 102 if (record) { 103 avahi_log_debug("RB: record [%s] on %i.%i is %s", t = avahi_record_to_string(record), interface, protocol, browser_event_to_string(event)); 104 avahi_free(t); 105 } else 106 avahi_log_debug("RB: [%s]", browser_event_to_string(event)); 107 108} 109 110static void remove_entries(void); 111static void create_entries(int new_name); 112 113static void entry_group_callback(AVAHI_GCC_UNUSED AvahiServer *s, AVAHI_GCC_UNUSED AvahiSEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void* userdata) { 114 avahi_log_debug("entry group state: %i", state); 115 116 if (state == AVAHI_ENTRY_GROUP_COLLISION) { 117 remove_entries(); 118 create_entries(1); 119 avahi_log_debug("Service name conflict, retrying with <%s>", service_name); 120 } else if (state == AVAHI_ENTRY_GROUP_ESTABLISHED) { 121 avahi_log_debug("Service established under name <%s>", service_name); 122 } 123} 124 125static void server_callback(AvahiServer *s, AvahiServerState state, AVAHI_GCC_UNUSED void* userdata) { 126 127 server = s; 128 avahi_log_debug("server state: %i", state); 129 130 if (state == AVAHI_SERVER_RUNNING) { 131 avahi_log_debug("Server startup complete. Host name is <%s>. Service cookie is %u", avahi_server_get_host_name_fqdn(s), avahi_server_get_local_service_cookie(s)); 132 create_entries(0); 133 } else if (state == AVAHI_SERVER_COLLISION) { 134 char *n; 135 remove_entries(); 136 137 n = avahi_alternative_host_name(avahi_server_get_host_name(s)); 138 139 avahi_log_debug("Host name conflict, retrying with <%s>", n); 140 avahi_server_set_host_name(s, n); 141 avahi_free(n); 142 } 143} 144 145static void remove_entries(void) { 146 if (group) 147 avahi_s_entry_group_reset(group); 148} 149 150static void create_entries(int new_name) { 151 AvahiAddress a; 152 AvahiRecord *r; 153 154 remove_entries(); 155 156 if (!group) 157 group = avahi_s_entry_group_new(server, entry_group_callback, NULL); 158 159 assert(avahi_s_entry_group_is_empty(group)); 160 161 if (!service_name) 162 service_name = avahi_strdup("Test Service"); 163 else if (new_name) { 164 char *n = avahi_alternative_service_name(service_name); 165 avahi_free(service_name); 166 service_name = n; 167 } 168 169 if (avahi_server_add_service(server, group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, service_name, "_http._tcp", NULL, NULL, 80, "foo", NULL) < 0) { 170 avahi_log_error("Failed to add HTTP service"); 171 goto fail; 172 } 173 174 if (avahi_server_add_service(server, group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, service_name, "_ftp._tcp", NULL, NULL, 21, "foo", NULL) < 0) { 175 avahi_log_error("Failed to add FTP service"); 176 goto fail; 177 } 178 179 if (avahi_server_add_service(server, group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0,service_name, "_webdav._tcp", NULL, NULL, 80, "foo", NULL) < 0) { 180 avahi_log_error("Failed to add WEBDAV service"); 181 goto fail; 182 } 183 184 if (avahi_server_add_dns_server_address(server, group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, NULL, AVAHI_DNS_SERVER_RESOLVE, avahi_address_parse("192.168.50.1", AVAHI_PROTO_UNSPEC, &a), 53) < 0) { 185 avahi_log_error("Failed to add new DNS Server address"); 186 goto fail; 187 } 188 189 r = avahi_record_new_full("cname.local", AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_CNAME, AVAHI_DEFAULT_TTL); 190 r->data.cname.name = avahi_strdup("cocaine.local"); 191 192 if (avahi_server_add(server, group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, r) < 0) { 193 avahi_record_unref(r); 194 avahi_log_error("Failed to add CNAME record"); 195 goto fail; 196 } 197 avahi_record_unref(r); 198 199 avahi_s_entry_group_commit(group); 200 return; 201 202fail: 203 if (group) 204 avahi_s_entry_group_free(group); 205 206 group = NULL; 207} 208 209static void hnr_callback( 210 AVAHI_GCC_UNUSED AvahiSHostNameResolver *r, 211 AvahiIfIndex iface, 212 AvahiProtocol protocol, 213 AvahiResolverEvent event, 214 const char *hostname, 215 const AvahiAddress *a, 216 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, 217 AVAHI_GCC_UNUSED void* userdata) { 218 char t[AVAHI_ADDRESS_STR_MAX]; 219 220 if (a) 221 avahi_address_snprint(t, sizeof(t), a); 222 223 avahi_log_debug("HNR: (%i.%i) <%s> -> %s [%s]", iface, protocol, hostname, a ? t : "n/a", resolver_event_to_string(event)); 224} 225 226static void ar_callback( 227 AVAHI_GCC_UNUSED AvahiSAddressResolver *r, 228 AvahiIfIndex iface, 229 AvahiProtocol protocol, 230 AvahiResolverEvent event, 231 const AvahiAddress *a, 232 const char *hostname, 233 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, 234 AVAHI_GCC_UNUSED void* userdata) { 235 char t[AVAHI_ADDRESS_STR_MAX]; 236 237 avahi_address_snprint(t, sizeof(t), a); 238 239 avahi_log_debug("AR: (%i.%i) %s -> <%s> [%s]", iface, protocol, t, hostname ? hostname : "n/a", resolver_event_to_string(event)); 240} 241 242static void db_callback( 243 AVAHI_GCC_UNUSED AvahiSDomainBrowser *b, 244 AvahiIfIndex iface, 245 AvahiProtocol protocol, 246 AvahiBrowserEvent event, 247 const char *domain, 248 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, 249 AVAHI_GCC_UNUSED void* userdata) { 250 251 avahi_log_debug("DB: (%i.%i) <%s> [%s]", iface, protocol, domain ? domain : "NULL", browser_event_to_string(event)); 252} 253 254static void stb_callback( 255 AVAHI_GCC_UNUSED AvahiSServiceTypeBrowser *b, 256 AvahiIfIndex iface, 257 AvahiProtocol protocol, 258 AvahiBrowserEvent event, 259 const char *service_type, 260 const char *domain, 261 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, 262 AVAHI_GCC_UNUSED void* userdata) { 263 264 avahi_log_debug("STB: (%i.%i) %s in <%s> [%s]", iface, protocol, service_type ? service_type : "NULL", domain ? domain : "NULL", browser_event_to_string(event)); 265} 266 267static void sb_callback( 268 AVAHI_GCC_UNUSED AvahiSServiceBrowser *b, 269 AvahiIfIndex iface, 270 AvahiProtocol protocol, 271 AvahiBrowserEvent event, 272 const char *name, 273 const char *service_type, 274 const char *domain, 275 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, 276 AVAHI_GCC_UNUSED void* userdata) { 277 avahi_log_debug("SB: (%i.%i) <%s> as %s in <%s> [%s]", iface, protocol, name ? name : "NULL", service_type ? service_type : "NULL", domain ? domain : "NULL", browser_event_to_string(event)); 278} 279 280static void sr_callback( 281 AVAHI_GCC_UNUSED AvahiSServiceResolver *r, 282 AvahiIfIndex iface, 283 AvahiProtocol protocol, 284 AvahiResolverEvent event, 285 const char *name, 286 const char*service_type, 287 const char*domain_name, 288 const char*hostname, 289 const AvahiAddress *a, 290 uint16_t port, 291 AvahiStringList *txt, 292 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, 293 AVAHI_GCC_UNUSED void* userdata) { 294 295 if (event != AVAHI_RESOLVER_FOUND) 296 avahi_log_debug("SR: (%i.%i) <%s> as %s in <%s> [%s]", iface, protocol, name, service_type, domain_name, resolver_event_to_string(event)); 297 else { 298 char t[AVAHI_ADDRESS_STR_MAX], *s; 299 300 avahi_address_snprint(t, sizeof(t), a); 301 302 s = avahi_string_list_to_string(txt); 303 avahi_log_debug("SR: (%i.%i) <%s> as %s in <%s>: %s/%s:%i (%s) [%s]", iface, protocol, name, service_type, domain_name, hostname, t, port, s, resolver_event_to_string(event)); 304 avahi_free(s); 305 } 306} 307 308static void dsb_callback( 309 AVAHI_GCC_UNUSED AvahiSDNSServerBrowser *b, 310 AvahiIfIndex iface, 311 AvahiProtocol protocol, 312 AvahiBrowserEvent event, 313 const char*hostname, 314 const AvahiAddress *a, 315 uint16_t port, 316 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, 317 AVAHI_GCC_UNUSED void* userdata) { 318 319 char t[AVAHI_ADDRESS_STR_MAX] = "n/a"; 320 321 if (a) 322 avahi_address_snprint(t, sizeof(t), a); 323 324 avahi_log_debug("DSB: (%i.%i): %s/%s:%i [%s]", iface, protocol, hostname ? hostname : "NULL", t, port, browser_event_to_string(event)); 325} 326 327int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char *argv[]) { 328 AvahiSRecordBrowser *r; 329 AvahiSHostNameResolver *hnr; 330 AvahiSAddressResolver *ar; 331 AvahiKey *k; 332 AvahiServerConfig config; 333 AvahiAddress a; 334 AvahiSDomainBrowser *db; 335 AvahiSServiceTypeBrowser *stb; 336 AvahiSServiceBrowser *sb; 337 AvahiSServiceResolver *sr; 338 AvahiSDNSServerBrowser *dsb; 339 AvahiSimplePoll *simple_poll; 340 int error; 341 struct timeval tv; 342 343 simple_poll = avahi_simple_poll_new(); 344 poll_api = avahi_simple_poll_get(simple_poll); 345 346 avahi_server_config_init(&config); 347 348 avahi_address_parse("192.168.50.1", AVAHI_PROTO_UNSPEC, &config.wide_area_servers[0]); 349 config.n_wide_area_servers = 1; 350 config.enable_wide_area = 1; 351 352 server = avahi_server_new(poll_api, &config, server_callback, NULL, &error); 353 avahi_server_config_free(&config); 354 355 k = avahi_key_new("_http._tcp.0pointer.de", AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_PTR); 356 r = avahi_s_record_browser_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, k, 0, record_browser_callback, NULL); 357 avahi_key_unref(k); 358 359 hnr = avahi_s_host_name_resolver_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "cname.local", AVAHI_PROTO_UNSPEC, 0, hnr_callback, NULL); 360 361 ar = avahi_s_address_resolver_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, avahi_address_parse("192.168.50.1", AVAHI_PROTO_INET, &a), 0, ar_callback, NULL); 362 363 db = avahi_s_domain_browser_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, NULL, AVAHI_DOMAIN_BROWSER_BROWSE, 0, db_callback, NULL); 364 365 stb = avahi_s_service_type_browser_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, NULL, 0, stb_callback, NULL); 366 367 sb = avahi_s_service_browser_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_http._tcp", NULL, 0, sb_callback, NULL); 368 369 sr = avahi_s_service_resolver_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "Ecstasy HTTP", "_http._tcp", "local", AVAHI_PROTO_UNSPEC, 0, sr_callback, NULL); 370 371 dsb = avahi_s_dns_server_browser_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "local", AVAHI_DNS_SERVER_RESOLVE, AVAHI_PROTO_UNSPEC, 0, dsb_callback, NULL); 372 373 avahi_elapse_time(&tv, 1000*5, 0); 374 poll_api->timeout_new(poll_api, &tv, dump_timeout_callback, server); 375 376 avahi_elapse_time(&tv, 1000*60, 0); 377 poll_api->timeout_new(poll_api, &tv, quit_timeout_callback, simple_poll); 378 379 avahi_simple_poll_loop(simple_poll); 380 381 avahi_s_record_browser_free(r); 382 avahi_s_host_name_resolver_free(hnr); 383 avahi_s_address_resolver_free(ar); 384 avahi_s_domain_browser_free(db); 385 avahi_s_service_type_browser_free(stb); 386 avahi_s_service_browser_free(sb); 387 avahi_s_service_resolver_free(sr); 388 avahi_s_dns_server_browser_free(dsb); 389 390 if (group) 391 avahi_s_entry_group_free(group); 392 393 if (server) 394 avahi_server_free(server); 395 396 if (simple_poll) 397 avahi_simple_poll_free(simple_poll); 398 399 avahi_free(service_name); 400 401 return 0; 402} 403