Home | History | Annotate | Line # | Download | only in base
      1 /*
      2  * Copyright (c) 2022-2023 Apple Inc. All rights reserved.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     https://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef DNS_OBJECT_H
     18 #define DNS_OBJECT_H
     19 
     20 //======================================================================================================================
     21 // MARK: - Headers
     22 
     23 #include "ref_count.h"
     24 
     25 #include "nullability.h"
     26 
     27 //======================================================================================================================
     28 // MARK: - DNS Object Kind and Subkind Helper Macros
     29 
     30 // Define a base DNS object.
     31 #define DNS_OBJECT_DEFINE_FULL(NAME)							REF_COUNT_OBJECT_DEFINE_FULL(dns_obj, NAME)
     32 // Define a kind type for a DNS object that has a subkind.
     33 #define DNS_OBJECT_DEFINE_KIND_TYPE_FOR_SUBKIND(NAME, ...)		REF_COUNT_OBJECT_DEFINE_KIND_TYPE_FOR_SUBKIND(dns_obj, NAME, __VA_ARGS__)
     34 
     35 // Define a subkind of a DNS object.
     36 // Subkind with no comparator nor finalizer.
     37 #define DNS_OBJECT_SUBKIND_DEFINE_ABSTRUCT(SUPER, NAME, ...)			REF_COUNT_OBJECT_SUBKIND_DEFINE_ABSTRUCT(dns_obj, SUPER, NAME, __VA_ARGS__)
     38 // Subkind with no finalizer, but with comparator.
     39 #define DNS_OBJECT_SUBKIND_DEFINE_WITHOUT_FINALIZER(SUPER, NAME, ...)	REF_COUNT_OBJECT_SUBKIND_DEFINE_WITHOUT_FINALIZER(dns_obj, SUPER, NAME, __VA_ARGS__)
     40 // Subkind with finalizer, but with no comparator.
     41 #define DNS_OBJECT_SUBKIND_DEFINE_WITHOUT_COMPARATOR(SUPER, NAME, ...)	REF_COUNT_OBJECT_SUBKIND_DEFINE_WITHOUT_COMPARATOR(dns_obj, SUPER, NAME, __VA_ARGS__)
     42 // Subkind with both finalizer and comparator.
     43 #define DNS_OBJECT_SUBKIND_DEFINE_FULL(SUPER, NAME, ...)				REF_COUNT_OBJECT_SUBKIND_DEFINE_FULL(dns_obj, SUPER, NAME, __VA_ARGS__)
     44 
     45 // Declare all kinds and subkinds as the DNS objects.
     46 // Declare an object as a DNS object.
     47 #define DNS_OBJECT_DECLARE_SUPPORTED_OBJECT(NAME)						REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(dns_obj, NAME)
     48 // Declare a subkind of object as a DNS object.
     49 #define DNS_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(SUPER, NAME)		REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(dns_obj, SUPER, NAME)
     50 
     51 // Declare an object array as a DNS object array.
     52 #define DNS_OBJECT_ARRAY_DECLARE_SUPPORTED_OBJECT(NAME)					REF_COUNT_OBJECT_ARRAY_DECLARE_SUPPORTED_OBJECT(dns_obj, NAME)
     53 // Declare a subkind of object array as a DNS object array.
     54 #define DNS_OBJECT_ARRAY_DECLARE_SUPPORTED_OBJECT_SUBKIND(SUPER, NAME)	REF_COUNT_OBJECT_ARRAY_DECLARE_SUPPORTED_OBJECT_SUBKIND(dns_obj, SUPER, NAME)
     55 
     56 #define DNS_OBJECT_TYPEDEF_OPAQUE_POINTER(NAME)					OBJECT_TYPEDEF_OPAQUE_POINTER(dns_obj_ ## NAME)
     57 #define DNS_OBJECT_SUBKIND_TYPEDEF_OPAQUE_POINTER(SUPER, NAME)	OBJECT_TYPEDEF_OPAQUE_POINTER(dns_obj_ ## SUPER ## _ ## NAME)
     58 
     59 //======================================================================================================================
     60 // MARK: - DNS Object Families
     61 
     62 OBJECT_TYPEDEF_OPAQUE_POINTER(dns_obj);
     63 
     64 typedef union {
     65 	STRUCT_PTR_DECLARE(dns_obj);								// Declare dns_obj_t object family.
     66 
     67 	DNS_OBJECT_DECLARE_SUPPORTED_OBJECT(domain_name);			// Declare dns_obj_domain_name_t as a dns_obj_t object.
     68 
     69 	DNS_OBJECT_DECLARE_SUPPORTED_OBJECT(rr);					// Declare dns_obj_rr_t as a dns_obj_t object.
     70 	DNS_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(rr, cname);		// Declare dns_obj_rr_cname_t as a subkind of dns_obj_rr_t.
     71 	DNS_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(rr, soa);		// Declare dns_obj_rr_soa_t as a subkind of dns_obj_rr_t.
     72 	DNS_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(rr, srv);		// Declare dns_obj_rr_srv_t as a subkind of dns_obj_rr_t.
     73 	DNS_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(rr, nsec);		// Declare dns_obj_rr_nsec_t as a subkind of dns_obj_rr_t.
     74 	DNS_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(rr, ds);		// Declare dns_obj_rr_ds_t as a subkind of dns_obj_rr_t.
     75 	DNS_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(rr, rrsig);		// Declare dns_obj_rr_rrsig_t as a subkind of dns_obj_rr_t.
     76 	DNS_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(rr, dnskey);	// Declare dns_obj_rr_dnskey_t as a subkind of dns_obj_rr_t.
     77 	DNS_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(rr, nsec3);		// Declare dns_obj_rr_nsec3_t as a subkind of dns_obj_rr_t.
     78 
     79 } dns_obj_any_t __attribute__((__transparent_union__)); // __transparent_union__ makes all object above as valid DNS objects.
     80 
     81 typedef union {
     82 	STRUCT_ARRAY_PTR_DECLARE(dns_obj);								// Declare dns_obj_t objects to be sortable.
     83 	DNS_OBJECT_ARRAY_DECLARE_SUPPORTED_OBJECT(domain_name);				// Declare dns_obj_domain_name_t objects to be sortable.
     84 	DNS_OBJECT_ARRAY_DECLARE_SUPPORTED_OBJECT(rr);						// Declare dns_obj_rr_t objects to be sortable.
     85 	DNS_OBJECT_ARRAY_DECLARE_SUPPORTED_OBJECT_SUBKIND(rr, nsec);		// Declare dns_obj_rr_nsec_t objects to be sortable.
     86 	DNS_OBJECT_ARRAY_DECLARE_SUPPORTED_OBJECT_SUBKIND(rr, dnskey);		// Declare dns_obj_rr_dnskey_t objects to be sortable.
     87 	DNS_OBJECT_ARRAY_DECLARE_SUPPORTED_OBJECT_SUBKIND(rr, nsec3);		// Declare dns_obj_rr_nsec3_t objects to be sortable.
     88 } dns_objs_any_t __attribute__((__transparent_union__));				// __transparent_union__ makes all arrays above as valid DNS object arrays.
     89 
     90 //======================================================================================================================
     91 // MARK: - Object Methods
     92 
     93 /*!
     94  *	@brief
     95  *		Retain a supported DNS object by increasing the reference count by one.
     96  *
     97  *	@param dns_object
     98  *		The supported DNS object contained in dns_obj_any_t union.
     99  *
    100  *	@result
    101  *		The retained DNS object.
    102  */
    103 dns_obj_t NONNULL
    104 dns_obj_retain(dns_obj_any_t dns_object);
    105 
    106 /*!
    107  *	@brief
    108  *		Release a supported DNS object by decreasing the reference count by one. If the reference count becomes zero after releasing, the object will be
    109  *		finalized.
    110  *
    111  *	@param dns_object
    112  *		The supported DNS object contained in dns_obj_any_t union.
    113  *
    114  *	@discussion
    115  *		Use <code>MDNS_DISPOSE_DNS_OBJ()</code> provided by <code>mdns_strict.h</code> rather than the <code>dns_obj_release()</code>,
    116  *		because the macro checks the nullability of the pointer and always set the pointer to NULL after releasing.
    117  */
    118 void
    119 dns_obj_release(dns_obj_any_t dns_object);
    120 
    121 /*!
    122  *	@brief
    123  *		Check if two supported DNS objects are equal or not, based on the definition of the comparator of the object.
    124  *
    125  *	@param dns_object1
    126  *		The supported DNS object to check the equality.
    127  *
    128  *	@param dns_object2
    129  *		The supported DNS object to check the equality.
    130  *
    131  *	@result
    132  *		True if two objects have the same kind and the defined comparator indicates that they are equal, or the two objects are pointing to the same object
    133  *		instance. Otherwise, false.
    134  *
    135  *	@discussion
    136  *		If the kind of the two objects has no comparator defined, the comparator of the super kind will be used to determine their equality. Such process will
    137  *		continue until one available comparator is found or the root kind (NULL) is reached. If no comparator is available for the current kind, the result will be
    138  *		false.
    139  */
    140 bool
    141 dns_obj_equal(dns_obj_any_t dns_object1, dns_obj_any_t dns_object2);
    142 
    143 /*!
    144  *	@brief
    145  *		Compare two supported DNS objects, based on the definition of the comparator of the object.
    146  *
    147  *	@param dns_object1
    148  *		The supported DNS object to compare.
    149  *
    150  *	@param dns_object2
    151  *		The supported DNS object to compare.
    152  *
    153  *	@result
    154  *		<code>compare_result_less</code> if <code>dns_object1</code> is less than <code>dns_object2</code>.
    155  *		<code>compare_result_equal</code> if <code>dns_object1</code> is equal to <code>dns_object2</code>.
    156  *		<code>compare_result_greater</code> if <code>dns_object1</code> is greater than <code>dns_object2</code>.
    157  *		<code>compare_result_notequal</code> if two objects can be compared and they are not equal, but the specific order of the two objects cannot be determined.
    158  *		<code>compare_result_unknown</code> if two objects have different kind or no any comparator available to determine the comparison result, or any
    159  *			unexpected cases defined by the comparator.
    160  *
    161  *	@discussion
    162  *		If the kind of the two objects has no comparator defined, the comparator of the super kind will be used to determine their equality. Such process will
    163  *		continue until one available comparator is found or the root kind (NULL) is reached. If no comparator is available for the current kind, the result will be
    164  *		<code>compare_result_unknown</code>.
    165  *
    166  *		When the caller only wants know the equality of the two objects, use <code>dns_obj_equal()</code> instead of <code>dns_obj_compare()</code>
    167  *		because the former is faster than the latter.
    168  */
    169 compare_result_t
    170 dns_obj_compare(dns_obj_any_t dns_object1, dns_obj_any_t dns_object2);
    171 
    172 /*!
    173  *	@brief
    174  *		Sort the DNS objects array by the ascending or descending order.
    175  *
    176  *	@param dns_objects
    177  *		The DNS object array to be sorted.
    178  *
    179  *	@param count
    180  *		The number of objects in the array.
    181  *
    182  *	@param order
    183  *		The order of the sorted array, it can be
    184  *		<code>sort_order_ascending</code> for the ascending order.
    185  *		<code>sort_order_descending</code> for the descending order.
    186  *
    187  *	@discussion
    188  *		The object has to have a comparator that can determine the specific order of the two objects that have the same kind, in order to be sortable. If no
    189  *		comparator is available or the comparator can only determine the equality of the objects, the array will be returned untouched.
    190  */
    191 void
    192 dns_objs_sort(dns_objs_any_t dns_objects, size_t count, sort_order_t order);
    193 
    194 #define MDNS_DISPOSE_DNS_OBJ(obj) _MDNS_STRICT_DISPOSE_TEMPLATE(obj, dns_obj_release)
    195 
    196 #define dns_obj_replace(PTR, OBJ)			\
    197 	do {									\
    198 		if ((OBJ) != NULL) {				\
    199 			dns_obj_retain(OBJ);			\
    200 		}									\
    201 		if (*(PTR)) {						\
    202 			MDNS_DISPOSE_DNS_OBJ(*(PTR));	\
    203 		}									\
    204 		*(PTR) = (OBJ);						\
    205 	} while(0)
    206 
    207 #define dns_obj_forget(PTR)					\
    208 	do {									\
    209 		if (*(PTR)) {						\
    210 			dns_obj_release(*(PTR));		\
    211 			*(PTR) = NULL;					\
    212 		}									\
    213 	} while(0)
    214 
    215 #endif // DNS_OBJECT_H
    216