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
23 #include <mach/mach_error.h>
24 #include <stdio.h> // debug
25 #include <Security/debugging.h>
26 #include <servers/bootstrap_defs.h> // debug
29 namespace MachPlusPlus
{
32 Error::Error(kern_return_t err
) : error(err
)
36 Error::~Error() throw()
41 Error::cssmError() const
44 case BOOTSTRAP_UNKNOWN_SERVICE
:
46 return CSSM_ERRCODE_SERVICE_NOT_AVAILABLE
;
48 return CSSM_ERRCODE_INTERNAL_ERROR
;
53 Error::osStatus() const
58 void Error::check(kern_return_t status
)
60 if (status
!= KERN_SUCCESS
)
61 Error::throwMe(status
);
64 void Error::throwMe(kern_return_t err
)
71 void Error::debugDiagnose(const void *id
) const
76 name
= mach_error_string(error
); break;
77 case BOOTSTRAP_UNKNOWN_SERVICE
:
78 name
= "BOOTSTRAP_UNKNOWN_SERVICE"; break;
79 case BOOTSTRAP_NAME_IN_USE
:
80 name
= "BOOTSTRAP_NAME_IN_USE"; break;
81 case BOOTSTRAP_NOT_PRIVILEGED
:
82 name
= "BOOTSTRAP_NOT_PRIVILEGED"; break;
83 case BOOTSTRAP_SERVICE_ACTIVE
:
84 name
= "BOOTSTRAP_SERVICE_ACTIVE"; break;
86 debug("exception", "%p Mach Error %s (%d) osStatus %ld",
87 id
, name
, error
, osStatus());
95 void *allocate(size_t size
)
98 check(vm_allocate(mach_task_self(), &address
, size
, true));
99 return reinterpret_cast<void *>(address
);
102 void deallocate(vm_address_t address
, size_t size
)
104 check(vm_deallocate(mach_task_self(), address
, size
));
111 mach_port_urefs_t
Port::getRefs(mach_port_right_t right
)
113 mach_port_urefs_t count
;
114 check(::mach_port_get_refs(self(), mPort
, right
, &count
));
117 mach_port_t
Port::requestNotify(mach_port_t notify
, mach_msg_id_t type
, mach_port_mscount_t sync
)
119 mach_port_t previous
;
120 check(mach_port_request_notification(self(), mPort
, type
, sync
, notify
,
121 MACH_MSG_TYPE_MAKE_SEND_ONCE
, &previous
));
122 debug("port", "%d request notify(%d) to %d (sync=%d)", port(), type
, notify
, sync
);
126 mach_port_t
Port::cancelNotify(mach_msg_id_t type
)
128 // Mach won't let us unset the DPN port if we are already dead
129 // (EVEN if the DPN has already been sent!) So just ignore that case...
131 return MACH_PORT_NULL
;
132 debug("port", "%d cancel DPN", port());
133 return requestNotify(MACH_PORT_NULL
, type
);
140 set
<Port
> PortSet::members() const
142 mach_port_array_t members
;
143 mach_msg_type_number_t count
;
144 check(::mach_port_get_set_status(self(), mPort
, &members
, &count
));
147 copy(members
, members
+count
, inserter(result
, result
.begin()));
148 vm_deallocate(self(), vm_address_t(members
), count
* sizeof(members
[0]));
151 vm_deallocate(self(), vm_address_t(members
), count
* sizeof(members
[0]));
157 bool PortSet::contains(Port member
) const
159 set
<Port
> memberSet
= members();
160 return memberSet
.find(member
) != memberSet
.end();
165 // Task port features
167 pid_t
TaskPort::pid() const
170 check(::pid_for_task(mPort
, &pid
));
174 TaskPort
TaskPort::forPid(pid_t pid
)
177 check(::task_for_pid(self(), pid
, &taskPort
.port()));
183 // Bootstrap port management
185 mach_port_t
Bootstrap::checkIn(const char *name
) const
188 check(::bootstrap_check_in(mPort
, makeName(name
), &port
));
192 mach_port_t
Bootstrap::checkInOptional(const char *name
) const
195 switch (kern_return_t err
= ::bootstrap_check_in(mPort
, makeName(name
), &port
)) {
196 case BOOTSTRAP_SERVICE_ACTIVE
:
197 case BOOTSTRAP_UNKNOWN_SERVICE
:
198 case BOOTSTRAP_NOT_PRIVILEGED
:
206 void Bootstrap::registerAs(mach_port_t port
, const char *name
) const
208 debug("bootstrap", "creating service port %d in %d:%s", port
, this->port(), name
);
209 check(::bootstrap_register(mPort
, makeName(name
), port
));
212 mach_port_t
Bootstrap::lookup(const char *name
) const
215 check(::bootstrap_look_up(mPort
, makeName(name
), &port
));
219 mach_port_t
Bootstrap::lookupOptional(const char *name
) const
222 kern_return_t err
= ::bootstrap_look_up(mPort
, makeName(name
), &port
);
223 if (err
== BOOTSTRAP_UNKNOWN_SERVICE
)
230 Bootstrap
Bootstrap::subset(Port requestor
)
233 check(::bootstrap_subset(mPort
, requestor
, &sub
));
241 ReceivePort::ReceivePort(const char *name
, const Bootstrap
&bootstrap
)
243 mPort
= bootstrap
.checkInOptional(name
);
246 // Bootstrap registration requires a send right to (copy) send.
247 // Make a temporary one, send it, then take it away again, to avoid
248 // messing up the caller's send right accounting.
249 insertRight(MACH_MSG_TYPE_MAKE_SEND
);
250 bootstrap
.registerAs(mPort
, name
);
251 modRefs(MACH_PORT_RIGHT_SEND
, -1);
257 // Stack-based bootstrap switcher
259 ModuleNexus
<Mutex
> StBootstrap::critical
;
261 StBootstrap::StBootstrap(const Bootstrap
&newBoot
, const TaskPort
&task
)
262 : mTask(task
), locker(critical())
264 mOldBoot
= Bootstrap();
265 mTask
.bootstrap(newBoot
);
266 debug("StBoot", "bootstrap for %d switched to %d", mTask
.port(), newBoot
.port());
269 StBootstrap::~StBootstrap()
271 mTask
.bootstrap(mOldBoot
);
272 debug("StBoot", "bootstrap for %d returned to %d", mTask
.port(), mOldBoot
.port());
277 // Mach message buffers
279 Message::Message(void *buffer
, size_t size
)
280 : mBuffer(reinterpret_cast<mig_reply_error_t
*>(buffer
)),
281 mSize(size
), mRelease(false)
283 assert(size
>= sizeof(mach_msg_header_t
));
286 Message::Message(size_t size
)
288 mSize
= size
+ MAX_TRAILER_SIZE
;
289 mBuffer
= (mig_reply_error_t
*)new char[mSize
];
300 bool Message::check(kern_return_t status
)
305 case MACH_RCV_TIMED_OUT
:
306 case MACH_SEND_TIMED_OUT
:
309 Error::throwMe(status
);
314 bool Message::send(mach_msg_option_t options
,
315 mach_msg_timeout_t timeout
,
316 mach_port_name_t notify
)
318 return check(mach_msg_overwrite(*this,
319 options
| MACH_SEND_MSG
,
326 bool Message::receive(mach_port_t receivePort
,
327 mach_msg_option_t options
,
328 mach_msg_timeout_t timeout
,
329 mach_port_name_t notify
)
331 return check(mach_msg_overwrite(*this,
332 options
| MACH_RCV_MSG
,
339 bool Message::sendReceive(mach_port_t receivePort
,
340 mach_msg_option_t options
,
341 mach_msg_timeout_t timeout
,
342 mach_port_name_t notify
)
344 return check(mach_msg_overwrite(*this,
345 options
| MACH_SEND_MSG
| MACH_RCV_MSG
,
354 // Debug dumping of ports etc.
356 #if defined(DEBUGDUMP)
358 void Port::dump(const char *descr
)
360 if (mPort
== MACH_PORT_NULL
) {
361 Debug::dump("[%s==NULL]\n", descr
? descr
: "port");
363 Debug::dump("[%s(%d)", descr
? descr
: "port", mPort
);
364 mach_port_type_t type
;
365 if (kern_return_t err
= mach_port_type(self(), mPort
, &type
)) {
366 Debug::dump(" !%s", mach_error_string(err
));
368 if (type
& MACH_PORT_TYPE_SEND
)
369 Debug::dump(" send(%d)", getRefs(MACH_PORT_RIGHT_SEND
));
370 if (type
& MACH_PORT_TYPE_RECEIVE
)
372 if (type
& MACH_PORT_TYPE_SEND_ONCE
)
373 Debug::dump(" once(%d)", getRefs(MACH_PORT_RIGHT_SEND
));
374 if (type
& MACH_PORT_TYPE_PORT_SET
)
376 if (type
& MACH_PORT_TYPE_DEAD_NAME
)
377 Debug::dump(" dead(%d)", getRefs(MACH_PORT_RIGHT_SEND
));
378 if (type
& MACH_PORT_TYPE_DNREQUEST
)
379 Debug::dump(" dnreq");
380 // handle unknown/unexpected type flags
381 if (type
& ~(MACH_PORT_TYPE_SEND
|MACH_PORT_TYPE_RECEIVE
|MACH_PORT_TYPE_SEND_ONCE
|
382 MACH_PORT_TYPE_PORT_SET
|MACH_PORT_TYPE_DEAD_NAME
|MACH_PORT_TYPE_DNREQUEST
))
383 Debug::dump(" type(0x%x)", type
);
390 void Bootstrap::dump()
392 name_array_t services
, servers
;
394 mach_msg_type_number_t nServices
, nServers
, nActive
;
395 check(bootstrap_info(mPort
, &services
, &nServices
,
396 &servers
, &nServers
, &active
, &nActive
));
398 Debug::dump(" %d services\n", nServices
);
399 for (mach_msg_type_number_t n
= 0; n
< nServices
; n
++)
400 Debug::dump("%s\n", services
[n
]);
406 } // end namespace MachPlusPlus
407 } // end namespace Security