Libinfo-517.200.9.tar.gz
[apple/libinfo.git] / lookup.subproj / cache_module.c
1 /*
2 * Copyright (c) 2008-2018 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 #include "libinfo_common.h"
25
26 #include <si_module.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <time.h>
31 #include <errno.h>
32 #include <arpa/inet.h>
33 #include <sys/stat.h>
34 #include <ils.h>
35 #include <pthread.h>
36 #include <libkern/OSAtomic.h>
37 #include <dispatch/dispatch.h>
38
39 /* GLOBAL */
40 LIBINFO_EXPORT
41 uint32_t gL1CacheEnabled = 1;
42
43 #define CACHE_COUNT CATEGORY_COUNT
44 #define CACHE_MAX 20
45
46 typedef struct
47 {
48 pthread_mutex_t mutex;
49 int head;
50 si_item_t *item[CACHE_MAX];
51 si_list_t *list;
52 } cache_store_t;
53
54 typedef struct
55 {
56 cache_store_t cache_store[CACHE_COUNT];
57 } cache_si_private_t;
58
59 static void *
60 cache_validate_item(cache_si_private_t *pp, int cat, int where)
61 {
62 si_item_t *item;
63
64 item = pp->cache_store[cat].item[where];
65 if (item == NULL) return NULL;
66
67 if (si_item_is_valid(item)) return si_item_retain(item);
68
69 si_item_release(item);
70 pp->cache_store[cat].item[where] = NULL;
71
72 return NULL;
73 }
74
75 static void *
76 cache_validate_list(cache_si_private_t *pp, int cat)
77 {
78 uint32_t i, valid;
79 si_item_t *item, *last;
80 si_list_t *list;
81
82 list = pp->cache_store[cat].list;
83
84 if (list == NULL) return NULL;
85 if (list->count == 0) return NULL;
86
87 last = list->entry[0];
88 valid = si_item_is_valid(last);
89
90 for (i = 1; (i < list->count) && (valid == 1); i++)
91 {
92 item = list->entry[i];
93 if ((item->src == last->src) && (item->type == last->type) && (item->validation_a == last->validation_a) && (item->validation_b == last->validation_b)) continue;
94
95 last = item;
96 valid = si_item_is_valid(last);
97 }
98
99 if (valid) return si_list_retain(list);
100
101 si_list_release(list);
102 pp->cache_store[cat].list = NULL;
103
104 return NULL;
105 }
106
107 static si_item_t *
108 cache_fetch_item(si_mod_t *si, int cat, const char *name, uint32_t num, int which)
109 {
110 int i;
111 cache_si_private_t *pp;
112 si_item_t *item;
113
114 if (si == NULL) return NULL;
115 if (gL1CacheEnabled == 0) return NULL;
116
117 pp = (cache_si_private_t *)si->private;
118 if (pp == NULL) return NULL;
119
120 pthread_mutex_lock(&pp->cache_store[cat].mutex);
121
122 for (i = 0; i < CACHE_MAX; i++)
123 {
124 item = cache_validate_item(pp, cat, i);
125 if (item && si_item_match(item, cat, name, num, which))
126 {
127 break;
128 }
129 else
130 {
131 si_item_release(item);
132 item = NULL;
133 }
134 }
135
136 pthread_mutex_unlock(&(pp->cache_store[cat].mutex));
137
138 return item;
139 }
140
141 static si_list_t *
142 cache_fetch_list(si_mod_t *si, int cat)
143 {
144 cache_si_private_t *pp;
145 si_list_t *list;
146
147 if (si == NULL) return NULL;
148 if (gL1CacheEnabled == 0) return NULL;
149
150 pp = (cache_si_private_t *)si->private;
151 if (pp == NULL) return NULL;
152
153 pthread_mutex_lock(&(pp->cache_store[cat].mutex));
154 list = cache_validate_list(pp, cat);
155 pthread_mutex_unlock(&(pp->cache_store[cat].mutex));
156
157 return list;
158 }
159
160 static si_item_t *
161 cache_user_byname(si_mod_t *si, const char *name)
162 {
163 return cache_fetch_item(si, CATEGORY_USER, name, 0, SEL_NAME);
164 }
165
166 static si_item_t *
167 cache_user_byuid(si_mod_t *si, uid_t uid)
168 {
169 return cache_fetch_item(si, CATEGORY_USER, NULL, uid, SEL_NUMBER);
170 }
171
172 static si_list_t *
173 cache_user_all(si_mod_t *si)
174 {
175 return cache_fetch_list(si, CATEGORY_USER);
176 }
177
178 static si_item_t *
179 cache_group_byname(si_mod_t *si, const char *name)
180 {
181 return cache_fetch_item(si, CATEGORY_GROUP, name, 0, SEL_NAME);
182 }
183
184 static si_item_t *
185 cache_group_bygid(si_mod_t *si, gid_t gid)
186 {
187 return cache_fetch_item(si, CATEGORY_GROUP, NULL, gid, SEL_NUMBER);
188 }
189
190 static si_list_t *
191 cache_group_all(si_mod_t *si)
192 {
193 return cache_fetch_list(si, CATEGORY_GROUP);
194 }
195
196 static si_item_t *
197 cache_grouplist(si_mod_t *si, const char *name, uint32_t count)
198 {
199 return cache_fetch_item(si, CATEGORY_GROUPLIST, name, 0, SEL_NAME);
200 }
201
202 static si_item_t *
203 cache_alias_byname(si_mod_t *si, const char *name)
204 {
205 return cache_fetch_item(si, CATEGORY_ALIAS, name, 0, SEL_NAME);
206 }
207
208 static si_list_t *
209 cache_alias_all(si_mod_t *si)
210 {
211 return cache_fetch_list(si, CATEGORY_ALIAS);
212 }
213
214 static si_item_t *
215 cache_host_byname(si_mod_t *si, const char *name, int af, const char *ignored, uint32_t *err)
216 {
217 si_item_t *item;
218
219 if (err != NULL) *err = SI_STATUS_NO_ERROR;
220 item = NULL;
221
222 if (af == AF_INET) item = cache_fetch_item(si, CATEGORY_HOST_IPV4, name, af, SEL_NAME);
223 else item = cache_fetch_item(si, CATEGORY_HOST_IPV6, name, af, SEL_NAME);
224
225 if ((item == NULL) && (err != NULL) && (*err == 0)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
226
227 return item;
228 }
229
230 static si_item_t *
231 cache_host_byaddr(si_mod_t *si, const void *addr, int af, const char *ignored, uint32_t *err)
232 {
233 si_item_t *item;
234
235 if (err != NULL) *err = SI_STATUS_NO_ERROR;
236 item = NULL;
237
238 if (af == AF_INET) item = cache_fetch_item(si, CATEGORY_HOST_IPV4, addr, af, SEL_NUMBER);
239 else item = cache_fetch_item(si, CATEGORY_HOST_IPV6, addr, af, SEL_NUMBER);
240
241 if ((item == NULL) && (err != NULL) && (*err == 0)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
242
243 return item;
244 }
245
246 static si_list_t *
247 cache_host_all(si_mod_t *si)
248 {
249 return cache_fetch_list(si, CATEGORY_HOST);
250 }
251
252 static si_item_t *
253 cache_network_byname(si_mod_t *si, const char *name)
254 {
255 return cache_fetch_item(si, CATEGORY_NETWORK, name, 0, SEL_NAME);
256 }
257
258 static si_item_t *
259 cache_network_byaddr(si_mod_t *si, uint32_t addr)
260 {
261 return cache_fetch_item(si, CATEGORY_NETWORK, NULL, addr, SEL_NUMBER);
262 }
263
264 static si_list_t *
265 cache_network_all(si_mod_t *si)
266 {
267 return cache_fetch_list(si, CATEGORY_NETWORK);
268 }
269
270 static si_item_t *
271 cache_service_byname(si_mod_t *si, const char *name, const char *proto)
272 {
273 uint32_t pn;
274
275 if (name == NULL) return NULL;
276 if (proto == NULL) return cache_fetch_item(si, CATEGORY_SERVICE, name, 0, SEL_NAME);
277
278 pn = 1;
279 if (string_equal(proto, "tcp")) pn = 2;
280
281 return cache_fetch_item(si, CATEGORY_SERVICE, name, pn, SEL_NAME);
282 }
283
284 static si_item_t *
285 cache_service_byport(si_mod_t *si, int port, const char *proto)
286 {
287 return cache_fetch_item(si, CATEGORY_SERVICE, proto, port, SEL_NUMBER);
288 }
289
290 static si_list_t *
291 cache_service_all(si_mod_t *si)
292 {
293 return cache_fetch_list(si, CATEGORY_SERVICE);
294 }
295
296 static si_item_t *
297 cache_protocol_byname(si_mod_t *si, const char *name)
298 {
299 return cache_fetch_item(si, CATEGORY_PROTOCOL, name, 0, SEL_NAME);
300 }
301
302 static si_item_t *
303 cache_protocol_bynumber(si_mod_t *si, int number)
304 {
305 return cache_fetch_item(si, CATEGORY_PROTOCOL, NULL, number, SEL_NUMBER);
306 }
307
308 static si_list_t *
309 cache_protocol_all(si_mod_t *si)
310 {
311 return cache_fetch_list(si, CATEGORY_PROTOCOL);
312 }
313
314 static si_item_t *
315 cache_rpc_byname(si_mod_t *si, const char *name)
316 {
317 return cache_fetch_item(si, CATEGORY_RPC, name, 0, SEL_NAME);
318 }
319
320 static si_item_t *
321 cache_rpc_bynumber(si_mod_t *si, int number)
322 {
323 return cache_fetch_item(si, CATEGORY_RPC, NULL, number, SEL_NUMBER);
324 }
325
326 static si_list_t *
327 cache_rpc_all(si_mod_t *si)
328 {
329 return cache_fetch_list(si, CATEGORY_RPC);
330 }
331
332 static si_item_t *
333 cache_fs_byspec(si_mod_t *si, const char *name)
334 {
335 return cache_fetch_item(si, CATEGORY_FS, name, 0, SEL_NAME);
336 }
337
338 static si_item_t *
339 cache_fs_byfile(si_mod_t *si, const char *name)
340 {
341 return cache_fetch_item(si, CATEGORY_FS, name, 0, SEL_NUMBER);
342 }
343
344 static si_list_t *
345 cache_fs_all(si_mod_t *si)
346 {
347 return cache_fetch_list(si, CATEGORY_FS);
348 }
349
350 static si_item_t *
351 cache_mac_byname(si_mod_t *si, const char *name)
352 {
353 return cache_fetch_item(si, CATEGORY_MAC, name, 0, SEL_NAME);
354 }
355
356 static si_item_t *
357 cache_mac_bymac(si_mod_t *si, const char *mac)
358 {
359 return cache_fetch_item(si, CATEGORY_MAC, mac, 0, SEL_NUMBER);
360 }
361
362 static si_list_t *
363 cache_mac_all(si_mod_t *si)
364 {
365 return cache_fetch_list(si, CATEGORY_MAC);
366 }
367
368 static si_item_t *
369 cache_nameinfo(si_mod_t *si, const struct sockaddr *sa, int flags, const char *ignored, uint32_t *err)
370 {
371 /*
372 * Caching of getnameinfo(3) is not supported.
373 * Only the individual host_byaddr and serv_byaddr responses will be cached.
374 * This is because getnameinfo(3) returns numeric responses instead of
375 * failing, which would poison the cache.
376 */
377 if (err) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
378 return NULL;
379 }
380
381 static void
382 cache_close(si_mod_t *si)
383 {
384 cache_si_private_t *pp;
385 int i, j;
386
387 if (si == NULL) return;
388
389 pp = (cache_si_private_t *)si->private;
390 if (pp == NULL) return;
391
392 for (i = 0; i < CACHE_COUNT; i++)
393 {
394 si_list_release(pp->cache_store[i].list);
395
396 for (j = 0; j < CACHE_MAX; j++)
397 {
398 si_item_release(pp->cache_store[i].item[j]);
399 pp->cache_store[i].item[j] = NULL;
400 }
401
402 pthread_mutex_destroy(&(pp->cache_store[i].mutex));
403 }
404
405 free(pp);
406 }
407
408 si_mod_t *
409 si_module_static_cache(void)
410 {
411 static const struct si_mod_vtable_s cache_vtable =
412 {
413 .sim_close = &cache_close,
414
415 .sim_user_byname = &cache_user_byname,
416 .sim_user_byuid = &cache_user_byuid,
417 .sim_user_byuuid = NULL,
418 .sim_user_all = &cache_user_all,
419
420 .sim_group_byname = &cache_group_byname,
421 .sim_group_bygid = &cache_group_bygid,
422 .sim_group_byuuid = NULL,
423 .sim_group_all = &cache_group_all,
424
425 .sim_grouplist = &cache_grouplist,
426
427 /* no netgroup support */
428 .sim_netgroup_byname = NULL,
429 .sim_in_netgroup = NULL,
430
431 .sim_alias_byname = &cache_alias_byname,
432 .sim_alias_all = &cache_alias_all,
433
434 .sim_host_byname = &cache_host_byname,
435 .sim_host_byaddr = &cache_host_byaddr,
436 .sim_host_all = &cache_host_all,
437
438 .sim_network_byname = &cache_network_byname,
439 .sim_network_byaddr = &cache_network_byaddr,
440 .sim_network_all = &cache_network_all,
441
442 .sim_service_byname = &cache_service_byname,
443 .sim_service_byport = &cache_service_byport,
444 .sim_service_all = &cache_service_all,
445
446 .sim_protocol_byname = &cache_protocol_byname,
447 .sim_protocol_bynumber = &cache_protocol_bynumber,
448 .sim_protocol_all = &cache_protocol_all,
449
450 .sim_rpc_byname = &cache_rpc_byname,
451 .sim_rpc_bynumber = &cache_rpc_bynumber,
452 .sim_rpc_all = &cache_rpc_all,
453
454 .sim_fs_byspec = &cache_fs_byspec,
455 .sim_fs_byfile = &cache_fs_byfile,
456 .sim_fs_all = &cache_fs_all,
457
458 .sim_mac_byname = &cache_mac_byname,
459 .sim_mac_bymac = &cache_mac_bymac,
460 .sim_mac_all = &cache_mac_all,
461
462 /* no addrinfo support */
463 .sim_wants_addrinfo = NULL,
464 .sim_addrinfo = NULL,
465
466 .sim_nameinfo = &cache_nameinfo,
467 };
468
469 static si_mod_t si =
470 {
471 .vers = 1,
472 .refcount = 1,
473 .flags = SI_MOD_FLAG_STATIC,
474
475 .private = NULL,
476 .vtable = &cache_vtable,
477 };
478
479 static dispatch_once_t once;
480
481 dispatch_once(&once, ^{
482 cache_si_private_t *cache;
483 int i, j;
484
485 cache = calloc(1, sizeof(cache_si_private_t));
486 si.name = strdup("cache");
487 si.private = cache;
488
489 for (i = 0; i < CACHE_COUNT; i++) {
490 for (j = 0; j < CACHE_MAX; j++) {
491 pthread_mutex_init(&(cache->cache_store[i].mutex), NULL);
492 }
493 }
494 });
495
496 return &si;
497 }
498
499 void
500 si_cache_add_item(si_mod_t *si, si_mod_t *src, si_item_t *item)
501 {
502 cache_si_private_t *pp;
503 int head, cat;
504
505 if (si == NULL) return;
506 if (src == NULL) return;
507 if (item == NULL) return;
508
509 if (si == src) return;
510
511 if (src->name == NULL) return;
512 if (string_equal(src->name, "cache")) return;
513
514 cat = item->type;
515 if ((cat < 0) || (cat >= CACHE_COUNT)) return;
516
517 pp = (cache_si_private_t *)si->private;
518 if (pp == NULL) return;
519
520 pthread_mutex_lock(&(pp->cache_store[cat].mutex));
521
522 head = pp->cache_store[item->type].head;
523
524 si_item_release(pp->cache_store[item->type].item[head]);
525 pp->cache_store[item->type].item[head] = si_item_retain(item);
526
527 head++;
528 if (head >= CACHE_MAX) head = 0;
529 pp->cache_store[item->type].head = head;
530
531 pthread_mutex_unlock(&(pp->cache_store[cat].mutex));
532 }
533
534 void
535 si_cache_add_list(si_mod_t *si, si_mod_t *src, si_list_t *list)
536 {
537 cache_si_private_t *pp;
538 si_item_t *item;
539 int cat;
540
541 if (si == NULL) return;
542 if (src == NULL) return;
543 if (list == NULL) return;
544 if (list->count == 0) return;
545
546 if (si == src) return;
547
548 if (src->name == NULL) return;
549 if (string_equal(src->name, "cache")) return;
550
551 item = list->entry[0];
552 if (item == NULL) return;
553
554 cat = item->type;
555 if ((cat < 0) || (cat >= CACHE_COUNT)) return;
556
557 pp = (cache_si_private_t *)si->private;
558 if (pp == NULL) return;
559
560 pthread_mutex_lock(&(pp->cache_store[cat].mutex));
561
562 si_list_release(pp->cache_store[item->type].list);
563 pp->cache_store[item->type].list = si_list_retain(list);
564
565 pthread_mutex_unlock(&(pp->cache_store[cat].mutex));
566 }