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
{
33 // Mach subsystem exceptions, a subclass of CssmCommonError
35 Error::Error(kern_return_t err
) : error(err
)
39 Error::~Error() throw()
44 Error::cssmError() const
47 case BOOTSTRAP_UNKNOWN_SERVICE
:
49 return CSSM_ERRCODE_SERVICE_NOT_AVAILABLE
;
51 return CSSM_ERRCODE_INTERNAL_ERROR
;
56 Error::osStatus() const
61 void Error::check(kern_return_t status
)
63 if (status
!= KERN_SUCCESS
)
64 Error::throwMe(status
);
67 void Error::throwMe(kern_return_t err
)
74 void Error::debugDiagnose(const void *id
) const
79 name
= mach_error_string(error
); break;
80 case BOOTSTRAP_UNKNOWN_SERVICE
:
81 name
= "BOOTSTRAP_UNKNOWN_SERVICE"; break;
82 case BOOTSTRAP_NAME_IN_USE
:
83 name
= "BOOTSTRAP_NAME_IN_USE"; break;
84 case BOOTSTRAP_NOT_PRIVILEGED
:
85 name
= "BOOTSTRAP_NOT_PRIVILEGED"; break;
86 case BOOTSTRAP_SERVICE_ACTIVE
:
87 name
= "BOOTSTRAP_SERVICE_ACTIVE"; break;
89 secdebug("exception", "%p Mach Error %s (%d) osStatus %ld",
90 id
, name
, error
, osStatus());
98 void *allocate(size_t size
)
100 vm_address_t address
;
101 check(vm_allocate(mach_task_self(), &address
, size
, true));
102 return reinterpret_cast<void *>(address
);
105 void deallocate(vm_address_t address
, size_t size
)
107 check(vm_deallocate(mach_task_self(), address
, size
));
114 mach_port_urefs_t
Port::getRefs(mach_port_right_t right
)
116 mach_port_urefs_t count
;
117 check(::mach_port_get_refs(self(), mPort
, right
, &count
));
121 mach_port_t
Port::requestNotify(mach_port_t notify
, mach_msg_id_t type
, mach_port_mscount_t sync
)
123 mach_port_t previous
;
124 check(mach_port_request_notification(self(), mPort
, type
, sync
, notify
,
125 MACH_MSG_TYPE_MAKE_SEND_ONCE
, &previous
));
128 const char *typeName
;
130 case MACH_NOTIFY_PORT_DELETED
: typeName
= "port deleted"; break;
131 case MACH_NOTIFY_PORT_DESTROYED
:typeName
= "port destroyed"; break;
132 case MACH_NOTIFY_NO_SENDERS
: typeName
= "no senders"; break;
133 case MACH_NOTIFY_SEND_ONCE
: typeName
= "send once"; break;
134 case MACH_NOTIFY_DEAD_NAME
: typeName
= "dead name"; break;
135 default: typeName
= "???"; break;
137 if (notify
== MACH_PORT_NULL
)
138 secdebug("port", "%d cancel notify %s", port(), typeName
);
140 secdebug("port", "%d request notify %s to %d (sync %d)", port(), typeName
, notify
, sync
);
146 mach_port_t
Port::cancelNotify(mach_msg_id_t type
)
148 // Mach won't let us unset the DPN port if we are already dead
149 // (EVEN if the DPN has already been sent!) So just ignore that case...
151 return MACH_PORT_NULL
;
152 return requestNotify(MACH_PORT_NULL
, type
);
159 set
<Port
> PortSet::members() const
161 mach_port_array_t members
;
162 mach_msg_type_number_t count
;
163 check(::mach_port_get_set_status(self(), mPort
, &members
, &count
));
166 copy(members
, members
+count
, inserter(result
, result
.begin()));
167 vm_deallocate(self(), vm_address_t(members
), count
* sizeof(members
[0]));
170 vm_deallocate(self(), vm_address_t(members
), count
* sizeof(members
[0]));
176 bool PortSet::contains(Port member
) const
178 set
<Port
> memberSet
= members();
179 return memberSet
.find(member
) != memberSet
.end();
184 // Task port features
186 pid_t
TaskPort::pid() const
189 check(::pid_for_task(mPort
, &pid
));
193 TaskPort
TaskPort::forPid(pid_t pid
)
196 check(::task_for_pid(self(), pid
, &taskPort
.port()));
202 // Bootstrap port management
204 mach_port_t
Bootstrap::checkIn(const char *name
) const
207 check(::bootstrap_check_in(mPort
, makeName(name
), &port
));
211 mach_port_t
Bootstrap::checkInOptional(const char *name
) const
214 switch (kern_return_t err
= ::bootstrap_check_in(mPort
, makeName(name
), &port
)) {
215 case BOOTSTRAP_SERVICE_ACTIVE
:
216 case BOOTSTRAP_UNKNOWN_SERVICE
:
217 case BOOTSTRAP_NOT_PRIVILEGED
:
218 return MACH_PORT_NULL
;
225 void Bootstrap::registerAs(mach_port_t port
, const char *name
) const
227 secdebug("bootstrap", "creating service port %d in %d:%s", port
, this->port(), name
);
228 check(::bootstrap_register(mPort
, makeName(name
), port
));
231 mach_port_t
Bootstrap::lookup(const char *name
) const
234 check(::bootstrap_look_up(mPort
, makeName(name
), &port
));
238 mach_port_t
Bootstrap::lookupOptional(const char *name
) const
241 kern_return_t err
= ::bootstrap_look_up(mPort
, makeName(name
), &port
);
242 if (err
== BOOTSTRAP_UNKNOWN_SERVICE
)
249 Bootstrap
Bootstrap::subset(Port requestor
)
252 check(::bootstrap_subset(mPort
, requestor
, &sub
));
260 ReceivePort::ReceivePort(const char *name
, const Bootstrap
&bootstrap
)
262 mPort
= bootstrap
.checkInOptional(name
);
265 // Bootstrap registration requires a send right to (copy) send.
266 // Make a temporary one, send it, then take it away again, to avoid
267 // messing up the caller's send right accounting.
268 insertRight(MACH_MSG_TYPE_MAKE_SEND
);
269 bootstrap
.registerAs(mPort
, name
);
270 modRefs(MACH_PORT_RIGHT_SEND
, -1);
276 // Stack-based bootstrap switcher
278 ModuleNexus
<Mutex
> StBootstrap::critical
;
280 StBootstrap::StBootstrap(const Bootstrap
&newBoot
, const TaskPort
&task
)
281 : mTask(task
), locker(critical())
283 mOldBoot
= Bootstrap();
284 mTask
.bootstrap(newBoot
);
285 secdebug("StBoot", "bootstrap for %d switched to %d", mTask
.port(), newBoot
.port());
288 StBootstrap::~StBootstrap()
290 mTask
.bootstrap(mOldBoot
);
291 secdebug("StBoot", "bootstrap for %d returned to %d", mTask
.port(), mOldBoot
.port());
296 // Mach message buffers
298 Message::Message(void *buffer
, size_t size
)
299 : mBuffer(reinterpret_cast<mig_reply_error_t
*>(buffer
)),
300 mSize(size
), mRelease(false)
302 assert(size
>= sizeof(mach_msg_header_t
));
305 Message::Message(size_t size
)
307 mSize
= size
+ MAX_TRAILER_SIZE
;
308 mBuffer
= (mig_reply_error_t
*)new char[mSize
];
319 bool Message::check(kern_return_t status
)
324 case MACH_RCV_TIMED_OUT
:
325 case MACH_SEND_TIMED_OUT
:
328 Error::throwMe(status
);
333 bool Message::send(mach_msg_option_t options
,
334 mach_msg_timeout_t timeout
,
335 mach_port_name_t notify
)
337 return check(mach_msg_overwrite(*this,
338 options
| MACH_SEND_MSG
,
345 bool Message::receive(mach_port_t receivePort
,
346 mach_msg_option_t options
,
347 mach_msg_timeout_t timeout
,
348 mach_port_name_t notify
)
350 return check(mach_msg_overwrite(*this,
351 options
| MACH_RCV_MSG
,
358 bool Message::sendReceive(mach_port_t receivePort
,
359 mach_msg_option_t options
,
360 mach_msg_timeout_t timeout
,
361 mach_port_name_t notify
)
363 return check(mach_msg_overwrite(*this,
364 options
| MACH_SEND_MSG
| MACH_RCV_MSG
,
373 // Debug dumping of ports etc.
375 #if defined(DEBUGDUMP)
377 void Port::dump(const char *descr
)
379 if (mPort
== MACH_PORT_NULL
) {
380 Debug::dump("[%s==NULL]\n", descr
? descr
: "port");
382 Debug::dump("[%s(%d)", descr
? descr
: "port", mPort
);
383 mach_port_type_t type
;
384 if (kern_return_t err
= mach_port_type(self(), mPort
, &type
)) {
385 Debug::dump(" !%s", mach_error_string(err
));
387 if (type
& MACH_PORT_TYPE_SEND
)
388 Debug::dump(" send(%d)", getRefs(MACH_PORT_RIGHT_SEND
));
389 if (type
& MACH_PORT_TYPE_RECEIVE
)
391 if (type
& MACH_PORT_TYPE_SEND_ONCE
)
392 Debug::dump(" once(%d)", getRefs(MACH_PORT_RIGHT_SEND
));
393 if (type
& MACH_PORT_TYPE_PORT_SET
)
395 if (type
& MACH_PORT_TYPE_DEAD_NAME
)
396 Debug::dump(" dead(%d)", getRefs(MACH_PORT_RIGHT_SEND
));
397 if (type
& MACH_PORT_TYPE_DNREQUEST
)
398 Debug::dump(" dnreq");
399 // handle unknown/unexpected type flags
400 if (type
& ~(MACH_PORT_TYPE_SEND
|MACH_PORT_TYPE_RECEIVE
|MACH_PORT_TYPE_SEND_ONCE
|
401 MACH_PORT_TYPE_PORT_SET
|MACH_PORT_TYPE_DEAD_NAME
|MACH_PORT_TYPE_DNREQUEST
))
402 Debug::dump(" type(0x%x)", type
);
409 void Bootstrap::dump()
411 name_array_t services
, servers
;
413 mach_msg_type_number_t nServices
, nServers
, nActive
;
414 check(bootstrap_info(mPort
, &services
, &nServices
,
415 &servers
, &nServers
, &active
, &nActive
));
417 Debug::dump(" %d services\n", nServices
);
418 for (mach_msg_type_number_t n
= 0; n
< nServices
; n
++)
419 Debug::dump("%s\n", services
[n
]);
425 } // end namespace MachPlusPlus
426 } // end namespace Security