2 * Copyright (c) 2008-2018 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 #include "libinfo_common.h"
26 #include <si_module.h>
32 #include <arpa/inet.h>
36 #include <libkern/OSAtomic.h>
37 #include <dispatch/dispatch.h>
41 uint32_t gL1CacheEnabled
= 1;
43 #define CACHE_COUNT CATEGORY_COUNT
48 pthread_mutex_t mutex
;
50 si_item_t
*item
[CACHE_MAX
];
56 cache_store_t cache_store
[CACHE_COUNT
];
60 cache_validate_item(cache_si_private_t
*pp
, int cat
, int where
)
64 item
= pp
->cache_store
[cat
].item
[where
];
65 if (item
== NULL
) return NULL
;
67 if (si_item_is_valid(item
)) return si_item_retain(item
);
69 si_item_release(item
);
70 pp
->cache_store
[cat
].item
[where
] = NULL
;
76 cache_validate_list(cache_si_private_t
*pp
, int cat
)
79 si_item_t
*item
, *last
;
82 list
= pp
->cache_store
[cat
].list
;
84 if (list
== NULL
) return NULL
;
85 if (list
->count
== 0) return NULL
;
87 last
= list
->entry
[0];
88 valid
= si_item_is_valid(last
);
90 for (i
= 1; (i
< list
->count
) && (valid
== 1); i
++)
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;
96 valid
= si_item_is_valid(last
);
99 if (valid
) return si_list_retain(list
);
101 si_list_release(list
);
102 pp
->cache_store
[cat
].list
= NULL
;
108 cache_fetch_item(si_mod_t
*si
, int cat
, const char *name
, uint32_t num
, int which
)
111 cache_si_private_t
*pp
;
114 if (si
== NULL
) return NULL
;
115 if (gL1CacheEnabled
== 0) return NULL
;
117 pp
= (cache_si_private_t
*)si
->private;
118 if (pp
== NULL
) return NULL
;
120 pthread_mutex_lock(&pp
->cache_store
[cat
].mutex
);
122 for (i
= 0; i
< CACHE_MAX
; i
++)
124 item
= cache_validate_item(pp
, cat
, i
);
125 if (item
&& si_item_match(item
, cat
, name
, num
, which
))
131 si_item_release(item
);
136 pthread_mutex_unlock(&(pp
->cache_store
[cat
].mutex
));
142 cache_fetch_list(si_mod_t
*si
, int cat
)
144 cache_si_private_t
*pp
;
147 if (si
== NULL
) return NULL
;
148 if (gL1CacheEnabled
== 0) return NULL
;
150 pp
= (cache_si_private_t
*)si
->private;
151 if (pp
== NULL
) return NULL
;
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
));
161 cache_user_byname(si_mod_t
*si
, const char *name
)
163 return cache_fetch_item(si
, CATEGORY_USER
, name
, 0, SEL_NAME
);
167 cache_user_byuid(si_mod_t
*si
, uid_t uid
)
169 return cache_fetch_item(si
, CATEGORY_USER
, NULL
, uid
, SEL_NUMBER
);
173 cache_user_all(si_mod_t
*si
)
175 return cache_fetch_list(si
, CATEGORY_USER
);
179 cache_group_byname(si_mod_t
*si
, const char *name
)
181 return cache_fetch_item(si
, CATEGORY_GROUP
, name
, 0, SEL_NAME
);
185 cache_group_bygid(si_mod_t
*si
, gid_t gid
)
187 return cache_fetch_item(si
, CATEGORY_GROUP
, NULL
, gid
, SEL_NUMBER
);
191 cache_group_all(si_mod_t
*si
)
193 return cache_fetch_list(si
, CATEGORY_GROUP
);
197 cache_grouplist(si_mod_t
*si
, const char *name
, uint32_t count
)
199 return cache_fetch_item(si
, CATEGORY_GROUPLIST
, name
, 0, SEL_NAME
);
203 cache_alias_byname(si_mod_t
*si
, const char *name
)
205 return cache_fetch_item(si
, CATEGORY_ALIAS
, name
, 0, SEL_NAME
);
209 cache_alias_all(si_mod_t
*si
)
211 return cache_fetch_list(si
, CATEGORY_ALIAS
);
215 cache_host_byname(si_mod_t
*si
, const char *name
, int af
, const char *ignored
, uint32_t *err
)
219 if (err
!= NULL
) *err
= SI_STATUS_NO_ERROR
;
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
);
225 if ((item
== NULL
) && (err
!= NULL
) && (*err
== 0)) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
231 cache_host_byaddr(si_mod_t
*si
, const void *addr
, int af
, const char *ignored
, uint32_t *err
)
235 if (err
!= NULL
) *err
= SI_STATUS_NO_ERROR
;
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
);
241 if ((item
== NULL
) && (err
!= NULL
) && (*err
== 0)) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
247 cache_host_all(si_mod_t
*si
)
249 return cache_fetch_list(si
, CATEGORY_HOST
);
253 cache_network_byname(si_mod_t
*si
, const char *name
)
255 return cache_fetch_item(si
, CATEGORY_NETWORK
, name
, 0, SEL_NAME
);
259 cache_network_byaddr(si_mod_t
*si
, uint32_t addr
)
261 return cache_fetch_item(si
, CATEGORY_NETWORK
, NULL
, addr
, SEL_NUMBER
);
265 cache_network_all(si_mod_t
*si
)
267 return cache_fetch_list(si
, CATEGORY_NETWORK
);
271 cache_service_byname(si_mod_t
*si
, const char *name
, const char *proto
)
275 if (name
== NULL
) return NULL
;
276 if (proto
== NULL
) return cache_fetch_item(si
, CATEGORY_SERVICE
, name
, 0, SEL_NAME
);
279 if (string_equal(proto
, "tcp")) pn
= 2;
281 return cache_fetch_item(si
, CATEGORY_SERVICE
, name
, pn
, SEL_NAME
);
285 cache_service_byport(si_mod_t
*si
, int port
, const char *proto
)
287 return cache_fetch_item(si
, CATEGORY_SERVICE
, proto
, port
, SEL_NUMBER
);
291 cache_service_all(si_mod_t
*si
)
293 return cache_fetch_list(si
, CATEGORY_SERVICE
);
297 cache_protocol_byname(si_mod_t
*si
, const char *name
)
299 return cache_fetch_item(si
, CATEGORY_PROTOCOL
, name
, 0, SEL_NAME
);
303 cache_protocol_bynumber(si_mod_t
*si
, int number
)
305 return cache_fetch_item(si
, CATEGORY_PROTOCOL
, NULL
, number
, SEL_NUMBER
);
309 cache_protocol_all(si_mod_t
*si
)
311 return cache_fetch_list(si
, CATEGORY_PROTOCOL
);
315 cache_rpc_byname(si_mod_t
*si
, const char *name
)
317 return cache_fetch_item(si
, CATEGORY_RPC
, name
, 0, SEL_NAME
);
321 cache_rpc_bynumber(si_mod_t
*si
, int number
)
323 return cache_fetch_item(si
, CATEGORY_RPC
, NULL
, number
, SEL_NUMBER
);
327 cache_rpc_all(si_mod_t
*si
)
329 return cache_fetch_list(si
, CATEGORY_RPC
);
333 cache_fs_byspec(si_mod_t
*si
, const char *name
)
335 return cache_fetch_item(si
, CATEGORY_FS
, name
, 0, SEL_NAME
);
339 cache_fs_byfile(si_mod_t
*si
, const char *name
)
341 return cache_fetch_item(si
, CATEGORY_FS
, name
, 0, SEL_NUMBER
);
345 cache_fs_all(si_mod_t
*si
)
347 return cache_fetch_list(si
, CATEGORY_FS
);
351 cache_mac_byname(si_mod_t
*si
, const char *name
)
353 return cache_fetch_item(si
, CATEGORY_MAC
, name
, 0, SEL_NAME
);
357 cache_mac_bymac(si_mod_t
*si
, const char *mac
)
359 return cache_fetch_item(si
, CATEGORY_MAC
, mac
, 0, SEL_NUMBER
);
363 cache_mac_all(si_mod_t
*si
)
365 return cache_fetch_list(si
, CATEGORY_MAC
);
369 cache_nameinfo(si_mod_t
*si
, const struct sockaddr
*sa
, int flags
, const char *ignored
, uint32_t *err
)
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.
377 if (err
) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
382 cache_close(si_mod_t
*si
)
384 cache_si_private_t
*pp
;
387 if (si
== NULL
) return;
389 pp
= (cache_si_private_t
*)si
->private;
390 if (pp
== NULL
) return;
392 for (i
= 0; i
< CACHE_COUNT
; i
++)
394 si_list_release(pp
->cache_store
[i
].list
);
396 for (j
= 0; j
< CACHE_MAX
; j
++)
398 si_item_release(pp
->cache_store
[i
].item
[j
]);
399 pp
->cache_store
[i
].item
[j
] = NULL
;
402 pthread_mutex_destroy(&(pp
->cache_store
[i
].mutex
));
409 si_module_static_cache(void)
411 static const struct si_mod_vtable_s cache_vtable
=
413 .sim_close
= &cache_close
,
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
,
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
,
425 .sim_grouplist
= &cache_grouplist
,
427 /* no netgroup support */
428 .sim_netgroup_byname
= NULL
,
429 .sim_in_netgroup
= NULL
,
431 .sim_alias_byname
= &cache_alias_byname
,
432 .sim_alias_all
= &cache_alias_all
,
434 .sim_host_byname
= &cache_host_byname
,
435 .sim_host_byaddr
= &cache_host_byaddr
,
436 .sim_host_all
= &cache_host_all
,
438 .sim_network_byname
= &cache_network_byname
,
439 .sim_network_byaddr
= &cache_network_byaddr
,
440 .sim_network_all
= &cache_network_all
,
442 .sim_service_byname
= &cache_service_byname
,
443 .sim_service_byport
= &cache_service_byport
,
444 .sim_service_all
= &cache_service_all
,
446 .sim_protocol_byname
= &cache_protocol_byname
,
447 .sim_protocol_bynumber
= &cache_protocol_bynumber
,
448 .sim_protocol_all
= &cache_protocol_all
,
450 .sim_rpc_byname
= &cache_rpc_byname
,
451 .sim_rpc_bynumber
= &cache_rpc_bynumber
,
452 .sim_rpc_all
= &cache_rpc_all
,
454 .sim_fs_byspec
= &cache_fs_byspec
,
455 .sim_fs_byfile
= &cache_fs_byfile
,
456 .sim_fs_all
= &cache_fs_all
,
458 .sim_mac_byname
= &cache_mac_byname
,
459 .sim_mac_bymac
= &cache_mac_bymac
,
460 .sim_mac_all
= &cache_mac_all
,
462 /* no addrinfo support */
463 .sim_wants_addrinfo
= NULL
,
464 .sim_addrinfo
= NULL
,
466 .sim_nameinfo
= &cache_nameinfo
,
473 .flags
= SI_MOD_FLAG_STATIC
,
476 .vtable
= &cache_vtable
,
479 static dispatch_once_t once
;
481 dispatch_once(&once
, ^{
482 cache_si_private_t
*cache
;
485 cache
= calloc(1, sizeof(cache_si_private_t
));
486 si
.name
= strdup("cache");
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
);
500 si_cache_add_item(si_mod_t
*si
, si_mod_t
*src
, si_item_t
*item
)
502 cache_si_private_t
*pp
;
505 if (si
== NULL
) return;
506 if (src
== NULL
) return;
507 if (item
== NULL
) return;
509 if (si
== src
) return;
511 if (src
->name
== NULL
) return;
512 if (string_equal(src
->name
, "cache")) return;
515 if ((cat
< 0) || (cat
>= CACHE_COUNT
)) return;
517 pp
= (cache_si_private_t
*)si
->private;
518 if (pp
== NULL
) return;
520 pthread_mutex_lock(&(pp
->cache_store
[cat
].mutex
));
522 head
= pp
->cache_store
[item
->type
].head
;
524 si_item_release(pp
->cache_store
[item
->type
].item
[head
]);
525 pp
->cache_store
[item
->type
].item
[head
] = si_item_retain(item
);
528 if (head
>= CACHE_MAX
) head
= 0;
529 pp
->cache_store
[item
->type
].head
= head
;
531 pthread_mutex_unlock(&(pp
->cache_store
[cat
].mutex
));
535 si_cache_add_list(si_mod_t
*si
, si_mod_t
*src
, si_list_t
*list
)
537 cache_si_private_t
*pp
;
541 if (si
== NULL
) return;
542 if (src
== NULL
) return;
543 if (list
== NULL
) return;
544 if (list
->count
== 0) return;
546 if (si
== src
) return;
548 if (src
->name
== NULL
) return;
549 if (string_equal(src
->name
, "cache")) return;
551 item
= list
->entry
[0];
552 if (item
== NULL
) return;
555 if ((cat
< 0) || (cat
>= CACHE_COUNT
)) return;
557 pp
= (cache_si_private_t
*)si
->private;
558 if (pp
== NULL
) return;
560 pthread_mutex_lock(&(pp
->cache_store
[cat
].mutex
));
562 si_list_release(pp
->cache_store
[item
->type
].list
);
563 pp
->cache_store
[item
->type
].list
= si_list_retain(list
);
565 pthread_mutex_unlock(&(pp
->cache_store
[cat
].mutex
));