this repo has no description
1/*
2 * Copyright (c) 2019 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * serviceID_number.c
26 * - assigns numbers to serviceID strings
27 */
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <unistd.h>
32
33#include "serviceIDNumber.h"
34#include <CoreFoundation/CFDictionary.h>
35
36#if TEST_SERVICEID_NUMBER
37#include <SystemConfiguration/SCPrivate.h>
38#endif /* TEST_SERVICEID_NUMBER */
39
40
41/* dictionary to hold serviceIDNumber: key is the serviceID */
42static CFMutableDictionaryRef S_serviceID_to_number_dict;
43
44/* dictionary to hold serviceID: key is the serviceIDNumber */
45static CFMutableDictionaryRef S_number_to_serviceID_dict;
46
47static Boolean
48serviceIDNumberEqual(const void * ptr1, const void * ptr2)
49{
50 return (((serviceIDNumber)ptr1) == ((serviceIDNumber)ptr2));
51}
52
53static CFStringRef
54serviceIDNumberCopyDescription(const void * ptr)
55{
56 return CFStringCreateWithFormat(NULL, NULL, CFSTR("%ld"),
57 (serviceIDNumber)ptr);
58}
59
60static CFHashCode
61serviceIDNumberHash(const void * ptr) {
62 return (CFHashCode)((serviceIDNumber)ptr);
63}
64
65static const CFDictionaryValueCallBacks kserviceIDNumberValueCallBacks = {
66 0, NULL, NULL, serviceIDNumberCopyDescription, serviceIDNumberEqual
67};
68
69static const CFDictionaryKeyCallBacks kserviceIDNumberKeyCallBacks = {
70 0, NULL, NULL, serviceIDNumberCopyDescription, serviceIDNumberEqual,
71 serviceIDNumberHash
72};
73
74/**
75 ** S_serviceID_numbers
76 **/
77
78__private_extern__ Boolean
79serviceIDNumberGetIfPresent(CFStringRef serviceID, serviceIDNumber *sidn)
80{
81 Boolean has_number;
82 const void * val;
83
84 has_number = CFDictionaryGetValueIfPresent(S_serviceID_to_number_dict,
85 serviceID, &val);
86 if (has_number) {
87 *sidn = (serviceIDNumber)val;
88 }
89 return (has_number);
90}
91
92/*
93 * Function: serviceIDNumberGet
94 * Purpose:
95 * Return the currently assigned serviceIDNumber for the given serviceID.
96 * If one is already assigned, return that. If one isn't assigned, check
97 * the next integer value after 'current_sidn', but skip zero.
98 * If that number is assigned, pick the next one.
99 */
100static serviceIDNumber S_current_sidn;
101
102__private_extern__ serviceIDNumber
103serviceIDNumberGet(CFStringRef serviceID)
104{
105 serviceIDNumber sidn;
106
107 if (serviceIDNumberGetIfPresent(serviceID, &sidn)) {
108 return (sidn);
109 }
110 while (1) {
111 /* assign a number to the serviceID */
112 S_current_sidn++;
113 if (S_current_sidn == kserviceIDNumberZero) {
114 /* skip zero */
115 S_current_sidn++;
116 }
117 /* if it's in use, skip to the next value */
118 if (CFDictionaryContainsKey(S_number_to_serviceID_dict,
119 (const void *)S_current_sidn)) {
120 continue;
121 }
122 /* it's not in use, use it */
123 sidn = S_current_sidn;
124 CFDictionarySetValue(S_serviceID_to_number_dict,
125 serviceID, (const void *)sidn);
126 CFDictionarySetValue(S_number_to_serviceID_dict,
127 (const void *)sidn, serviceID);
128 break;
129 }
130 return (sidn);
131}
132
133
134__private_extern__ void
135serviceIDNumberRemove(CFStringRef serviceID)
136{
137 const void * val;
138
139 if (CFDictionaryGetValueIfPresent(S_serviceID_to_number_dict, serviceID,
140 &val)) {
141#if TEST_SERVICEID_NUMBER
142 SCPrint(TRUE, stdout, CFSTR("Removing %@ %ld\n"),
143 serviceID, (serviceIDNumber)val);
144#endif
145 CFDictionaryRemoveValue(S_serviceID_to_number_dict, serviceID);
146 CFDictionaryRemoveValue(S_number_to_serviceID_dict, val);
147 }
148}
149
150__private_extern__ void
151serviceIDNumberInit(void)
152{
153 S_serviceID_to_number_dict
154 = CFDictionaryCreateMutable(NULL, 0,
155 &kCFTypeDictionaryKeyCallBacks,
156 &kserviceIDNumberValueCallBacks);
157 S_number_to_serviceID_dict
158 = CFDictionaryCreateMutable(NULL, 0,
159 &kserviceIDNumberKeyCallBacks,
160 &kCFTypeDictionaryValueCallBacks);
161}
162
163#if TEST_SERVICEID_NUMBER
164
165static CFStringRef
166my_CFUUIDStringCreate(CFAllocatorRef alloc)
167{
168 CFUUIDRef uuid;
169 CFStringRef uuid_str;
170
171 uuid = CFUUIDCreate(alloc);
172 uuid_str = CFUUIDCreateString(alloc, uuid);
173 CFRelease(uuid);
174 return (uuid_str);
175}
176
177int
178main()
179{
180#define N_LIST 10
181 CFStringRef serviceID_list[N_LIST];
182
183 serviceIDNumberInit();
184 for (int i = 0; i < N_LIST; i++) {
185 CFStringRef serviceID = my_CFUUIDStringCreate(NULL);
186 serviceIDNumber sidn;
187
188 /* force a collision */
189 S_current_sidn = -1;
190
191 sidn = serviceIDNumberGet(serviceID);
192 SCPrint(TRUE, stdout, CFSTR("%d: %@ %ld\n"),
193 i, serviceID, sidn);
194 serviceID_list[i] = serviceID;
195
196 }
197 for (int i = 0; i < N_LIST; i++) {
198 CFStringRef serviceID = serviceID_list[i];
199 serviceIDNumber sidn;
200
201 if (!serviceIDNumberGetIfPresent(serviceID, &sidn)) {
202 SCPrint(TRUE, stderr, CFSTR("Failed to find %@\n"),
203 serviceID);
204 exit(1);
205 }
206 SCPrint(TRUE, stdout, CFSTR("%@ => %ld\n"), serviceID, sidn);
207 }
208 {
209 serviceIDNumber sidn;
210
211 if (serviceIDNumberGetIfPresent(CFSTR("blah"), &sidn)) {
212 fprintf(stderr,
213 "Shouldn't have been able to look that up\n");
214 exit(1);
215 }
216 }
217
218 for (int i = 0; i < N_LIST / 2; i++) {
219 CFStringRef serviceID = serviceID_list[i];
220 serviceIDNumber sidn;
221
222 serviceIDNumberRemove(serviceID);
223 if (serviceIDNumberGetIfPresent(serviceID, &sidn)) {
224 SCPrint(TRUE, stderr,
225 CFSTR("Found %@, but shouldn't have\n"),
226 serviceID);
227 exit(1);
228 }
229 }
230
231 for (int i = 0; i < N_LIST; i++) {
232 CFStringRef serviceID = serviceID_list[i];
233 serviceIDNumber sidn;
234
235 sidn = serviceIDNumberGet(serviceID);
236 SCPrint(TRUE, stdout, CFSTR("%d: %@ %ld\n"),
237 i, serviceID, sidn);
238 }
239 exit(0);
240}
241#endif /* TEST_SERVICEID_NUMBER */