static AvahiEntry *server_add_ptr_internal( AvahiServer *s, AvahiSEntryGroup *g, AvahiIfIndex interface, AvahiProtocol protocol, AvahiPublishFlags flags, uint32_t ttl, const char *name, const char *dest) { AvahiRecord *r; AvahiEntry *e; assert(s); assert(dest); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, !name || avahi_is_valid_domain_name(name), AVAHI_ERR_INVALID_HOST_NAME); AVAHI_CHECK_VALIDITY_RETURN_NULL(s, avahi_is_valid_domain_name(dest), AVAHI_ERR_INVALID_HOST_NAME); if (!name) name = s->host_name_fqdn; if (!(r = avahi_record_new_full(name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_PTR, ttl))) { avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); return NULL; } r->data.ptr.name = avahi_normalize_name_strdup(dest); e = server_add_internal(s, g, interface, protocol, flags, r); avahi_record_unref(r); return e; }
int avahi_is_valid_fqdn(const char *t) { char label[AVAHI_LABEL_MAX]; char normalized[AVAHI_DOMAIN_NAME_MAX]; const char *k = t; AvahiAddress a; assert(t); if (strlen(t) >= AVAHI_DOMAIN_NAME_MAX) return 0; if (!avahi_is_valid_domain_name(t)) return 0; /* Check if there are at least two labels*/ if (!(avahi_unescape_label(&k, label, sizeof(label)))) return 0; if (label[0] == 0 || !k) return 0; if (!(avahi_unescape_label(&k, label, sizeof(label)))) return 0; if (label[0] == 0 || !k) return 0; /* Make sure that the name is not an IP address */ if (!(avahi_normalize_name(t, normalized, sizeof(normalized)))) return 0; if (avahi_address_parse(normalized, AVAHI_PROTO_UNSPEC, &a)) return 0; return 1; }
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; }
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; }
static void update_browse_domains(void) { AvahiStringList *l; int n; char **p; if (!resolv_conf_search_domains) { avahi_server_set_browse_domains(avahi_server, NULL); return; } l = avahi_string_list_copy(config.server_config.browse_domains); for (p = resolv_conf_search_domains, n = 0; *p && n < BROWSE_DOMAINS_MAX; p++, n++) { if (!avahi_is_valid_domain_name(*p)) avahi_log_warn("'%s' is no valid domain name, ignoring.", *p); else l = avahi_string_list_add(l, *p); } l = filter_duplicate_domains(l); avahi_server_set_browse_domains(avahi_server, l); }
DBusHandlerResult avahi_dbus_msg_entry_group_impl(DBusConnection *c, DBusMessage *m, void *userdata) { DBusError error; EntryGroupInfo *i = userdata; assert(c); assert(m); assert(i); dbus_error_init(&error); avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s", dbus_message_get_interface(m), dbus_message_get_path(m), dbus_message_get_member(m)); /* Introspection */ if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect")) return avahi_dbus_handle_introspect(c, m, "org.freedesktop.Avahi.EntryGroup.xml"); /* Access control */ if (strcmp(dbus_message_get_sender(m), i->client->name)) return avahi_dbus_respond_error(c, m, AVAHI_ERR_ACCESS_DENIED, NULL); if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Free")) { if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) { avahi_log_warn("Error parsing EntryGroup::Free message"); goto fail; } avahi_dbus_entry_group_free(i); return avahi_dbus_respond_ok(c, m); } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Commit")) { if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) { avahi_log_warn("Error parsing EntryGroup::Commit message"); goto fail; } if (avahi_s_entry_group_commit(i->entry_group) < 0) return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL); return avahi_dbus_respond_ok(c, m); } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Reset")) { if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) { avahi_log_warn("Error parsing EntryGroup::Reset message"); goto fail; } avahi_s_entry_group_reset(i->entry_group); i->n_entries = 0; return avahi_dbus_respond_ok(c, m); } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "IsEmpty")) { if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) { avahi_log_warn("Error parsing EntryGroup::IsEmpty message"); goto fail; } return avahi_dbus_respond_boolean(c, m, !!avahi_s_entry_group_is_empty(i->entry_group)); } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "GetState")) { AvahiEntryGroupState state; if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) { avahi_log_warn("Error parsing EntryGroup::GetState message"); goto fail; } state = avahi_s_entry_group_get_state(i->entry_group); return avahi_dbus_respond_int32(c, m, (int32_t) state); } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddService")) { int32_t interface, protocol; uint32_t flags; char *type, *name, *domain, *host; uint16_t port; AvahiStringList *strlst = NULL; if (!dbus_message_get_args( m, &error, DBUS_TYPE_INT32, &interface, DBUS_TYPE_INT32, &protocol, DBUS_TYPE_UINT32, &flags, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &type, DBUS_TYPE_STRING, &domain, DBUS_TYPE_STRING, &host, DBUS_TYPE_UINT16, &port, DBUS_TYPE_INVALID) || !type || !name || avahi_dbus_read_strlst(m, 8, &strlst) < 0) { avahi_log_warn("Error parsing EntryGroup::AddService message"); goto fail; } if (!(flags & AVAHI_PUBLISH_UPDATE) && i->n_entries >= server->n_entries_per_entry_group_max) { avahi_string_list_free(strlst); return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_ENTRIES, NULL); } if (domain && !*domain) domain = NULL; if (host && !*host) host = NULL; if (avahi_server_add_service_strlst(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, (AvahiPublishFlags) flags, name, type, domain, host, port, strlst) < 0) { avahi_string_list_free(strlst); return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL); } if (!(flags & AVAHI_PUBLISH_UPDATE)) i->n_entries ++; avahi_string_list_free(strlst); return avahi_dbus_respond_ok(c, m); } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddServiceSubtype")) { int32_t interface, protocol; uint32_t flags; char *type, *name, *domain, *subtype; if (!dbus_message_get_args( m, &error, DBUS_TYPE_INT32, &interface, DBUS_TYPE_INT32, &protocol, DBUS_TYPE_UINT32, &flags, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &type, DBUS_TYPE_STRING, &domain, DBUS_TYPE_STRING, &subtype, DBUS_TYPE_INVALID) || !type || !name || !subtype) { avahi_log_warn("Error parsing EntryGroup::AddServiceSubtype message"); goto fail; } if (!(flags & AVAHI_PUBLISH_UPDATE) && i->n_entries >= server->n_entries_per_entry_group_max) return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_ENTRIES, NULL); if (domain && !*domain) domain = NULL; if (avahi_server_add_service_subtype(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, (AvahiPublishFlags) flags, name, type, domain, subtype) < 0) return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL); if (!(flags & AVAHI_PUBLISH_UPDATE)) i->n_entries ++; return avahi_dbus_respond_ok(c, m); } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "UpdateServiceTxt")) { int32_t interface, protocol; uint32_t flags; char *type, *name, *domain; AvahiStringList *strlst; if (!dbus_message_get_args( m, &error, DBUS_TYPE_INT32, &interface, DBUS_TYPE_INT32, &protocol, DBUS_TYPE_UINT32, &flags, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &type, DBUS_TYPE_STRING, &domain, DBUS_TYPE_INVALID) || !type || !name || avahi_dbus_read_strlst(m, 6, &strlst)) { avahi_log_warn("Error parsing EntryGroup::UpdateServiceTxt message"); goto fail; } if (domain && !*domain) domain = NULL; if (avahi_server_update_service_txt_strlst(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, (AvahiPublishFlags) flags, name, type, domain, strlst) < 0) { avahi_string_list_free(strlst); return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL); } avahi_string_list_free(strlst); return avahi_dbus_respond_ok(c, m); } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddAddress")) { int32_t interface, protocol; uint32_t flags; char *name, *address; AvahiAddress a; if (!dbus_message_get_args( m, &error, DBUS_TYPE_INT32, &interface, DBUS_TYPE_INT32, &protocol, DBUS_TYPE_UINT32, &flags, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &address, DBUS_TYPE_INVALID) || !name || !address) { avahi_log_warn("Error parsing EntryGroup::AddAddress message"); goto fail; } if (!(flags & AVAHI_PUBLISH_UPDATE) && i->n_entries >= server->n_entries_per_entry_group_max) return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_ENTRIES, NULL); if (!(avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a))) return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_ADDRESS, NULL); if (avahi_server_add_address(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, (AvahiPublishFlags) flags, name, &a) < 0) return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL); if (!(flags & AVAHI_PUBLISH_UPDATE)) i->n_entries ++; return avahi_dbus_respond_ok(c, m); } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddRecord")) { int32_t interface, protocol; uint32_t flags, ttl, size; uint16_t clazz, type; char *name; void *rdata; AvahiRecord *r; if (!dbus_message_get_args( m, &error, DBUS_TYPE_INT32, &interface, DBUS_TYPE_INT32, &protocol, DBUS_TYPE_UINT32, &flags, DBUS_TYPE_STRING, &name, DBUS_TYPE_UINT16, &clazz, DBUS_TYPE_UINT16, &type, DBUS_TYPE_UINT32, &ttl, DBUS_TYPE_INVALID) || !name || avahi_dbus_read_rdata (m, 7, &rdata, &size)) { avahi_log_warn("Error parsing EntryGroup::AddRecord message"); goto fail; } if (!(flags & AVAHI_PUBLISH_UPDATE) && i->n_entries >= server->n_entries_per_entry_group_max) return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_ENTRIES, NULL); if (!avahi_is_valid_domain_name (name)) return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_DOMAIN_NAME, NULL); if (!(r = avahi_record_new_full (name, clazz, type, ttl))) return avahi_dbus_respond_error(c, m, AVAHI_ERR_NO_MEMORY, NULL); if (avahi_rdata_parse (r, rdata, size) < 0) { avahi_record_unref (r); return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_RDATA, NULL); } if (avahi_server_add(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, (AvahiPublishFlags) flags, r) < 0) { avahi_record_unref (r); return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL); } if (!(flags & AVAHI_PUBLISH_UPDATE)) i->n_entries ++; avahi_record_unref (r); return avahi_dbus_respond_ok(c, m); } avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m)); fail: if (dbus_error_is_set(&error)) dbus_error_free(&error); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; }
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; }
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; }
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; }