2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 // mach++ - C++ bindings for useful Mach primitives
25 #include <Security/utilities.h>
26 #include <Security/threading.h>
27 #include <Security/globalizer.h>
28 #include <mach/mach.h>
29 #include <servers/bootstrap.h>
31 // yes, we use some UNIX (non-mach) headers...
32 #include <sys/types.h>
36 namespace MachPlusPlus
{
40 // Exceptions thrown by the mach++ interface.
42 class Error
: public CssmCommonError
{
44 // actually, kern_return_t can be just about any subsystem type return code
45 Error(kern_return_t err
);
49 virtual CSSM_RETURN
cssmError() const;
50 virtual OSStatus
osStatus() const;
52 const kern_return_t error
;
54 static void check(kern_return_t err
);
55 static void throwMe(kern_return_t err
) __attribute__((noreturn
));
58 // generic return code checker
59 inline void check(kern_return_t status
)
60 { Error::check(status
); }
64 // An encapsulation of a Mach 3 port
68 static mach_port_t
self() { return mach_task_self(); }
72 Port(mach_port_t port
) { mPort
= port
; }
74 // devolve to Mach primitive type
75 operator mach_port_t () const { return mPort
; }
77 // access reference (for primitives storing into &mach_port_t)
78 mach_port_t
&port () { return mPort
; }
79 const mach_port_t
&port () const { return mPort
; }
82 mach_port_type_t
type() const
83 { mach_port_type_t typ
; check(mach_port_type(self(), mPort
, &typ
)); return typ
; }
85 bool isType(mach_port_type_t typ
) const { return type() & typ
; }
86 bool isDead() const { return isType(MACH_PORT_TYPE_DEAD_NAME
); }
88 // port allocation and management
89 void allocate(mach_port_right_t right
= MACH_PORT_RIGHT_RECEIVE
)
90 { check(mach_port_allocate(self(), right
, &mPort
)); }
91 void deallocate() { check(mach_port_deallocate(self(), mPort
)); }
92 void destroy() { check(mach_port_destroy(self(), mPort
)); }
94 void insertRight(mach_msg_type_name_t type
)
95 { check(mach_port_insert_right(self(), mPort
, mPort
, type
)); }
97 void modRefs(mach_port_right_t right
, mach_port_delta_t delta
= 1)
98 { check(mach_port_mod_refs(self(), mPort
, right
, delta
)); }
100 mach_port_urefs_t
getRefs(mach_port_right_t right
);
102 // port notification interface
103 mach_port_t
requestNotify(mach_port_t notify
, mach_msg_id_t type
, mach_port_mscount_t sync
= 1)
105 mach_port_t previous
;
106 check(mach_port_request_notification(self(), mPort
, type
, sync
, notify
,
107 MACH_MSG_TYPE_MAKE_SEND_ONCE
, &previous
));
111 IFDUMP(void dump(const char *name
= NULL
));
119 // Ports representing PortSets
121 class PortSet
: public Port
{
123 PortSet() { allocate(MACH_PORT_RIGHT_PORT_SET
); }
124 ~PortSet() { destroy(); }
126 void operator += (const Port
&port
)
127 { check(mach_port_move_member(self(), port
, mPort
)); }
129 void operator -= (const Port
&port
)
130 { check(mach_port_move_member(self(), port
, MACH_PORT_NULL
)); }
135 // Ports that are bootstrap ports
137 class Bootstrap
: public Port
{
139 Bootstrap() { check(task_get_bootstrap_port(mach_task_self(), &mPort
)); }
140 Bootstrap(mach_port_t bootp
) : Port(bootp
) { }
142 mach_port_t
checkIn(const char *name
) const;
143 mach_port_t
checkInOptional(const char *name
) const;
145 void registerAs(mach_port_t port
, const char *name
) const;
147 mach_port_t
lookup(const char *name
) const;
148 mach_port_t
lookupOptional(const char *name
) const;
150 Bootstrap
subset(Port requestor
);
155 // officially, the register/lookup IPCs take an array of 128 characters (not a zero-end string)
156 mutable char nameBuffer
[BOOTSTRAP_MAX_NAME_LEN
];
159 char *Bootstrap::makeName(const char *s
) const
160 { return strncpy(nameBuffer
, s
, BOOTSTRAP_MAX_NAME_LEN
); }
165 // Ports that are Task Ports
167 class TaskPort
: public Port
{
169 TaskPort() { mPort
= self(); }
170 TaskPort(const Port
&p
) { mPort
= p
; }
172 Bootstrap
bootstrap() const
173 { mach_port_t boot
; check(task_get_bootstrap_port(mPort
, &boot
)); return boot
; }
174 void bootstrap(Bootstrap boot
)
175 { check(task_set_bootstrap_port(mPort
, boot
)); }
178 static TaskPort
forPid(pid_t pid
);
183 // Ports that are are self-allocated and have receive rights
185 class ReceivePort
: public Port
{
187 ReceivePort() { allocate(); }
188 ReceivePort(const char *name
, const Bootstrap
&bootstrap
);
189 ~ReceivePort() { destroy(); }
194 // A little stack utility for temporarily switching your bootstrap around.
195 // Essentially, it restores your bootstrap port when it dies. Since the
196 // "current bootstrap port" is a process-global item, this uses a global
197 // zone of exclusion (aka critical region). There's no protection against
198 // someone else calling the underlying system service, of course.
202 StBootstrap(const Bootstrap
&boot
, const TaskPort
&task
= TaskPort());
208 StLock
<Mutex
> locker
;
209 static ModuleNexus
<Mutex
> critical
; // critical region guard (of a sort)
214 // Message buffers for Mach messages.
215 // This class is for relatively simple uses.
219 Message(void *buffer
, size_t size
);
220 Message(size_t size
);
223 operator mig_reply_error_t
& () const { return *mBuffer
; }
224 operator mach_msg_header_t
& () const { return mBuffer
->Head
; }
225 operator mig_reply_error_t
* () const { return mBuffer
; }
226 operator mach_msg_header_t
* () const { return &mBuffer
->Head
; }
227 operator NDR_record_t
& () const { return mBuffer
->NDR
; }
229 void *data() const { return mBuffer
; }
230 size_t length() const { return mBuffer
->Head
.msgh_size
; }
231 Port
localPort() const { return mBuffer
->Head
.msgh_local_port
; }
232 Port
remotePort() const { return mBuffer
->Head
.msgh_remote_port
; }
233 mach_msg_id_t
msgId() const { return mBuffer
->Head
.msgh_id
; }
234 mach_msg_bits_t
bits() const { return mBuffer
->Head
.msgh_bits
; }
235 kern_return_t
returnCode() const { return mBuffer
->RetCode
; }
237 void localPort(mach_port_t p
) { mBuffer
->Head
.msgh_local_port
= p
; }
238 void remotePort(mach_port_t p
) { mBuffer
->Head
.msgh_remote_port
= p
; }
241 void send(mach_msg_option_t options
= 0,
242 mach_msg_timeout_t timeout
= MACH_MSG_TIMEOUT_NONE
,
243 mach_port_name_t notify
= MACH_PORT_NULL
);
244 void receive(mach_port_t receivePort
,
245 mach_msg_option_t options
= 0,
246 mach_msg_timeout_t timeout
= MACH_MSG_TIMEOUT_NONE
,
247 mach_port_name_t notify
= MACH_PORT_NULL
);
248 void sendReceive(mach_port_t receivePort
,
249 mach_msg_option_t options
= 0,
250 mach_msg_timeout_t timeout
= MACH_MSG_TIMEOUT_NONE
,
251 mach_port_name_t notify
= MACH_PORT_NULL
);
253 void destroy() { mach_msg_destroy(*this); }
256 mig_reply_error_t
*mBuffer
;
262 } // end namespace MachPlusPlus
263 } // end namespace Security