static int load_config_file(DaemonConfig *c) { int r = -1; AvahiIniFile *f; AvahiIniFileGroup *g; assert(c); if (!(f = avahi_ini_file_load(c->config_file ? c->config_file : AVAHI_CONFIG_FILE))) goto finish; for (g = f->groups; g; g = g->groups_next) { if (strcasecmp(g->name, "server") == 0) { AvahiIniFilePair *p; for (p = g->pairs; p; p = p->pairs_next) { if (strcasecmp(p->key, "host-name") == 0) { avahi_free(c->server_config.host_name); c->server_config.host_name = avahi_strdup(p->value); } else if (strcasecmp(p->key, "domain-name") == 0) { avahi_free(c->server_config.domain_name); c->server_config.domain_name = avahi_strdup(p->value); } else if (strcasecmp(p->key, "browse-domains") == 0) { char **e, **t; e = avahi_split_csv(p->value); for (t = e; *t; t++) { char cleaned[AVAHI_DOMAIN_NAME_MAX]; if (!avahi_normalize_name(*t, cleaned, sizeof(cleaned))) { avahi_log_error("Invalid domain name \"%s\" for key \"%s\" in group \"%s\"\n", *t, p->key, g->name); avahi_strfreev(e); goto finish; } c->server_config.browse_domains = avahi_string_list_add(c->server_config.browse_domains, cleaned); } avahi_strfreev(e); c->server_config.browse_domains = filter_duplicate_domains(c->server_config.browse_domains); } else if (strcasecmp(p->key, "use-ipv4") == 0) c->server_config.use_ipv4 = is_yes(p->value); else if (strcasecmp(p->key, "use-ipv6") == 0) c->server_config.use_ipv6 = is_yes(p->value); else if (strcasecmp(p->key, "check-response-ttl") == 0) c->server_config.check_response_ttl = is_yes(p->value); else if (strcasecmp(p->key, "allow-point-to-point") == 0) c->server_config.allow_point_to_point = is_yes(p->value); else if (strcasecmp(p->key, "use-iff-running") == 0) c->server_config.use_iff_running = is_yes(p->value); else if (strcasecmp(p->key, "disallow-other-stacks") == 0) c->server_config.disallow_other_stacks = is_yes(p->value); #ifdef HAVE_DBUS else if (strcasecmp(p->key, "enable-dbus") == 0) { if (*(p->value) == 'w' || *(p->value) == 'W') { c->fail_on_missing_dbus = 0; c->enable_dbus = 1; } else if (*(p->value) == 'y' || *(p->value) == 'Y') { c->fail_on_missing_dbus = 1; c->enable_dbus = 1; } else { c->enable_dbus = 0; } } #endif else { avahi_log_error("Invalid configuration key \"%s\" in group \"%s\"\n", p->key, g->name); goto finish; } } } else if (strcasecmp(g->name, "publish") == 0) { AvahiIniFilePair *p; for (p = g->pairs; p; p = p->pairs_next) { if (strcasecmp(p->key, "publish-addresses") == 0) c->server_config.publish_addresses = is_yes(p->value); else if (strcasecmp(p->key, "publish-hinfo") == 0) c->server_config.publish_hinfo = is_yes(p->value); else if (strcasecmp(p->key, "publish-workstation") == 0) c->server_config.publish_workstation = is_yes(p->value); else if (strcasecmp(p->key, "publish-domain") == 0) c->server_config.publish_domain = is_yes(p->value); else if (strcasecmp(p->key, "publish-resolv-conf-dns-servers") == 0) c->publish_resolv_conf = is_yes(p->value); else if (strcasecmp(p->key, "disable-publishing") == 0) c->server_config.disable_publishing = is_yes(p->value); else if (strcasecmp(p->key, "disable-user-service-publishing") == 0) c->disable_user_service_publishing = is_yes(p->value); else if (strcasecmp(p->key, "add-service-cookie") == 0) c->server_config.add_service_cookie = is_yes(p->value); else if (strcasecmp(p->key, "publish-dns-servers") == 0) { avahi_strfreev(c->publish_dns_servers); c->publish_dns_servers = avahi_split_csv(p->value); } else if (strcasecmp(p->key, "publish-a-on-ipv6") == 0) c->server_config.publish_a_on_ipv6 = is_yes(p->value); else if (strcasecmp(p->key, "publish-aaaa-on-ipv4") == 0) c->server_config.publish_aaaa_on_ipv4 = is_yes(p->value); else { avahi_log_error("Invalid configuration key \"%s\" in group \"%s\"\n", p->key, g->name); goto finish; } } } else if (strcasecmp(g->name, "wide-area") == 0) { AvahiIniFilePair *p; for (p = g->pairs; p; p = p->pairs_next) { if (strcasecmp(p->key, "enable-wide-area") == 0) c->server_config.enable_wide_area = is_yes(p->value); else { avahi_log_error("Invalid configuration key \"%s\" in group \"%s\"\n", p->key, g->name); goto finish; } } } else if (strcasecmp(g->name, "reflector") == 0) { AvahiIniFilePair *p; for (p = g->pairs; p; p = p->pairs_next) { if (strcasecmp(p->key, "enable-reflector") == 0) c->server_config.enable_reflector = is_yes(p->value); else if (strcasecmp(p->key, "reflect-ipv") == 0) c->server_config.reflect_ipv = is_yes(p->value); else { avahi_log_error("Invalid configuration key \"%s\" in group \"%s\"\n", p->key, g->name); goto finish; } } } else if (strcasecmp(g->name, "rlimits") == 0) { AvahiIniFilePair *p; for (p = g->pairs; p; p = p->pairs_next) { if (strcasecmp(p->key, "rlimit-as") == 0) { c->rlimit_as_set = 1; c->rlimit_as = atoi(p->value); } else if (strcasecmp(p->key, "rlimit-core") == 0) { c->rlimit_core_set = 1; c->rlimit_core = atoi(p->value); } else if (strcasecmp(p->key, "rlimit-data") == 0) { c->rlimit_data_set = 1; c->rlimit_data = atoi(p->value); } else if (strcasecmp(p->key, "rlimit-fsize") == 0) { c->rlimit_fsize_set = 1; c->rlimit_fsize = atoi(p->value); } else if (strcasecmp(p->key, "rlimit-nofile") == 0) { c->rlimit_nofile_set = 1; c->rlimit_nofile = atoi(p->value); } else if (strcasecmp(p->key, "rlimit-stack") == 0) { c->rlimit_stack_set = 1; c->rlimit_stack = atoi(p->value); } else if (strcasecmp(p->key, "rlimit-nproc") == 0) { #ifdef RLIMIT_NPROC c->rlimit_nproc_set = 1; c->rlimit_nproc = atoi(p->value); #else avahi_log_error("Ignoring configuration key \"%s\" in group \"%s\"\n", p->key, g->name); #endif } else { avahi_log_error("Invalid configuration key \"%s\" in group \"%s\"\n", p->key, g->name); goto finish; } } } else { avahi_log_error("Invalid configuration file group \"%s\".\n", g->name); goto finish; } } r = 0; finish: if (f) avahi_ini_file_free(f); return r; }
char *avahi_alternative_service_name(const char *s) { const char *e; char *r; assert(s); if (!avahi_is_valid_service_name(s)) return NULL; if ((e = strstr(s, " #"))) { const char *n, *p; e += 2; while ((n = strstr(e, " #"))) e = n + 2; for (p = e; *p; p++) if (!isdigit(*p)) { e = NULL; break; } if (e && (*e == '0' || *e == 0)) e = NULL; } if (e) { char *c, *m; size_t l; int n; n = atoi(e)+1; if (!(m = avahi_strdup_printf("%i", n))) return NULL; l = e-s-2; if (l >= AVAHI_LABEL_MAX-1-strlen(m)-2) l = AVAHI_LABEL_MAX-1-strlen(m)-2; if (!(c = avahi_strndup(s, l))) { avahi_free(m); return NULL; } drop_incomplete_utf8(c); r = avahi_strdup_printf("%s #%s", c, m); avahi_free(c); avahi_free(m); } else { char *c; if (!(c = avahi_strndup(s, AVAHI_LABEL_MAX-1-3))) return NULL; drop_incomplete_utf8(c); r = avahi_strdup_printf("%s #2", c); avahi_free(c); } assert(avahi_is_valid_service_name(r)); return r; }
static void server_callback(AvahiServer *s, AvahiServerState state, void *userdata) { DaemonConfig *c = userdata; assert(s); assert(c); /* This function is possibly called before the global variable * avahi_server has been set, therefore we do it explicitly */ avahi_server = s; #ifdef HAVE_DBUS if (c->enable_dbus && state != AVAHI_SERVER_INVALID && state != AVAHI_SERVER_FAILURE) dbus_protocol_server_state_changed(state); #endif switch (state) { case AVAHI_SERVER_RUNNING: avahi_log_info("Server startup complete. Host name is %s. Local service cookie is %u.", avahi_server_get_host_name_fqdn(s), avahi_server_get_local_service_cookie(s)); avahi_set_proc_title(argv0, "%s: running [%s]", argv0, avahi_server_get_host_name_fqdn(s)); static_service_add_to_server(); static_hosts_add_to_server(); remove_dns_server_entry_groups(); if (c->publish_resolv_conf && resolv_conf_name_servers && resolv_conf_name_servers[0]) resolv_conf_entry_group = add_dns_servers(s, resolv_conf_entry_group, resolv_conf_name_servers); if (c->publish_dns_servers && c->publish_dns_servers[0]) dns_servers_entry_group = add_dns_servers(s, dns_servers_entry_group, c->publish_dns_servers); simple_protocol_restart_queries(); break; case AVAHI_SERVER_COLLISION: { char *n; avahi_set_proc_title(argv0, "%s: collision", argv0); static_service_remove_from_server(); static_hosts_remove_from_server(); remove_dns_server_entry_groups(); n = avahi_alternative_host_name(avahi_server_get_host_name(s)); avahi_log_warn("Host name conflict, retrying with <%s>", n); avahi_server_set_host_name(s, n); avahi_free(n); break; } case AVAHI_SERVER_FAILURE: avahi_log_error("Server error: %s", avahi_strerror(avahi_server_errno(s))); avahi_simple_poll_quit(simple_poll_api); break; case AVAHI_SERVER_REGISTERING: avahi_set_proc_title(argv0, "%s: registering [%s]", argv0, avahi_server_get_host_name_fqdn(s)); static_service_remove_from_server(); static_hosts_remove_from_server(); remove_dns_server_entry_groups(); break; case AVAHI_SERVER_INVALID: break; } }
static int parse_command_line(DaemonConfig *c, int argc, char *argv[]) { int o; enum { OPTION_NO_RLIMITS = 256, OPTION_NO_DROP_ROOT, #ifdef ENABLE_CHROOT OPTION_NO_CHROOT, #endif OPTION_NO_PROC_TITLE, OPTION_DEBUG }; static const struct option long_options[] = { { "help", no_argument, NULL, 'h' }, { "daemonize", no_argument, NULL, 'D' }, { "kill", no_argument, NULL, 'k' }, { "version", no_argument, NULL, 'V' }, { "file", required_argument, NULL, 'f' }, { "reload", no_argument, NULL, 'r' }, { "check", no_argument, NULL, 'c' }, { "syslog", no_argument, NULL, 's' }, { "no-rlimits", no_argument, NULL, OPTION_NO_RLIMITS }, { "no-drop-root", no_argument, NULL, OPTION_NO_DROP_ROOT }, #ifdef ENABLE_CHROOT { "no-chroot", no_argument, NULL, OPTION_NO_CHROOT }, #endif { "no-proc-title", no_argument, NULL, OPTION_NO_PROC_TITLE }, { "debug", no_argument, NULL, OPTION_DEBUG }, { NULL, 0, NULL, 0 } }; assert(c); while ((o = getopt_long(argc, argv, "hDkVf:rcs", long_options, NULL)) >= 0) { switch(o) { case 's': c->use_syslog = 1; break; case 'h': c->command = DAEMON_HELP; break; case 'D': c->daemonize = 1; break; case 'k': c->command = DAEMON_KILL; break; case 'V': c->command = DAEMON_VERSION; break; case 'f': avahi_free(c->config_file); c->config_file = avahi_strdup(optarg); break; case 'r': c->command = DAEMON_RELOAD; break; case 'c': c->command = DAEMON_CHECK; break; case OPTION_NO_RLIMITS: c->set_rlimits = 0; break; case OPTION_NO_DROP_ROOT: c->drop_root = 0; break; #ifdef ENABLE_CHROOT case OPTION_NO_CHROOT: c->use_chroot = 0; break; #endif case OPTION_NO_PROC_TITLE: c->modify_proc_title = 0; break; case OPTION_DEBUG: c->debug = 1; break; default: return -1; } } if (optind < argc) { fprintf(stderr, "Too many arguments\n"); return -1; } return 0; }
void avahi_llmnr_query_scheduler_free(AvahiLLMNRQueryScheduler *s) { assert(s); avahi_llmnr_query_scheduler_clear(s); avahi_free(s); }
int main(int argc, char *argv[]) { int r = 255; int wrote_pid_file = 0; avahi_set_log_function(log_function); init_rand_seed(); avahi_server_config_init(&config.server_config); config.command = DAEMON_RUN; config.daemonize = 0; config.config_file = NULL; #ifdef HAVE_DBUS config.enable_dbus = 1; config.fail_on_missing_dbus = 1; #endif config.drop_root = 1; config.set_rlimits = 1; #ifdef ENABLE_CHROOT config.use_chroot = 1; #endif config.modify_proc_title = 1; config.disable_user_service_publishing = 0; config.publish_dns_servers = NULL; config.publish_resolv_conf = 0; config.use_syslog = 0; config.debug = 0; config.rlimit_as_set = 0; config.rlimit_core_set = 0; config.rlimit_data_set = 0; config.rlimit_fsize_set = 0; config.rlimit_nofile_set = 0; config.rlimit_stack_set = 0; #ifdef RLIMIT_NPROC config.rlimit_nproc_set = 0; #endif if ((argv0 = strrchr(argv[0], '/'))) argv0 = avahi_strdup(argv0 + 1); else argv0 = avahi_strdup(argv[0]); daemon_pid_file_ident = (const char *) argv0; daemon_log_ident = (char*) argv0; daemon_pid_file_proc = pid_file_proc; if (parse_command_line(&config, argc, argv) < 0) goto finish; if (config.modify_proc_title) avahi_init_proc_title(argc, argv); #ifdef ENABLE_CHROOT config.use_chroot = config.use_chroot && config.drop_root; #endif if (config.command == DAEMON_HELP) { help(stdout); r = 0; } else if (config.command == DAEMON_VERSION) { printf("%s "PACKAGE_VERSION"\n", argv0); r = 0; } else if (config.command == DAEMON_KILL) { if (daemon_pid_file_kill_wait(SIGTERM, 5) < 0) { avahi_log_warn("Failed to kill daemon: %s", strerror(errno)); goto finish; } r = 0; } else if (config.command == DAEMON_RELOAD) { if (daemon_pid_file_kill(SIGHUP) < 0) { avahi_log_warn("Failed to kill daemon: %s", strerror(errno)); goto finish; } r = 0; } else if (config.command == DAEMON_CHECK) r = (daemon_pid_file_is_running() >= 0) ? 0 : 1; else if (config.command == DAEMON_RUN) { pid_t pid; if (getuid() != 0 && config.drop_root) { avahi_log_error("This program is intended to be run as root."); goto finish; } if ((pid = daemon_pid_file_is_running()) >= 0) { avahi_log_error("Daemon already running on PID %u", pid); goto finish; } if (load_config_file(&config) < 0) goto finish; if (config.daemonize) { daemon_retval_init(); if ((pid = daemon_fork()) < 0) goto finish; else if (pid != 0) { int ret; /** Parent **/ if ((ret = daemon_retval_wait(20)) < 0) { avahi_log_error("Could not receive return value from daemon process."); goto finish; } r = ret; goto finish; } /* Child */ } if (config.use_syslog || config.daemonize) daemon_log_use = DAEMON_LOG_SYSLOG; if (daemon_close_all(-1) < 0) { avahi_log_error("Failed to close remaining file descriptors: %s", strerror(errno)); goto finish; } if (make_runtime_dir() < 0) goto finish; if (config.drop_root) { #ifdef ENABLE_CHROOT if (config.use_chroot) if (avahi_caps_reduce() < 0) goto finish; #endif if (drop_root() < 0) goto finish; #ifdef ENABLE_CHROOT if (config.use_chroot) if (avahi_caps_reduce2() < 0) goto finish; #endif } if (daemon_pid_file_create() < 0) { avahi_log_error("Failed to create PID file: %s", strerror(errno)); if (config.daemonize) daemon_retval_send(1); goto finish; } else wrote_pid_file = 1; if (config.set_rlimits) enforce_rlimits(); chdir("/"); #ifdef ENABLE_CHROOT if (config.drop_root && config.use_chroot) if (avahi_chroot_helper_start(argv0) < 0) { avahi_log_error("failed to start chroot() helper daemon."); goto finish; } #endif avahi_log_info("%s "PACKAGE_VERSION" starting up.", argv0); avahi_set_proc_title(argv0, "%s: starting up", argv0); if (run_server(&config) == 0) r = 0; } finish: if (config.daemonize) daemon_retval_done(); avahi_server_config_free(&config.server_config); avahi_free(config.config_file); avahi_strfreev(config.publish_dns_servers); avahi_strfreev(resolv_conf_name_servers); avahi_strfreev(resolv_conf_search_domains); if (wrote_pid_file) { #ifdef ENABLE_CHROOT avahi_chroot_helper_unlink(pid_file_proc()); #else daemon_pid_file_remove(); #endif } #ifdef ENABLE_CHROOT avahi_chroot_helper_shutdown(); #endif avahi_free(argv0); return r; }
static void create_services(AvahiClient *c) { char *n, r[128]; int ret; assert(c); /* If this is the first time we're called, let's create a new * entry group if necessary */ if (!group) if (!(group = avahi_entry_group_new(c, entry_group_callback, NULL))) { fprintf(stderr, "avahi_entry_group_new() failed: %s\n", avahi_strerror(avahi_client_errno(c))); goto fail; } /* If the group is empty (either because it was just created, or * because it was reset previously, add our entries. */ if (avahi_entry_group_is_empty(group)) { fprintf(stderr, "Adding service '%s'\n", name); /* Create some random TXT data */ snprintf(r, sizeof(r), "random=%i", rand()); /* We will now add two services and one subtype to the entry * group. The two services have the same name, but differ in * the service type (IPP vs. BSD LPR). Only services with the * same name should be put in the same entry group. */ /* Add the service for IPP */ if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, name, "_gbmon._tcp", NULL, NULL, 1000, "test=blah", r, NULL)) < 0) { if (ret == AVAHI_ERR_COLLISION) goto collision; fprintf(stderr, "Failed to add _ipp._tcp service: %s\n", avahi_strerror(ret)); goto fail; } /* Tell the server to register the service */ if ((ret = avahi_entry_group_commit(group)) < 0) { fprintf(stderr, "Failed to commit entry group: %s\n", avahi_strerror(ret)); goto fail; } } return; collision: /* A service name collision with a local service happened. Let's * pick a new name */ n = avahi_alternative_service_name(name); avahi_free(name); name = n; fprintf(stderr, "Service name collision, renaming service to '%s'\n", name); avahi_entry_group_reset(group); create_services(c); return; fail: avahi_simple_poll_quit(simple_poll); }
void Publisher::nextName() { char *newName = avahi_alternative_service_name(info.getServiceName().c_str()); info.setServiceName(std::string(newName)); avahi_free(newName); }
void static_hosts_load(int in_chroot) { FILE *f; unsigned int line = 0; StaticHost *h, *next; const char *filename = in_chroot ? "/hosts" : AVAHI_CONFIG_DIR "/hosts"; if (!(f = fopen(filename, "r"))) { if (errno != ENOENT) avahi_log_error ("Failed to open static hosts file: %s", strerror (errno)); return; } current_iteration++; while (!feof(f)) { unsigned int len; char ln[256], *s; char *host, *ip; AvahiAddress a; if (!fgets(ln, sizeof (ln), f)) break; line++; /* Find the start of the line, ignore whitespace */ s = ln + strspn(ln, " \t"); /* Set the end of the string to NULL */ s[strcspn(s, "#\r\n")] = 0; /* Ignore blank lines */ if (*s == 0) continue; /* Read the first string (ip) up to the next whitespace */ len = strcspn(s, " \t"); ip = avahi_strndup(s, len); /* Skip past it */ s += len; /* Find the next token */ s += strspn(s, " \t"); len = strcspn(s, " \t"); host = avahi_strndup(s, len); if (*host == 0) { avahi_log_error("%s:%d: Error, unexpected end of line!", filename, line); avahi_free(host); avahi_free(ip); goto fail; } /* Skip over the host */ s += len; /* Skip past any more spaces */ s += strspn(s, " \t"); /* Anything left? */ if (*s != 0) { avahi_log_error ("%s:%d: Junk on the end of the line!", filename, line); avahi_free(host); avahi_free(ip); goto fail; } if (!avahi_address_parse(ip, AVAHI_PROTO_UNSPEC, &a)) { avahi_log_error("Static host name %s: failed to parse address %s", host, ip); avahi_free(host); avahi_free(ip); goto fail; } avahi_free(ip); if ((h = static_host_find(host, &a))) avahi_free(host); else { h = static_host_new(); h->host = host; h->address = a; avahi_log_info("Loading new static hostname %s.", h->host); } h->iteration = current_iteration; } for (h = hosts; h; h = next) { next = h->hosts_next; if (h->iteration != current_iteration) { avahi_log_info("Static hostname %s vanished, removing.", h->host); static_host_free(h); } } fail: fclose(f); }
/* handle address coming or going away */ static int rtm_dispatch_newdeladdr(struct rtm_dispinfo *di) { Address *ap; struct ifa_msghdr *ifam; struct sockaddr *sa; struct sockaddr_in *sin; int link_local; /* macro to skip to next RTA; has side-effects */ #define SKIPRTA(ifamsgp, rta, sa) \ do { \ if ((ifamsgp)->ifam_addrs & (rta)) \ (sa) = next_sa((sa)); \ } while (0) ifam = &((rtmunion_t *)di->di_buf)->ifam; assert(ifam->ifam_type == RTM_NEWADDR || ifam->ifam_type == RTM_DELADDR); daemon_log(LOG_DEBUG, "%s: %s for iface %d (%s)", __func__, ifam->ifam_type == RTM_NEWADDR ? "NEWADDR" : "DELADDR", ifam->ifam_index, (ifam->ifam_index == ifindex) ? "ours" : "not ours"); if (ifam->ifam_index != ifindex) return (0); if (!(ifam->ifam_addrs & RTA_IFA)) { daemon_log(LOG_ERR, "ifa msg has no RTA_IFA."); return (0); } /* skip over rtmsg padding correctly */ sa = (struct sockaddr *)(ifam + 1); SKIPRTA(ifam, RTA_DST, sa); SKIPRTA(ifam, RTA_GATEWAY, sa); SKIPRTA(ifam, RTA_NETMASK, sa); SKIPRTA(ifam, RTA_GENMASK, sa); SKIPRTA(ifam, RTA_IFP, sa); /* * sa now points to RTA_IFA sockaddr; we are only interested * in updates for routable addresses. */ if (sa->sa_family != AF_INET) { daemon_log(LOG_DEBUG, "%s: RTA_IFA family not AF_INET (=%d)", __func__, sa->sa_family); return (0); } sin = (struct sockaddr_in *)sa; link_local = IN_LINKLOCAL(ntohl(sin->sin_addr.s_addr)); daemon_log(LOG_DEBUG, "%s: %s for %s (%s)", __func__, ifam->ifam_type == RTM_NEWADDR ? "NEWADDR" : "DELADDR", inet_ntoa(sin->sin_addr), link_local ? "link local" : "routable"); if (link_local) return (0); for (ap = addresses; ap; ap = ap->addresses_next) { if (ap->address == sin->sin_addr.s_addr) break; } if (ifam->ifam_type == RTM_DELADDR && ap != NULL) { AVAHI_LLIST_REMOVE(Address, addresses, addresses, ap); avahi_free(ap); } if (ifam->ifam_type == RTM_NEWADDR && ap == NULL) { ap = avahi_new(Address, 1); ap->address = sin->sin_addr.s_addr; AVAHI_LLIST_PREPEND(Address, addresses, addresses, ap); } return (0); #undef SKIPRTA }
AvahiNetlink *avahi_netlink_new(const AvahiPoll *poll_api, uint32_t groups, void (*cb) (AvahiNetlink *nl, struct nlmsghdr *n, void* userdata), void* userdata) { int fd = -1; const int on = 1; struct sockaddr_nl addr; AvahiNetlink *nl = NULL; assert(poll_api); assert(cb); if ((fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) { avahi_log_error(__FILE__": socket(PF_NETLINK): %s", strerror(errno)); return NULL; } memset(&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; addr.nl_groups = groups; addr.nl_pid = 0; if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { avahi_log_error(__FILE__": bind(): %s", strerror(errno)); goto fail; } if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) { avahi_log_error(__FILE__": SO_PASSCRED: %s", strerror(errno)); goto fail; } if (!(nl = avahi_new(AvahiNetlink, 1))) { avahi_log_error(__FILE__": avahi_new() failed."); goto fail; } nl->poll_api = poll_api; nl->fd = fd; nl->seq = 0; nl->callback = cb; nl->userdata = userdata; if (!(nl->buffer = avahi_new(uint8_t, nl->buffer_length = 64*1024))) { avahi_log_error(__FILE__": avahi_new() failed."); goto fail; } if (!(nl->watch = poll_api->watch_new(poll_api, fd, AVAHI_WATCH_IN, socket_event, nl))) { avahi_log_error(__FILE__": Failed to create watch."); goto fail; } return nl; fail: if (fd >= 0) close(fd); if (nl) { avahi_free(nl->buffer); avahi_free(nl); } return NULL; }
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char *argv[]) { char *t, *v; uint8_t data[1024]; AvahiStringList *a = NULL, *b, *p; size_t size, n; int r; a = avahi_string_list_new("prefix", "a", "b", NULL); a = avahi_string_list_add(a, "start"); a = avahi_string_list_add(a, "foo=99"); a = avahi_string_list_add(a, "bar"); a = avahi_string_list_add(a, ""); a = avahi_string_list_add(a, ""); a = avahi_string_list_add(a, "quux"); a = avahi_string_list_add(a, ""); a = avahi_string_list_add_arbitrary(a, (const uint8_t*) "null\0null", 9); a = avahi_string_list_add_printf(a, "seven=%i %c", 7, 'x'); a = avahi_string_list_add_pair(a, "blubb", "blaa"); a = avahi_string_list_add_pair(a, "uxknurz", NULL); a = avahi_string_list_add_pair_arbitrary(a, "uxknurz2", (const uint8_t*) "blafasel\0oerks", 14); a = avahi_string_list_add(a, "end"); t = avahi_string_list_to_string(a); printf("--%s--\n", t); avahi_free(t); n = avahi_string_list_serialize(a, NULL, 0); size = avahi_string_list_serialize(a, data, sizeof(data)); assert(size == n); printf("%u\n", size); for (t = (char*) data, n = 0; n < size; n++, t++) { if (*t <= 32) printf("(%u)", *t); else printf("%c", *t); } printf("\n"); assert(avahi_string_list_parse(data, size, &b) == 0); printf("equal: %i\n", avahi_string_list_equal(a, b)); t = avahi_string_list_to_string(b); printf("--%s--\n", t); avahi_free(t); avahi_string_list_free(b); b = avahi_string_list_copy(a); assert(avahi_string_list_equal(a, b)); t = avahi_string_list_to_string(b); printf("--%s--\n", t); avahi_free(t); p = avahi_string_list_find(a, "seven"); assert(p); r = avahi_string_list_get_pair(p, &t, &v, NULL); assert(r >= 0); assert(t); assert(v); printf("<%s>=<%s>\n", t, v); avahi_free(t); avahi_free(v); p = avahi_string_list_find(a, "quux"); assert(p); r = avahi_string_list_get_pair(p, &t, &v, NULL); assert(r >= 0); assert(t); assert(!v); printf("<%s>=<%s>\n", t, v); avahi_free(t); avahi_free(v); avahi_string_list_free(a); avahi_string_list_free(b); n = avahi_string_list_serialize(NULL, NULL, 0); size = avahi_string_list_serialize(NULL, data, sizeof(data)); assert(size == 1); assert(size == n); assert(avahi_string_list_parse(data, size, &a) == 0); assert(!a); return 0; }
static void resolve_callback( AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIndex interface, AVAHI_GCC_UNUSED AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, AVAHI_GCC_UNUSED void* userdata) { assert(r); /* Called whenever a service has been resolved successfully or timed out */ switch (event) { case AVAHI_RESOLVER_FAILURE: fprintf(stderr, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r)))); break; case AVAHI_RESOLVER_FOUND: { char a[AVAHI_ADDRESS_STR_MAX], *t; fprintf(stderr, "Service '%s' of type '%s' in domain '%s':\n", name, type, domain); avahi_address_snprint(a, sizeof(a), address); /* Copy hostname and port to global variables, ready to be returned later */ if (tvh_hostname == NULL) { tvh_hostname = strdup(host_name); tvh_ip = strdup(a); tvh_port = port; } t = avahi_string_list_to_string(txt); fprintf(stderr, "\t%s:%u (%s)\n" "\tTXT=%s\n" "\tcookie is %u\n" "\tis_local: %i\n" "\tour_own: %i\n" "\twide_area: %i\n" "\tmulticast: %i\n" "\tcached: %i\n", host_name, port, a, t, avahi_string_list_get_service_cookie(txt), !!(flags & AVAHI_LOOKUP_RESULT_LOCAL), !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN), !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA), !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST), !!(flags & AVAHI_LOOKUP_RESULT_CACHED)); avahi_free(t); } } avahi_service_resolver_free(r); }
char *avahi_alternative_host_name(const char *s) { const char *e; char *r; assert(s); if (!avahi_is_valid_host_name(s)) return NULL; if ((e = strrchr(s, '-'))) { const char *p; e++; for (p = e; *p; p++) if (!isdigit(*p)) { e = NULL; break; } if (e && (*e == '0' || *e == 0)) e = NULL; } if (e) { char *c, *m; size_t l; int n; n = atoi(e)+1; if (!(m = avahi_strdup_printf("%i", n))) return NULL; l = e-s-1; if (l >= AVAHI_LABEL_MAX-1-strlen(m)-1) l = AVAHI_LABEL_MAX-1-strlen(m)-1; if (!(c = avahi_strndup(s, l))) { avahi_free(m); return NULL; } drop_incomplete_utf8(c); r = avahi_strdup_printf("%s-%s", c, m); avahi_free(c); avahi_free(m); } else { char *c; if (!(c = avahi_strndup(s, AVAHI_LABEL_MAX-1-2))) return NULL; drop_incomplete_utf8(c); r = avahi_strdup_printf("%s-2", c); avahi_free(c); } assert(avahi_is_valid_host_name(r)); return r; }
/***************************************************************************** * resolve_callback *****************************************************************************/ static void resolve_callback( AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void* userdata ) { services_discovery_t *p_sd = ( services_discovery_t* )userdata; services_discovery_sys_t *p_sys = p_sd->p_sys; VLC_UNUSED(interface); VLC_UNUSED(host_name); VLC_UNUSED(flags); if( event == AVAHI_RESOLVER_FAILURE ) { msg_Err( p_sd, "failed to resolve service '%s' of type '%s' in domain '%s'", name, type, domain ); } else if( event == AVAHI_RESOLVER_FOUND ) { char a[128]; char *psz_uri = NULL; char *psz_addr = NULL; AvahiStringList *asl = NULL; input_item_t *p_input = NULL; msg_Err( p_sd, "service '%s' of type '%s' in domain '%s' port %i", name, type, domain, port ); avahi_address_snprint(a, (sizeof(a)/sizeof(a[0]))-1, address); if( protocol == AVAHI_PROTO_INET6 ) if( asprintf( &psz_addr, "[%s]", a ) == -1 ) return; const char *psz_protocol = NULL; for( unsigned int i = 0; i < NB_PROTOCOLS; i++ ) { if( !strcmp(type, protocols[i].psz_service_name) ) psz_protocol = protocols[i].psz_protocol; } if( psz_protocol == NULL ) return; if( txt != NULL ) asl = avahi_string_list_find( txt, "path" ); if( asl != NULL ) { size_t size; char *key = NULL; char *value = NULL; if( avahi_string_list_get_pair( asl, &key, &value, &size ) == 0 && value != NULL ) { if( asprintf( &psz_uri, "%s://%s:%d%s", psz_protocol, psz_addr != NULL ? psz_addr : a, port, value ) == -1 ) { free( psz_addr ); return; } } if( key != NULL ) avahi_free( (void *)key ); if( value != NULL ) avahi_free( (void *)value ); } else { if( asprintf( &psz_uri, "%s://%s:%d", psz_protocol, psz_addr != NULL ? psz_addr : a, port ) == -1 ) { free( psz_addr ); return; } } free( psz_addr ); if( psz_uri != NULL ) { p_input = input_item_New( psz_uri, name ); free( psz_uri ); } if( p_input != NULL ) { vlc_dictionary_insert( &p_sys->services_name_to_input_item, name, p_input ); services_discovery_AddItem( p_sd, p_input ); input_item_Release( p_input ); } } avahi_service_resolver_free( r ); }
static void create_services(AvahiClient *c) { char *n; int ret; assert(c); /* If this is the first time we're called, let's create a new * entry group if necessary */ if (!group) if (!(group = avahi_entry_group_new(c, entry_group_callback, NULL))) { tvhlog(LOG_ERR, "AVAHI", "avahi_enty_group_new() failed: %s", avahi_strerror(avahi_client_errno(c))); goto fail; } /* If the group is empty (either because it was just created, or * because it was reset previously, add our entries. */ if (avahi_entry_group_is_empty(group)) { tvhlog(LOG_DEBUG, "AVAHI", "Adding service '%s'", name); /* Add the service for HTSP */ if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, name, "_htsp._tcp", NULL, NULL, 9982, NULL)) < 0) { if (ret == AVAHI_ERR_COLLISION) goto collision; tvhlog(LOG_ERR, "AVAHI", "Failed to add _htsp._tcp service: %s", avahi_strerror(ret)); goto fail; } /* Add the service for HTTP */ if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, name, "_http._tcp", NULL, NULL, 9981, "path=/", NULL)) < 0) { if (ret == AVAHI_ERR_COLLISION) goto collision; tvhlog(LOG_ERR, "AVAHI", "Failed to add _http._tcp service: %s", avahi_strerror(ret)); goto fail; } /* Tell the server to register the service */ if ((ret = avahi_entry_group_commit(group)) < 0) { tvhlog(LOG_ERR, "AVAHI", "Failed to commit entry group: %s", avahi_strerror(ret)); goto fail; } } return; collision: /* A service name collision with a local service happened. Let's * pick a new name */ n = avahi_alternative_service_name(name); avahi_free(name); name = n; tvhlog(LOG_ERR, "AVAHI", "Service name collision, renaming service to '%s'", name); avahi_entry_group_reset(group); create_services(c); return; fail: return; }
static void destroy_timeout(AvahiTimeout *t) { assert(t); AVAHI_LLIST_REMOVE(AvahiTimeout, timeouts, t->glib_poll->timeouts, t); avahi_free(t); }