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>
32 // yes, we use some UNIX (non-mach) headers...
33 #include <sys/types.h>
37 namespace MachPlusPlus
{
41 // Exceptions thrown by the mach++ interface.
43 class Error
: public CssmCommonError
{
45 // actually, kern_return_t can be just about any subsystem type return code
46 Error(kern_return_t err
);
48 virtual ~Error() throw();
50 virtual CSSM_RETURN
cssmError() const;
51 virtual OSStatus
osStatus() const;
53 const kern_return_t error
;
55 static void check(kern_return_t err
);
56 static void throwMe(kern_return_t err
) __attribute__((noreturn
));
59 IFDEBUG(void debugDiagnose(const void *id
) const);
62 // generic return code checker
63 inline void check(kern_return_t status
)
64 { Error::check(status
); }
68 // Simple vm_allocate/deallocate glue
70 void *allocate(size_t size
);
71 void deallocate(vm_address_t addr
, size_t size
);
73 inline void deallocate(const void *addr
, size_t size
)
74 { deallocate(reinterpret_cast<vm_address_t
>(addr
), size
); }
78 // An encapsulation of a Mach 3 port
82 static mach_port_t
self() { return mach_task_self(); }
86 Port(mach_port_t port
) { mPort
= port
; }
88 // devolve to Mach primitive type
89 operator mach_port_t () const { return mPort
; }
91 // access reference (for primitives storing into &mach_port_t)
92 mach_port_t
&port () { return mPort
; }
93 const mach_port_t
&port () const { return mPort
; }
96 mach_port_type_t
type() const
97 { mach_port_type_t typ
; check(mach_port_type(self(), mPort
, &typ
)); return typ
; }
99 bool isType(mach_port_type_t typ
) const { return type() & typ
; }
100 bool isDead() const { return isType(MACH_PORT_TYPE_DEAD_NAME
); }
102 // port allocation and management
103 void allocate(mach_port_right_t right
= MACH_PORT_RIGHT_RECEIVE
)
104 { check(mach_port_allocate(self(), right
, &mPort
)); }
105 void deallocate() { check(mach_port_deallocate(self(), mPort
)); }
106 void destroy() { check(mach_port_destroy(self(), mPort
)); }
108 void insertRight(mach_msg_type_name_t type
)
109 { check(mach_port_insert_right(self(), mPort
, mPort
, type
)); }
111 void modRefs(mach_port_right_t right
, mach_port_delta_t delta
= 1)
112 { check(mach_port_mod_refs(self(), mPort
, right
, delta
)); }
114 mach_port_urefs_t
getRefs(mach_port_right_t right
);
116 // port notification interface
117 mach_port_t
requestNotify(mach_port_t notify
, mach_msg_id_t type
, mach_port_mscount_t sync
= 1);
118 mach_port_t
cancelNotify(mach_msg_id_t type
);
120 IFDUMP(void dump(const char *name
= NULL
));
128 // Ports representing PortSets
130 class PortSet
: public Port
{
132 PortSet() { allocate(MACH_PORT_RIGHT_PORT_SET
); }
133 ~PortSet() { destroy(); }
135 void operator += (const Port
&port
)
136 { check(mach_port_move_member(self(), port
, mPort
)); }
138 void operator -= (const Port
&port
)
139 { check(mach_port_move_member(self(), port
, MACH_PORT_NULL
)); }
141 set
<Port
> members() const;
142 bool contains(Port member
) const; // relatively slow
147 // Ports that are bootstrap ports
149 class Bootstrap
: public Port
{
151 Bootstrap() { check(task_get_bootstrap_port(mach_task_self(), &mPort
)); }
152 Bootstrap(mach_port_t bootp
) : Port(bootp
) { }
154 mach_port_t
checkIn(const char *name
) const;
155 mach_port_t
checkInOptional(const char *name
) const;
157 void registerAs(mach_port_t port
, const char *name
) const;
159 mach_port_t
lookup(const char *name
) const;
160 mach_port_t
lookupOptional(const char *name
) const;
162 Bootstrap
subset(Port requestor
);
167 // officially, the register/lookup IPCs take an array of 128 characters (not a zero-end string)
168 mutable char nameBuffer
[BOOTSTRAP_MAX_NAME_LEN
];
171 char *Bootstrap::makeName(const char *s
) const
172 { return strncpy(nameBuffer
, s
, BOOTSTRAP_MAX_NAME_LEN
); }
177 // Ports that are Task Ports
179 class TaskPort
: public Port
{
181 TaskPort() { mPort
= self(); }
182 TaskPort(const Port
&p
) { mPort
= p
; }
184 Bootstrap
bootstrap() const
185 { mach_port_t boot
; check(task_get_bootstrap_port(mPort
, &boot
)); return boot
; }
186 void bootstrap(Bootstrap boot
)
187 { check(task_set_bootstrap_port(mPort
, boot
)); }
190 static TaskPort
forPid(pid_t pid
);
195 // Ports that are are self-allocated and have receive rights
197 class ReceivePort
: public Port
{
199 ReceivePort() { allocate(); }
200 ReceivePort(const char *name
, const Bootstrap
&bootstrap
);
201 ~ReceivePort() { destroy(); }
206 // A little stack utility for temporarily switching your bootstrap around.
207 // Essentially, it restores your bootstrap port when it dies. Since the
208 // "current bootstrap port" is a process-global item, this uses a global
209 // zone of exclusion (aka critical region). There's no protection against
210 // someone else calling the underlying system service, of course.
214 StBootstrap(const Bootstrap
&boot
, const TaskPort
&task
= TaskPort());
220 StLock
<Mutex
> locker
;
221 static ModuleNexus
<Mutex
> critical
; // critical region guard (of a sort)
226 // A Mach-level memory guard.
227 // This will vm_deallocate its argument when it gets destroyed.
231 VMGuard(void *addr
, size_t length
) : mAddr(addr
), mLength(length
) { }
232 ~VMGuard() { deallocate(mAddr
, mLength
); }
241 // Message buffers for Mach messages.
242 // This class is for relatively simple uses.
246 Message(void *buffer
, size_t size
);
247 Message(size_t size
);
250 operator mig_reply_error_t
& () const { return *mBuffer
; }
251 operator mach_msg_header_t
& () const { return mBuffer
->Head
; }
252 operator mig_reply_error_t
* () const { return mBuffer
; }
253 operator mach_msg_header_t
* () const { return &mBuffer
->Head
; }
254 operator NDR_record_t
& () const { return mBuffer
->NDR
; }
256 void *data() const { return mBuffer
; }
257 size_t length() const { return mBuffer
->Head
.msgh_size
; }
258 Port
localPort() const { return mBuffer
->Head
.msgh_local_port
; }
259 Port
remotePort() const { return mBuffer
->Head
.msgh_remote_port
; }
260 mach_msg_id_t
msgId() const { return mBuffer
->Head
.msgh_id
; }
261 mach_msg_bits_t
bits() const { return mBuffer
->Head
.msgh_bits
; }
262 kern_return_t
returnCode() const { return mBuffer
->RetCode
; }
264 void localPort(mach_port_t p
) { mBuffer
->Head
.msgh_local_port
= p
; }
265 void remotePort(mach_port_t p
) { mBuffer
->Head
.msgh_remote_port
= p
; }
268 bool send(mach_msg_option_t options
= 0,
269 mach_msg_timeout_t timeout
= MACH_MSG_TIMEOUT_NONE
,
270 mach_port_name_t notify
= MACH_PORT_NULL
);
271 bool receive(mach_port_t receivePort
,
272 mach_msg_option_t options
= 0,
273 mach_msg_timeout_t timeout
= MACH_MSG_TIMEOUT_NONE
,
274 mach_port_name_t notify
= MACH_PORT_NULL
);
275 bool sendReceive(mach_port_t receivePort
,
276 mach_msg_option_t options
= 0,
277 mach_msg_timeout_t timeout
= MACH_MSG_TIMEOUT_NONE
,
278 mach_port_name_t notify
= MACH_PORT_NULL
);
280 void destroy() { mach_msg_destroy(*this); }
283 bool check(kern_return_t status
);
286 mig_reply_error_t
*mBuffer
;
292 } // end namespace MachPlusPlus
293 } // end namespace Security