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