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 <sys/types.h>
25 #include <sys/socket.h>
26 #include <net/ethernet.h>
27 #include <libkern/OSAtomic.h>
33 #include <mach/mach.h>
35 #include "si_module.h"
37 #define PLUGIN_DIR_PATH "/usr/lib/info"
38 #define PLUGIN_BUNDLE_SUFFIX "so"
40 #define WORKUNIT_CALL_ACTIVE 0x00000001
41 #define WORKUNIT_THREAD_ACTIVE 0x00000002
42 #define WORKUNIT_RETURNS_LIST 0x00000004
44 typedef struct si_async_workunit_s
56 /* async support below */
64 struct si_async_workunit_s
*next
;
65 } si_async_workunit_t
;
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
;
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();
77 __private_extern__ si_mod_t
*si_module_static_ds();
81 si_mod_dlsym(void *so
, const char *name
, const char *sym
)
86 if ((so
== NULL
) || (name
== NULL
) || (sym
== NULL
)) return NULL
;
89 asprintf(&str
, "%s_%s", name
, sym
);
90 if (str
== NULL
) return NULL
;
98 si_mod_static(const char *name
)
100 if (name
== NULL
) return NULL
;
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();
107 if (string_equal(name
, "ds")) return si_module_static_ds();
112 __private_extern__ si_mod_t
*
113 si_module_with_path(const char *path
, const char *name
)
116 int (*si_sym_init
)(si_mod_t
*);
117 void (*si_sym_close
)(si_mod_t
*);
122 if ((path
== NULL
) || (name
== NULL
))
128 so
= dlopen(path
, RTLD_LOCAL
);
129 if (so
== NULL
) return NULL
;
131 si_sym_init
= si_mod_dlsym(so
, name
, "init");
132 if (si_sym_init
== NULL
)
135 errno
= ECONNREFUSED
;
139 si_sym_close
= si_mod_dlsym(so
, name
, "close");
140 if (si_sym_close
== NULL
)
143 errno
= ECONNREFUSED
;
147 out
= (si_mod_t
*)calloc(1, sizeof(si_mod_t
));
148 outname
= strdup(name
);
150 if ((out
== NULL
) || (outname
== NULL
))
152 if (out
!= NULL
) free(out
);
153 if (outname
!= NULL
) free(outname
);
163 status
= si_sym_init(out
);
169 errno
= ECONNREFUSED
;
177 si_module_with_name(const char *name
)
189 pthread_mutex_lock(&module_mutex
);
191 for (i
= 0; i
< module_count
; i
++)
193 if (string_equal(module_list
[i
]->name
, name
))
195 si_module_retain(module_list
[i
]);
196 pthread_mutex_unlock(&module_mutex
);
197 return module_list
[i
];
201 pthread_mutex_unlock(&module_mutex
);
202 out
= si_mod_static(name
);
203 pthread_mutex_lock(&module_mutex
);
209 /* mdns lives in dns.so */
210 asprintf(&path
, "%s/%s.%s", PLUGIN_DIR_PATH
, name
, PLUGIN_BUNDLE_SUFFIX
);
215 pthread_mutex_unlock(&module_mutex
);
219 out
= si_module_with_path(path
, name
);
225 pthread_mutex_unlock(&module_mutex
);
229 /* add out to module_list */
230 if (module_count
== 0)
232 module_list
= (si_mod_t
**)calloc(1, sizeof(si_mod_t
*));
236 module_list
= (si_mod_t
**)reallocf(module_list
, (module_count
+ 1) * sizeof(si_mod_t
*));
239 if (module_list
== NULL
)
241 pthread_mutex_unlock(&module_mutex
);
245 module_list
[module_count
] = out
;
248 pthread_mutex_unlock(&module_mutex
);
253 __private_extern__ si_mod_t
*
254 si_module_retain(si_mod_t
*si
)
256 if (si
== NULL
) return NULL
;
258 OSAtomicIncrement32Barrier(&si
->refcount
);
264 si_module_release(si_mod_t
*si
)
268 if (si
== NULL
) return;
270 i
= OSAtomicDecrement32Barrier(&si
->refcount
);
273 pthread_mutex_lock(&module_mutex
);
275 for (i
= 0; (i
< module_count
) && (module_list
[i
] != si
); i
++);
276 if (i
>= module_count
)
278 pthread_mutex_unlock(&module_mutex
);
282 if (module_count
== 1)
287 pthread_mutex_unlock(&module_mutex
);
291 for (i
++; i
< module_count
; i
++) module_list
[i
- 1] = module_list
[i
];
293 module_list
= (si_mod_t
**)reallocf(module_list
, module_count
* sizeof(si_mod_t
*));
294 if (module_list
== NULL
) module_count
= 0;
296 pthread_mutex_unlock(&module_mutex
);
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
);
304 __private_extern__
const char *
305 si_module_name(si_mod_t
*si
)
307 if (si
== NULL
) return NULL
;
312 __private_extern__
int
313 si_module_vers(si_mod_t
*si
)
315 if (si
== NULL
) return 0;
320 __private_extern__
int
321 si_item_match(si_item_t
*item
, int cat
, const void *name
, uint32_t num
, int which
)
329 struct grouplist_s
*l
;
340 if (item
== NULL
) return 0;
341 if (which
== SEL_ALL
) return 1;
342 if ((which
== SEL_NAME
) && (name
== NULL
)) return 0;
344 ent
.x
= (char *)((uintptr_t)item
+ sizeof(si_item_t
));
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;
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;
360 case CATEGORY_GROUPLIST
:
362 if ((which
== SEL_NAME
) && (string_equal(name
, ent
.l
->gl_user
))) return 1;
367 if ((which
== SEL_NAME
) && (string_equal(name
, ent
.a
->alias_name
))) return 1;
370 case CATEGORY_HOST_IPV4
:
371 case CATEGORY_HOST_IPV6
:
373 /* N.B. address family is passed in num variable */
374 if (ent
.h
->h_addrtype
!= num
) return 0;
375 if (which
== SEL_NAME
)
377 if (string_equal(name
, ent
.h
->h_name
)) return 1;
378 if (ent
.h
->h_aliases
!= NULL
)
380 for (i
= 0; ent
.h
->h_aliases
[i
] != NULL
; i
++)
382 if (string_equal(name
, ent
.h
->h_aliases
[i
])) return 1;
386 else if (which
== SEL_NUMBER
)
388 if (memcmp(name
, ent
.h
->h_addr_list
[0], ent
.h
->h_length
) == 0) return 1;
392 case CATEGORY_NETWORK
:
394 if (which
== SEL_NAME
)
396 if (string_equal(name
, ent
.n
->n_name
)) return 1;
397 if (ent
.n
->n_aliases
!= NULL
)
399 for (i
= 0; ent
.n
->n_aliases
[i
] != NULL
; i
++)
401 if (string_equal(name
, ent
.n
->n_aliases
[i
])) return 1;
405 else if (which
== SEL_NUMBER
)
407 if (num
== ent
.n
->n_net
) return 1;
411 case CATEGORY_SERVICE
:
413 if (which
== SEL_NAME
)
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;
419 if (string_equal(name
, ent
.s
->s_name
)) return 1;
420 if (ent
.s
->s_aliases
!= NULL
)
422 for (i
= 0; ent
.s
->s_aliases
[i
] != NULL
; i
++)
424 if (string_equal(name
, ent
.s
->s_aliases
[i
])) return 1;
428 else if (which
== SEL_NUMBER
)
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;
436 case CATEGORY_PROTOCOL
:
438 if (which
== SEL_NAME
)
440 if (string_equal(name
, ent
.p
->p_name
)) return 1;
441 if (ent
.p
->p_aliases
!= NULL
)
443 for (i
= 0; ent
.p
->p_aliases
[i
] != NULL
; i
++)
445 if (string_equal(name
, ent
.p
->p_aliases
[i
])) return 1;
449 else if (which
== SEL_NUMBER
)
451 if (num
== ent
.p
->p_proto
) return 1;
457 if (which
== SEL_NAME
)
459 if (string_equal(name
, ent
.r
->r_name
)) return 1;
460 if (ent
.r
->r_aliases
!= NULL
)
462 for (i
= 0; ent
.r
->r_aliases
[i
] != NULL
; i
++)
464 if (string_equal(name
, ent
.r
->r_aliases
[i
])) return 1;
468 else if (which
== SEL_NUMBER
)
470 if (num
== ent
.r
->r_number
) return 1;
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;
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;
492 __private_extern__
int
493 si_item_is_valid(si_item_t
*item
)
497 if (item
== NULL
) return 0;
501 if (si
== NULL
) return 0;
502 if (si
->sim_is_valid
== NULL
) return 0;
504 return si
->sim_is_valid(si
, item
);
507 __private_extern__ si_item_t
*
508 si_user_byname(si_mod_t
*si
, const char *name
)
510 if (si
== NULL
) return NULL
;
511 if (si
->sim_user_byname
== NULL
) return NULL
;
512 return si
->sim_user_byname(si
, name
);
515 __private_extern__ si_item_t
*
516 si_user_byuid(si_mod_t
*si
, uid_t uid
)
518 if (si
== NULL
) return NULL
;
519 if (si
->sim_user_byuid
== NULL
) return NULL
;
520 return si
->sim_user_byuid(si
, uid
);
523 __private_extern__ si_list_t
*
524 si_user_all(si_mod_t
*si
)
526 if (si
== NULL
) return NULL
;
527 if (si
->sim_user_all
== NULL
) return NULL
;
528 return si
->sim_user_all(si
);
531 __private_extern__ si_item_t
*
532 si_group_byname(si_mod_t
*si
, const char *name
)
534 if (si
== NULL
) return NULL
;
535 if (si
->sim_group_byname
== NULL
) return NULL
;
536 return si
->sim_group_byname(si
, name
);
539 __private_extern__ si_item_t
*
540 si_group_bygid(si_mod_t
*si
, gid_t gid
)
542 if (si
== NULL
) return NULL
;
543 if (si
->sim_group_bygid
== NULL
) return NULL
;
544 return si
->sim_group_bygid(si
, gid
);
547 __private_extern__ si_list_t
*
548 si_group_all(si_mod_t
*si
)
550 if (si
== NULL
) return NULL
;
551 if (si
->sim_group_all
== NULL
) return NULL
;
552 return si
->sim_group_all(si
);
555 __private_extern__ si_item_t
*
556 si_grouplist(si_mod_t
*si
, const char *name
)
558 if (si
== NULL
) return NULL
;
559 if (si
->sim_grouplist
== NULL
) return NULL
;
560 return si
->sim_grouplist(si
, name
);
563 __private_extern__ si_list_t
*
564 si_netgroup_byname(struct si_mod_s
*si
, const char *name
)
566 if (si
== NULL
) return NULL
;
567 if (si
->sim_netgroup_byname
== NULL
) return NULL
;
568 return si
->sim_netgroup_byname(si
, name
);
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
)
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
);
579 __private_extern__ si_item_t
*
580 si_alias_byname(si_mod_t
*si
, const char *name
)
582 if (si
== NULL
) return NULL
;
583 if (si
->sim_alias_byname
== NULL
) return NULL
;
584 return si
->sim_alias_byname(si
, name
);
587 __private_extern__ si_list_t
*
588 si_alias_all(si_mod_t
*si
)
590 if (si
== NULL
) return NULL
;
591 if (si
->sim_alias_all
== NULL
) return NULL
;
592 return si
->sim_alias_all(si
);
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
)
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
);
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
)
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
);
611 __private_extern__ si_list_t
*
612 si_host_all(si_mod_t
*si
)
614 if (si
== NULL
) return NULL
;
615 if (si
->sim_host_all
== NULL
) return NULL
;
616 return si
->sim_host_all(si
);
619 __private_extern__ si_item_t
*
620 si_mac_byname(struct si_mod_s
*si
, const char *name
)
622 if (si
== NULL
) return NULL
;
623 if (si
->sim_mac_byname
== NULL
) return NULL
;
624 return si
->sim_mac_byname(si
, name
);
627 __private_extern__ si_item_t
*
628 si_mac_bymac(struct si_mod_s
*si
, const char *mac
)
630 if (si
== NULL
) return NULL
;
631 if (si
->sim_mac_bymac
== NULL
) return NULL
;
632 return si
->sim_mac_bymac(si
, mac
);
635 __private_extern__ si_list_t
*
636 si_mac_all(si_mod_t
*si
)
638 if (si
== NULL
) return NULL
;
639 if (si
->sim_mac_all
== NULL
) return NULL
;
640 return si
->sim_mac_all(si
);
643 __private_extern__ si_item_t
*
644 si_network_byname(si_mod_t
*si
, const char *name
)
646 if (si
== NULL
) return NULL
;
647 if (si
->sim_network_byname
== NULL
) return NULL
;
648 return si
->sim_network_byname(si
, name
);
651 __private_extern__ si_item_t
*
652 si_network_byaddr(si_mod_t
*si
, uint32_t addr
)
654 if (si
== NULL
) return NULL
;
655 if (si
->sim_network_byaddr
== NULL
) return NULL
;
656 return si
->sim_network_byaddr(si
, addr
);
659 __private_extern__ si_list_t
*
660 si_network_all(si_mod_t
*si
)
662 if (si
== NULL
) return NULL
;
663 if (si
->sim_network_all
== NULL
) return NULL
;
664 return si
->sim_network_all(si
);
667 __private_extern__ si_item_t
*
668 si_service_byname(si_mod_t
*si
, const char *name
, const char *proto
)
670 if (si
== NULL
) return NULL
;
671 if (si
->sim_service_byname
== NULL
) return NULL
;
672 return si
->sim_service_byname(si
, name
, proto
);
675 __private_extern__ si_item_t
*
676 si_service_byport(si_mod_t
*si
, int port
, const char *proto
)
678 if (si
== NULL
) return NULL
;
679 if (si
->sim_service_byport
== NULL
) return NULL
;
680 return si
->sim_service_byport(si
, port
, proto
);
683 __private_extern__ si_list_t
*
684 si_service_all(si_mod_t
*si
)
686 if (si
== NULL
) return NULL
;
687 if (si
->sim_service_all
== NULL
) return NULL
;
688 return si
->sim_service_all(si
);
691 __private_extern__ si_item_t
*
692 si_protocol_byname(si_mod_t
*si
, const char *name
)
694 if (si
== NULL
) return NULL
;
695 if (si
->sim_protocol_byname
== NULL
) return NULL
;
696 return si
->sim_protocol_byname(si
, name
);
699 __private_extern__ si_item_t
*
700 si_protocol_bynumber(si_mod_t
*si
, uint32_t number
)
702 if (si
== NULL
) return NULL
;
703 if (si
->sim_protocol_bynumber
== NULL
) return NULL
;
704 return si
->sim_protocol_bynumber(si
, number
);
707 __private_extern__ si_list_t
*
708 si_protocol_all(si_mod_t
*si
)
710 if (si
== NULL
) return NULL
;
711 if (si
->sim_protocol_all
== NULL
) return NULL
;
712 return si
->sim_protocol_all(si
);
715 __private_extern__ si_item_t
*
716 si_rpc_byname(si_mod_t
*si
, const char *name
)
718 if (si
== NULL
) return NULL
;
719 if (si
->sim_rpc_byname
== NULL
) return NULL
;
720 return si
->sim_rpc_byname(si
, name
);
723 __private_extern__ si_item_t
*
724 si_rpc_bynumber(si_mod_t
*si
, int number
)
726 if (si
== NULL
) return NULL
;
727 if (si
->sim_rpc_bynumber
== NULL
) return NULL
;
728 return si
->sim_rpc_bynumber(si
, number
);
731 __private_extern__ si_list_t
*
732 si_rpc_all(si_mod_t
*si
)
734 if (si
== NULL
) return NULL
;
735 if (si
->sim_rpc_all
== NULL
) return NULL
;
736 return si
->sim_rpc_all(si
);
739 __private_extern__ si_item_t
*
740 si_fs_byspec(si_mod_t
*si
, const char *spec
)
742 if (si
== NULL
) return NULL
;
743 if (si
->sim_fs_byspec
== NULL
) return NULL
;
744 return si
->sim_fs_byspec(si
, spec
);
747 __private_extern__ si_item_t
*
748 si_fs_byfile(si_mod_t
*si
, const char *file
)
750 if (si
== NULL
) return NULL
;
751 if (si
->sim_fs_byfile
== NULL
) return NULL
;
752 return si
->sim_fs_byfile(si
, file
);
755 __private_extern__ si_list_t
*
756 si_fs_all(si_mod_t
*si
)
758 if (si
== NULL
) return NULL
;
759 if (si
->sim_fs_all
== NULL
) return NULL
;
760 return si
->sim_fs_all(si
);
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
)
766 if (si
== NULL
) return NULL
;
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
);
793 /* Support for DNS async calls */
794 case SI_CALL_DNS_QUERY
:
795 case SI_CALL_DNS_SEARCH
:
797 if (si
->sim_item_call
== NULL
) return NULL
;
798 return si
->sim_item_call(si
, call
, str1
, str2
, str3
, num1
, num2
, err
);
801 default: return NULL
;
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
)
810 if (si
== NULL
) return NULL
;
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
;
832 si_async_worklist_add_unit(si_async_workunit_t
*r
)
834 pthread_mutex_lock(&module_mutex
);
835 r
->next
= si_async_worklist
;
836 si_async_worklist
= r
;
837 pthread_mutex_unlock(&module_mutex
);
841 si_async_worklist_remove_unit(si_async_workunit_t
*r
)
843 si_async_workunit_t
*x
;
845 pthread_mutex_lock(&module_mutex
);
846 if (si_async_worklist
== r
)
848 si_async_worklist
= r
->next
;
852 for (x
= si_async_worklist
; (x
!= NULL
) && (x
->next
!= r
); x
= x
->next
) {;}
853 if (x
!= NULL
) x
->next
= r
->next
;
855 pthread_mutex_unlock(&module_mutex
);
858 static si_async_workunit_t
*
859 si_async_worklist_find_unit(mach_port_t p
)
861 si_async_workunit_t
*r
;
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
);
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
)
873 si_async_workunit_t
*r
;
874 kern_return_t status
;
875 mach_port_t reply
, send
;
876 mach_msg_type_name_t type
;
883 if (si_call_str1_is_buffer(call
))
887 s1
= calloc(1, num3
);
888 if (s1
== NULL
) return NULL
;
889 memcpy(s1
, str1
, num3
);
892 else if (str1
!= NULL
)
895 if (s1
== NULL
) return NULL
;
903 if (s1
!= NULL
) free(s1
);
913 if (s1
!= NULL
) free(s1
);
914 if (s2
!= NULL
) free(s2
);
919 r
= (si_async_workunit_t
*)calloc(1, sizeof(si_async_workunit_t
));
922 if (s1
!= NULL
) free(s1
);
923 if (s2
!= NULL
) free(s2
);
924 if (s3
!= NULL
) free(s3
);
928 reply
= MACH_PORT_NULL
;
929 send
= MACH_PORT_NULL
;
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
)
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
);
954 r
->flags
= WORKUNIT_CALL_ACTIVE
| WORKUNIT_THREAD_ACTIVE
;
955 if (si_call_returns_list(call
)) r
->flags
|= WORKUNIT_RETURNS_LIST
;
957 r
->callback
= callback
;
958 r
->context
= context
;
962 si_async_worklist_add_unit(r
);
968 si_async_workunit_release(si_async_workunit_t
*r
)
970 if (r
== NULL
) return;
972 if (r
->flags
& (WORKUNIT_THREAD_ACTIVE
| WORKUNIT_CALL_ACTIVE
)) return;
974 si_async_worklist_remove_unit(r
);
976 if (r
->resitem
!= NULL
) si_item_release(r
->resitem
);
977 if (r
->reslist
!= NULL
) si_list_release(r
->reslist
);
979 if (r
->str1
!= NULL
) free(r
->str1
);
980 if (r
->str2
!= NULL
) free(r
->str2
);
981 if (r
->str3
!= NULL
) free(r
->str3
);
987 si_async_launchpad(void *x
)
989 si_async_workunit_t
*r
;
990 kern_return_t status
;
991 mach_msg_empty_send_t msg
;
993 if (x
== NULL
) pthread_exit(NULL
);
994 r
= (si_async_workunit_t
*)x
;
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
));
999 memset(&msg
, 0, sizeof(mach_msg_empty_send_t
));
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
;
1007 OSAtomicAnd32Barrier(~WORKUNIT_THREAD_ACTIVE
, &r
->flags
);
1009 si_async_workunit_release(r
);
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
)
1014 /* receiver failed - clean up to avoid a port leak */
1015 mach_msg_destroy(&(msg
.header
));
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
)
1027 si_async_workunit_t
*req
;
1028 pthread_attr_t attr
;
1031 if (si
== NULL
) return MACH_PORT_NULL
;
1032 if (callback
== NULL
) return MACH_PORT_NULL
;
1034 /* if module does async on it's own, hand off the call */
1035 if (si
->sim_async_call
!= NULL
)
1037 return si
->sim_async_call(si
, call
, str1
, str2
, str3
, num1
, num2
, num3
, num4
, callback
, context
);
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
;
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
);
1053 si_async_cancel(mach_port_t p
)
1055 si_async_workunit_t
*r
;
1057 r
= si_async_worklist_find_unit(p
);
1058 if (r
== NULL
) return;
1060 OSAtomicAnd32Barrier(~WORKUNIT_CALL_ACTIVE
, &r
->flags
);
1062 if (r
->callback
!= NULL
)
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
);
1068 si_async_workunit_release(r
);
1070 mach_port_mod_refs(mach_task_self(), p
, MACH_PORT_RIGHT_RECEIVE
, -1);
1074 si_async_handle_reply(mach_msg_header_t
*msg
)
1076 si_async_workunit_t
*r
;
1077 mach_port_t reply
= msg
->msgh_local_port
;
1079 r
= si_async_worklist_find_unit(reply
);
1083 fprintf(stderr
, "** %s can't find worklist item\n", __func__
);
1088 if (r
->flags
& WORKUNIT_THREAD_ACTIVE
)
1091 fprintf(stderr
, "** %s workunit thread is still active\n", __func__
);
1096 if (r
->callback
!= NULL
)
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
);
1107 fprintf(stderr
, "** %s workunit has no callback\n", __func__
);
1111 OSAtomicAnd32Barrier(~WORKUNIT_CALL_ACTIVE
, &r
->flags
);
1113 si_async_workunit_release(r
);
1115 mach_port_mod_refs(mach_task_self(), reply
, MACH_PORT_RIGHT_RECEIVE
, -1);
1118 __private_extern__
char *
1119 si_canonical_mac_address(const char *addr
)
1123 struct ether_addr
*ether
;
1126 if (addr
== NULL
) return NULL
;
1128 /* ether_aton isn't thread-safe */
1129 pthread_mutex_lock(&module_mutex
);
1131 ether
= ether_aton(addr
);
1134 pthread_mutex_unlock(&module_mutex
);
1138 for (i
= 0, bit
= 1; i
< 6; i
++, bit
*= 2)
1140 if ((i
& bit
) && (ether
->ether_addr_octet
[i
] <= 15))
1142 sprintf(e
[i
], "0%x", ether
->ether_addr_octet
[i
]);
1146 sprintf(e
[i
], "%x", ether
->ether_addr_octet
[i
]);
1150 pthread_mutex_unlock(&module_mutex
);
1153 asprintf(&out
, "%s:%s:%s:%s:%s:%s", e
[0], e
[1], e
[2], e
[3], e
[4], e
[5]);