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 const char *cmd_dnssd_service_name( cmd_parms *cmd, AVAHI_GCC_UNUSED void *mconfig, const char *value) { const char *err; if ((err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|NOT_IN_LIMIT))) return err; if (!avahi_is_valid_service_name(value)) return "Invalid service name"; return NULL; }
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; }
int avahi_service_name_join(char *p, size_t size, const char *name, const char *type, const char *domain) { char escaped_name[AVAHI_LABEL_MAX*4]; char normalized_type[AVAHI_DOMAIN_NAME_MAX]; char normalized_domain[AVAHI_DOMAIN_NAME_MAX]; assert(p); /* Validity checks */ if ((name && !avahi_is_valid_service_name(name))) return AVAHI_ERR_INVALID_SERVICE_NAME; if (!avahi_is_valid_service_type_generic(type)) return AVAHI_ERR_INVALID_SERVICE_TYPE; if (!avahi_is_valid_domain_name(domain)) return AVAHI_ERR_INVALID_DOMAIN_NAME; /* Preparation */ if (name) { size_t l = sizeof(escaped_name); char *e = escaped_name, *r; r = avahi_escape_label(name, strlen(name), &e, &l); assert(r); } if (!(avahi_normalize_name(type, normalized_type, sizeof(normalized_type)))) return AVAHI_ERR_INVALID_SERVICE_TYPE; if (!(avahi_normalize_name(domain, normalized_domain, sizeof(normalized_domain)))) return AVAHI_ERR_INVALID_DOMAIN_NAME; /* Concatenation */ snprintf(p, size, "%s%s%s.%s", name ? escaped_name : "", name ? "." : "", normalized_type, normalized_domain); return AVAHI_OK; }
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; }
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; }
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; }