2 * Copyright (c) 2000-2004,2011-2012,2014 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@
26 // mach++ - C++ bindings for useful Mach primitives
31 #include <security_utilities/utilities.h>
32 #include <security_utilities/errors.h>
33 #include <security_utilities/threading.h>
34 #include <security_utilities/globalizer.h>
35 #include <security_utilities/debugging_internal.h>
36 #include <mach/mach.h>
37 #include <servers/bootstrap.h>
40 // yes, we use some UNIX (non-mach) headers...
41 #include <sys/types.h>
45 namespace MachPlusPlus
{
49 // Exceptions thrown by the mach++ interface.
51 class Error
: public CommonError
{
53 // actually, kern_return_t can be just about any subsystem type return code
54 Error(kern_return_t err
);
56 virtual ~Error() throw();
58 virtual OSStatus
osStatus() const;
59 virtual int unixError() const;
61 const kern_return_t error
;
63 static void check(kern_return_t err
);
64 static void throwMe(kern_return_t err
) __attribute__((noreturn
));
67 // generic return code checker
68 inline void check(kern_return_t status
)
69 { Error::check(status
); }
73 // Simple vm_allocate/deallocate glue
75 void *allocate(size_t size
);
76 void deallocate(vm_address_t addr
, size_t size
);
78 inline void deallocate(const void *addr
, size_t size
)
79 { deallocate(reinterpret_cast<vm_address_t
>(addr
), size
); }
83 // An encapsulation of a Mach 3 port
87 static mach_port_t
self() { return mach_task_self(); }
90 Port() { mPort
= MACH_PORT_NULL
; }
91 Port(mach_port_t port
) { mPort
= port
; }
93 // devolve to Mach primitive type
94 operator mach_port_t () const { return mPort
; }
96 // access reference (for primitives storing into &mach_port_t)
97 mach_port_t
&port () { return mPort
; }
98 const mach_port_t
&port () const { return mPort
; }
101 mach_port_type_t
type() const
102 { mach_port_type_t typ
; check(mach_port_type(self(), mPort
, &typ
)); return typ
; }
104 bool isType(mach_port_type_t typ
) const { return type() & typ
; }
105 bool isDead() const { return isType(MACH_PORT_TYPE_DEAD_NAME
); }
107 // port allocation and management
108 void allocate(mach_port_right_t right
= MACH_PORT_RIGHT_RECEIVE
)
109 { check(mach_port_allocate(self(), right
, &mPort
)); }
110 void deallocate() { check(mach_port_deallocate(self(), mPort
)); mPort
= MACH_PORT_NULL
;}
111 void destroy() { check(mach_port_destroy(self(), mPort
)); mPort
= MACH_PORT_NULL
; }
113 void insertRight(mach_msg_type_name_t type
)
114 { check(mach_port_insert_right(self(), mPort
, mPort
, type
)); }
116 void modRefs(mach_port_right_t right
, mach_port_delta_t delta
= 1)
117 { check(mach_port_mod_refs(self(), mPort
, right
, delta
)); }
119 mach_port_urefs_t
getRefs(mach_port_right_t right
);
121 // port notification interface
122 mach_port_t
requestNotify(mach_port_t notify
,
123 mach_msg_id_t type
= MACH_NOTIFY_DEAD_NAME
, mach_port_mscount_t sync
= 1);
124 mach_port_t
cancelNotify(mach_msg_id_t type
= MACH_NOTIFY_DEAD_NAME
);
126 // queue state management
127 mach_port_msgcount_t
qlimit() const;
128 void qlimit(mach_port_msgcount_t limit
);
130 IFDUMP(void dump(const char *name
= NULL
));
138 // A simple Port that deallocates itself on destruction.
139 // If you need a subclass of Port, just assign it to a separate AutoPort.
141 class AutoPort
: public Port
{
144 AutoPort(mach_port_t port
) : Port(port
) { }
145 ~AutoPort() { if (mPort
!= MACH_PORT_NULL
) deallocate(); }
150 // Ports representing PortSets
152 class PortSet
: public Port
{
154 PortSet() { allocate(MACH_PORT_RIGHT_PORT_SET
); }
155 ~PortSet() { destroy(); }
157 void operator += (const Port
&port
)
158 { check(mach_port_move_member(self(), port
, mPort
)); }
160 void operator -= (const Port
&port
)
161 { check(mach_port_move_member(self(), port
, MACH_PORT_NULL
)); }
163 set
<Port
> members() const;
164 bool contains(Port member
) const; // relatively slow
169 // Ports that are bootstrap ports
171 class Bootstrap
: public Port
{
173 Bootstrap() { check(task_get_bootstrap_port(mach_task_self(), &mPort
)); }
174 Bootstrap(mach_port_t bootp
) : Port(bootp
) { }
176 mach_port_t
checkIn(const char *name
) const;
177 mach_port_t
checkInOptional(const char *name
) const;
179 void registerAs(mach_port_t port
, const char *name
) const;
181 mach_port_t
lookup(const char *name
) const;
182 mach_port_t
lookup2(const char *name
) const;
183 mach_port_t
lookupOptional(const char *name
) const;
185 Bootstrap
subset(Port requestor
);
190 // officially, the register/lookup IPCs take an array of 128 characters (not a zero-end string)
191 mutable char nameBuffer
[BOOTSTRAP_MAX_NAME_LEN
];
194 char *makeName(const char *s
) const
195 { return strncpy(nameBuffer
, s
, BOOTSTRAP_MAX_NAME_LEN
); }
200 // Ports that are Task Ports
202 class TaskPort
: public Port
{
204 TaskPort() { mPort
= self(); }
205 TaskPort(mach_port_t p
) : Port(p
) { }
206 TaskPort(const Port
&p
) : Port(p
) { }
209 Bootstrap
bootstrap() const
210 { mach_port_t boot
; check(task_get_bootstrap_port(mPort
, &boot
)); return boot
; }
211 void bootstrap(Bootstrap boot
)
212 { check(task_set_bootstrap_port(mPort
, boot
)); }
219 // Ports that are are self-allocated and have receive rights
221 class ReceivePort
: public Port
{
223 ReceivePort() { allocate(); }
224 ReceivePort(const char *name
, const Bootstrap
&bootstrap
, bool tryCheckin
= true);
225 ~ReceivePort() { destroy(); }
230 // A little stack utility for temporarily switching your bootstrap around.
231 // Essentially, it restores your bootstrap port when it dies. Since the
232 // "current bootstrap port" is a process-global item, this uses a global
233 // zone of exclusion (aka critical region). There's no protection against
234 // someone else calling the underlying system service, of course.
238 StBootstrap(const Bootstrap
&boot
, const TaskPort
&task
= TaskPort());
244 StLock
<Mutex
> locker
;
245 static ModuleNexus
<Mutex
> critical
; // critical region guard (of a sort)
250 // A Mach-level memory guard.
251 // This will vm_deallocate its argument when it gets destroyed.
255 VMGuard(void *addr
, size_t length
) : mAddr(addr
), mLength(length
) { }
256 ~VMGuard() { deallocate(mAddr
, mLength
); }
265 // Message buffers for Mach messages.
266 // The logic here is somewhat inverted from the usual: send/receive
267 // are methods on the buffers (rather than buffers being arguments to send/receive).
268 // It's rather handy once you get used to that view.
272 Message(void *buffer
, mach_msg_size_t size
); // use buffer with size
273 Message(mach_msg_size_t size
); // allocate buffer with size
274 Message(); // set buffer later
277 void setBuffer(void *buffer
, mach_msg_size_t size
); // use buffer with size
278 void setBuffer(mach_msg_size_t size
); // allocate buffer with size
279 void clearBuffer(void);
280 void release(); // discard buffer (if any)
282 operator mig_reply_error_t
& () const { return *mBuffer
; }
283 operator mach_msg_header_t
& () const { return mBuffer
->Head
; }
284 operator mig_reply_error_t
* () const { return mBuffer
; }
285 operator mach_msg_header_t
* () const { return &mBuffer
->Head
; }
286 operator NDR_record_t
& () const { return mBuffer
->NDR
; }
288 void *data() const { return mBuffer
; }
289 mach_msg_size_t
length() const { return mBuffer
->Head
.msgh_size
; }
290 Port
localPort() const { return mBuffer
->Head
.msgh_local_port
; }
291 Port
remotePort() const { return mBuffer
->Head
.msgh_remote_port
; }
292 mach_msg_id_t
msgId() const { return mBuffer
->Head
.msgh_id
; }
293 mach_msg_bits_t
bits() const { return mBuffer
->Head
.msgh_bits
; }
294 kern_return_t
returnCode() const { return mBuffer
->RetCode
; }
295 mach_msg_audit_trailer_t
*auditTrailer();
297 void localPort(mach_port_t p
) { mBuffer
->Head
.msgh_local_port
= p
; }
298 void remotePort(mach_port_t p
) { mBuffer
->Head
.msgh_remote_port
= p
; }
301 bool send(mach_msg_option_t options
= 0,
302 mach_msg_timeout_t timeout
= MACH_MSG_TIMEOUT_NONE
,
303 mach_port_name_t notify
= MACH_PORT_NULL
);
304 bool receive(mach_port_t receivePort
,
305 mach_msg_option_t options
= 0,
306 mach_msg_timeout_t timeout
= MACH_MSG_TIMEOUT_NONE
,
307 mach_port_name_t notify
= MACH_PORT_NULL
);
308 bool sendReceive(mach_port_t receivePort
,
309 mach_msg_option_t options
= 0,
310 mach_msg_timeout_t timeout
= MACH_MSG_TIMEOUT_NONE
,
311 mach_port_name_t notify
= MACH_PORT_NULL
);
313 void destroy() { mach_msg_destroy(*this); }
316 bool check(kern_return_t status
);
319 mig_reply_error_t
*mBuffer
;
320 mach_msg_size_t mSize
;
325 } // end namespace MachPlusPlus
326 } // end namespace Security