blob: eddee56ca6a2a1483a812ab0ea2c1afae6159b79 [file]
/*
* Copyright (c) 2019-2022 Apple Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dnssd_private.h"
#include "dnssd_xpc.h"
#include "mdns_strict.h"
//======================================================================================================================
// MARK: - XPC Dictionary Helper Declarations
static int32_t
_dnssd_xpc_dictionary_get_int32(xpc_object_t dict, const char *key, bool *out_valid);
static int64_t
_dnssd_xpc_dictionary_get_int64(xpc_object_t dict, const char *key, bool *out_valid);
static int64_t
_dnssd_xpc_dictionary_get_int64_limited(xpc_object_t dict, const char *key, int64_t min, int64_t max, bool *out_valid);
static uint16_t
_dnssd_xpc_dictionary_get_uint16(xpc_object_t dict, const char *key, bool *out_valid);
static uint32_t
_dnssd_xpc_dictionary_get_uint32(xpc_object_t dict, const char *key, bool *out_valid);
static uint64_t
_dnssd_xpc_dictionary_get_uint64(xpc_object_t dict, const char *key, bool *out_valid);
static uint64_t
_dnssd_xpc_dictionary_get_uint64_limited(xpc_object_t dict, const char *key, uint64_t min, uint64_t max,
bool *out_valid);
static xpc_object_t _Nullable
_dnssd_xpc_dictionary_get_value(xpc_object_t dict, const char *key, xpc_type_t type);
//======================================================================================================================
// MARK: - Top-Level Message Dictionaries
#define DNSSD_XPC_MESSAGE_KEY_COMMAND "command"
#define DNSSD_XPC_MESSAGE_KEY_ERROR "error"
#define DNSSD_XPC_MESSAGE_KEY_ID "id"
#define DNSSD_XPC_MESSAGE_KEY_PARAMS "params"
#define DNSSD_XPC_MESSAGE_KEY_RESULTS "results"
//======================================================================================================================
const char * _Nullable
dnssd_xpc_message_get_command(xpc_object_t msg)
{
return xpc_dictionary_get_string(msg, DNSSD_XPC_MESSAGE_KEY_COMMAND);
}
//======================================================================================================================
void
dnssd_xpc_message_set_command(xpc_object_t msg, const char *command)
{
xpc_dictionary_set_string(msg, DNSSD_XPC_MESSAGE_KEY_COMMAND, command);
}
//======================================================================================================================
DNSServiceErrorType
dnssd_xpc_message_get_error(xpc_object_t msg, bool *out_valid)
{
return _dnssd_xpc_dictionary_get_int32(msg, DNSSD_XPC_MESSAGE_KEY_ERROR, out_valid);
}
//======================================================================================================================
void
dnssd_xpc_message_set_error(xpc_object_t msg, DNSServiceErrorType error)
{
xpc_dictionary_set_int64(msg, DNSSD_XPC_MESSAGE_KEY_ERROR, error);
}
//======================================================================================================================
uint64_t
dnssd_xpc_message_get_id(xpc_object_t msg, bool *out_valid)
{
return _dnssd_xpc_dictionary_get_uint64(msg, DNSSD_XPC_MESSAGE_KEY_ID, out_valid);
}
//======================================================================================================================
void
dnssd_xpc_message_set_id(xpc_object_t msg, uint64_t ident)
{
xpc_dictionary_set_uint64(msg, DNSSD_XPC_MESSAGE_KEY_ID, ident);
}
//======================================================================================================================
xpc_object_t
dnssd_xpc_message_get_parameters(xpc_object_t msg)
{
return xpc_dictionary_get_dictionary(msg, DNSSD_XPC_MESSAGE_KEY_PARAMS);
}
//======================================================================================================================
void
dnssd_xpc_message_set_parameters(xpc_object_t msg, xpc_object_t params)
{
xpc_dictionary_set_value(msg, DNSSD_XPC_MESSAGE_KEY_PARAMS, params);
}
//======================================================================================================================
xpc_object_t
dnssd_xpc_message_get_results(xpc_object_t msg)
{
return xpc_dictionary_get_array(msg, DNSSD_XPC_MESSAGE_KEY_RESULTS);
}
//======================================================================================================================
void
dnssd_xpc_message_set_results(xpc_object_t msg, xpc_object_t results)
{
xpc_dictionary_set_value(msg, DNSSD_XPC_MESSAGE_KEY_RESULTS, results);
}
//======================================================================================================================
// MARK: - Parameter Dictionaries
#define DNSSD_XPC_PARAMETERS_KEY_ACCOUNT_ID "account_id"
#define DNSSD_XPC_PARAMETERS_KEY_DELEGATE_ID "delegate_id"
#define DNSSD_XPC_PARAMETERS_KEY_FALLBACK_CONFIG "fallback_config"
#define DNSSD_XPC_PARAMETERS_KEY_FLAGS "flags"
#define DNSSD_XPC_PARAMETERS_KEY_HOSTNAME "hostname"
#define DNSSD_XPC_PARAMETERS_KEY_INTERFACE_INDEX "interface_index"
#define DNSSD_XPC_PARAMETERS_KEY_LOG_PRIVACY_LEVEL "log_privacy_level"
#define DNSSD_XPC_PARAMETERS_KEY_NEED_AUTH_TAGS "need_auth_tags"
#define DNSSD_XPC_PARAMETERS_KEY_NEED_ENCRYPTION "need_encryption"
#define DNSSD_XPC_PARAMETERS_KEY_PROHIBIT_ENCRYPTED_DNS "prohibit_encrypted_dns"
#define DNSSD_XPC_PARAMETERS_KEY_PROTOCOLS "protocols"
#define DNSSD_XPC_PARAMETERS_KEY_RESOLVER_UUIDS "resolver_uuids"
#define DNSSD_XPC_PARAMETERS_KEY_SERVICE_SCHEME "service_scheme"
#define DNSSD_XPC_PARAMETERS_KEY_USE_FAILOVER "use_failover"
#define DNSSD_XPC_PARAMETERS_KEY_VALIDATION_DATA "validation_data"
//======================================================================================================================
pid_t
dnssd_xpc_parameters_get_delegate_pid(xpc_object_t params, bool *out_valid)
{
return (pid_t)_dnssd_xpc_dictionary_get_int64(params, DNSSD_XPC_PARAMETERS_KEY_DELEGATE_ID, out_valid);
}
//======================================================================================================================
void
dnssd_xpc_parameters_set_delegate_pid(xpc_object_t params, pid_t pid)
{
xpc_dictionary_set_int64(params, DNSSD_XPC_PARAMETERS_KEY_DELEGATE_ID, pid);
}
//======================================================================================================================
const uint8_t *
dnssd_xpc_parameters_get_delegate_uuid(xpc_object_t params)
{
return xpc_dictionary_get_uuid(params, DNSSD_XPC_PARAMETERS_KEY_DELEGATE_ID);
}
//======================================================================================================================
void
dnssd_xpc_parameters_set_delegate_uuid(xpc_object_t params, uuid_t uuid)
{
xpc_dictionary_set_uuid(params, DNSSD_XPC_PARAMETERS_KEY_DELEGATE_ID, uuid);
}
//======================================================================================================================
audit_token_t * _Nullable
dnssd_xpc_parameters_get_delegate_audit_token(const xpc_object_t params, audit_token_t * const audit_token_storage)
{
size_t size;
const void * const data = xpc_dictionary_get_data(params, DNSSD_XPC_PARAMETERS_KEY_DELEGATE_ID, &size);
if (data && (size == sizeof(*audit_token_storage))) {
memcpy(audit_token_storage, data, size);
return audit_token_storage;
} else {
return NULL;
}
}
//======================================================================================================================
void
dnssd_xpc_parameters_set_delegate_audit_token(const xpc_object_t params, const audit_token_t * const audit_token)
{
xpc_dictionary_set_data(params, DNSSD_XPC_PARAMETERS_KEY_DELEGATE_ID, audit_token, sizeof(*audit_token));
}
//======================================================================================================================
DNSServiceFlags
dnssd_xpc_parameters_get_flags(xpc_object_t params, bool *out_valid)
{
return _dnssd_xpc_dictionary_get_uint32(params, DNSSD_XPC_PARAMETERS_KEY_FLAGS, out_valid);
}
//======================================================================================================================
void
dnssd_xpc_parameters_set_flags(xpc_object_t params, DNSServiceFlags flags)
{
xpc_dictionary_set_uint64(params, DNSSD_XPC_PARAMETERS_KEY_FLAGS, flags);
}
//======================================================================================================================
const char *
dnssd_xpc_parameters_get_account_id(xpc_object_t params)
{
return xpc_dictionary_get_string(params, DNSSD_XPC_PARAMETERS_KEY_ACCOUNT_ID);
}
//======================================================================================================================
void
dnssd_xpc_parameters_set_account_id(xpc_object_t params, const char *account_id)
{
xpc_dictionary_set_string(params, DNSSD_XPC_PARAMETERS_KEY_ACCOUNT_ID, account_id);
}
//======================================================================================================================
xpc_object_t
dnssd_xpc_parameters_get_hostname_object(xpc_object_t params)
{
return _dnssd_xpc_dictionary_get_value(params, DNSSD_XPC_PARAMETERS_KEY_HOSTNAME, XPC_TYPE_STRING);
}
//======================================================================================================================
const char *
dnssd_xpc_parameters_get_hostname(xpc_object_t params)
{
return xpc_dictionary_get_string(params, DNSSD_XPC_PARAMETERS_KEY_HOSTNAME);
}
//======================================================================================================================
void
dnssd_xpc_parameters_set_hostname(xpc_object_t params, const char *hostname)
{
xpc_dictionary_set_string(params, DNSSD_XPC_PARAMETERS_KEY_HOSTNAME, hostname);
}
//======================================================================================================================
uint32_t
dnssd_xpc_parameters_get_interface_index(xpc_object_t params, bool *out_valid)
{
return _dnssd_xpc_dictionary_get_uint32(params, DNSSD_XPC_PARAMETERS_KEY_INTERFACE_INDEX, out_valid);
}
//======================================================================================================================
void
dnssd_xpc_parameters_set_interface_index(xpc_object_t params, uint32_t interface_index)
{
xpc_dictionary_set_uint64(params, DNSSD_XPC_PARAMETERS_KEY_INTERFACE_INDEX, interface_index);
}
//======================================================================================================================
bool
dnssd_xpc_parameters_get_need_authentication_tags(xpc_object_t params)
{
return xpc_dictionary_get_bool(params, DNSSD_XPC_PARAMETERS_KEY_NEED_AUTH_TAGS);
}
//======================================================================================================================
void
dnssd_xpc_parameters_set_need_authentication_tags(xpc_object_t params, bool need_auth_tags)
{
xpc_dictionary_set_bool(params, DNSSD_XPC_PARAMETERS_KEY_NEED_AUTH_TAGS, need_auth_tags);
}
//======================================================================================================================
void
dnssd_xpc_parameters_set_need_encrypted_query(xpc_object_t params, bool need, _Nullable xpc_object_t fallback_config)
{
xpc_dictionary_set_bool(params, DNSSD_XPC_PARAMETERS_KEY_NEED_ENCRYPTION, need);
if (fallback_config != NULL) {
xpc_dictionary_set_value(params, DNSSD_XPC_PARAMETERS_KEY_FALLBACK_CONFIG, fallback_config);
}
}
//======================================================================================================================
bool
dnssd_xpc_parameters_get_need_encrypted_query(xpc_object_t params)
{
return xpc_dictionary_get_bool(params, DNSSD_XPC_PARAMETERS_KEY_NEED_ENCRYPTION);
}
//======================================================================================================================
xpc_object_t _Nullable
dnssd_xpc_parameters_get_fallback_config(xpc_object_t params)
{
return xpc_dictionary_get_value(params, DNSSD_XPC_PARAMETERS_KEY_FALLBACK_CONFIG);
}
//======================================================================================================================
xpc_object_t _Nullable
dnssd_xpc_parameters_get_resolver_uuid_array(xpc_object_t params)
{
return xpc_dictionary_get_value(params, DNSSD_XPC_PARAMETERS_KEY_RESOLVER_UUIDS);
}
//======================================================================================================================
void
dnssd_xpc_parameters_add_resolver_uuid(xpc_object_t params, uuid_t _Nonnull uuid)
{
xpc_object_t resolver_uuid_array = xpc_dictionary_get_value(params, DNSSD_XPC_PARAMETERS_KEY_RESOLVER_UUIDS);
if (resolver_uuid_array == NULL) {
resolver_uuid_array = xpc_array_create(NULL, 0);
xpc_dictionary_set_value(params, DNSSD_XPC_PARAMETERS_KEY_RESOLVER_UUIDS, resolver_uuid_array);
xpc_object_t tmp = resolver_uuid_array;
xpc_forget(&tmp);
}
xpc_array_set_uuid(resolver_uuid_array, XPC_ARRAY_APPEND, uuid);
}
//======================================================================================================================
DNSServiceProtocol
dnssd_xpc_parameters_get_protocols(xpc_object_t params, bool *out_valid)
{
return _dnssd_xpc_dictionary_get_uint32(params, DNSSD_XPC_PARAMETERS_KEY_PROTOCOLS, out_valid);
}
//======================================================================================================================
void
dnssd_xpc_parameters_set_protocols(xpc_object_t params, DNSServiceProtocol protocols)
{
xpc_dictionary_set_uint64(params, DNSSD_XPC_PARAMETERS_KEY_PROTOCOLS, protocols);
}
//======================================================================================================================
const char * _Nullable
dnssd_xpc_parameters_get_service_scheme(xpc_object_t params)
{
return xpc_dictionary_get_string(params, DNSSD_XPC_PARAMETERS_KEY_SERVICE_SCHEME);
}
//======================================================================================================================
void
dnssd_xpc_parameters_set_service_scheme(xpc_object_t params, const char *service_scheme)
{
xpc_dictionary_set_string(params, DNSSD_XPC_PARAMETERS_KEY_SERVICE_SCHEME, service_scheme);
}
//======================================================================================================================
bool
dnssd_xpc_parameters_get_use_failover(const xpc_object_t params)
{
return xpc_dictionary_get_bool(params, DNSSD_XPC_PARAMETERS_KEY_USE_FAILOVER);
}
//======================================================================================================================
void
dnssd_xpc_parameters_set_use_failover(const xpc_object_t params, const bool use_failover)
{
xpc_dictionary_set_bool(params, DNSSD_XPC_PARAMETERS_KEY_USE_FAILOVER, use_failover);
}
//======================================================================================================================
dnssd_log_privacy_level_t
dnssd_xpc_parameters_get_log_privacy_level(const xpc_object_t params)
{
bool valid;
// Make sure that dnssd_log_privacy_level_t is indeed a 32-bit signed integer.
check_compile_time_code(sizeof(dnssd_log_privacy_level_t) == sizeof(int32_t));
check_compile_time_code(((dnssd_log_privacy_level_t)-1) < 0);
const dnssd_log_privacy_level_t level = _dnssd_xpc_dictionary_get_int32(params,
DNSSD_XPC_PARAMETERS_KEY_LOG_PRIVACY_LEVEL, &valid);
if (valid) {
// A default case isn't used to allow the compiler to catch missing dnssd_log_privacy_level_t enum values.
switch (level) {
case dnssd_log_privacy_level_default:
case dnssd_log_privacy_level_private:
return level;
}
}
return dnssd_log_privacy_level_default;
}
//======================================================================================================================
void
dnssd_xpc_parameters_set_log_privacy_level(const xpc_object_t params, const dnssd_log_privacy_level_t level)
{
xpc_dictionary_set_int64(params, DNSSD_XPC_PARAMETERS_KEY_LOG_PRIVACY_LEVEL, level);
}
//======================================================================================================================
const uint8_t *
dnssd_xpc_parameters_get_validation_data(const xpc_object_t params, size_t * const out_length)
{
return (const uint8_t *)xpc_dictionary_get_data(params, DNSSD_XPC_PARAMETERS_KEY_VALIDATION_DATA, out_length);
}
//======================================================================================================================
void
dnssd_xpc_parameters_set_validation_data(const xpc_object_t params, const uint8_t * const data_ptr,
const size_t data_len)
{
xpc_dictionary_set_data(params, DNSSD_XPC_PARAMETERS_KEY_VALIDATION_DATA, data_ptr, data_len);
}
//======================================================================================================================
bool
dnssd_xpc_parameters_get_prohibit_encrypted_dns(const xpc_object_t params)
{
return xpc_dictionary_get_bool(params, DNSSD_XPC_PARAMETERS_KEY_PROHIBIT_ENCRYPTED_DNS);
}
//======================================================================================================================
void
dnssd_xpc_parameters_set_prohibit_encrypted_dns(const xpc_object_t params, const bool prohibit)
{
xpc_dictionary_set_bool(params, DNSSD_XPC_PARAMETERS_KEY_PROHIBIT_ENCRYPTED_DNS, prohibit);
}
//======================================================================================================================
// MARK: - Result Dictionaries
#define DNSSD_XPC_RESULT_KEY_AUTH_TAG "auth_tag"
#define DNSSD_XPC_RESULT_KEY_CNAME_UPDATE "cname_update"
#define DNSSD_XPC_RESULT_KEY_ERROR "error"
#define DNSSD_XPC_RESULT_KEY_FLAGS "flags"
#define DNSSD_XPC_RESULT_KEY_INTERFACE_INDEX "interface_index"
#define DNSSD_XPC_RESULT_KEY_NEGATIVE_REASON "negative_reason"
#define DNSSD_XPC_RESULT_KEY_PROVIDER_NAME "provider_name"
#define DNSSD_XPC_RESULT_KEY_RECORD_CLASS "rclass"
#define DNSSD_XPC_RESULT_KEY_RECORD_DATA "rdata"
#define DNSSD_XPC_RESULT_KEY_RECORD_NAME "rname"
#define DNSSD_XPC_RESULT_KEY_RECORD_PROTOCOL "rprotocol"
#define DNSSD_XPC_RESULT_KEY_RECORD_TYPE "rtype"
#define DNSSD_XPC_RESULT_KEY_TRACKER_HOSTNAME "tracker_hostname"
#define DNSSD_XPC_RESULT_KEY_TRACKER_OWNER "tracker_owner"
#define DNSSD_XPC_RESULT_KEY_TRACKER_APPROVED "tracker_approved"
#define DNSSD_XPC_RESULT_KEY_VALIDATION_DATA "validation_data"
//======================================================================================================================
xpc_object_t
dnssd_xpc_result_get_authentication_tag_object(xpc_object_t result)
{
return _dnssd_xpc_dictionary_get_value(result, DNSSD_XPC_RESULT_KEY_AUTH_TAG, XPC_TYPE_DATA);
}
//======================================================================================================================
void
dnssd_xpc_result_set_authentication_tag(xpc_object_t result, const void *auth_tag_ptr, size_t auth_tag_len)
{
xpc_dictionary_set_data(result, DNSSD_XPC_RESULT_KEY_AUTH_TAG, auth_tag_ptr, auth_tag_len);
}
//======================================================================================================================
DNSServiceErrorType
dnssd_xpc_result_get_error(xpc_object_t result, bool *out_valid)
{
return _dnssd_xpc_dictionary_get_int32(result, DNSSD_XPC_RESULT_KEY_ERROR, out_valid);
}
//======================================================================================================================
void
dnssd_xpc_result_set_error(xpc_object_t result, DNSServiceErrorType error)
{
xpc_dictionary_set_int64(result, DNSSD_XPC_RESULT_KEY_ERROR, error);
}
//======================================================================================================================
DNSServiceFlags
dnssd_xpc_result_get_flags(xpc_object_t result, bool *out_valid)
{
return _dnssd_xpc_dictionary_get_uint32(result, DNSSD_XPC_RESULT_KEY_FLAGS, out_valid);
}
//======================================================================================================================
void
dnssd_xpc_result_set_flags(xpc_object_t result, DNSServiceFlags flags)
{
xpc_dictionary_set_uint64(result, DNSSD_XPC_RESULT_KEY_FLAGS, flags);
}
//======================================================================================================================
uint32_t
dnssd_xpc_result_get_interface_index(xpc_object_t result, bool *out_valid)
{
return _dnssd_xpc_dictionary_get_uint32(result, DNSSD_XPC_RESULT_KEY_INTERFACE_INDEX, out_valid);
}
//======================================================================================================================
void
dnssd_xpc_result_set_interface_index(xpc_object_t result, uint32_t interface_index)
{
xpc_dictionary_set_uint64(result, DNSSD_XPC_RESULT_KEY_INTERFACE_INDEX, interface_index);
}
//======================================================================================================================
uint16_t
dnssd_xpc_result_get_record_class(xpc_object_t result, bool *out_valid)
{
return _dnssd_xpc_dictionary_get_uint16(result, DNSSD_XPC_RESULT_KEY_RECORD_CLASS, out_valid);
}
//======================================================================================================================
void
dnssd_xpc_result_set_record_class(xpc_object_t result, uint16_t class)
{
xpc_dictionary_set_uint64(result, DNSSD_XPC_RESULT_KEY_RECORD_CLASS, class);
}
//======================================================================================================================
xpc_object_t
dnssd_xpc_result_get_record_data_object(xpc_object_t result)
{
return _dnssd_xpc_dictionary_get_value(result, DNSSD_XPC_RESULT_KEY_RECORD_DATA, XPC_TYPE_DATA);
}
//======================================================================================================================
void
dnssd_xpc_result_set_record_data(xpc_object_t result, const void * const data_ptr, const size_t data_len)
{
if (data_ptr || (data_len == 0)) {
const void * const safe_data_ptr = data_ptr ? data_ptr : "";
xpc_dictionary_set_data(result, DNSSD_XPC_RESULT_KEY_RECORD_DATA, safe_data_ptr, data_len);
}
}
//======================================================================================================================
xpc_object_t
dnssd_xpc_result_get_record_name_object(xpc_object_t result)
{
return _dnssd_xpc_dictionary_get_value(result, DNSSD_XPC_RESULT_KEY_RECORD_NAME, XPC_TYPE_STRING);
}
//======================================================================================================================
void
dnssd_xpc_result_set_record_name(xpc_object_t result, const char *name)
{
xpc_dictionary_set_string(result, DNSSD_XPC_RESULT_KEY_RECORD_NAME, name);
}
//======================================================================================================================
uint16_t
dnssd_xpc_result_get_record_type(xpc_object_t result, bool *out_valid)
{
return _dnssd_xpc_dictionary_get_uint16(result, DNSSD_XPC_RESULT_KEY_RECORD_TYPE, out_valid);
}
//======================================================================================================================
void
dnssd_xpc_result_set_record_type(xpc_object_t result, uint16_t type)
{
xpc_dictionary_set_uint64(result, DNSSD_XPC_RESULT_KEY_RECORD_TYPE, type);
}
//======================================================================================================================
uint16_t
dnssd_xpc_result_get_record_protocol(xpc_object_t result, bool * out_valid)
{
return _dnssd_xpc_dictionary_get_uint16(result, DNSSD_XPC_RESULT_KEY_RECORD_PROTOCOL, out_valid);
}
//======================================================================================================================
void
dnssd_xpc_result_set_record_protocol(xpc_object_t result, uint16_t protocol)
{
xpc_dictionary_set_uint64(result, DNSSD_XPC_RESULT_KEY_RECORD_PROTOCOL, protocol);
}
//======================================================================================================================
xpc_object_t
dnssd_xpc_result_get_provider_name_object(xpc_object_t result)
{
return _dnssd_xpc_dictionary_get_value(result, DNSSD_XPC_RESULT_KEY_PROVIDER_NAME, XPC_TYPE_STRING);
}
//======================================================================================================================
void
dnssd_xpc_result_set_provider_name(const xpc_object_t result, const mdns_xpc_string_t name)
{
xpc_dictionary_set_value(result, DNSSD_XPC_RESULT_KEY_PROVIDER_NAME, mdns_xpc_string_to_xpc_object(name));
}
//======================================================================================================================
xpc_object_t
dnssd_xpc_result_get_cname_update(xpc_object_t result)
{
return xpc_dictionary_get_array(result, DNSSD_XPC_RESULT_KEY_CNAME_UPDATE);
}
//======================================================================================================================
void
dnssd_xpc_result_set_cname_update(xpc_object_t result, xpc_object_t cname_update)
{
xpc_dictionary_set_value(result, DNSSD_XPC_RESULT_KEY_CNAME_UPDATE, cname_update);
}
//======================================================================================================================
mdns_xpc_string_t
dnssd_xpc_result_get_tracker_hostname(const xpc_object_t result)
{
return mdns_xpc_dictionary_get_string(result, DNSSD_XPC_RESULT_KEY_TRACKER_HOSTNAME);
}
//======================================================================================================================
void
dnssd_xpc_result_set_tracker_hostname(const xpc_object_t result, const mdns_xpc_string_t hostname)
{
xpc_dictionary_set_value(result, DNSSD_XPC_RESULT_KEY_TRACKER_HOSTNAME, mdns_xpc_string_to_xpc_object(hostname));
}
//======================================================================================================================
mdns_xpc_string_t
dnssd_xpc_result_get_tracker_owner(const xpc_object_t result)
{
return mdns_xpc_dictionary_get_string(result, DNSSD_XPC_RESULT_KEY_TRACKER_OWNER);
}
//======================================================================================================================
void
dnssd_xpc_result_set_tracker_owner(const xpc_object_t result, const mdns_xpc_string_t owner)
{
xpc_dictionary_set_value(result, DNSSD_XPC_RESULT_KEY_TRACKER_OWNER, mdns_xpc_string_to_xpc_object(owner));
}
//======================================================================================================================
bool
dnssd_xpc_result_get_tracker_is_approved(const xpc_object_t result)
{
return xpc_dictionary_get_bool(result, DNSSD_XPC_RESULT_KEY_TRACKER_APPROVED);
}
//======================================================================================================================
void
dnssd_xpc_result_set_tracker_is_approved(const xpc_object_t result, const bool approved)
{
xpc_dictionary_set_bool(result, DNSSD_XPC_RESULT_KEY_TRACKER_APPROVED, approved);
}
//======================================================================================================================
dnssd_negative_reason_t
dnssd_xpc_result_get_negative_reason(const xpc_object_t result)
{
bool valid;
// Make sure that dnssd_negative_reason_t is indeed a 32-bit signed integer.
check_compile_time_code(sizeof(dnssd_negative_reason_t) == sizeof(int32_t));
check_compile_time_code(((dnssd_negative_reason_t)-1) < 0);
const dnssd_negative_reason_t reason = _dnssd_xpc_dictionary_get_int32(result,
DNSSD_XPC_RESULT_KEY_NEGATIVE_REASON, &valid);
if (valid) {
// A default case isn't used to allow the compiler to catch missing dnssd_negative_reason_t enum values.
switch (reason) {
case dnssd_negative_reason_none:
case dnssd_negative_reason_no_data:
case dnssd_negative_reason_nxdomain:
case dnssd_negative_reason_query_suppressed:
case dnssd_negative_reason_no_dns_service:
case dnssd_negative_reason_server_error:
return reason;
}
}
return dnssd_negative_reason_none;
}
//======================================================================================================================
void
dnssd_xpc_result_set_negative_reason(const xpc_object_t result, const dnssd_negative_reason_t reason)
{
xpc_dictionary_set_int64(result, DNSSD_XPC_RESULT_KEY_NEGATIVE_REASON, reason);
}
//======================================================================================================================
xpc_object_t
dnssd_xpc_result_get_validation_data_object(const xpc_object_t result)
{
return _dnssd_xpc_dictionary_get_value(result, DNSSD_XPC_RESULT_KEY_VALIDATION_DATA, XPC_TYPE_DATA);
}
//======================================================================================================================
void
dnssd_xpc_result_set_validation_data(const xpc_object_t result, const uint8_t * const data_ptr,
const size_t data_len)
{
xpc_dictionary_set_data(result, DNSSD_XPC_RESULT_KEY_VALIDATION_DATA, data_ptr, data_len);
}
//======================================================================================================================
// MARK: - XPC Dictionary Helpers
static int32_t
_dnssd_xpc_dictionary_get_int32(xpc_object_t dict, const char *key, bool *out_valid)
{
return (int32_t)_dnssd_xpc_dictionary_get_int64_limited(dict, key, INT32_MIN, INT32_MAX, out_valid);
}
//======================================================================================================================
static int64_t
_dnssd_xpc_dictionary_get_int64(xpc_object_t dict, const char *key, bool *out_valid)
{
return _dnssd_xpc_dictionary_get_int64_limited(dict, key, INT64_MIN, INT64_MAX, out_valid);
}
//======================================================================================================================
static int64_t
_dnssd_xpc_dictionary_get_int64_limited(xpc_object_t dict, const char *key, int64_t min, int64_t max, bool *out_valid)
{
int64_t i64;
bool valid;
xpc_object_t const value = _dnssd_xpc_dictionary_get_value(dict, key, XPC_TYPE_INT64);
if (value) {
i64 = xpc_int64_get_value(value);
if ((i64 >= min) && (i64 <= max)) {
valid = true;
} else {
i64 = 0;
valid = false;
}
} else {
i64 = 0;
valid = false;
}
if (out_valid) {
*out_valid = valid;
}
return i64;
}
//======================================================================================================================
static uint16_t
_dnssd_xpc_dictionary_get_uint16(xpc_object_t dict, const char *key, bool *out_valid)
{
return (uint16_t)_dnssd_xpc_dictionary_get_uint64_limited(dict, key, 0, UINT16_MAX, out_valid);
}
//======================================================================================================================
static uint32_t
_dnssd_xpc_dictionary_get_uint32(xpc_object_t dict, const char *key, bool *out_valid)
{
return (uint32_t)_dnssd_xpc_dictionary_get_uint64_limited(dict, key, 0, UINT32_MAX, out_valid);
}
//======================================================================================================================
static uint64_t
_dnssd_xpc_dictionary_get_uint64(xpc_object_t dict, const char *key, bool *out_valid)
{
return _dnssd_xpc_dictionary_get_uint64_limited(dict, key, 0, UINT64_MAX, out_valid);
}
//======================================================================================================================
static uint64_t
_dnssd_xpc_dictionary_get_uint64_limited(xpc_object_t dict, const char *key, uint64_t min, uint64_t max,
bool *out_valid)
{
uint64_t u64;
bool valid;
xpc_object_t const value = _dnssd_xpc_dictionary_get_value(dict, key, XPC_TYPE_UINT64);
if (value) {
u64 = xpc_uint64_get_value(value);
if ((u64 >= min) && (u64 <= max)) {
valid = true;
} else {
u64 = 0;
valid = false;
}
} else {
u64 = 0;
valid = false;
}
if (out_valid) {
*out_valid = valid;
}
return u64;
}
//======================================================================================================================
static xpc_object_t
_dnssd_xpc_dictionary_get_value(xpc_object_t dict, const char *key, xpc_type_t type)
{
xpc_object_t value = xpc_dictionary_get_value(dict, key);
return (value && (xpc_get_type(value) == type)) ? value : NULL;
}