int avahi_server_add_dns_server_address( AvahiServer *s, AvahiSEntryGroup *g, AvahiIfIndex interface, AvahiProtocol protocol, AvahiPublishFlags flags, const char *domain, AvahiDNSServerType type, const AvahiAddress *address, uint16_t port /** should be 53 */) { AvahiRecord *r; char n[64], h[64]; AvahiEntry *a_entry, *s_entry; assert(s); assert(address); AVAHI_CHECK_VALIDITY(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); AVAHI_CHECK_VALIDITY(s, AVAHI_PROTO_VALID(protocol) && AVAHI_PROTO_VALID(address->proto), AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY(s, AVAHI_FLAGS_VALID(flags, AVAHI_PUBLISH_USE_MULTICAST|AVAHI_PUBLISH_USE_WIDE_AREA), AVAHI_ERR_INVALID_FLAGS); AVAHI_CHECK_VALIDITY(s, type == AVAHI_DNS_SERVER_UPDATE || type == AVAHI_DNS_SERVER_RESOLVE, AVAHI_ERR_INVALID_FLAGS); AVAHI_CHECK_VALIDITY(s, port != 0, AVAHI_ERR_INVALID_PORT); AVAHI_CHECK_VALIDITY(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME); if (!domain) domain = s->domain_name; transport_flags_from_domain(s, &flags, domain); AVAHI_CHECK_VALIDITY(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED); if (address->proto == AVAHI_PROTO_INET) { hexstring(h, sizeof(h), &address->data, sizeof(AvahiIPv4Address)); snprintf(n, sizeof(n), "ip-%s.%s", h, domain); r = avahi_record_new_full(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_A, AVAHI_DEFAULT_TTL_HOST_NAME); r->data.a.address = address->data.ipv4; } else { hexstring(h, sizeof(h), &address->data, sizeof(AvahiIPv6Address)); snprintf(n, sizeof(n), "ip6-%s.%s", h, domain); r = avahi_record_new_full(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA, AVAHI_DEFAULT_TTL_HOST_NAME); r->data.aaaa.address = address->data.ipv6; } if (!r) return avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); a_entry = server_add_internal(s, g, interface, protocol, AVAHI_PUBLISH_UNIQUE | AVAHI_PUBLISH_ALLOW_MULTIPLE, r); avahi_record_unref(r); if (!a_entry) return avahi_server_errno(s); if (!(s_entry = server_add_dns_server_name(s, g, interface, protocol, flags, domain, type, n, port))) { if (!(flags & AVAHI_PUBLISH_UPDATE)) avahi_entry_free(s, a_entry); return avahi_server_errno(s); } return AVAHI_OK; }
static int server_update_service_txt_strlst_nocopy( AvahiServer *s, AvahiSEntryGroup *g, AvahiIfIndex interface, AvahiProtocol protocol, AvahiPublishFlags flags, const char *name, const char *type, const char *domain, AvahiStringList *strlst) { char svc_name[AVAHI_DOMAIN_NAME_MAX]; int ret = AVAHI_OK; AvahiEntry *e; assert(s); assert(type); assert(name); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_FLAGS_VALID(flags, AVAHI_PUBLISH_NO_COOKIE| AVAHI_PUBLISH_USE_WIDE_AREA| AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_name(name), AVAHI_ERR_INVALID_SERVICE_NAME); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_type_strict(type), AVAHI_ERR_INVALID_SERVICE_TYPE); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME); if (!domain) domain = s->domain_name; transport_flags_from_domain(s, &flags, domain); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED); if ((ret = avahi_service_name_join(svc_name, sizeof(svc_name), name, type, domain)) < 0) { avahi_server_set_errno(s, ret); goto fail; } /* Add TXT record */ if (!(flags & AVAHI_PUBLISH_NO_COOKIE)) strlst = add_magic_cookie(s, strlst); e = server_add_txt_strlst_nocopy(s, g, interface, protocol, AVAHI_PUBLISH_UNIQUE | AVAHI_PUBLISH_UPDATE, AVAHI_DEFAULT_TTL, svc_name, strlst); strlst = NULL; if (!e) ret = avahi_server_errno(s); fail: avahi_string_list_free(strlst); return ret; }
static AvahiEntry *server_add_dns_server_name( AvahiServer *s, AvahiSEntryGroup *g, AvahiIfIndex interface, AvahiProtocol protocol, AvahiPublishFlags flags, const char *domain, AvahiDNSServerType type, const char *name, uint16_t port /** should be 53 */) { AvahiEntry *e; char t[AVAHI_DOMAIN_NAME_MAX], normalized_d[AVAHI_DOMAIN_NAME_MAX], *n; AvahiRecord *r; assert(s); assert(name); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, AVAHI_FLAGS_VALID(flags, AVAHI_PUBLISH_USE_WIDE_AREA|AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, type == AVAHI_DNS_SERVER_UPDATE || type == AVAHI_DNS_SERVER_RESOLVE, AVAHI_ERR_INVALID_FLAGS); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, port != 0, AVAHI_ERR_INVALID_PORT); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, avahi_is_valid_fqdn(name), AVAHI_ERR_INVALID_HOST_NAME); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME); if (!domain) domain = s->domain_name; transport_flags_from_domain(s, &flags, domain); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED); if (!(n = avahi_normalize_name_strdup(name))) { avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); return NULL; } AVAHI_ASSERT_TRUE(avahi_normalize_name(domain, normalized_d, sizeof(normalized_d))); snprintf(t, sizeof(t), "%s.%s", type == AVAHI_DNS_SERVER_RESOLVE ? "_domain._udp" : "_dns-update._udp", normalized_d); if (!(r = avahi_record_new_full(t, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV, AVAHI_DEFAULT_TTL_HOST_NAME))) { avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); avahi_free(n); return NULL; } r->data.srv.priority = 0; r->data.srv.weight = 0; r->data.srv.port = port; r->data.srv.name = n; e = server_add_internal(s, g, interface, protocol, 0, r); avahi_record_unref(r); return e; }
AvahiSRecordBrowser *avahi_s_record_browser_new( AvahiServer *server, AvahiIfIndex interface, AvahiProtocol protocol, AvahiKey *key, AvahiLookupFlags flags, AvahiSRecordBrowserCallback callback, void* userdata) { AvahiSRecordBrowser *b; assert(server); assert(key); assert(callback); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, !avahi_key_is_pattern(key), AVAHI_ERR_IS_PATTERN); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, avahi_key_is_valid(key), AVAHI_ERR_INVALID_KEY); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_FLAGS_VALID(flags, AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, !(flags & AVAHI_LOOKUP_USE_WIDE_AREA) || !(flags & AVAHI_LOOKUP_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS); if (!(b = avahi_new(AvahiSRecordBrowser, 1))) { avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY); return NULL; } b->dead = 0; b->server = server; b->interface = interface; b->protocol = protocol; b->key = avahi_key_ref(key); b->flags = flags; b->callback = callback; b->userdata = userdata; b->n_lookups = 0; AVAHI_LLIST_HEAD_INIT(AvahiSRBLookup, b->lookups); b->root_lookup = NULL; AVAHI_LLIST_PREPEND(AvahiSRecordBrowser, browser, server->record_browsers, b); /* The currently cached entries are scanned a bit later, and than we will start querying, too */ b->defer_time_event = avahi_time_event_new(server->time_event_queue, NULL, defer_callback, b); assert(b->defer_time_event); return b; }
int avahi_server_add_service_subtype( AvahiServer *s, AvahiSEntryGroup *g, AvahiIfIndex interface, AvahiProtocol protocol, AvahiPublishFlags flags, const char *name, const char *type, const char *domain, const char *subtype) { int ret = AVAHI_OK; char svc_name[AVAHI_DOMAIN_NAME_MAX], ptr_name[AVAHI_DOMAIN_NAME_MAX]; assert(name); assert(type); assert(subtype); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_FLAGS_VALID(flags, AVAHI_PUBLISH_USE_MULTICAST|AVAHI_PUBLISH_USE_WIDE_AREA), AVAHI_ERR_INVALID_FLAGS); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_name(name), AVAHI_ERR_INVALID_SERVICE_NAME); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_type_strict(type), AVAHI_ERR_INVALID_SERVICE_TYPE); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_subtype(subtype), AVAHI_ERR_INVALID_SERVICE_SUBTYPE); if (!domain) domain = s->domain_name; transport_flags_from_domain(s, &flags, domain); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED); if ((ret = avahi_service_name_join(svc_name, sizeof(svc_name), name, type, domain)) < 0 || (ret = avahi_service_name_join(ptr_name, sizeof(ptr_name), NULL, subtype, domain)) < 0) { avahi_server_set_errno(s, ret); goto fail; } if ((ret = avahi_server_add_ptr(s, g, interface, protocol, 0, AVAHI_DEFAULT_TTL, ptr_name, svc_name)) < 0) goto fail; fail: return ret; }
AvahiSDomainBrowser *avahi_s_domain_browser_prepare( AvahiServer *server, AvahiIfIndex interface, AvahiProtocol protocol, const char *domain, AvahiDomainBrowserType type, AvahiLookupFlags flags, AvahiSDomainBrowserCallback callback, void* userdata) { static const char * const type_table[AVAHI_DOMAIN_BROWSER_MAX] = { "b", "db", "r", "dr", "lb" }; AvahiSDomainBrowser *b; AvahiKey *k = NULL; char n[AVAHI_DOMAIN_NAME_MAX]; int r; assert(server); assert(callback); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, type < AVAHI_DOMAIN_BROWSER_MAX, AVAHI_ERR_INVALID_FLAGS); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_FLAGS_VALID(flags, AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS); if (!domain) domain = server->domain_name; if ((r = avahi_service_name_join(n, sizeof(n), type_table[type], "_dns-sd._udp", domain)) < 0) { avahi_server_set_errno(server, r); return NULL; } if (!(b = avahi_new(AvahiSDomainBrowser, 1))) { avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY); return NULL; } b->ref = 1; b->server = server; b->callback = callback; b->userdata = userdata; b->record_browser = NULL; b->type = type; b->all_for_now_scheduled = 0; b->defer_event = NULL; AVAHI_LLIST_PREPEND(AvahiSDomainBrowser, browser, server->domain_browsers, b); if (!(k = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_PTR))) { avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY); goto fail; } if (!(b->record_browser = avahi_s_record_browser_prepare(server, interface, protocol, k, flags, record_browser_callback, b))) goto fail; avahi_key_unref(k); if (type == AVAHI_DOMAIN_BROWSER_BROWSE && b->server->config.browse_domains) b->defer_event = avahi_time_event_new(server->time_event_queue, NULL, defer_callback, b); return b; fail: if (k) avahi_key_unref(k); avahi_s_domain_browser_free(b); return NULL; }
AvahiSServiceResolver *avahi_s_service_resolver_new( AvahiServer *server, AvahiIfIndex interface, AvahiProtocol protocol, const char *name, const char *type, const char *domain, AvahiProtocol aprotocol, AvahiLookupFlags flags, AvahiSServiceResolverCallback callback, void* userdata) { AvahiSServiceResolver *r; AvahiKey *k; char n[AVAHI_DOMAIN_NAME_MAX]; int ret; assert(server); assert(type); assert(callback); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_PROTO_VALID(aprotocol), AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, !name || avahi_is_valid_service_name(name), AVAHI_ERR_INVALID_SERVICE_NAME); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, avahi_is_valid_service_type_strict(type), AVAHI_ERR_INVALID_SERVICE_TYPE); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_FLAGS_VALID(flags, AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_MULTICAST|AVAHI_LOOKUP_NO_TXT|AVAHI_LOOKUP_NO_ADDRESS), AVAHI_ERR_INVALID_FLAGS); if (!domain) domain = server->domain_name; if ((ret = avahi_service_name_join(n, sizeof(n), name, type, domain)) < 0) { avahi_server_set_errno(server, ret); return NULL; } if (!(r = avahi_new(AvahiSServiceResolver, 1))) { avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY); return NULL; } r->server = server; r->service_name = avahi_strdup(name); r->service_type = avahi_normalize_name_strdup(type); r->domain_name = avahi_normalize_name_strdup(domain); r->callback = callback; r->userdata = userdata; r->address_protocol = aprotocol; r->srv_record = r->txt_record = r->address_record = NULL; r->srv_flags = r->txt_flags = r->address_flags = 0; r->interface = interface; r->protocol = protocol; r->user_flags = flags; r->record_browser_a = r->record_browser_aaaa = r->record_browser_srv = r->record_browser_txt = NULL; r->time_event = NULL; AVAHI_LLIST_PREPEND(AvahiSServiceResolver, resolver, server->service_resolvers, r); k = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV); r->record_browser_srv = avahi_s_record_browser_new(server, interface, protocol, k, flags & ~(AVAHI_LOOKUP_NO_TXT|AVAHI_LOOKUP_NO_ADDRESS), record_browser_callback, r); avahi_key_unref(k); if (!r->record_browser_srv) { avahi_s_service_resolver_free(r); return NULL; } if (!(flags & AVAHI_LOOKUP_NO_TXT)) { k = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_TXT); r->record_browser_txt = avahi_s_record_browser_new(server, interface, protocol, k, flags & ~(AVAHI_LOOKUP_NO_TXT|AVAHI_LOOKUP_NO_ADDRESS), record_browser_callback, r); avahi_key_unref(k); if (!r->record_browser_txt) { avahi_s_service_resolver_free(r); return NULL; } } start_timeout(r); return r; }
AvahiSAddressResolver *avahi_s_address_resolver_new( AvahiServer *server, AvahiIfIndex interface, AvahiProtocol protocol, const AvahiAddress *address, AvahiLookupFlags flags, AvahiSAddressResolverCallback callback, void* userdata) { AvahiSAddressResolver *r; AvahiKey *k; char n[AVAHI_DOMAIN_NAME_MAX]; assert(server); assert(address); assert(callback); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, address->proto == AVAHI_PROTO_INET || address->proto == AVAHI_PROTO_INET6, AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_FLAGS_VALID(flags, AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_MULTICAST|AVAHI_LOOKUP_USE_LLMNR), AVAHI_ERR_INVALID_FLAGS); avahi_reverse_lookup_name(address, n, sizeof(n)); if (!(k = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_PTR))) { avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY); return NULL; } if (!(r = avahi_new(AvahiSAddressResolver, 1))) { avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY); avahi_key_unref(k); return NULL; } r->server = server; r->address = *address; r->callback = callback; r->userdata = userdata; r->ptr_record = NULL; r->interface = interface; r->protocol = protocol; r->flags = 0; r->retry_with_multicast = 0; r->retry_with_llmnr = 0; r->llmnr_has_record = 0; r->key = k; r->record_browser = NULL; AVAHI_LLIST_PREPEND(AvahiSAddressResolver, resolver, server->address_resolvers, r); r->time_event = NULL; if (!(flags & (AVAHI_LOOKUP_USE_MULTICAST|AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_LLMNR))) { if (!server->wide_area.wide_area_lookup_engine || !avahi_wide_area_has_servers(server->wide_area.wide_area_lookup_engine)) flags |= AVAHI_LOOKUP_USE_LLMNR; else { flags |= AVAHI_LOOKUP_USE_WIDE_AREA; r->retry_with_llmnr = 1; } r->retry_with_multicast = 1; } r->record_browser = avahi_s_record_browser_new(server, interface, protocol, k, flags, record_browser_callback, r); if (!r->record_browser) { avahi_s_address_resolver_free(r); return NULL; } start_timeout(r); return r; }
static int server_add_service_strlst_nocopy( AvahiServer *s, AvahiSEntryGroup *g, AvahiIfIndex interface, AvahiProtocol protocol, AvahiPublishFlags flags, const char *name, const char *type, const char *domain, const char *host, uint16_t port, AvahiStringList *strlst) { char ptr_name[AVAHI_DOMAIN_NAME_MAX], svc_name[AVAHI_DOMAIN_NAME_MAX], enum_ptr[AVAHI_DOMAIN_NAME_MAX], *h = NULL; AvahiRecord *r = NULL; int ret = AVAHI_OK; AvahiEntry *srv_entry = NULL, *txt_entry = NULL, *ptr_entry = NULL, *enum_entry = NULL; assert(s); assert(type); assert(name); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_FLAGS_VALID(flags, AVAHI_PUBLISH_NO_COOKIE| AVAHI_PUBLISH_UPDATE| AVAHI_PUBLISH_USE_WIDE_AREA| AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_name(name), AVAHI_ERR_INVALID_SERVICE_NAME); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_type_strict(type), AVAHI_ERR_INVALID_SERVICE_TYPE); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, !host || avahi_is_valid_fqdn(host), AVAHI_ERR_INVALID_HOST_NAME); if (!domain) domain = s->domain_name; if (!host) host = s->host_name_fqdn; transport_flags_from_domain(s, &flags, domain); AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED); if (!(h = avahi_normalize_name_strdup(host))) { ret = avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); goto fail; } if ((ret = avahi_service_name_join(svc_name, sizeof(svc_name), name, type, domain)) < 0 || (ret = avahi_service_name_join(ptr_name, sizeof(ptr_name), NULL, type, domain)) < 0 || (ret = avahi_service_name_join(enum_ptr, sizeof(enum_ptr), NULL, "_services._dns-sd._udp", domain)) < 0) { avahi_server_set_errno(s, ret); goto fail; } /* Add service enumeration PTR record */ if (!(ptr_entry = server_add_ptr_internal(s, g, interface, protocol, 0, AVAHI_DEFAULT_TTL, ptr_name, svc_name))) { ret = avahi_server_errno(s); goto fail; } /* Add SRV record */ if (!(r = avahi_record_new_full(svc_name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV, AVAHI_DEFAULT_TTL_HOST_NAME))) { ret = avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); goto fail; } r->data.srv.priority = 0; r->data.srv.weight = 0; r->data.srv.port = port; r->data.srv.name = h; h = NULL; srv_entry = server_add_internal(s, g, interface, protocol, AVAHI_PUBLISH_UNIQUE, r); avahi_record_unref(r); if (!srv_entry) { ret = avahi_server_errno(s); goto fail; } /* Add TXT record */ if (!(flags & AVAHI_PUBLISH_NO_COOKIE)) strlst = add_magic_cookie(s, strlst); txt_entry = server_add_txt_strlst_nocopy(s, g, interface, protocol, AVAHI_PUBLISH_UNIQUE, AVAHI_DEFAULT_TTL, svc_name, strlst); strlst = NULL; if (!txt_entry) { ret = avahi_server_errno(s); goto fail; } /* Add service type enumeration record */ if (!(enum_entry = server_add_ptr_internal(s, g, interface, protocol, 0, AVAHI_DEFAULT_TTL, enum_ptr, ptr_name))) { ret = avahi_server_errno(s); goto fail; } fail: if (ret != AVAHI_OK && !(flags & AVAHI_PUBLISH_UPDATE)) { if (srv_entry) avahi_entry_free(s, srv_entry); if (txt_entry) avahi_entry_free(s, txt_entry); if (ptr_entry) avahi_entry_free(s, ptr_entry); if (enum_entry) avahi_entry_free(s, enum_entry); } avahi_string_list_free(strlst); avahi_free(h); return ret; }
int avahi_server_add_address( AvahiServer *s, AvahiSEntryGroup *g, AvahiIfIndex interface, AvahiProtocol protocol, AvahiPublishFlags flags, const char *name, AvahiAddress *a) { char n[AVAHI_DOMAIN_NAME_MAX]; int ret = AVAHI_OK; AvahiEntry *entry = NULL, *reverse = NULL; AvahiRecord *r; assert(s); assert(a); AVAHI_CHECK_VALIDITY(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); AVAHI_CHECK_VALIDITY(s, AVAHI_PROTO_VALID(protocol) && AVAHI_PROTO_VALID(a->proto), AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY(s, AVAHI_FLAGS_VALID(flags, AVAHI_PUBLISH_NO_REVERSE| AVAHI_PUBLISH_NO_ANNOUNCE| AVAHI_PUBLISH_NO_PROBE| AVAHI_PUBLISH_UPDATE| AVAHI_PUBLISH_USE_WIDE_AREA| AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS); AVAHI_CHECK_VALIDITY(s, !name || avahi_is_valid_fqdn(name), AVAHI_ERR_INVALID_HOST_NAME); /* Prepare the host naem */ if (!name) name = s->host_name_fqdn; else { AVAHI_ASSERT_TRUE(avahi_normalize_name(name, n, sizeof(n))); name = n; } transport_flags_from_domain(s, &flags, name); AVAHI_CHECK_VALIDITY(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED); /* Create the A/AAAA record */ if (a->proto == AVAHI_PROTO_INET) { if (!(r = avahi_record_new_full(name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_A, AVAHI_DEFAULT_TTL_HOST_NAME))) { ret = avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); goto finish; } r->data.a.address = a->data.ipv4; } else { assert(a->proto == AVAHI_PROTO_INET6); if (!(r = avahi_record_new_full(name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA, AVAHI_DEFAULT_TTL_HOST_NAME))) { ret = avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); goto finish; } r->data.aaaa.address = a->data.ipv6; } entry = server_add_internal(s, g, interface, protocol, (flags & ~ AVAHI_PUBLISH_NO_REVERSE) | AVAHI_PUBLISH_UNIQUE | AVAHI_PUBLISH_ALLOW_MULTIPLE, r); avahi_record_unref(r); if (!entry) { ret = avahi_server_errno(s); goto finish; } /* Create the reverse lookup entry */ if (!(flags & AVAHI_PUBLISH_NO_REVERSE)) { char reverse_n[AVAHI_DOMAIN_NAME_MAX]; avahi_reverse_lookup_name(a, reverse_n, sizeof(reverse_n)); if (!(reverse = server_add_ptr_internal(s, g, interface, protocol, flags | AVAHI_PUBLISH_UNIQUE, AVAHI_DEFAULT_TTL_HOST_NAME, reverse_n, name))) { ret = avahi_server_errno(s); goto finish; } } finish: if (ret != AVAHI_OK && !(flags & AVAHI_PUBLISH_UPDATE)) { if (entry) avahi_entry_free(s, entry); if (reverse) avahi_entry_free(s, reverse); } return ret; }
static AvahiEntry * server_add_internal( AvahiServer *s, AvahiSEntryGroup *g, AvahiIfIndex interface, AvahiProtocol protocol, AvahiPublishFlags flags, AvahiRecord *r) { AvahiEntry *e; assert(s); assert(r); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, s->state != AVAHI_SERVER_FAILURE && s->state != AVAHI_SERVER_INVALID, AVAHI_ERR_BAD_STATE); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, AVAHI_FLAGS_VALID( flags, AVAHI_PUBLISH_NO_ANNOUNCE| AVAHI_PUBLISH_NO_PROBE| AVAHI_PUBLISH_UNIQUE| AVAHI_PUBLISH_ALLOW_MULTIPLE| AVAHI_PUBLISH_UPDATE| AVAHI_PUBLISH_USE_WIDE_AREA| AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, avahi_is_valid_domain_name(r->key->name), AVAHI_ERR_INVALID_HOST_NAME); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, r->ttl != 0, AVAHI_ERR_INVALID_TTL); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, !avahi_key_is_pattern(r->key), AVAHI_ERR_IS_PATTERN); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, avahi_record_is_valid(r), AVAHI_ERR_INVALID_RECORD); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, r->key->clazz == AVAHI_DNS_CLASS_IN, AVAHI_ERR_INVALID_DNS_CLASS); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, (r->key->type != 0) && (r->key->type != AVAHI_DNS_TYPE_ANY) && (r->key->type != AVAHI_DNS_TYPE_OPT) && (r->key->type != AVAHI_DNS_TYPE_TKEY) && (r->key->type != AVAHI_DNS_TYPE_TSIG) && (r->key->type != AVAHI_DNS_TYPE_IXFR) && (r->key->type != AVAHI_DNS_TYPE_AXFR), AVAHI_ERR_INVALID_DNS_TYPE); transport_flags_from_domain(s, &flags, r->key->name); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, !s->config.disable_publishing, AVAHI_ERR_NOT_PERMITTED); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, !g || (g->state != AVAHI_ENTRY_GROUP_ESTABLISHED && g->state != AVAHI_ENTRY_GROUP_REGISTERING) || (flags & AVAHI_PUBLISH_UPDATE), AVAHI_ERR_BAD_STATE); if (flags & AVAHI_PUBLISH_UPDATE) { AvahiRecord *old_record; int is_first = 1; /* Update and existing record */ /* Find the first matching entry */ for (e = avahi_hashmap_lookup(s->entries_by_key, r->key); e; e = e->by_key_next) { if (!e->dead && e->group == g && e->interface == interface && e->protocol == protocol) break; is_first = 0; } /* Hmm, nothing found? */ if (!e) { avahi_server_set_errno(s, AVAHI_ERR_NOT_FOUND); return NULL; } /* Update the entry */ old_record = e->record; e->record = avahi_record_ref(r); e->flags = flags; /* Announce our changes when needed */ if (!avahi_record_equal_no_ttl(old_record, r) && (!g || g->state != AVAHI_ENTRY_GROUP_UNCOMMITED)) { /* Remove the old entry from all caches, if needed */ if (!(e->flags & AVAHI_PUBLISH_UNIQUE)) avahi_goodbye_entry(s, e, 1, 0); /* Reannounce our updated entry */ avahi_reannounce_entry(s, e); } /* If we were the first entry in the list, we need to update the key */ if (is_first) avahi_hashmap_replace(s->entries_by_key, e->record->key, e); avahi_record_unref(old_record); } else { AvahiEntry *t; /* Add a new record */ if (check_record_conflict(s, interface, protocol, r, flags) < 0) { avahi_server_set_errno(s, AVAHI_ERR_COLLISION); return NULL; } if (!(e = avahi_new(AvahiEntry, 1))) { avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); return NULL; } e->server = s; e->record = avahi_record_ref(r); e->group = g; e->interface = interface; e->protocol = protocol; e->flags = flags; e->dead = 0; AVAHI_LLIST_HEAD_INIT(AvahiAnnouncer, e->announcers); AVAHI_LLIST_PREPEND(AvahiEntry, entries, s->entries, e); /* Insert into hash table indexed by name */ t = avahi_hashmap_lookup(s->entries_by_key, e->record->key); AVAHI_LLIST_PREPEND(AvahiEntry, by_key, t, e); avahi_hashmap_replace(s->entries_by_key, e->record->key, t); /* Insert into group list */ if (g) AVAHI_LLIST_PREPEND(AvahiEntry, by_group, g->entries, e); avahi_announce_entry(s, e); } return e; }