2 * Copyright (c) 2008-2009 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>
36 uint32_t gL1CacheEnabled
= 1;
38 #define CACHE_COUNT CATEGORY_COUNT
43 /* XXX should be mutex */
46 si_item_t
*item
[CACHE_MAX
];
52 cache_store_t cache_store
[CACHE_COUNT
];
56 cache_validate_item(cache_si_private_t
*pp
, int cat
, int where
)
60 item
= pp
->cache_store
[cat
].item
[where
];
61 if (item
== NULL
) return NULL
;
63 if (si_item_is_valid(item
)) return si_item_retain(item
);
65 si_item_release(item
);
66 pp
->cache_store
[cat
].item
[where
] = NULL
;
72 cache_validate_list(cache_si_private_t
*pp
, int cat
)
75 si_item_t
*item
, *last
;
78 list
= pp
->cache_store
[cat
].list
;
80 if (list
== NULL
) return NULL
;
81 if (list
->count
== 0) return NULL
;
83 last
= list
->entry
[0];
84 valid
= si_item_is_valid(last
);
86 for (i
= 1; (i
< list
->count
) && (valid
== 1); i
++)
88 item
= list
->entry
[i
];
89 if ((item
->src
== last
->src
) && (item
->type
== last
->type
) && (item
->validation_a
== last
->validation_a
) && (item
->validation_b
== last
->validation_b
)) continue;
92 valid
= si_item_is_valid(last
);
95 if (valid
) return si_list_retain(list
);
97 si_list_release(list
);
98 pp
->cache_store
[cat
].list
= NULL
;
104 cache_fetch_item(si_mod_t
*si
, int cat
, const char *name
, uint32_t num
, int which
)
107 cache_si_private_t
*pp
;
110 if (si
== NULL
) return NULL
;
111 if (gL1CacheEnabled
== 0) return NULL
;
113 pp
= (cache_si_private_t
*)si
->private;
114 if (pp
== NULL
) return NULL
;
116 OSSpinLockLock(&(pp
->cache_store
[cat
].lock
));
118 for (i
= 0; i
< CACHE_MAX
; i
++)
120 item
= cache_validate_item(pp
, cat
, i
);
121 if (item
&& si_item_match(item
, cat
, name
, num
, which
))
127 si_item_release(item
);
132 OSSpinLockUnlock(&(pp
->cache_store
[cat
].lock
));
138 cache_fetch_list(si_mod_t
*si
, int cat
)
140 cache_si_private_t
*pp
;
143 if (si
== NULL
) return NULL
;
144 if (gL1CacheEnabled
== 0) return NULL
;
146 pp
= (cache_si_private_t
*)si
->private;
147 if (pp
== NULL
) return NULL
;
149 OSSpinLockLock(&(pp
->cache_store
[cat
].lock
));
150 list
= cache_validate_list(pp
, cat
);
151 OSSpinLockUnlock(&(pp
->cache_store
[cat
].lock
));
156 __private_extern__ si_item_t
*
157 cache_user_byname(si_mod_t
*si
, const char *name
)
159 return cache_fetch_item(si
, CATEGORY_USER
, name
, 0, SEL_NAME
);
162 __private_extern__ si_item_t
*
163 cache_user_byuid(si_mod_t
*si
, uid_t uid
)
165 return cache_fetch_item(si
, CATEGORY_USER
, NULL
, uid
, SEL_NUMBER
);
168 __private_extern__ si_list_t
*
169 cache_user_all(si_mod_t
*si
)
171 return cache_fetch_list(si
, CATEGORY_USER
);
174 __private_extern__ si_item_t
*
175 cache_group_byname(si_mod_t
*si
, const char *name
)
177 return cache_fetch_item(si
, CATEGORY_GROUP
, name
, 0, SEL_NAME
);
180 __private_extern__ si_item_t
*
181 cache_group_bygid(si_mod_t
*si
, gid_t gid
)
183 return cache_fetch_item(si
, CATEGORY_GROUP
, NULL
, gid
, SEL_NUMBER
);
186 __private_extern__ si_list_t
*
187 cache_group_all(si_mod_t
*si
)
189 return cache_fetch_list(si
, CATEGORY_GROUP
);
192 __private_extern__ si_item_t
*
193 cache_grouplist(si_mod_t
*si
, const char *name
)
195 return cache_fetch_item(si
, CATEGORY_GROUPLIST
, name
, 0, SEL_NAME
);
198 __private_extern__ si_item_t
*
199 cache_alias_byname(si_mod_t
*si
, const char *name
)
201 return cache_fetch_item(si
, CATEGORY_ALIAS
, name
, 0, SEL_NAME
);
204 __private_extern__ si_list_t
*
205 cache_alias_all(si_mod_t
*si
)
207 return cache_fetch_list(si
, CATEGORY_ALIAS
);
210 __private_extern__ si_item_t
*
211 cache_host_byname(si_mod_t
*si
, const char *name
, int af
, uint32_t *err
)
215 if (err
!= NULL
) *err
= SI_STATUS_NO_ERROR
;
218 if (af
== AF_INET
) item
= cache_fetch_item(si
, CATEGORY_HOST_IPV4
, name
, af
, SEL_NAME
);
219 else item
= cache_fetch_item(si
, CATEGORY_HOST_IPV6
, name
, af
, SEL_NAME
);
221 if ((item
== NULL
) && (err
!= NULL
) && (*err
== 0)) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
226 __private_extern__ si_item_t
*
227 cache_host_byaddr(si_mod_t
*si
, const void *addr
, int af
, uint32_t *err
)
231 if (err
!= NULL
) *err
= SI_STATUS_NO_ERROR
;
234 if (af
== AF_INET
) item
= cache_fetch_item(si
, CATEGORY_HOST_IPV4
, addr
, af
, SEL_NUMBER
);
235 else item
= cache_fetch_item(si
, CATEGORY_HOST_IPV6
, addr
, af
, SEL_NUMBER
);
237 if ((item
== NULL
) && (err
!= NULL
) && (*err
== 0)) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
242 __private_extern__ si_list_t
*
243 cache_host_all(si_mod_t
*si
)
245 return cache_fetch_list(si
, CATEGORY_HOST
);
248 __private_extern__ si_item_t
*
249 cache_network_byname(si_mod_t
*si
, const char *name
)
251 return cache_fetch_item(si
, CATEGORY_NETWORK
, name
, 0, SEL_NAME
);
254 __private_extern__ si_item_t
*
255 cache_network_byaddr(si_mod_t
*si
, uint32_t addr
)
257 return cache_fetch_item(si
, CATEGORY_NETWORK
, NULL
, addr
, SEL_NUMBER
);
260 __private_extern__ si_list_t
*
261 cache_network_all(si_mod_t
*si
)
263 return cache_fetch_list(si
, CATEGORY_NETWORK
);
266 __private_extern__ si_item_t
*
267 cache_service_byname(si_mod_t
*si
, const char *name
, const char *proto
)
271 if (name
== NULL
) return NULL
;
272 if (proto
== NULL
) return cache_fetch_item(si
, CATEGORY_SERVICE
, name
, 0, SEL_NAME
);
275 if (string_equal(proto
, "tcp")) pn
= 2;
277 return cache_fetch_item(si
, CATEGORY_SERVICE
, name
, pn
, SEL_NAME
);
280 __private_extern__ si_item_t
*
281 cache_service_byport(si_mod_t
*si
, int port
, const char *proto
)
283 return cache_fetch_item(si
, CATEGORY_SERVICE
, proto
, port
, SEL_NUMBER
);
286 __private_extern__ si_list_t
*
287 cache_service_all(si_mod_t
*si
)
289 return cache_fetch_list(si
, CATEGORY_SERVICE
);
292 __private_extern__ si_item_t
*
293 cache_protocol_byname(si_mod_t
*si
, const char *name
)
295 return cache_fetch_item(si
, CATEGORY_PROTOCOL
, name
, 0, SEL_NAME
);
298 __private_extern__ si_item_t
*
299 cache_protocol_bynumber(si_mod_t
*si
, int number
)
301 return cache_fetch_item(si
, CATEGORY_PROTOCOL
, NULL
, number
, SEL_NUMBER
);
304 __private_extern__ si_list_t
*
305 cache_protocol_all(si_mod_t
*si
)
307 return cache_fetch_list(si
, CATEGORY_PROTOCOL
);
310 __private_extern__ si_item_t
*
311 cache_rpc_byname(si_mod_t
*si
, const char *name
)
313 return cache_fetch_item(si
, CATEGORY_RPC
, name
, 0, SEL_NAME
);
316 __private_extern__ si_item_t
*
317 cache_rpc_bynumber(si_mod_t
*si
, int number
)
319 return cache_fetch_item(si
, CATEGORY_RPC
, NULL
, number
, SEL_NUMBER
);
322 __private_extern__ si_list_t
*
323 cache_rpc_all(si_mod_t
*si
)
325 return cache_fetch_list(si
, CATEGORY_RPC
);
328 __private_extern__ si_item_t
*
329 cache_fs_byspec(si_mod_t
*si
, const char *name
)
331 return cache_fetch_item(si
, CATEGORY_FS
, name
, 0, SEL_NAME
);
334 __private_extern__ si_item_t
*
335 cache_fs_byfile(si_mod_t
*si
, const char *name
)
337 return cache_fetch_item(si
, CATEGORY_FS
, name
, 0, SEL_NUMBER
);
340 __private_extern__ si_list_t
*
341 cache_fs_all(si_mod_t
*si
)
343 return cache_fetch_list(si
, CATEGORY_FS
);
346 __private_extern__ si_item_t
*
347 cache_mac_byname(si_mod_t
*si
, const char *name
)
349 return cache_fetch_item(si
, CATEGORY_MAC
, name
, 0, SEL_NAME
);
352 __private_extern__ si_item_t
*
353 cache_mac_bymac(si_mod_t
*si
, const char *mac
)
355 return cache_fetch_item(si
, CATEGORY_MAC
, mac
, 0, SEL_NUMBER
);
358 __private_extern__ si_list_t
*
359 cache_mac_all(si_mod_t
*si
)
361 return cache_fetch_list(si
, CATEGORY_MAC
);
364 __private_extern__ si_item_t
*
365 cache_nameinfo(si_mod_t
*si
, const struct sockaddr
*sa
, int flags
, uint32_t *err
)
368 * Caching of getnameinfo(3) is not supported.
369 * Only the individual host_byaddr and serv_byaddr responses will be cached.
370 * This is because getnameinfo(3) returns numeric responses instead of
371 * failing, which would poison the cache.
373 if (err
) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
377 __private_extern__
void
378 cache_close(si_mod_t
*si
)
380 cache_si_private_t
*pp
;
383 if (si
== NULL
) return;
385 pp
= (cache_si_private_t
*)si
->private;
386 if (pp
== NULL
) return;
388 for (i
= 0; i
< CACHE_COUNT
; i
++)
390 si_list_release(pp
->cache_store
[i
].list
);
392 for (j
= 0; j
< CACHE_MAX
; j
++)
394 si_item_release(pp
->cache_store
[i
].item
[j
]);
395 pp
->cache_store
[i
].item
[j
] = NULL
;
402 __private_extern__ si_mod_t
*
403 si_module_static_cache()
407 cache_si_private_t
*pp
;
409 out
= (si_mod_t
*)calloc(1, sizeof(si_mod_t
));
410 outname
= strdup("cache");
411 pp
= (cache_si_private_t
*)calloc(1, sizeof(cache_si_private_t
));
413 if ((out
== NULL
) || (outname
== NULL
) || (pp
== NULL
))
415 if (out
!= NULL
) free(out
);
416 if (outname
!= NULL
) free(outname
);
417 if (pp
!= NULL
) free(pp
);
428 out
->sim_close
= cache_close
;
430 out
->sim_user_byname
= cache_user_byname
;
431 out
->sim_user_byuid
= cache_user_byuid
;
432 out
->sim_user_all
= cache_user_all
;
434 out
->sim_group_byname
= cache_group_byname
;
435 out
->sim_group_bygid
= cache_group_bygid
;
436 out
->sim_group_all
= cache_group_all
;
438 out
->sim_grouplist
= cache_grouplist
;
440 /* no netgroup support */
441 out
->sim_netgroup_byname
= NULL
;
442 out
->sim_in_netgroup
= NULL
;
444 out
->sim_alias_byname
= cache_alias_byname
;
445 out
->sim_alias_all
= cache_alias_all
;
447 out
->sim_host_byname
= cache_host_byname
;
448 out
->sim_host_byaddr
= cache_host_byaddr
;
449 out
->sim_host_all
= cache_host_all
;
451 out
->sim_network_byname
= cache_network_byname
;
452 out
->sim_network_byaddr
= cache_network_byaddr
;
453 out
->sim_network_all
= cache_network_all
;
455 out
->sim_service_byname
= cache_service_byname
;
456 out
->sim_service_byport
= cache_service_byport
;
457 out
->sim_service_all
= cache_service_all
;
459 out
->sim_protocol_byname
= cache_protocol_byname
;
460 out
->sim_protocol_bynumber
= cache_protocol_bynumber
;
461 out
->sim_protocol_all
= cache_protocol_all
;
463 out
->sim_rpc_byname
= cache_rpc_byname
;
464 out
->sim_rpc_bynumber
= cache_rpc_bynumber
;
465 out
->sim_rpc_all
= cache_rpc_all
;
467 out
->sim_fs_byspec
= cache_fs_byspec
;
468 out
->sim_fs_byfile
= cache_fs_byfile
;
469 out
->sim_fs_all
= cache_fs_all
;
471 out
->sim_mac_byname
= cache_mac_byname
;
472 out
->sim_mac_bymac
= cache_mac_bymac
;
473 out
->sim_mac_all
= cache_mac_all
;
475 /* no addrinfo support */
476 out
->sim_wants_addrinfo
= NULL
;
477 out
->sim_addrinfo
= NULL
;
479 /* no nameinfo support */
480 out
->sim_nameinfo
= cache_nameinfo
;
485 __private_extern__
void
486 si_cache_add_item(si_mod_t
*si
, si_mod_t
*src
, si_item_t
*item
)
488 cache_si_private_t
*pp
;
491 if (si
== NULL
) return;
492 if (src
== NULL
) return;
493 if (item
== NULL
) return;
495 if (si
== src
) return;
497 if (src
->name
== NULL
) return;
498 if (string_equal(src
->name
, "cache")) return;
501 if ((cat
< 0) || (cat
>= CACHE_COUNT
)) return;
503 pp
= (cache_si_private_t
*)si
->private;
504 if (pp
== NULL
) return;
506 OSSpinLockLock(&(pp
->cache_store
[cat
].lock
));
508 head
= pp
->cache_store
[item
->type
].head
;
510 si_item_release(pp
->cache_store
[item
->type
].item
[head
]);
511 pp
->cache_store
[item
->type
].item
[head
] = si_item_retain(item
);
514 if (head
>= CACHE_MAX
) head
= 0;
515 pp
->cache_store
[item
->type
].head
= head
;
517 OSSpinLockUnlock(&(pp
->cache_store
[cat
].lock
));
520 __private_extern__
void
521 si_cache_add_list(si_mod_t
*si
, si_mod_t
*src
, si_list_t
*list
)
523 cache_si_private_t
*pp
;
527 if (si
== NULL
) return;
528 if (src
== NULL
) return;
529 if (list
== NULL
) return;
530 if (list
->count
== 0) return;
532 if (si
== src
) return;
534 if (src
->name
== NULL
) return;
535 if (string_equal(src
->name
, "cache")) return;
537 item
= list
->entry
[0];
538 if (item
== NULL
) return;
541 if ((cat
< 0) || (cat
>= CACHE_COUNT
)) return;
543 pp
= (cache_si_private_t
*)si
->private;
544 if (pp
== NULL
) return;
546 OSSpinLockLock(&(pp
->cache_store
[cat
].lock
));
548 si_list_release(pp
->cache_store
[item
->type
].list
);
549 pp
->cache_store
[item
->type
].list
= si_list_retain(list
);
551 OSSpinLockUnlock(&(pp
->cache_store
[cat
].lock
));