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