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