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
mdns_set_create(void)72 mdns_set_create(void)
73 {
74 	return _mdns_set_alloc();
75 }
76 
77 //======================================================================================================================
78 
79 OSStatus
mdns_set_add(const mdns_set_t me,const uintptr_t subset_id,const mdns_object_t object)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
mdns_set_remove(const mdns_set_t me,const uintptr_t subset_id,const mdns_object_t object)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
mdns_set_get_count(const mdns_set_t me,const uintptr_t subset_id)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
mdns_set_iterate(const mdns_set_t me,const uintptr_t subset_id,mdns_set_applier_t applier)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 *
_mdns_set_copy_description(const mdns_set_t me,__unused const bool debug,__unused const bool privacy)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
_mdns_set_finalize(const mdns_set_t me)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
_subset_create(const uintptr_t subset_id)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
_subset_free(const _subset_t me)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
_item_create(mdns_object_t object)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
_item_free(const _item_t me)275 _item_free(const _item_t me)
276 {
277 	me->next = NULL;
278 	mdns_forget(&me->object);
279 	free(me);
280 }
281