]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/mdns_objects/mdns_set.c
mDNSResponder-1310.40.42.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / mdns_objects / mdns_set.c
1 /*
2 * Copyright (c) 2020 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 #include "mdns_set.h"
18 #include "mdns_helpers.h"
19 #include "mdns_objects.h"
20
21 #include <CoreUtils/CoreUtils.h>
22
23 //======================================================================================================================
24 // MARK: - Set Kind Definition
25
26 typedef struct _subset_s * _subset_t;
27
28 struct mdns_set_s {
29 struct mdns_object_s base; // Object base.
30 _subset_t list; // Subset list.
31 };
32
33 MDNS_OBJECT_SUBKIND_DEFINE(set);
34
35 //======================================================================================================================
36 // MARK: - Internal Data Structures
37
38 typedef struct _item_s * _item_t;
39 struct _item_s {
40 _item_t next; // Next item in list.
41 mdns_object_t object; // Object.
42 };
43
44 struct _subset_s {
45 _subset_t next; // Next subset in list.
46 uintptr_t ident; // Subset ID.
47 _item_t list; // Querier list.
48 size_t count; // Item count.
49 };
50
51 //======================================================================================================================
52 // MARK: - Internal Helper Function Prototypes
53
54 static _subset_t
55 _subset_create(uintptr_t subset_id);
56
57 static void
58 _subset_free(_subset_t subset);
59 #define _subset_forget(X) ForgetCustom(X, _subset_free)
60
61 static _item_t
62 _item_create(mdns_object_t object);
63
64 static void
65 _item_free(_item_t item);
66 #define _item_forget(X) ForgetCustom(X, _item_free)
67
68 //======================================================================================================================
69 // MARK: - Set Public Methods
70
71 mdns_set_t
72 mdns_set_create(void)
73 {
74 return _mdns_set_alloc();
75 }
76
77 //======================================================================================================================
78
79 OSStatus
80 mdns_set_add(const mdns_set_t me, const uintptr_t subset_id, const mdns_object_t object)
81 {
82 _subset_t *subset_ptr;
83 _subset_t subset;
84 for (subset_ptr = &me->list; (subset = *subset_ptr) != NULL; subset_ptr = &subset->next) {
85 if (subset->ident == subset_id) {
86 break;
87 }
88 }
89 OSStatus err;
90 _subset_t new_subset = NULL;
91 if (!subset) {
92 new_subset = _subset_create(subset_id);
93 require_action_quiet(new_subset, exit, err = kNoMemoryErr);
94 subset = new_subset;
95 }
96 _item_t *item_ptr;
97 _item_t item;
98 for (item_ptr = &subset->list; (item = *item_ptr) != NULL; item_ptr = &item->next) {
99 if (item->object == object) {
100 break;
101 }
102 }
103 require_action_quiet(!item, exit, err = kNoErr);
104
105 item = _item_create(object);
106 require_action_quiet(item, exit, err = kNoMemoryErr);
107
108 *item_ptr = item;
109 item = NULL;
110 ++subset->count;
111 if (new_subset) {
112 *subset_ptr = new_subset;
113 new_subset = NULL;
114 }
115 err = kNoErr;
116
117 exit:
118 _subset_forget(&new_subset);
119 return err;
120 }
121
122 //======================================================================================================================
123
124 OSStatus
125 mdns_set_remove(const mdns_set_t me, const uintptr_t subset_id, const mdns_object_t object)
126 {
127 _subset_t *subset_ptr;
128 _subset_t subset;
129 for (subset_ptr = &me->list; (subset = *subset_ptr) != NULL; subset_ptr = &subset->next) {
130 if (subset->ident == subset_id) {
131 break;
132 }
133 }
134 OSStatus err;
135 require_action_quiet(subset, exit, err = kNotFoundErr);
136
137 _item_t *item_ptr;
138 _item_t item;
139 for (item_ptr = &subset->list; (item = *item_ptr) != NULL; item_ptr = &item->next) {
140 if (item->object == object) {
141 break;
142 }
143 }
144 require_action_quiet(item, exit, err = kNotFoundErr);
145
146 *item_ptr = item->next;
147 --subset->count;
148 _item_forget(&item);
149 if (!subset->list) {
150 *subset_ptr = subset->next;
151 _subset_forget(&subset);
152 }
153 err = kNoErr;
154
155 exit:
156 return err;
157 }
158
159 //======================================================================================================================
160
161 size_t
162 mdns_set_get_count(const mdns_set_t me, const uintptr_t subset_id)
163 {
164 _subset_t subset;
165 for (subset = me->list; subset; subset = subset->next) {
166 if (subset->ident == subset_id) {
167 return subset->count;
168 }
169 }
170 return 0;
171 }
172
173 //======================================================================================================================
174
175 void
176 mdns_set_iterate(const mdns_set_t me, const uintptr_t subset_id, mdns_set_applier_t applier)
177 {
178 _subset_t subset = me->list;
179 while (subset && (subset->ident != subset_id)) {
180 subset = subset->next;
181 }
182 require_quiet(subset, exit);
183
184 for (_item_t item = subset->list; item; item = item->next) {
185 const bool stop = applier(item->object);
186 if (stop) {
187 break;
188 }
189 }
190
191 exit:
192 return;
193 }
194
195 //======================================================================================================================
196 // MARK: - Set Private Methods
197
198 static char *
199 _mdns_set_copy_description(const mdns_set_t me, __unused const bool debug, __unused const bool privacy)
200 {
201 char * description = NULL;
202 char buffer[128];
203 char * dst = buffer;
204 const char * const lim = &buffer[countof(buffer)];
205 int n;
206
207 *dst = '\0';
208 n = mdns_snprintf_add(&dst, lim, "<%s: %p>: ", me->base.kind->name, me);
209 require_quiet(n >= 0, exit);
210
211 description = strdup(buffer);
212
213 exit:
214 return description;
215 }
216 //======================================================================================================================
217
218 static void
219 _mdns_set_finalize(const mdns_set_t me)
220 {
221 _subset_t subset;
222 while ((subset = me->list) != NULL) {
223 me->list = subset->next;
224 _subset_free(subset);
225 }
226 }
227
228 //======================================================================================================================
229 // MARK: - Internal Helper Functions
230
231 static _subset_t
232 _subset_create(const uintptr_t subset_id)
233 {
234 const _subset_t obj = (_subset_t)calloc(1, sizeof(*obj));
235 require_quiet(obj, exit);
236
237 obj->ident = subset_id;
238
239 exit:
240 return obj;
241 }
242
243 //======================================================================================================================
244
245 static void
246 _subset_free(const _subset_t me)
247 {
248 me->next = NULL;
249 _item_t item;
250 while ((item = me->list) != NULL) {
251 me->list = item->next;
252 _item_free(item);
253 }
254 free(me);
255 }
256
257 //======================================================================================================================
258
259 static _item_t
260 _item_create(mdns_object_t object)
261 {
262 const _item_t obj = (_item_t)calloc(1, sizeof(*obj));
263 require_quiet(obj, exit);
264
265 obj->object = object;
266 mdns_retain(obj->object);
267
268 exit:
269 return obj;
270 }
271
272 //======================================================================================================================
273
274 static void
275 _item_free(const _item_t me)
276 {
277 me->next = NULL;
278 mdns_forget(&me->object);
279 free(me);
280 }