Libinfo-324.1.tar.gz
[apple/libinfo.git] / lookup.subproj / si_module.c
1 /*
2 * Copyright (c) 2008-2009 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 <sys/types.h>
25 #include <sys/socket.h>
26 #include <net/ethernet.h>
27 #include <libkern/OSAtomic.h>
28 #include <dlfcn.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <errno.h>
32 #include <pthread.h>
33 #include <mach/mach.h>
34
35 #include "si_module.h"
36
37 #define PLUGIN_DIR_PATH "/usr/lib/info"
38 #define PLUGIN_BUNDLE_SUFFIX "so"
39
40 #define WORKUNIT_CALL_ACTIVE 0x00000001
41 #define WORKUNIT_THREAD_ACTIVE 0x00000002
42 #define WORKUNIT_RETURNS_LIST 0x00000004
43
44 typedef struct si_async_workunit_s
45 {
46 si_mod_t *si;
47 uint32_t call;
48 char *str1;
49 char *str2;
50 uint32_t num1;
51 uint32_t num2;
52 uint32_t num3;
53 uint32_t num4;
54 uint32_t err;
55 /* async support below */
56 uint32_t flags;
57 void *callback;
58 void *context;
59 mach_port_t port;
60 mach_port_t send;
61 si_item_t *resitem;
62 si_list_t *reslist;
63 struct si_async_workunit_s *next;
64 } si_async_workunit_t;
65
66 static si_mod_t **module_list = NULL;
67 static uint32_t module_count = 0;
68 static pthread_mutex_t module_mutex = PTHREAD_MUTEX_INITIALIZER;
69 static si_async_workunit_t *si_async_worklist = NULL;
70
71 __private_extern__ si_mod_t *si_module_static_search();
72 __private_extern__ si_mod_t *si_module_static_file();
73 __private_extern__ si_mod_t *si_module_static_cache();
74 __private_extern__ si_mod_t *si_module_static_mdns();
75 #ifdef DS_AVAILABLE
76 __private_extern__ si_mod_t *si_module_static_ds();
77 #endif
78
79 static void *
80 si_mod_dlsym(void *so, const char *name, const char *sym)
81 {
82 char *str;
83 void *out;
84
85 if ((so == NULL) || (name == NULL) || (sym == NULL)) return NULL;
86
87 str = NULL;
88 asprintf(&str, "%s_%s", name, sym);
89 if (str == NULL) return NULL;
90
91 out = dlsym(so, str);
92 free(str);
93 return out;
94 }
95
96 static si_mod_t *
97 si_mod_static(const char *name)
98 {
99 if (name == NULL) return NULL;
100
101 if (string_equal(name, "search")) return si_module_static_search();
102 if (string_equal(name, "file")) return si_module_static_file();
103 if (string_equal(name, "cache")) return si_module_static_cache();
104 if (string_equal(name, "mdns")) return si_module_static_mdns();
105 #ifdef DS_AVAILABLE
106 if (string_equal(name, "ds")) return si_module_static_ds();
107 #endif
108 return NULL;
109 }
110
111 __private_extern__ si_mod_t *
112 si_module_with_path(const char *path, const char *name)
113 {
114 void *so;
115 int (*si_sym_init)(si_mod_t *);
116 void (*si_sym_close)(si_mod_t *);
117 int status;
118 si_mod_t *out;
119 char *outname;
120
121 if ((path == NULL) || (name == NULL))
122 {
123 errno = EINVAL;
124 return NULL;
125 }
126
127 so = dlopen(path, RTLD_LOCAL);
128 if (so == NULL) return NULL;
129
130 si_sym_init = si_mod_dlsym(so, name, "init");
131 if (si_sym_init == NULL)
132 {
133 dlclose(so);
134 errno = ECONNREFUSED;
135 return NULL;
136 }
137
138 si_sym_close = si_mod_dlsym(so, name, "close");
139 if (si_sym_close == NULL)
140 {
141 dlclose(so);
142 errno = ECONNREFUSED;
143 return NULL;
144 }
145
146 out = (si_mod_t *)calloc(1, sizeof(si_mod_t));
147 outname = strdup(name);
148
149 if ((out == NULL) || (outname == NULL))
150 {
151 if (out != NULL) free(out);
152 if (outname != NULL) free(outname);
153 dlclose(so);
154 errno = ENOMEM;
155 return NULL;
156 }
157
158 out->name = outname;
159 out->refcount = 1;
160 out->bundle = so;
161
162 status = si_sym_init(out);
163 if (status != 0)
164 {
165 dlclose(so);
166 free(out);
167 free(outname);
168 errno = ECONNREFUSED;
169 return NULL;
170 }
171
172 return out;
173 }
174
175 si_mod_t *
176 si_module_with_name(const char *name)
177 {
178 uint32_t i;
179 char *path;
180 si_mod_t *out;
181
182 if (name == NULL)
183 {
184 errno = EINVAL;
185 return NULL;
186 }
187
188 pthread_mutex_lock(&module_mutex);
189
190 for (i = 0; i < module_count; i++)
191 {
192 if (string_equal(module_list[i]->name, name))
193 {
194 si_module_retain(module_list[i]);
195 pthread_mutex_unlock(&module_mutex);
196 return module_list[i];
197 }
198 }
199
200 pthread_mutex_unlock(&module_mutex);
201 out = si_mod_static(name);
202 pthread_mutex_lock(&module_mutex);
203
204 if (out == NULL)
205 {
206 path = NULL;
207
208 /* mdns lives in dns.so */
209 asprintf(&path, "%s/%s.%s", PLUGIN_DIR_PATH, name, PLUGIN_BUNDLE_SUFFIX);
210
211 if (path == NULL)
212 {
213 errno = ENOMEM;
214 pthread_mutex_unlock(&module_mutex);
215 return NULL;
216 }
217
218 out = si_module_with_path(path, name);
219 free(path);
220 }
221
222 if (out == NULL)
223 {
224 pthread_mutex_unlock(&module_mutex);
225 return NULL;
226 }
227
228 /* add out to module_list */
229 if (module_count == 0)
230 {
231 module_list = (si_mod_t **)calloc(1, sizeof(si_mod_t *));
232 }
233 else
234 {
235 module_list = (si_mod_t **)reallocf(module_list, (module_count + 1) * sizeof(si_mod_t *));
236 }
237
238 if (module_list == NULL)
239 {
240 pthread_mutex_unlock(&module_mutex);
241 return out;
242 }
243
244 module_list[module_count] = out;
245 module_count++;
246
247 pthread_mutex_unlock(&module_mutex);
248
249 return out;
250 }
251
252 __private_extern__ si_mod_t *
253 si_module_retain(si_mod_t *si)
254 {
255 if (si == NULL) return NULL;
256
257 OSAtomicIncrement32Barrier(&si->refcount);
258
259 return si;
260 }
261
262 void
263 si_module_release(si_mod_t *si)
264 {
265 int32_t i;
266
267 if (si == NULL) return;
268
269 i = OSAtomicDecrement32Barrier(&si->refcount);
270 if (i > 0) return;
271
272 pthread_mutex_lock(&module_mutex);
273
274 for (i = 0; (i < module_count) && (module_list[i] != si); i++);
275 if (i >= module_count)
276 {
277 pthread_mutex_unlock(&module_mutex);
278 return;
279 }
280
281 if (module_count == 1)
282 {
283 free(module_list);
284 module_list = NULL;
285 module_count = 0;
286 pthread_mutex_unlock(&module_mutex);
287 return;
288 }
289
290 for (i++; i < module_count; i++) module_list[i - 1] = module_list[i];
291 module_count--;
292 module_list = (si_mod_t **)reallocf(module_list, module_count * sizeof(si_mod_t *));
293 if (module_list == NULL) module_count = 0;
294
295 pthread_mutex_unlock(&module_mutex);
296
297 if (si->sim_close != NULL) si->sim_close(si);
298 if (si->bundle != NULL) dlclose(si->bundle);
299 if (si->name != NULL) free(si->name);
300 free(si);
301 }
302
303 __private_extern__ const char *
304 si_module_name(si_mod_t *si)
305 {
306 if (si == NULL) return NULL;
307
308 return si->name;
309 }
310
311 __private_extern__ int
312 si_module_vers(si_mod_t *si)
313 {
314 if (si == NULL) return 0;
315
316 return si->vers;
317 }
318
319 __private_extern__ int
320 si_item_match(si_item_t *item, int cat, const void *name, uint32_t num, int which)
321 {
322 int i;
323 union
324 {
325 char *x;
326 struct passwd *u;
327 struct group *g;
328 struct grouplist_s *l;
329 struct aliasent *a;
330 struct hostent *h;
331 struct netent *n;
332 struct servent *s;
333 struct protoent *p;
334 struct rpcent *r;
335 struct fstab *f;
336 struct mac_s *m;
337 } ent;
338
339 if (item == NULL) return 0;
340 if (which == SEL_ALL) return 1;
341 if ((which == SEL_NAME) && (name == NULL)) return 0;
342
343 ent.x = (char *)((uintptr_t)item + sizeof(si_item_t));
344
345 switch (cat)
346 {
347 case CATEGORY_USER:
348 {
349 if ((which == SEL_NAME) && (string_equal(name, ent.u->pw_name))) return 1;
350 else if ((which == SEL_NUMBER) && (num == (uint32_t)ent.u->pw_uid)) return 1;
351 return 0;
352 }
353 case CATEGORY_GROUP:
354 {
355 if ((which == SEL_NAME) && (string_equal(name, ent.g->gr_name))) return 1;
356 else if ((which == SEL_NUMBER) && (num == (uint32_t)ent.g->gr_gid)) return 1;
357 return 0;
358 }
359 case CATEGORY_GROUPLIST:
360 {
361 if ((which == SEL_NAME) && (string_equal(name, ent.l->gl_user))) return 1;
362 return 0;
363 }
364 case CATEGORY_ALIAS:
365 {
366 if ((which == SEL_NAME) && (string_equal(name, ent.a->alias_name))) return 1;
367 return 0;
368 }
369 case CATEGORY_HOST_IPV4:
370 case CATEGORY_HOST_IPV6:
371 {
372 /* N.B. address family is passed in num variable */
373 if (ent.h->h_addrtype != num) return 0;
374 if (which == SEL_NAME)
375 {
376 if (string_equal(name, ent.h->h_name)) return 1;
377 if (ent.h->h_aliases != NULL)
378 {
379 for (i = 0; ent.h->h_aliases[i] != NULL; i++)
380 {
381 if (string_equal(name, ent.h->h_aliases[i])) return 1;
382 }
383 }
384 }
385 else if (which == SEL_NUMBER)
386 {
387 if (memcmp(name, ent.h->h_addr_list[0], ent.h->h_length) == 0) return 1;
388 }
389 return 0;
390 }
391 case CATEGORY_NETWORK:
392 {
393 if (which == SEL_NAME)
394 {
395 if (string_equal(name, ent.n->n_name)) return 1;
396 if (ent.n->n_aliases != NULL)
397 {
398 for (i = 0; ent.n->n_aliases[i] != NULL; i++)
399 {
400 if (string_equal(name, ent.n->n_aliases[i])) return 1;
401 }
402 }
403 }
404 else if (which == SEL_NUMBER)
405 {
406 if (num == ent.n->n_net) return 1;
407 }
408 return 0;
409 }
410 case CATEGORY_SERVICE:
411 {
412 if (which == SEL_NAME)
413 {
414 /* N.B. for SEL_NAME, num is 0 (don't care), 1 (udp) or 2 (tcp) */
415 if ((num == 1) && (string_not_equal("udp", ent.s->s_proto))) return 0;
416 if ((num == 2) && (string_not_equal("tcp", ent.s->s_proto))) return 0;
417
418 if (string_equal(name, ent.s->s_name)) return 1;
419 if (ent.s->s_aliases != NULL)
420 {
421 for (i = 0; ent.s->s_aliases[i] != NULL; i++)
422 {
423 if (string_equal(name, ent.s->s_aliases[i])) return 1;
424 }
425 }
426 }
427 else if (which == SEL_NUMBER)
428 {
429 /* N.B. for SEL_NUMBER, protocol is sent in name variable */
430 if ((name != NULL) && (string_not_equal(name, ent.s->s_proto))) return 0;
431 if (num == ent.s->s_port) return 1;
432 }
433 return 0;
434 }
435 case CATEGORY_PROTOCOL:
436 {
437 if (which == SEL_NAME)
438 {
439 if (string_equal(name, ent.p->p_name)) return 1;
440 if (ent.p->p_aliases != NULL)
441 {
442 for (i = 0; ent.p->p_aliases[i] != NULL; i++)
443 {
444 if (string_equal(name, ent.p->p_aliases[i])) return 1;
445 }
446 }
447 }
448 else if (which == SEL_NUMBER)
449 {
450 if (num == ent.p->p_proto) return 1;
451 }
452 return 0;
453 }
454 case CATEGORY_RPC:
455 {
456 if (which == SEL_NAME)
457 {
458 if (string_equal(name, ent.r->r_name)) return 1;
459 if (ent.r->r_aliases != NULL)
460 {
461 for (i = 0; ent.r->r_aliases[i] != NULL; i++)
462 {
463 if (string_equal(name, ent.r->r_aliases[i])) return 1;
464 }
465 }
466 }
467 else if (which == SEL_NUMBER)
468 {
469 if (num == ent.r->r_number) return 1;
470 }
471 return 0;
472 }
473 case CATEGORY_FS:
474 {
475 if ((which == SEL_NAME) && (string_equal(name, ent.f->fs_spec))) return 1;
476 if ((which == SEL_NUMBER) && (string_equal(name, ent.f->fs_file))) return 1;
477 return 0;
478 }
479 case CATEGORY_MAC:
480 {
481 if ((which == SEL_NAME) && (string_equal(name, ent.m->host))) return 1;
482 if ((which == SEL_NUMBER) && (string_equal(name, ent.m->mac))) return 1;
483 return 0;
484 }
485 default: return 0;
486 }
487
488 return 0;
489 }
490
491 __private_extern__ int
492 si_item_is_valid(si_item_t *item)
493 {
494 si_mod_t *si;
495
496 if (item == NULL) return 0;
497
498 si = item->src;
499
500 if (si == NULL) return 0;
501 if (si->sim_is_valid == NULL) return 0;
502
503 return si->sim_is_valid(si, item);
504 }
505
506 __private_extern__ si_item_t *
507 si_user_byname(si_mod_t *si, const char *name)
508 {
509 if (si == NULL) return NULL;
510 if (si->sim_user_byname == NULL) return NULL;
511 return si->sim_user_byname(si, name);
512 }
513
514 __private_extern__ si_item_t *
515 si_user_byuid(si_mod_t *si, uid_t uid)
516 {
517 if (si == NULL) return NULL;
518 if (si->sim_user_byuid == NULL) return NULL;
519 return si->sim_user_byuid(si, uid);
520 }
521
522 __private_extern__ si_list_t *
523 si_user_all(si_mod_t *si)
524 {
525 if (si == NULL) return NULL;
526 if (si->sim_user_all == NULL) return NULL;
527 return si->sim_user_all(si);
528 }
529
530 __private_extern__ si_item_t *
531 si_group_byname(si_mod_t *si, const char *name)
532 {
533 if (si == NULL) return NULL;
534 if (si->sim_group_byname == NULL) return NULL;
535 return si->sim_group_byname(si, name);
536 }
537
538 __private_extern__ si_item_t *
539 si_group_bygid(si_mod_t *si, gid_t gid)
540 {
541 if (si == NULL) return NULL;
542 if (si->sim_group_bygid == NULL) return NULL;
543 return si->sim_group_bygid(si, gid);
544 }
545
546 __private_extern__ si_list_t *
547 si_group_all(si_mod_t *si)
548 {
549 if (si == NULL) return NULL;
550 if (si->sim_group_all == NULL) return NULL;
551 return si->sim_group_all(si);
552 }
553
554 __private_extern__ si_item_t *
555 si_grouplist(si_mod_t *si, const char *name)
556 {
557 if (si == NULL) return NULL;
558 if (si->sim_grouplist == NULL) return NULL;
559 return si->sim_grouplist(si, name);
560 }
561
562 __private_extern__ si_list_t *
563 si_netgroup_byname(struct si_mod_s *si, const char *name)
564 {
565 if (si == NULL) return NULL;
566 if (si->sim_netgroup_byname == NULL) return NULL;
567 return si->sim_netgroup_byname(si, name);
568 }
569
570 __private_extern__ int
571 si_in_netgroup(struct si_mod_s *si, const char *name, const char *host, const char *user, const char *domain)
572 {
573 if (si == NULL) return 0;
574 if (si->sim_in_netgroup == NULL) return 0;
575 return si->sim_in_netgroup(si, name, host, user, domain);
576 }
577
578 __private_extern__ si_item_t *
579 si_alias_byname(si_mod_t *si, const char *name)
580 {
581 if (si == NULL) return NULL;
582 if (si->sim_alias_byname == NULL) return NULL;
583 return si->sim_alias_byname(si, name);
584 }
585
586 __private_extern__ si_list_t *
587 si_alias_all(si_mod_t *si)
588 {
589 if (si == NULL) return NULL;
590 if (si->sim_alias_all == NULL) return NULL;
591 return si->sim_alias_all(si);
592 }
593
594 __private_extern__ si_item_t *
595 si_host_byname(si_mod_t *si, const char *name, int af, uint32_t *err)
596 {
597 if (si == NULL) return NULL;
598 if (si->sim_host_byname == NULL) return NULL;
599 return si->sim_host_byname(si, name, af, err);
600 }
601
602 __private_extern__ si_item_t *
603 si_host_byaddr(si_mod_t *si, const void *addr, int af, uint32_t *err)
604 {
605 if (si == NULL) return NULL;
606 if (si->sim_host_byaddr == NULL) return NULL;
607 return si->sim_host_byaddr(si, addr, af, err);
608 }
609
610 __private_extern__ si_list_t *
611 si_host_all(si_mod_t *si)
612 {
613 if (si == NULL) return NULL;
614 if (si->sim_host_all == NULL) return NULL;
615 return si->sim_host_all(si);
616 }
617
618 __private_extern__ si_item_t *
619 si_mac_byname(struct si_mod_s *si, const char *name)
620 {
621 if (si == NULL) return NULL;
622 if (si->sim_mac_byname == NULL) return NULL;
623 return si->sim_mac_byname(si, name);
624 }
625
626 __private_extern__ si_item_t *
627 si_mac_bymac(struct si_mod_s *si, const char *mac)
628 {
629 if (si == NULL) return NULL;
630 if (si->sim_mac_bymac == NULL) return NULL;
631 return si->sim_mac_bymac(si, mac);
632 }
633
634 __private_extern__ si_list_t *
635 si_mac_all(si_mod_t *si)
636 {
637 if (si == NULL) return NULL;
638 if (si->sim_mac_all == NULL) return NULL;
639 return si->sim_mac_all(si);
640 }
641
642 __private_extern__ si_item_t *
643 si_network_byname(si_mod_t *si, const char *name)
644 {
645 if (si == NULL) return NULL;
646 if (si->sim_network_byname == NULL) return NULL;
647 return si->sim_network_byname(si, name);
648 }
649
650 __private_extern__ si_item_t *
651 si_network_byaddr(si_mod_t *si, uint32_t addr)
652 {
653 if (si == NULL) return NULL;
654 if (si->sim_network_byaddr == NULL) return NULL;
655 return si->sim_network_byaddr(si, addr);
656 }
657
658 __private_extern__ si_list_t *
659 si_network_all(si_mod_t *si)
660 {
661 if (si == NULL) return NULL;
662 if (si->sim_network_all == NULL) return NULL;
663 return si->sim_network_all(si);
664 }
665
666 __private_extern__ si_item_t *
667 si_service_byname(si_mod_t *si, const char *name, const char *proto)
668 {
669 if (si == NULL) return NULL;
670 if (si->sim_service_byname == NULL) return NULL;
671 return si->sim_service_byname(si, name, proto);
672 }
673
674 __private_extern__ si_item_t *
675 si_service_byport(si_mod_t *si, int port, const char *proto)
676 {
677 if (si == NULL) return NULL;
678 if (si->sim_service_byport == NULL) return NULL;
679 return si->sim_service_byport(si, port, proto);
680 }
681
682 __private_extern__ si_list_t *
683 si_service_all(si_mod_t *si)
684 {
685 if (si == NULL) return NULL;
686 if (si->sim_service_all == NULL) return NULL;
687 return si->sim_service_all(si);
688 }
689
690 __private_extern__ si_item_t *
691 si_protocol_byname(si_mod_t *si, const char *name)
692 {
693 if (si == NULL) return NULL;
694 if (si->sim_protocol_byname == NULL) return NULL;
695 return si->sim_protocol_byname(si, name);
696 }
697
698 __private_extern__ si_item_t *
699 si_protocol_bynumber(si_mod_t *si, uint32_t number)
700 {
701 if (si == NULL) return NULL;
702 if (si->sim_protocol_bynumber == NULL) return NULL;
703 return si->sim_protocol_bynumber(si, number);
704 }
705
706 __private_extern__ si_list_t *
707 si_protocol_all(si_mod_t *si)
708 {
709 if (si == NULL) return NULL;
710 if (si->sim_protocol_all == NULL) return NULL;
711 return si->sim_protocol_all(si);
712 }
713
714 __private_extern__ si_item_t *
715 si_rpc_byname(si_mod_t *si, const char *name)
716 {
717 if (si == NULL) return NULL;
718 if (si->sim_rpc_byname == NULL) return NULL;
719 return si->sim_rpc_byname(si, name);
720 }
721
722 __private_extern__ si_item_t *
723 si_rpc_bynumber(si_mod_t *si, int number)
724 {
725 if (si == NULL) return NULL;
726 if (si->sim_rpc_bynumber == NULL) return NULL;
727 return si->sim_rpc_bynumber(si, number);
728 }
729
730 __private_extern__ si_list_t *
731 si_rpc_all(si_mod_t *si)
732 {
733 if (si == NULL) return NULL;
734 if (si->sim_rpc_all == NULL) return NULL;
735 return si->sim_rpc_all(si);
736 }
737
738 __private_extern__ si_item_t *
739 si_fs_byspec(si_mod_t *si, const char *spec)
740 {
741 if (si == NULL) return NULL;
742 if (si->sim_fs_byspec == NULL) return NULL;
743 return si->sim_fs_byspec(si, spec);
744 }
745
746 __private_extern__ si_item_t *
747 si_fs_byfile(si_mod_t *si, const char *file)
748 {
749 if (si == NULL) return NULL;
750 if (si->sim_fs_byfile == NULL) return NULL;
751 return si->sim_fs_byfile(si, file);
752 }
753
754 __private_extern__ si_list_t *
755 si_fs_all(si_mod_t *si)
756 {
757 if (si == NULL) return NULL;
758 if (si->sim_fs_all == NULL) return NULL;
759 return si->sim_fs_all(si);
760 }
761
762 __private_extern__ si_item_t *
763 si_item_call(struct si_mod_s *si, int call, const char *str1, const char *str2, uint32_t num1, uint32_t num2, uint32_t *err)
764 {
765 if (si == NULL) return NULL;
766
767 switch (call)
768 {
769 case SI_CALL_USER_BYNAME: return si_user_byname(si, str1);
770 case SI_CALL_USER_BYUID: return si_user_byuid(si, (uid_t)num1);
771 case SI_CALL_GROUP_BYNAME: return si_group_byname(si, str1);
772 case SI_CALL_GROUP_BYGID: return si_group_bygid(si, (gid_t)num1);
773 case SI_CALL_GROUPLIST: return si_grouplist(si, str1);
774 case SI_CALL_ALIAS_BYNAME: return si_alias_byname(si, str1);
775 case SI_CALL_HOST_BYNAME: return si_host_byname(si, str1, num1, err);
776 case SI_CALL_HOST_BYADDR: return si_host_byaddr(si, (void *)str1, num1, err);
777 case SI_CALL_NETWORK_BYNAME: return si_network_byname(si, str1);
778 case SI_CALL_NETWORK_BYADDR: return si_network_byaddr(si, num1);
779 case SI_CALL_SERVICE_BYNAME: return si_service_byname(si, str1, str2);
780 case SI_CALL_SERVICE_BYPORT: return si_service_byport(si, num1, str2);
781 case SI_CALL_PROTOCOL_BYNAME: return si_protocol_byname(si, str1);
782 case SI_CALL_PROTOCOL_BYNUMBER: return si_protocol_bynumber(si, num1);
783 case SI_CALL_RPC_BYNAME: return si_network_byname(si, str1);
784 case SI_CALL_RPC_BYNUMBER: return si_rpc_bynumber(si, num1);
785 case SI_CALL_FS_BYSPEC: return si_fs_byspec(si, str1);
786 case SI_CALL_FS_BYFILE: return si_fs_byfile(si, str1);
787 case SI_CALL_NAMEINFO: return si_nameinfo(si, (const struct sockaddr *)str1, num1, err);
788 case SI_CALL_IPNODE_BYNAME: return si_ipnode_byname(si, (const char *)str1, num1, num2, err);
789 case SI_CALL_MAC_BYNAME: return si_mac_byname(si, (const char *)str1);
790 case SI_CALL_MAC_BYMAC: return si_mac_bymac(si, (const char *)str1);
791
792 /* Support for DNS async calls */
793 case SI_CALL_DNS_QUERY:
794 case SI_CALL_DNS_SEARCH:
795 {
796 if (si->sim_item_call == NULL) return NULL;
797 return si->sim_item_call(si, call, str1, str2, num1, num2, err);
798 }
799
800 default: return NULL;
801 }
802
803 return NULL;
804 }
805
806 __private_extern__ si_list_t *
807 si_list_call(struct si_mod_s *si, int call, const char *str1, const char *str2, uint32_t num1, uint32_t num2, uint32_t num3, uint32_t num4, uint32_t *err)
808 {
809 if (si == NULL) return NULL;
810
811 switch (call)
812 {
813 case SI_CALL_USER_ALL: return si_user_all(si);
814 case SI_CALL_GROUP_ALL: return si_group_all(si);
815 case SI_CALL_ALIAS_ALL: return si_alias_all(si);
816 case SI_CALL_HOST_ALL: return si_host_all(si);
817 case SI_CALL_NETWORK_ALL: return si_network_all(si);
818 case SI_CALL_SERVICE_ALL: return si_service_all(si);
819 case SI_CALL_PROTOCOL_ALL: return si_protocol_all(si);
820 case SI_CALL_RPC_ALL: return si_rpc_all(si);
821 case SI_CALL_FS_ALL: return si_fs_all(si);
822 case SI_CALL_MAC_ALL: return si_mac_all(si);
823 case SI_CALL_ADDRINFO: return si_addrinfo(si, str1, str2, num1, num2, num3, num4, err);
824 default: return NULL;
825 }
826
827 return NULL;
828 }
829
830 static void
831 si_async_worklist_add_unit(si_async_workunit_t *r)
832 {
833 pthread_mutex_lock(&module_mutex);
834 r->next = si_async_worklist;
835 si_async_worklist = r;
836 pthread_mutex_unlock(&module_mutex);
837 }
838
839 static void
840 si_async_worklist_remove_unit(si_async_workunit_t *r)
841 {
842 si_async_workunit_t *x;
843
844 pthread_mutex_lock(&module_mutex);
845 if (si_async_worklist == r)
846 {
847 si_async_worklist = r->next;
848 }
849 else
850 {
851 for (x = si_async_worklist; (x != NULL) && (x->next != r); x = x->next) {;}
852 if (x != NULL) x->next = r->next;
853 }
854 pthread_mutex_unlock(&module_mutex);
855 }
856
857 static si_async_workunit_t*
858 si_async_worklist_find_unit(mach_port_t p)
859 {
860 si_async_workunit_t *r;
861
862 pthread_mutex_lock(&module_mutex);
863 for (r = si_async_worklist; (r != NULL) && (r->port != p); r = r->next) {;}
864 pthread_mutex_unlock(&module_mutex);
865
866 return r;
867 }
868
869 static si_async_workunit_t *
870 si_async_workunit_create(si_mod_t *si, int call, const char *str1, const char *str2, uint32_t num1, uint32_t num2, uint32_t num3, uint32_t num4, void *callback, void *context)
871 {
872 si_async_workunit_t *r;
873 kern_return_t status;
874 mach_port_t reply, send;
875 mach_msg_type_name_t type;
876 char *s1, *s2;
877
878 s1 = NULL;
879 s2 = NULL;
880
881 if (si_call_str1_is_buffer(call))
882 {
883 if (num3 > 0)
884 {
885 s1 = calloc(1, num3);
886 if (s1 == NULL) return NULL;
887 memcpy(s1, str1, num3);
888 }
889 }
890 else if (str1 != NULL)
891 {
892 s1 = strdup(str1);
893 if (s1 == NULL) return NULL;
894 }
895
896 if (str2 != NULL)
897 {
898 s2 = strdup(str2);
899 if (s2 == NULL)
900 {
901 if (s1 != NULL) free(s1);
902 return NULL;
903 }
904 }
905
906 r = (si_async_workunit_t *)calloc(1, sizeof(si_async_workunit_t));
907 if (r == NULL)
908 {
909 if (s1 != NULL) free(s1);
910 if (s2 != NULL) free(s2);
911 return NULL;
912 }
913
914 reply = MACH_PORT_NULL;
915 send = MACH_PORT_NULL;
916 type = 0;
917
918 status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &reply);
919 if (status == KERN_SUCCESS) status = mach_port_extract_right(mach_task_self(), reply, MACH_MSG_TYPE_MAKE_SEND_ONCE, &send, &type);
920 if (status != KERN_SUCCESS)
921 {
922 if (reply != MACH_PORT_NULL) mach_port_mod_refs(mach_task_self(), reply, MACH_PORT_RIGHT_RECEIVE, -1);
923 if (s1 != NULL) free(s1);
924 if (s2 != NULL) free(s2);
925 free(r);
926 return NULL;
927 }
928
929 r->si = si;
930 r->call = call;
931 r->str1 = s1;
932 r->str2 = s2;
933 r->num1 = num1;
934 r->num2 = num2;
935 r->num3 = num3;
936 r->num4 = num4;
937
938 r->flags = WORKUNIT_CALL_ACTIVE | WORKUNIT_THREAD_ACTIVE;
939 if (si_call_returns_list(call)) r->flags |= WORKUNIT_RETURNS_LIST;
940
941 r->callback = callback;
942 r->context = context;
943 r->port = reply;
944 r->send = send;
945
946 si_async_worklist_add_unit(r);
947
948 return r;
949 }
950
951 static void
952 si_async_workunit_release(si_async_workunit_t *r)
953 {
954 if (r == NULL) return;
955
956 if (r->flags & (WORKUNIT_THREAD_ACTIVE | WORKUNIT_CALL_ACTIVE)) return;
957
958 si_async_worklist_remove_unit(r);
959
960 if (r->resitem != NULL) si_item_release(r->resitem);
961 if (r->reslist != NULL) si_list_release(r->reslist);
962
963 if (r->str1 != NULL) free(r->str1);
964 if (r->str2 != NULL) free(r->str2);
965
966 free(r);
967 }
968
969 static void *
970 si_async_launchpad(void *x)
971 {
972 si_async_workunit_t *r;
973 kern_return_t status;
974 mach_msg_empty_send_t msg;
975
976 if (x == NULL) pthread_exit(NULL);
977 r = (si_async_workunit_t *)x;
978
979 if (r->flags & WORKUNIT_RETURNS_LIST) r->reslist = si_list_call(r->si, r->call, r->str1, r->str2, r->num1, r->num2, r->num3, r->num4, &(r->err));
980 else r->resitem = si_item_call(r->si, r->call, r->str1, r->str2, r->num1, r->num2, &(r->err));
981
982 memset(&msg, 0, sizeof(mach_msg_empty_send_t));
983
984 msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, MACH_MSGH_BITS_ZERO);
985 msg.header.msgh_remote_port = r->send;
986 msg.header.msgh_local_port = MACH_PORT_NULL;
987 msg.header.msgh_size = sizeof(mach_msg_empty_send_t);
988 msg.header.msgh_id = r->call;
989
990 OSAtomicAnd32Barrier(~WORKUNIT_THREAD_ACTIVE, &r->flags);
991
992 si_async_workunit_release(r);
993
994 status = mach_msg(&(msg.header), MACH_SEND_MSG, msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
995 if (status != MACH_MSG_SUCCESS)
996 {
997 /* receiver failed - clean up to avoid a port leak */
998 mach_msg_destroy(&(msg.header));
999 }
1000
1001 pthread_exit(NULL);
1002
1003 /* UNREACHED */
1004 return NULL;
1005 }
1006
1007 mach_port_t
1008 si_async_call(struct si_mod_s *si, int call, const char *str1, const char *str2, uint32_t num1, uint32_t num2, uint32_t num3, uint32_t num4, void *callback, void *context)
1009 {
1010 si_async_workunit_t *req;
1011 pthread_attr_t attr;
1012 pthread_t t;
1013
1014 if (si == NULL) return MACH_PORT_NULL;
1015 if (callback == NULL) return MACH_PORT_NULL;
1016
1017 /* if module does async on it's own, hand off the call */
1018 if (si->sim_async_call != NULL)
1019 {
1020 return si->sim_async_call(si, call, str1, str2, num1, num2, num3, num4, callback, context);
1021 }
1022
1023 req = si_async_workunit_create(si, call, str1, str2, num1, num2, num3, num4, callback, context);
1024 if (req == NULL) return MACH_PORT_NULL;
1025
1026 /* start a new thread to do the work */
1027 pthread_attr_init(&attr);
1028 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1029 pthread_create(&t, &attr, si_async_launchpad, req);
1030 pthread_attr_destroy(&attr);
1031
1032 return req->port;
1033 }
1034
1035 void
1036 si_async_cancel(mach_port_t p)
1037 {
1038 si_async_workunit_t *r;
1039
1040 r = si_async_worklist_find_unit(p);
1041 if (r == NULL) return;
1042
1043 OSAtomicAnd32Barrier(~WORKUNIT_CALL_ACTIVE, &r->flags);
1044
1045 if (r->callback != NULL)
1046 {
1047 if (r->flags & WORKUNIT_RETURNS_LIST) ((list_async_callback)(r->callback))(NULL, SI_STATUS_CALL_CANCELLED, r->context);
1048 else ((item_async_callback)(r->callback))(NULL, SI_STATUS_CALL_CANCELLED, r->context);
1049 }
1050
1051 si_async_workunit_release(r);
1052
1053 mach_port_mod_refs(mach_task_self(), p, MACH_PORT_RIGHT_RECEIVE, -1);
1054 }
1055
1056 void
1057 si_async_handle_reply(mach_msg_header_t *msg)
1058 {
1059 si_async_workunit_t *r;
1060 mach_port_t reply = msg->msgh_local_port;
1061
1062 r = si_async_worklist_find_unit(reply);
1063 if (r == NULL)
1064 {
1065 #ifdef CALL_TRACE
1066 fprintf(stderr, "** %s can't find worklist item\n", __func__);
1067 #endif
1068 return;
1069 }
1070
1071 if (r->flags & WORKUNIT_THREAD_ACTIVE)
1072 {
1073 #ifdef CALL_TRACE
1074 fprintf(stderr, "** %s workunit thread is still active\n", __func__);
1075 #endif
1076 return;
1077 }
1078
1079 if (r->callback != NULL)
1080 {
1081 if (r->flags & WORKUNIT_RETURNS_LIST) ((list_async_callback)(r->callback))(r->reslist, r->err, r->context);
1082 else ((item_async_callback)(r->callback))(r->resitem, r->err, r->context);
1083
1084 r->reslist = NULL;
1085 r->resitem = NULL;
1086 }
1087 else
1088 {
1089 #ifdef CALL_TRACE
1090 fprintf(stderr, "** %s workunit has no callback\n", __func__);
1091 #endif
1092 }
1093
1094 OSAtomicAnd32Barrier(~WORKUNIT_CALL_ACTIVE, &r->flags);
1095
1096 si_async_workunit_release(r);
1097
1098 mach_port_mod_refs(mach_task_self(), reply, MACH_PORT_RIGHT_RECEIVE, -1);
1099 }
1100
1101 __private_extern__ char *
1102 si_canonical_mac_address(const char *addr)
1103 {
1104 char e[6][3];
1105 char *out;
1106 struct ether_addr *ether;
1107 int i, bit;
1108
1109 if (addr == NULL) return NULL;
1110
1111 /* ether_aton isn't thread-safe */
1112 pthread_mutex_lock(&module_mutex);
1113
1114 ether = ether_aton(addr);
1115 if (ether == NULL)
1116 {
1117 pthread_mutex_unlock(&module_mutex);
1118 return NULL;
1119 }
1120
1121 for (i = 0, bit = 1; i < 6; i++, bit *= 2)
1122 {
1123 if ((i & bit) && (ether->ether_addr_octet[i] <= 15))
1124 {
1125 sprintf(e[i], "0%x", ether->ether_addr_octet[i]);
1126 }
1127 else
1128 {
1129 sprintf(e[i], "%x", ether->ether_addr_octet[i]);
1130 }
1131 }
1132
1133 pthread_mutex_unlock(&module_mutex);
1134
1135 out = NULL;
1136 asprintf(&out, "%s:%s:%s:%s:%s:%s", e[0], e[1], e[2], e[3], e[4], e[5]);
1137 return out;
1138 }