+
+ return ret;
+}
+
+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, 0), 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;
+
+ 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, flags & AVAHI_PUBLISH_IS_PROXY, AVAHI_DEFAULT_TTL, ptr_name, svc_name)) < 0)
+ goto fail;
+
+fail:
+
+ return ret;
+}
+
+static void hexstring(char *s, size_t sl, const void *p, size_t pl) {
+ static const char hex[] = "0123456789abcdef";
+ int b = 0;
+ const uint8_t *k = p;
+
+ while (sl > 1 && pl > 0) {
+ *(s++) = hex[(b ? *k : *k >> 4) & 0xF];
+
+ if (b) {
+ k++;
+ pl--;
+ }
+
+ b = !b;
+
+ sl--;
+ }
+
+ if (sl > 0)
+ *s = 0;
+}
+
+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;
+ int ret;
+ char n[64], h[64];
+
+ assert(s);
+ assert(address);
+
+ if (!AVAHI_IF_VALID(interface))
+ return avahi_server_set_errno(s, AVAHI_ERR_INVALID_INTERFACE);
+
+ if (!AVAHI_PROTO_VALID(protocol) || !AVAHI_PROTO_VALID(address->proto))
+ return avahi_server_set_errno(s, AVAHI_ERR_INVALID_PROTOCOL);
+
+ if (!AVAHI_FLAGS_VALID(flags, 0) || (type != AVAHI_DNS_SERVER_UPDATE && type != AVAHI_DNS_SERVER_RESOLVE))
+ return avahi_server_set_errno(s, AVAHI_ERR_INVALID_FLAGS);
+
+ if (port == 0)
+ return avahi_server_set_errno(s, AVAHI_ERR_INVALID_PORT);
+
+ if (domain && !avahi_is_valid_domain_name(domain))
+ return avahi_server_set_errno(s, AVAHI_ERR_INVALID_DOMAIN_NAME);
+
+ if (!domain)
+ domain = s->domain_name;
+
+ 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);
+
+ ret = avahi_server_add(s, g, interface, protocol, AVAHI_PUBLISH_UNIQUE | AVAHI_PUBLISH_ALLOW_MULTIPLE, r);
+ avahi_record_unref(r);
+
+ if (ret < 0)
+ return ret;
+
+ return avahi_server_add_dns_server_name(s, g, interface, protocol, flags, domain, type, n, port);
+}
+
+int avahi_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 */) {
+
+ int ret = -1;
+ char t[256], *d = NULL, *n = NULL;
+ AvahiRecord *r;
+
+ assert(s);
+ assert(name);
+
+ if (!AVAHI_IF_VALID(interface))
+ return avahi_server_set_errno(s, AVAHI_ERR_INVALID_INTERFACE);
+
+ if (!AVAHI_PROTO_VALID(protocol))
+ return avahi_server_set_errno(s, AVAHI_ERR_INVALID_PROTOCOL);
+
+ if (!AVAHI_FLAGS_VALID(flags, 0) || (type != AVAHI_DNS_SERVER_UPDATE && type != AVAHI_DNS_SERVER_RESOLVE))
+ return avahi_server_set_errno(s, AVAHI_ERR_INVALID_FLAGS);
+
+ if (port == 0)
+ return avahi_server_set_errno(s, AVAHI_ERR_INVALID_PORT);
+
+ if (!avahi_is_valid_domain_name(name))
+ return avahi_server_set_errno(s, AVAHI_ERR_INVALID_HOST_NAME);
+
+ if (domain && !avahi_is_valid_domain_name(domain))
+ return avahi_server_set_errno(s, AVAHI_ERR_INVALID_DOMAIN_NAME);
+
+ if (!domain)
+ domain = s->domain_name;
+
+ if (!(n = avahi_normalize_name_strdup(name)) ||
+ !(d = avahi_normalize_name_strdup(domain))) {
+ avahi_free(n);
+ avahi_free(d);
+ return avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY);
+ }
+
+ snprintf(t, sizeof(t), "%s.%s", type == AVAHI_DNS_SERVER_RESOLVE ? "_domain._udp" : "_dns-update._udp", d);
+ avahi_free(d);
+
+ if (!(r = avahi_record_new_full(t, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV, AVAHI_DEFAULT_TTL_HOST_NAME))) {
+ avahi_free(n);
+ return avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY);
+ }
+
+ r->data.srv.priority = 0;
+ r->data.srv.weight = 0;
+ r->data.srv.port = port;
+ r->data.srv.name = n;
+ ret = avahi_server_add(s, g, interface, protocol, AVAHI_PUBLISH_NULL, r);
+ avahi_record_unref(r);
+
+ return ret;