2 * Copyright (c) 2008-2018 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 "libinfo_common.h"
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <net/ethernet.h>
29 #include <libkern/OSAtomic.h>
35 #include <mach/mach.h>
36 #include <dispatch/dispatch.h>
37 #include <dispatch/private.h>
38 #include "si_module.h"
40 #define PLUGIN_DIR_PATH "/usr/lib/info"
41 #define PLUGIN_BUNDLE_SUFFIX "so"
43 #define WORKUNIT_CANCELLED 0x00000001
44 #define WORKUNIT_RETURNS_LIST 0x00000002
47 #define WORKUNIT_CANCELLED_BIT_ADDRESS 31
49 #define WORKUNIT_CANCELLED_BIT_ADDRESS 7
52 typedef struct si_async_workunit_s
64 /* async support below */
73 struct si_async_workunit_s
*next
;
74 } si_async_workunit_t
;
76 static si_mod_t
**module_list
= NULL
;
77 static uint32_t module_count
= 0;
78 static pthread_mutex_t module_mutex
= PTHREAD_MUTEX_INITIALIZER
;
79 static si_async_workunit_t
*si_async_worklist
= NULL
;
81 si_mod_t
*si_module_static_search(void);
82 si_mod_t
*si_module_static_cache(void);
83 si_mod_t
*si_module_static_file(void);
84 #ifdef MUSER_AVAILABLE
85 si_mod_t
*si_module_static_muser(void);
88 si_mod_t
*si_module_static_ds(void);
90 si_mod_t
*si_module_static_mdns(void);
93 si_mod_dlsym(void *so
, const char *name
, const char *sym
)
98 if ((so
== NULL
) || (name
== NULL
) || (sym
== NULL
)) return NULL
;
101 asprintf(&str
, "%s_%s", name
, sym
);
102 if (str
== NULL
) return NULL
;
104 out
= dlsym(so
, str
);
110 si_module_with_path(const char *path
, const char *name
)
113 int (*si_sym_init
)(si_mod_t
*);
114 void (*si_sym_close
)(si_mod_t
*);
119 if ((path
== NULL
) || (name
== NULL
))
125 so
= dlopen(path
, RTLD_LOCAL
);
126 if (so
== NULL
) return NULL
;
128 si_sym_init
= si_mod_dlsym(so
, name
, "init");
129 if (si_sym_init
== NULL
)
132 errno
= ECONNREFUSED
;
136 si_sym_close
= si_mod_dlsym(so
, name
, "close");
137 if (si_sym_close
== NULL
)
140 errno
= ECONNREFUSED
;
144 out
= (si_mod_t
*)calloc(1, sizeof(si_mod_t
));
145 outname
= strdup(name
);
147 if ((out
== NULL
) || (outname
== NULL
))
161 status
= si_sym_init(out
);
167 errno
= ECONNREFUSED
;
176 si_module_with_name(const char *name
)
181 si_mod_t
*(*init
)(void);
185 { "search", si_module_static_search
, NULL
},
186 { "cache", si_module_static_cache
, NULL
},
187 { "file", si_module_static_file
, NULL
},
188 #ifdef MUSER_AVAILABLE
189 { "muser", si_module_static_muser
, NULL
},
192 { "ds", si_module_static_ds
, NULL
},
194 { "mdns", si_module_static_mdns
, NULL
},
202 * We don't need to worry about locking during initialization
203 * because all modules init routine returns static storage.
206 /* Find the module by name */
207 for (i
= 0; modules
[i
].name
!= NULL
; ++i
)
209 if (string_equal(name
, modules
[i
].name
))
211 si
= modules
[i
].module
;
214 si
= modules
[i
].init();
215 modules
[i
].module
= si
;
222 if (si
!= NULL
) return si
;
224 pthread_mutex_lock(&module_mutex
);
227 asprintf(&path
, "%s/%s.%s", PLUGIN_DIR_PATH
, name
, PLUGIN_BUNDLE_SUFFIX
);
232 pthread_mutex_unlock(&module_mutex
);
236 si
= si_module_with_path(path
, name
);
241 pthread_mutex_unlock(&module_mutex
);
245 /* add out to module_list */
246 module_list
= (si_mod_t
**)reallocf(module_list
, (module_count
+ 1) * sizeof(si_mod_t
*));
247 if (module_list
== NULL
)
249 pthread_mutex_unlock(&module_mutex
);
253 module_list
[module_count
] = si
;
256 pthread_mutex_unlock(&module_mutex
);
263 si_module_retain(si_mod_t
*si
)
265 if (si
== NULL
) return NULL
;
266 if (si
->flags
& SI_MOD_FLAG_STATIC
) return si
;
268 OSAtomicIncrement32Barrier(&si
->refcount
);
275 si_module_release(si_mod_t
*si
)
279 if (si
== NULL
) return;
280 if (si
->flags
& SI_MOD_FLAG_STATIC
) return;
282 i
= OSAtomicDecrement32Barrier(&si
->refcount
);
285 pthread_mutex_lock(&module_mutex
);
287 for (i
= 0; (i
< module_count
) && (module_list
[i
] != si
); i
++);
288 if (i
>= module_count
)
290 pthread_mutex_unlock(&module_mutex
);
294 if (module_count
== 1)
299 pthread_mutex_unlock(&module_mutex
);
303 for (i
++; i
< module_count
; i
++) module_list
[i
- 1] = module_list
[i
];
305 module_list
= (si_mod_t
**)reallocf(module_list
, module_count
* sizeof(si_mod_t
*));
306 if (module_list
== NULL
) module_count
= 0;
308 pthread_mutex_unlock(&module_mutex
);
310 if (si
->vtable
->sim_close
!= NULL
) si
->vtable
->sim_close(si
);
311 if (si
->bundle
!= NULL
) dlclose(si
->bundle
);
318 si_module_name(si_mod_t
*si
)
320 if (si
== NULL
) return NULL
;
322 return (const char *)si
->name
;
327 si_module_vers(si_mod_t
*si
)
329 if (si
== NULL
) return 0;
336 si_item_match(si_item_t
*item
, int cat
, const void *name
, uint32_t num
, int which
)
344 struct grouplist_s
*l
;
355 if (item
== NULL
) return 0;
356 if (which
== SEL_ALL
) return 1;
357 if ((which
== SEL_NAME
) && (name
== NULL
)) return 0;
359 ent
.x
= (char *)((uintptr_t)item
+ sizeof(si_item_t
));
365 if ((which
== SEL_NAME
) && (string_equal(name
, ent
.u
->pw_name
))) return 1;
366 else if ((which
== SEL_NUMBER
) && (num
== (uint32_t)ent
.u
->pw_uid
)) return 1;
371 if ((which
== SEL_NAME
) && (string_equal(name
, ent
.g
->gr_name
))) return 1;
372 else if ((which
== SEL_NUMBER
) && (num
== (uint32_t)ent
.g
->gr_gid
)) return 1;
375 case CATEGORY_GROUPLIST
:
377 if ((which
== SEL_NAME
) && (string_equal(name
, ent
.l
->gl_user
))) return 1;
382 if ((which
== SEL_NAME
) && (string_equal(name
, ent
.a
->alias_name
))) return 1;
385 case CATEGORY_HOST_IPV4
:
386 case CATEGORY_HOST_IPV6
:
388 /* N.B. address family is passed in num variable */
389 if (ent
.h
->h_addrtype
!= num
) return 0;
390 if (which
== SEL_NAME
)
392 if (string_equal(name
, ent
.h
->h_name
)) return 1;
393 if (ent
.h
->h_aliases
!= NULL
)
395 for (i
= 0; ent
.h
->h_aliases
[i
] != NULL
; i
++)
397 if (string_equal(name
, ent
.h
->h_aliases
[i
])) return 1;
401 else if (which
== SEL_NUMBER
)
403 if (memcmp(name
, ent
.h
->h_addr_list
[0], ent
.h
->h_length
) == 0) return 1;
407 case CATEGORY_NETWORK
:
409 if (which
== SEL_NAME
)
411 if (string_equal(name
, ent
.n
->n_name
)) return 1;
412 if (ent
.n
->n_aliases
!= NULL
)
414 for (i
= 0; ent
.n
->n_aliases
[i
] != NULL
; i
++)
416 if (string_equal(name
, ent
.n
->n_aliases
[i
])) return 1;
420 else if (which
== SEL_NUMBER
)
422 if (num
== ent
.n
->n_net
) return 1;
426 case CATEGORY_SERVICE
:
428 if (which
== SEL_NAME
)
430 /* N.B. for SEL_NAME, num is 0 (don't care), 1 (udp) or 2 (tcp) */
431 if ((num
== 1) && (string_not_equal("udp", ent
.s
->s_proto
))) return 0;
432 if ((num
== 2) && (string_not_equal("tcp", ent
.s
->s_proto
))) return 0;
434 if (string_equal(name
, ent
.s
->s_name
)) return 1;
435 if (ent
.s
->s_aliases
!= NULL
)
437 for (i
= 0; ent
.s
->s_aliases
[i
] != NULL
; i
++)
439 if (string_equal(name
, ent
.s
->s_aliases
[i
])) return 1;
443 else if (which
== SEL_NUMBER
)
445 /* N.B. for SEL_NUMBER, protocol is sent in name variable */
446 if ((name
!= NULL
) && (string_not_equal(name
, ent
.s
->s_proto
))) return 0;
447 if (num
== ent
.s
->s_port
) return 1;
451 case CATEGORY_PROTOCOL
:
453 if (which
== SEL_NAME
)
455 if (string_equal(name
, ent
.p
->p_name
)) return 1;
456 if (ent
.p
->p_aliases
!= NULL
)
458 for (i
= 0; ent
.p
->p_aliases
[i
] != NULL
; i
++)
460 if (string_equal(name
, ent
.p
->p_aliases
[i
])) return 1;
464 else if (which
== SEL_NUMBER
)
466 if (num
== ent
.p
->p_proto
) return 1;
472 if (which
== SEL_NAME
)
474 if (string_equal(name
, ent
.r
->r_name
)) return 1;
475 if (ent
.r
->r_aliases
!= NULL
)
477 for (i
= 0; ent
.r
->r_aliases
[i
] != NULL
; i
++)
479 if (string_equal(name
, ent
.r
->r_aliases
[i
])) return 1;
483 else if (which
== SEL_NUMBER
)
485 if (num
== ent
.r
->r_number
) return 1;
491 if ((which
== SEL_NAME
) && (string_equal(name
, ent
.f
->fs_spec
))) return 1;
492 if ((which
== SEL_NUMBER
) && (string_equal(name
, ent
.f
->fs_file
))) return 1;
497 if ((which
== SEL_NAME
) && (string_equal(name
, ent
.m
->host
))) return 1;
498 if ((which
== SEL_NUMBER
) && (string_equal(name
, ent
.m
->mac
))) return 1;
509 si_item_is_valid(si_item_t
*item
)
513 if (item
== NULL
) return 0;
517 if (si
== NULL
) return 0;
518 if (si
->vtable
->sim_is_valid
== NULL
) return 0;
520 return si
->vtable
->sim_is_valid(si
, item
);
525 si_user_byname(si_mod_t
*si
, const char *name
)
527 if (si
== NULL
) return NULL
;
528 if (si
->vtable
->sim_user_byname
== NULL
) return NULL
;
529 return si
->vtable
->sim_user_byname(si
, name
);
534 si_user_byuid(si_mod_t
*si
, uid_t uid
)
536 if (si
== NULL
) return NULL
;
537 if (si
->vtable
->sim_user_byuid
== NULL
) return NULL
;
538 return si
->vtable
->sim_user_byuid(si
, uid
);
543 si_user_byuuid(si_mod_t
*si
, uuid_t uuid
)
545 if (si
== NULL
) return NULL
;
546 if (si
->vtable
->sim_user_byuuid
== NULL
) return NULL
;
547 return si
->vtable
->sim_user_byuuid(si
, uuid
);
552 si_user_all(si_mod_t
*si
)
554 if (si
== NULL
) return NULL
;
555 if (si
->vtable
->sim_user_all
== NULL
) return NULL
;
556 return si
->vtable
->sim_user_all(si
);
561 si_group_byname(si_mod_t
*si
, const char *name
)
563 if (si
== NULL
) return NULL
;
564 if (si
->vtable
->sim_group_byname
== NULL
) return NULL
;
565 return si
->vtable
->sim_group_byname(si
, name
);
570 si_group_bygid(si_mod_t
*si
, gid_t gid
)
572 if (si
== NULL
) return NULL
;
573 if (si
->vtable
->sim_group_bygid
== NULL
) return NULL
;
574 return si
->vtable
->sim_group_bygid(si
, gid
);
579 si_group_byuuid(si_mod_t
*si
, uuid_t uuid
)
581 if (si
== NULL
) return NULL
;
582 if (si
->vtable
->sim_group_byuuid
== NULL
) return NULL
;
583 return si
->vtable
->sim_group_byuuid(si
, uuid
);
588 si_group_all(si_mod_t
*si
)
590 if (si
== NULL
) return NULL
;
591 if (si
->vtable
->sim_group_all
== NULL
) return NULL
;
592 return si
->vtable
->sim_group_all(si
);
597 si_grouplist(si_mod_t
*si
, const char *name
, uint32_t count
)
599 if (si
== NULL
) return NULL
;
600 if (si
->vtable
->sim_grouplist
== NULL
) return NULL
;
601 return si
->vtable
->sim_grouplist(si
, name
, count
);
606 si_netgroup_byname(struct si_mod_s
*si
, const char *name
)
608 if (si
== NULL
) return NULL
;
609 if (si
->vtable
->sim_netgroup_byname
== NULL
) return NULL
;
610 return si
->vtable
->sim_netgroup_byname(si
, name
);
615 si_in_netgroup(struct si_mod_s
*si
, const char *name
, const char *host
, const char *user
, const char *domain
)
617 if (si
== NULL
) return 0;
618 if (si
->vtable
->sim_in_netgroup
== NULL
) return 0;
619 return si
->vtable
->sim_in_netgroup(si
, name
, host
, user
, domain
);
624 si_alias_byname(si_mod_t
*si
, const char *name
)
626 if (si
== NULL
) return NULL
;
627 if (si
->vtable
->sim_alias_byname
== NULL
) return NULL
;
628 return si
->vtable
->sim_alias_byname(si
, name
);
633 si_alias_all(si_mod_t
*si
)
635 if (si
== NULL
) return NULL
;
636 if (si
->vtable
->sim_alias_all
== NULL
) return NULL
;
637 return si
->vtable
->sim_alias_all(si
);
642 si_host_byname(si_mod_t
*si
, const char *name
, int af
, const char *interface
, uint32_t *err
)
644 if (si
== NULL
) return NULL
;
645 if (si
->vtable
->sim_host_byname
== NULL
) return NULL
;
646 return si
->vtable
->sim_host_byname(si
, name
, af
, interface
, err
);
651 si_host_byaddr(si_mod_t
*si
, const void *addr
, int af
, const char *interface
, uint32_t *err
)
653 if (si
== NULL
) return NULL
;
654 if (si
->vtable
->sim_host_byaddr
== NULL
) return NULL
;
655 return si
->vtable
->sim_host_byaddr(si
, addr
, af
, interface
, err
);
660 si_host_all(si_mod_t
*si
)
662 if (si
== NULL
) return NULL
;
663 if (si
->vtable
->sim_host_all
== NULL
) return NULL
;
664 return si
->vtable
->sim_host_all(si
);
669 si_mac_byname(struct si_mod_s
*si
, const char *name
)
671 if (si
== NULL
) return NULL
;
672 if (si
->vtable
->sim_mac_byname
== NULL
) return NULL
;
673 return si
->vtable
->sim_mac_byname(si
, name
);
678 si_mac_bymac(struct si_mod_s
*si
, const char *mac
)
680 if (si
== NULL
) return NULL
;
681 if (si
->vtable
->sim_mac_bymac
== NULL
) return NULL
;
682 return si
->vtable
->sim_mac_bymac(si
, mac
);
687 si_mac_all(si_mod_t
*si
)
689 if (si
== NULL
) return NULL
;
690 if (si
->vtable
->sim_mac_all
== NULL
) return NULL
;
691 return si
->vtable
->sim_mac_all(si
);
696 si_network_byname(si_mod_t
*si
, const char *name
)
698 if (si
== NULL
) return NULL
;
699 if (si
->vtable
->sim_network_byname
== NULL
) return NULL
;
700 return si
->vtable
->sim_network_byname(si
, name
);
705 si_network_byaddr(si_mod_t
*si
, uint32_t addr
)
707 if (si
== NULL
) return NULL
;
708 if (si
->vtable
->sim_network_byaddr
== NULL
) return NULL
;
709 return si
->vtable
->sim_network_byaddr(si
, addr
);
714 si_network_all(si_mod_t
*si
)
716 if (si
== NULL
) return NULL
;
717 if (si
->vtable
->sim_network_all
== NULL
) return NULL
;
718 return si
->vtable
->sim_network_all(si
);
723 si_service_byname(si_mod_t
*si
, const char *name
, const char *proto
)
725 if (si
== NULL
) return NULL
;
726 if (si
->vtable
->sim_service_byname
== NULL
) return NULL
;
727 return si
->vtable
->sim_service_byname(si
, name
, proto
);
732 si_service_byport(si_mod_t
*si
, int port
, const char *proto
)
734 if (si
== NULL
) return NULL
;
735 if (si
->vtable
->sim_service_byport
== NULL
) return NULL
;
736 return si
->vtable
->sim_service_byport(si
, port
, proto
);
741 si_service_all(si_mod_t
*si
)
743 if (si
== NULL
) return NULL
;
744 if (si
->vtable
->sim_service_all
== NULL
) return NULL
;
745 return si
->vtable
->sim_service_all(si
);
750 si_protocol_byname(si_mod_t
*si
, const char *name
)
752 if (si
== NULL
) return NULL
;
753 if (si
->vtable
->sim_protocol_byname
== NULL
) return NULL
;
754 return si
->vtable
->sim_protocol_byname(si
, name
);
759 si_protocol_bynumber(si_mod_t
*si
, uint32_t number
)
761 if (si
== NULL
) return NULL
;
762 if (si
->vtable
->sim_protocol_bynumber
== NULL
) return NULL
;
763 return si
->vtable
->sim_protocol_bynumber(si
, number
);
768 si_protocol_all(si_mod_t
*si
)
770 if (si
== NULL
) return NULL
;
771 if (si
->vtable
->sim_protocol_all
== NULL
) return NULL
;
772 return si
->vtable
->sim_protocol_all(si
);
777 si_rpc_byname(si_mod_t
*si
, const char *name
)
779 if (si
== NULL
) return NULL
;
780 if (si
->vtable
->sim_rpc_byname
== NULL
) return NULL
;
781 return si
->vtable
->sim_rpc_byname(si
, name
);
786 si_rpc_bynumber(si_mod_t
*si
, int number
)
788 if (si
== NULL
) return NULL
;
789 if (si
->vtable
->sim_rpc_bynumber
== NULL
) return NULL
;
790 return si
->vtable
->sim_rpc_bynumber(si
, number
);
795 si_rpc_all(si_mod_t
*si
)
797 if (si
== NULL
) return NULL
;
798 if (si
->vtable
->sim_rpc_all
== NULL
) return NULL
;
799 return si
->vtable
->sim_rpc_all(si
);
804 si_fs_byspec(si_mod_t
*si
, const char *spec
)
806 if (si
== NULL
) return NULL
;
807 if (si
->vtable
->sim_fs_byspec
== NULL
) return NULL
;
808 return si
->vtable
->sim_fs_byspec(si
, spec
);
813 si_fs_byfile(si_mod_t
*si
, const char *file
)
815 if (si
== NULL
) return NULL
;
816 if (si
->vtable
->sim_fs_byfile
== NULL
) return NULL
;
817 return si
->vtable
->sim_fs_byfile(si
, file
);
822 si_fs_all(si_mod_t
*si
)
824 if (si
== NULL
) return NULL
;
825 if (si
->vtable
->sim_fs_all
== NULL
) return NULL
;
826 return si
->vtable
->sim_fs_all(si
);
831 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
)
833 if (si
== NULL
) return NULL
;
837 case SI_CALL_USER_BYNAME
: return si_user_byname(si
, str1
);
838 case SI_CALL_USER_BYUID
: return si_user_byuid(si
, (uid_t
)num1
);
839 case SI_CALL_GROUP_BYNAME
: return si_group_byname(si
, str1
);
840 case SI_CALL_GROUP_BYGID
: return si_group_bygid(si
, (gid_t
)num1
);
841 case SI_CALL_GROUPLIST
: return si_grouplist(si
, str1
, (int) num1
);
842 case SI_CALL_ALIAS_BYNAME
: return si_alias_byname(si
, str1
);
843 case SI_CALL_HOST_BYNAME
: return si_host_byname(si
, str1
, num1
, str3
, err
);
844 case SI_CALL_HOST_BYADDR
: return si_host_byaddr(si
, (void *)str1
, num1
, str3
, err
);
845 case SI_CALL_NETWORK_BYNAME
: return si_network_byname(si
, str1
);
846 case SI_CALL_NETWORK_BYADDR
: return si_network_byaddr(si
, num1
);
847 case SI_CALL_SERVICE_BYNAME
: return si_service_byname(si
, str1
, str2
);
848 case SI_CALL_SERVICE_BYPORT
: return si_service_byport(si
, num1
, str2
);
849 case SI_CALL_PROTOCOL_BYNAME
: return si_protocol_byname(si
, str1
);
850 case SI_CALL_PROTOCOL_BYNUMBER
: return si_protocol_bynumber(si
, num1
);
851 case SI_CALL_RPC_BYNAME
: return si_network_byname(si
, str1
);
852 case SI_CALL_RPC_BYNUMBER
: return si_rpc_bynumber(si
, num1
);
853 case SI_CALL_FS_BYSPEC
: return si_fs_byspec(si
, str1
);
854 case SI_CALL_FS_BYFILE
: return si_fs_byfile(si
, str1
);
855 case SI_CALL_NAMEINFO
: return si_nameinfo(si
, (const struct sockaddr
*)str1
, num1
, str3
, err
);
856 case SI_CALL_IPNODE_BYNAME
: return si_ipnode_byname(si
, (const char *)str1
, num1
, num2
, str3
, err
);
857 case SI_CALL_MAC_BYNAME
: return si_mac_byname(si
, (const char *)str1
);
858 case SI_CALL_MAC_BYMAC
: return si_mac_bymac(si
, (const char *)str1
);
860 /* Support for DNS async calls */
861 case SI_CALL_DNS_QUERY
:
862 case SI_CALL_DNS_SEARCH
:
864 if (si
->vtable
->sim_item_call
== NULL
) return NULL
;
865 return si
->vtable
->sim_item_call(si
, call
, str1
, str2
, str3
, num1
, num2
, err
);
868 default: return NULL
;
876 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
)
878 if (si
== NULL
) return NULL
;
882 case SI_CALL_USER_ALL
: return si_user_all(si
);
883 case SI_CALL_GROUP_ALL
: return si_group_all(si
);
884 case SI_CALL_ALIAS_ALL
: return si_alias_all(si
);
885 case SI_CALL_HOST_ALL
: return si_host_all(si
);
886 case SI_CALL_NETWORK_ALL
: return si_network_all(si
);
887 case SI_CALL_SERVICE_ALL
: return si_service_all(si
);
888 case SI_CALL_PROTOCOL_ALL
: return si_protocol_all(si
);
889 case SI_CALL_RPC_ALL
: return si_rpc_all(si
);
890 case SI_CALL_FS_ALL
: return si_fs_all(si
);
891 case SI_CALL_MAC_ALL
: return si_mac_all(si
);
892 case SI_CALL_ADDRINFO
: return si_addrinfo(si
, str1
, str2
, num1
, num2
, num3
, num4
, str3
, err
);
893 default: return NULL
;
900 si_async_worklist_add_unit(si_async_workunit_t
*r
)
902 pthread_mutex_lock(&module_mutex
);
903 r
->next
= si_async_worklist
;
904 si_async_worklist
= r
;
905 pthread_mutex_unlock(&module_mutex
);
909 si_async_worklist_remove_unit(si_async_workunit_t
*r
)
911 si_async_workunit_t
*x
;
913 pthread_mutex_lock(&module_mutex
);
914 if (si_async_worklist
== r
)
916 si_async_worklist
= r
->next
;
920 for (x
= si_async_worklist
; (x
!= NULL
) && (x
->next
!= r
); x
= x
->next
) {;}
921 if (x
!= NULL
) x
->next
= r
->next
;
923 pthread_mutex_unlock(&module_mutex
);
926 static si_async_workunit_t
*
927 si_async_worklist_find_unit(mach_port_t p
)
929 si_async_workunit_t
*r
;
931 pthread_mutex_lock(&module_mutex
);
932 for (r
= si_async_worklist
; (r
!= NULL
) && (r
->port
!= p
); r
= r
->next
) {;}
933 pthread_mutex_unlock(&module_mutex
);
938 static si_async_workunit_t
*
939 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
)
941 si_async_workunit_t
*r
;
942 kern_return_t status
;
943 mach_port_t reply
, send
;
944 mach_msg_type_name_t type
;
951 if (si_call_str1_is_buffer(call
))
955 s1
= calloc(1, num3
);
956 if (s1
== NULL
) return NULL
;
957 memcpy(s1
, str1
, num3
);
960 else if (str1
!= NULL
)
963 if (s1
== NULL
) return NULL
;
971 if (s1
!= NULL
) free(s1
);
981 if (s1
!= NULL
) free(s1
);
982 if (s2
!= NULL
) free(s2
);
987 r
= (si_async_workunit_t
*)calloc(1, sizeof(si_async_workunit_t
));
990 if (s1
!= NULL
) free(s1
);
991 if (s2
!= NULL
) free(s2
);
992 if (s3
!= NULL
) free(s3
);
996 reply
= MACH_PORT_NULL
;
997 send
= MACH_PORT_NULL
;
1000 status
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &reply
);
1001 if (status
== KERN_SUCCESS
) status
= mach_port_extract_right(mach_task_self(), reply
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &send
, &type
);
1002 if (status
!= KERN_SUCCESS
)
1004 if (reply
!= MACH_PORT_NULL
) mach_port_mod_refs(mach_task_self(), reply
, MACH_PORT_RIGHT_RECEIVE
, -1);
1005 if (s1
!= NULL
) free(s1
);
1006 if (s2
!= NULL
) free(s2
);
1007 if (s3
!= NULL
) free(s3
);
1024 if (si_call_returns_list(call
)) r
->flags
|= WORKUNIT_RETURNS_LIST
;
1026 r
->callback
= callback
;
1027 r
->context
= context
;
1031 si_async_worklist_add_unit(r
);
1037 si_async_workunit_release(si_async_workunit_t
*r
)
1039 if (r
== NULL
) return;
1041 if (OSAtomicDecrement32Barrier(&(r
->refcount
)) != 0) return;
1044 fprintf(stderr
, "** %s freeing worklist item %p\n", __func__
, r
);
1047 si_async_worklist_remove_unit(r
);
1049 if (r
->resitem
!= NULL
) si_item_release(r
->resitem
);
1050 if (r
->reslist
!= NULL
) si_list_release(r
->reslist
);
1052 if (r
->str1
!= NULL
) free(r
->str1
);
1053 if (r
->str2
!= NULL
) free(r
->str2
);
1054 if (r
->str3
!= NULL
) free(r
->str3
);
1056 /* release send-once right if it has not been used */
1057 if (r
->send
!= MACH_PORT_NULL
) mach_port_deallocate(mach_task_self(), r
->send
);
1059 /* release receive right */
1060 mach_port_mod_refs(mach_task_self(), r
->port
, MACH_PORT_RIGHT_RECEIVE
, -1);
1066 si_async_launchpad(si_async_workunit_t
*r
)
1068 kern_return_t status
;
1069 mach_msg_empty_send_t msg
;
1072 fprintf(stderr
, "** %s starting worklist item %p\n", __func__
, r
);
1075 if (r
->flags
& WORKUNIT_CANCELLED
)
1077 si_async_workunit_release(r
);
1079 fprintf(stderr
, "** %s worklist item %p was cancelled early\n", __func__
, r
);
1084 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
));
1085 else r
->resitem
= si_item_call(r
->si
, r
->call
, r
->str1
, r
->str2
, r
->str3
, r
->num1
, r
->num2
, &(r
->err
));
1088 * Test and set the cancelled flag.
1089 * If it was set, then this work item was cancelled.
1090 * Otherwise, setting it here prevents si_async_cancel from cancelling:
1091 * too late to cancel now!
1093 if (OSAtomicTestAndSetBarrier(WORKUNIT_CANCELLED_BIT_ADDRESS
, &(r
->flags
)) == 1)
1095 si_async_workunit_release(r
);
1097 fprintf(stderr
, "** %s worklist item %p was cancelled in flight\n", __func__
, r
);
1102 else fprintf(stderr
, "** %s worklist item %p flags are now 0x%08x\n", __func__
, r
, r
->flags
);
1105 memset(&msg
, 0, sizeof(mach_msg_empty_send_t
));
1107 msg
.header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE
, MACH_MSGH_BITS_ZERO
);
1108 msg
.header
.msgh_remote_port
= r
->send
;
1109 r
->send
= MACH_PORT_NULL
;
1110 msg
.header
.msgh_local_port
= MACH_PORT_NULL
;
1111 msg
.header
.msgh_size
= sizeof(mach_msg_empty_send_t
);
1112 msg
.header
.msgh_id
= r
->call
;
1114 status
= mach_msg(&(msg
.header
), MACH_SEND_MSG
, msg
.header
.msgh_size
, 0, MACH_PORT_NULL
, MACH_MSG_TIMEOUT_NONE
, MACH_PORT_NULL
);
1115 if ((status
== MACH_SEND_INVALID_DEST
) || (status
== MACH_SEND_TIMED_OUT
))
1117 /* receiver failed - clean up to avoid a port leak */
1118 mach_msg_destroy(&(msg
.header
));
1120 fprintf(stderr
, "** %s mach message send failed for worklist item %p\n", __func__
, r
);
1124 si_async_workunit_release(r
);
1127 * The client is now responsible for calling si_async_handle_reply,
1128 * which will invoke the client's callback and then release the workunit.
1132 fprintf(stderr
, "** %s completed async worklist item %p\n", __func__
, r
);
1138 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
)
1140 si_async_workunit_t
*req
;
1142 if (si
== NULL
) return MACH_PORT_NULL
;
1143 if (callback
== NULL
) return MACH_PORT_NULL
;
1145 /* if module does async on it's own, hand off the call */
1146 if (si
->vtable
->sim_async_call
!= NULL
)
1148 return si
->vtable
->sim_async_call(si
, call
, str1
, str2
, str3
, num1
, num2
, num3
, num4
, callback
, context
);
1151 req
= si_async_workunit_create(si
, call
, str1
, str2
, str3
, num1
, num2
, num3
, num4
, callback
, context
);
1152 if (req
== NULL
) return MACH_PORT_NULL
;
1154 /* queue the work on the global low-priority dispatch queue */
1156 fprintf(stderr
, "** %s dispatching worklist item %p\n", __func__
, req
);
1158 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, DISPATCH_QUEUE_OVERCOMMIT
), ^{ si_async_launchpad(req
); });
1165 si_async_cancel(mach_port_t p
)
1167 si_async_workunit_t
*r
;
1169 r
= si_async_worklist_find_unit(p
);
1173 fprintf(stderr
, "** %s can't find worklist item\n", __func__
);
1179 * Test and set the WORKUNIT_CANCELLED flag.
1180 * If it was already set, this work item has been executed - too late to really cancel.
1182 if (OSAtomicTestAndSetBarrier(WORKUNIT_CANCELLED_BIT_ADDRESS
, &(r
->flags
)) == 1)
1184 /* already executed */
1186 fprintf(stderr
, "** %s worklist item %p has executed\n", __func__
, r
);
1191 fprintf(stderr
, "** %s calling worklist item %p callback SI_STATUS_CALL_CANCELLED\n", __func__
, r
);
1194 if (r
->callback
!= NULL
)
1196 if (r
->flags
& WORKUNIT_RETURNS_LIST
) ((list_async_callback
)(r
->callback
))(NULL
, SI_STATUS_CALL_CANCELLED
, r
->context
);
1197 else ((item_async_callback
)(r
->callback
))(NULL
, SI_STATUS_CALL_CANCELLED
, r
->context
);
1200 si_async_workunit_release(r
);
1205 si_async_handle_reply(mach_msg_header_t
*msg
)
1207 si_async_workunit_t
*r
;
1208 mach_port_t reply
= msg
->msgh_local_port
;
1210 r
= si_async_worklist_find_unit(reply
);
1214 fprintf(stderr
, "** %s can't find worklist item\n", __func__
);
1220 fprintf(stderr
, "** %s worklist item %p flags are 0x%08x\n", __func__
, r
, r
->flags
);
1222 if ((r
->flags
& WORKUNIT_CANCELLED
) == 0)
1225 fprintf(stderr
, "** %s workunit thread is still active\n", __func__
);
1230 if (r
->callback
!= NULL
)
1232 if (r
->flags
& WORKUNIT_RETURNS_LIST
) ((list_async_callback
)(r
->callback
))(r
->reslist
, r
->err
, r
->context
);
1233 else ((item_async_callback
)(r
->callback
))(r
->resitem
, r
->err
, r
->context
);
1241 fprintf(stderr
, "** %s workunit has no callback\n", __func__
);
1245 si_async_workunit_release(r
);
1250 si_standardize_mac_address(const char *addr
)
1254 struct ether_addr
*ether
;
1257 if (addr
== NULL
) return NULL
;
1259 /* ether_aton isn't thread-safe */
1260 pthread_mutex_lock(&module_mutex
);
1262 ether
= ether_aton(addr
);
1265 pthread_mutex_unlock(&module_mutex
);
1269 for (i
= 0; i
< 6; i
++)
1271 if (ether
->ether_addr_octet
[i
] <= 15)
1273 sprintf(e
[i
], "0%x", ether
->ether_addr_octet
[i
]);
1277 sprintf(e
[i
], "%x", ether
->ether_addr_octet
[i
]);
1281 pthread_mutex_unlock(&module_mutex
);
1284 asprintf(&out
, "%s:%s:%s:%s:%s:%s", e
[0], e
[1], e
[2], e
[3], e
[4], e
[5]);