2 * Copyright (c) 2008-2011 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>
34 #include <libkern/OSAtomic.h>
35 #include <dispatch/dispatch.h>
38 uint32_t gL1CacheEnabled
= 1;
40 #define CACHE_COUNT CATEGORY_COUNT
45 pthread_mutex_t 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 pthread_mutex_lock(&pp
->cache_store
[cat
].mutex
);
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 pthread_mutex_unlock(&(pp
->cache_store
[cat
].mutex
));
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 pthread_mutex_lock(&(pp
->cache_store
[cat
].mutex
));
151 list
= cache_validate_list(pp
, cat
);
152 pthread_mutex_unlock(&(pp
->cache_store
[cat
].mutex
));
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
, uint32_t count
)
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
;
399 pthread_mutex_destroy(&(pp
->cache_store
[i
].mutex
));
406 si_module_static_cache(void)
408 static const struct si_mod_vtable_s cache_vtable
=
410 .sim_close
= &cache_close
,
412 .sim_user_byname
= &cache_user_byname
,
413 .sim_user_byuid
= &cache_user_byuid
,
414 .sim_user_byuuid
= NULL
,
415 .sim_user_all
= &cache_user_all
,
417 .sim_group_byname
= &cache_group_byname
,
418 .sim_group_bygid
= &cache_group_bygid
,
419 .sim_group_byuuid
= NULL
,
420 .sim_group_all
= &cache_group_all
,
422 .sim_grouplist
= &cache_grouplist
,
424 /* no netgroup support */
425 .sim_netgroup_byname
= NULL
,
426 .sim_in_netgroup
= NULL
,
428 .sim_alias_byname
= &cache_alias_byname
,
429 .sim_alias_all
= &cache_alias_all
,
431 .sim_host_byname
= &cache_host_byname
,
432 .sim_host_byaddr
= &cache_host_byaddr
,
433 .sim_host_all
= &cache_host_all
,
435 .sim_network_byname
= &cache_network_byname
,
436 .sim_network_byaddr
= &cache_network_byaddr
,
437 .sim_network_all
= &cache_network_all
,
439 .sim_service_byname
= &cache_service_byname
,
440 .sim_service_byport
= &cache_service_byport
,
441 .sim_service_all
= &cache_service_all
,
443 .sim_protocol_byname
= &cache_protocol_byname
,
444 .sim_protocol_bynumber
= &cache_protocol_bynumber
,
445 .sim_protocol_all
= &cache_protocol_all
,
447 .sim_rpc_byname
= &cache_rpc_byname
,
448 .sim_rpc_bynumber
= &cache_rpc_bynumber
,
449 .sim_rpc_all
= &cache_rpc_all
,
451 .sim_fs_byspec
= &cache_fs_byspec
,
452 .sim_fs_byfile
= &cache_fs_byfile
,
453 .sim_fs_all
= &cache_fs_all
,
455 .sim_mac_byname
= &cache_mac_byname
,
456 .sim_mac_bymac
= &cache_mac_bymac
,
457 .sim_mac_all
= &cache_mac_all
,
459 /* no addrinfo support */
460 .sim_wants_addrinfo
= NULL
,
461 .sim_addrinfo
= NULL
,
463 .sim_nameinfo
= &cache_nameinfo
,
470 .flags
= SI_MOD_FLAG_STATIC
,
473 .vtable
= &cache_vtable
,
476 static dispatch_once_t once
;
478 dispatch_once(&once
, ^{
479 cache_si_private_t
*cache
;
482 cache
= calloc(1, sizeof(cache_si_private_t
));
483 si
.name
= strdup("cache");
486 for (i
= 0; i
< CACHE_COUNT
; i
++) {
487 for (j
= 0; j
< CACHE_MAX
; j
++) {
488 pthread_mutex_init(&(cache
->cache_store
[i
].mutex
), NULL
);
497 si_cache_add_item(si_mod_t
*si
, si_mod_t
*src
, si_item_t
*item
)
499 cache_si_private_t
*pp
;
502 if (si
== NULL
) return;
503 if (src
== NULL
) return;
504 if (item
== NULL
) return;
506 if (si
== src
) return;
508 if (src
->name
== NULL
) return;
509 if (string_equal(src
->name
, "cache")) return;
512 if ((cat
< 0) || (cat
>= CACHE_COUNT
)) return;
514 pp
= (cache_si_private_t
*)si
->private;
515 if (pp
== NULL
) return;
517 pthread_mutex_lock(&(pp
->cache_store
[cat
].mutex
));
519 head
= pp
->cache_store
[item
->type
].head
;
521 si_item_release(pp
->cache_store
[item
->type
].item
[head
]);
522 pp
->cache_store
[item
->type
].item
[head
] = si_item_retain(item
);
525 if (head
>= CACHE_MAX
) head
= 0;
526 pp
->cache_store
[item
->type
].head
= head
;
528 pthread_mutex_unlock(&(pp
->cache_store
[cat
].mutex
));
532 si_cache_add_list(si_mod_t
*si
, si_mod_t
*src
, si_list_t
*list
)
534 cache_si_private_t
*pp
;
538 if (si
== NULL
) return;
539 if (src
== NULL
) return;
540 if (list
== NULL
) return;
541 if (list
->count
== 0) return;
543 if (si
== src
) return;
545 if (src
->name
== NULL
) return;
546 if (string_equal(src
->name
, "cache")) return;
548 item
= list
->entry
[0];
549 if (item
== NULL
) return;
552 if ((cat
< 0) || (cat
>= CACHE_COUNT
)) return;
554 pp
= (cache_si_private_t
*)si
->private;
555 if (pp
== NULL
) return;
557 pthread_mutex_lock(&(pp
->cache_store
[cat
].mutex
));
559 si_list_release(pp
->cache_store
[item
->type
].list
);
560 pp
->cache_store
[item
->type
].list
= si_list_retain(list
);
562 pthread_mutex_unlock(&(pp
->cache_store
[cat
].mutex
));