2 * Copyright (c) 2008-2010 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 <si_module.h>
30 #include <arpa/inet.h>
33 #include <libkern/OSAtomic.h>
34 #include <dispatch/dispatch.h>
37 uint32_t gL1CacheEnabled
= 1;
39 #define CACHE_COUNT CATEGORY_COUNT
44 /* XXX should be mutex */
47 si_item_t
*item
[CACHE_MAX
];
53 cache_store_t cache_store
[CACHE_COUNT
];
57 cache_validate_item(cache_si_private_t
*pp
, int cat
, int where
)
61 item
= pp
->cache_store
[cat
].item
[where
];
62 if (item
== NULL
) return NULL
;
64 if (si_item_is_valid(item
)) return si_item_retain(item
);
66 si_item_release(item
);
67 pp
->cache_store
[cat
].item
[where
] = NULL
;
73 cache_validate_list(cache_si_private_t
*pp
, int cat
)
76 si_item_t
*item
, *last
;
79 list
= pp
->cache_store
[cat
].list
;
81 if (list
== NULL
) return NULL
;
82 if (list
->count
== 0) return NULL
;
84 last
= list
->entry
[0];
85 valid
= si_item_is_valid(last
);
87 for (i
= 1; (i
< list
->count
) && (valid
== 1); i
++)
89 item
= list
->entry
[i
];
90 if ((item
->src
== last
->src
) && (item
->type
== last
->type
) && (item
->validation_a
== last
->validation_a
) && (item
->validation_b
== last
->validation_b
)) continue;
93 valid
= si_item_is_valid(last
);
96 if (valid
) return si_list_retain(list
);
98 si_list_release(list
);
99 pp
->cache_store
[cat
].list
= NULL
;
105 cache_fetch_item(si_mod_t
*si
, int cat
, const char *name
, uint32_t num
, int which
)
108 cache_si_private_t
*pp
;
111 if (si
== NULL
) return NULL
;
112 if (gL1CacheEnabled
== 0) return NULL
;
114 pp
= (cache_si_private_t
*)si
->private;
115 if (pp
== NULL
) return NULL
;
117 OSSpinLockLock(&(pp
->cache_store
[cat
].lock
));
119 for (i
= 0; i
< CACHE_MAX
; i
++)
121 item
= cache_validate_item(pp
, cat
, i
);
122 if (item
&& si_item_match(item
, cat
, name
, num
, which
))
128 si_item_release(item
);
133 OSSpinLockUnlock(&(pp
->cache_store
[cat
].lock
));
139 cache_fetch_list(si_mod_t
*si
, int cat
)
141 cache_si_private_t
*pp
;
144 if (si
== NULL
) return NULL
;
145 if (gL1CacheEnabled
== 0) return NULL
;
147 pp
= (cache_si_private_t
*)si
->private;
148 if (pp
== NULL
) return NULL
;
150 OSSpinLockLock(&(pp
->cache_store
[cat
].lock
));
151 list
= cache_validate_list(pp
, cat
);
152 OSSpinLockUnlock(&(pp
->cache_store
[cat
].lock
));
158 cache_user_byname(si_mod_t
*si
, const char *name
)
160 return cache_fetch_item(si
, CATEGORY_USER
, name
, 0, SEL_NAME
);
164 cache_user_byuid(si_mod_t
*si
, uid_t uid
)
166 return cache_fetch_item(si
, CATEGORY_USER
, NULL
, uid
, SEL_NUMBER
);
170 cache_user_all(si_mod_t
*si
)
172 return cache_fetch_list(si
, CATEGORY_USER
);
176 cache_group_byname(si_mod_t
*si
, const char *name
)
178 return cache_fetch_item(si
, CATEGORY_GROUP
, name
, 0, SEL_NAME
);
182 cache_group_bygid(si_mod_t
*si
, gid_t gid
)
184 return cache_fetch_item(si
, CATEGORY_GROUP
, NULL
, gid
, SEL_NUMBER
);
188 cache_group_all(si_mod_t
*si
)
190 return cache_fetch_list(si
, CATEGORY_GROUP
);
194 cache_grouplist(si_mod_t
*si
, const char *name
)
196 return cache_fetch_item(si
, CATEGORY_GROUPLIST
, name
, 0, SEL_NAME
);
200 cache_alias_byname(si_mod_t
*si
, const char *name
)
202 return cache_fetch_item(si
, CATEGORY_ALIAS
, name
, 0, SEL_NAME
);
206 cache_alias_all(si_mod_t
*si
)
208 return cache_fetch_list(si
, CATEGORY_ALIAS
);
212 cache_host_byname(si_mod_t
*si
, const char *name
, int af
, const char *ignored
, uint32_t *err
)
216 if (err
!= NULL
) *err
= SI_STATUS_NO_ERROR
;
219 if (af
== AF_INET
) item
= cache_fetch_item(si
, CATEGORY_HOST_IPV4
, name
, af
, SEL_NAME
);
220 else item
= cache_fetch_item(si
, CATEGORY_HOST_IPV6
, name
, af
, SEL_NAME
);
222 if ((item
== NULL
) && (err
!= NULL
) && (*err
== 0)) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
228 cache_host_byaddr(si_mod_t
*si
, const void *addr
, int af
, const char *ignored
, uint32_t *err
)
232 if (err
!= NULL
) *err
= SI_STATUS_NO_ERROR
;
235 if (af
== AF_INET
) item
= cache_fetch_item(si
, CATEGORY_HOST_IPV4
, addr
, af
, SEL_NUMBER
);
236 else item
= cache_fetch_item(si
, CATEGORY_HOST_IPV6
, addr
, af
, SEL_NUMBER
);
238 if ((item
== NULL
) && (err
!= NULL
) && (*err
== 0)) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
244 cache_host_all(si_mod_t
*si
)
246 return cache_fetch_list(si
, CATEGORY_HOST
);
250 cache_network_byname(si_mod_t
*si
, const char *name
)
252 return cache_fetch_item(si
, CATEGORY_NETWORK
, name
, 0, SEL_NAME
);
256 cache_network_byaddr(si_mod_t
*si
, uint32_t addr
)
258 return cache_fetch_item(si
, CATEGORY_NETWORK
, NULL
, addr
, SEL_NUMBER
);
262 cache_network_all(si_mod_t
*si
)
264 return cache_fetch_list(si
, CATEGORY_NETWORK
);
268 cache_service_byname(si_mod_t
*si
, const char *name
, const char *proto
)
272 if (name
== NULL
) return NULL
;
273 if (proto
== NULL
) return cache_fetch_item(si
, CATEGORY_SERVICE
, name
, 0, SEL_NAME
);
276 if (string_equal(proto
, "tcp")) pn
= 2;
278 return cache_fetch_item(si
, CATEGORY_SERVICE
, name
, pn
, SEL_NAME
);
282 cache_service_byport(si_mod_t
*si
, int port
, const char *proto
)
284 return cache_fetch_item(si
, CATEGORY_SERVICE
, proto
, port
, SEL_NUMBER
);
288 cache_service_all(si_mod_t
*si
)
290 return cache_fetch_list(si
, CATEGORY_SERVICE
);
294 cache_protocol_byname(si_mod_t
*si
, const char *name
)
296 return cache_fetch_item(si
, CATEGORY_PROTOCOL
, name
, 0, SEL_NAME
);
300 cache_protocol_bynumber(si_mod_t
*si
, int number
)
302 return cache_fetch_item(si
, CATEGORY_PROTOCOL
, NULL
, number
, SEL_NUMBER
);
306 cache_protocol_all(si_mod_t
*si
)
308 return cache_fetch_list(si
, CATEGORY_PROTOCOL
);
312 cache_rpc_byname(si_mod_t
*si
, const char *name
)
314 return cache_fetch_item(si
, CATEGORY_RPC
, name
, 0, SEL_NAME
);
318 cache_rpc_bynumber(si_mod_t
*si
, int number
)
320 return cache_fetch_item(si
, CATEGORY_RPC
, NULL
, number
, SEL_NUMBER
);
324 cache_rpc_all(si_mod_t
*si
)
326 return cache_fetch_list(si
, CATEGORY_RPC
);
330 cache_fs_byspec(si_mod_t
*si
, const char *name
)
332 return cache_fetch_item(si
, CATEGORY_FS
, name
, 0, SEL_NAME
);
336 cache_fs_byfile(si_mod_t
*si
, const char *name
)
338 return cache_fetch_item(si
, CATEGORY_FS
, name
, 0, SEL_NUMBER
);
342 cache_fs_all(si_mod_t
*si
)
344 return cache_fetch_list(si
, CATEGORY_FS
);
348 cache_mac_byname(si_mod_t
*si
, const char *name
)
350 return cache_fetch_item(si
, CATEGORY_MAC
, name
, 0, SEL_NAME
);
354 cache_mac_bymac(si_mod_t
*si
, const char *mac
)
356 return cache_fetch_item(si
, CATEGORY_MAC
, mac
, 0, SEL_NUMBER
);
360 cache_mac_all(si_mod_t
*si
)
362 return cache_fetch_list(si
, CATEGORY_MAC
);
366 cache_nameinfo(si_mod_t
*si
, const struct sockaddr
*sa
, int flags
, const char *ignored
, uint32_t *err
)
369 * Caching of getnameinfo(3) is not supported.
370 * Only the individual host_byaddr and serv_byaddr responses will be cached.
371 * This is because getnameinfo(3) returns numeric responses instead of
372 * failing, which would poison the cache.
374 if (err
) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
379 cache_close(si_mod_t
*si
)
381 cache_si_private_t
*pp
;
384 if (si
== NULL
) return;
386 pp
= (cache_si_private_t
*)si
->private;
387 if (pp
== NULL
) return;
389 for (i
= 0; i
< CACHE_COUNT
; i
++)
391 si_list_release(pp
->cache_store
[i
].list
);
393 for (j
= 0; j
< CACHE_MAX
; j
++)
395 si_item_release(pp
->cache_store
[i
].item
[j
]);
396 pp
->cache_store
[i
].item
[j
] = NULL
;
404 si_module_static_cache(void)
406 static const struct si_mod_vtable_s cache_vtable
=
408 .sim_close
= &cache_close
,
410 .sim_user_byname
= &cache_user_byname
,
411 .sim_user_byuid
= &cache_user_byuid
,
412 .sim_user_all
= &cache_user_all
,
414 .sim_group_byname
= &cache_group_byname
,
415 .sim_group_bygid
= &cache_group_bygid
,
416 .sim_group_all
= &cache_group_all
,
418 .sim_grouplist
= &cache_grouplist
,
420 /* no netgroup support */
421 .sim_netgroup_byname
= NULL
,
422 .sim_in_netgroup
= NULL
,
424 .sim_alias_byname
= &cache_alias_byname
,
425 .sim_alias_all
= &cache_alias_all
,
427 .sim_host_byname
= &cache_host_byname
,
428 .sim_host_byaddr
= &cache_host_byaddr
,
429 .sim_host_all
= &cache_host_all
,
431 .sim_network_byname
= &cache_network_byname
,
432 .sim_network_byaddr
= &cache_network_byaddr
,
433 .sim_network_all
= &cache_network_all
,
435 .sim_service_byname
= &cache_service_byname
,
436 .sim_service_byport
= &cache_service_byport
,
437 .sim_service_all
= &cache_service_all
,
439 .sim_protocol_byname
= &cache_protocol_byname
,
440 .sim_protocol_bynumber
= &cache_protocol_bynumber
,
441 .sim_protocol_all
= &cache_protocol_all
,
443 .sim_rpc_byname
= &cache_rpc_byname
,
444 .sim_rpc_bynumber
= &cache_rpc_bynumber
,
445 .sim_rpc_all
= &cache_rpc_all
,
447 .sim_fs_byspec
= &cache_fs_byspec
,
448 .sim_fs_byfile
= &cache_fs_byfile
,
449 .sim_fs_all
= &cache_fs_all
,
451 .sim_mac_byname
= &cache_mac_byname
,
452 .sim_mac_bymac
= &cache_mac_bymac
,
453 .sim_mac_all
= &cache_mac_all
,
455 /* no addrinfo support */
456 .sim_wants_addrinfo
= NULL
,
457 .sim_addrinfo
= NULL
,
459 .sim_nameinfo
= &cache_nameinfo
,
466 .flags
= SI_MOD_FLAG_STATIC
,
469 .vtable
= &cache_vtable
,
472 static dispatch_once_t once
;
474 dispatch_once(&once
, ^{
475 si
.name
= strdup("cache");
476 si
.private = calloc(1, sizeof(cache_si_private_t
));
483 si_cache_add_item(si_mod_t
*si
, si_mod_t
*src
, si_item_t
*item
)
485 cache_si_private_t
*pp
;
488 if (si
== NULL
) return;
489 if (src
== NULL
) return;
490 if (item
== NULL
) return;
492 if (si
== src
) return;
494 if (src
->name
== NULL
) return;
495 if (string_equal(src
->name
, "cache")) return;
498 if ((cat
< 0) || (cat
>= CACHE_COUNT
)) return;
500 pp
= (cache_si_private_t
*)si
->private;
501 if (pp
== NULL
) return;
503 OSSpinLockLock(&(pp
->cache_store
[cat
].lock
));
505 head
= pp
->cache_store
[item
->type
].head
;
507 si_item_release(pp
->cache_store
[item
->type
].item
[head
]);
508 pp
->cache_store
[item
->type
].item
[head
] = si_item_retain(item
);
511 if (head
>= CACHE_MAX
) head
= 0;
512 pp
->cache_store
[item
->type
].head
= head
;
514 OSSpinLockUnlock(&(pp
->cache_store
[cat
].lock
));
518 si_cache_add_list(si_mod_t
*si
, si_mod_t
*src
, si_list_t
*list
)
520 cache_si_private_t
*pp
;
524 if (si
== NULL
) return;
525 if (src
== NULL
) return;
526 if (list
== NULL
) return;
527 if (list
->count
== 0) return;
529 if (si
== src
) return;
531 if (src
->name
== NULL
) return;
532 if (string_equal(src
->name
, "cache")) return;
534 item
= list
->entry
[0];
535 if (item
== NULL
) return;
538 if ((cat
< 0) || (cat
>= CACHE_COUNT
)) return;
540 pp
= (cache_si_private_t
*)si
->private;
541 if (pp
== NULL
) return;
543 OSSpinLockLock(&(pp
->cache_store
[cat
].lock
));
545 si_list_release(pp
->cache_store
[item
->type
].list
);
546 pp
->cache_store
[item
->type
].list
= si_list_retain(list
);
548 OSSpinLockUnlock(&(pp
->cache_store
[cat
].lock
));