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
)
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
) {
62 // issue a diagnostic log for any discovered mach-level error
64 case BOOTSTRAP_UNKNOWN_SERVICE
:
65 debug("error", "mach error: BOOTSTRAP_UNKNOWN_SERVICE"); break;
66 case BOOTSTRAP_NAME_IN_USE
:
67 debug("error", "mach error: BOOTSTRAP_NAME_IN_USE"); break;
68 case BOOTSTRAP_NOT_PRIVILEGED
:
69 debug("error", "mach error: BOOTSTRAP_NOT_PRIVILEGED"); break;
70 case BOOTSTRAP_SERVICE_ACTIVE
:
71 debug("error", "mach error: BOOTSTRAP_SERVICE_ACTIVE"); break;
73 debug("error", "mach error: %s (%d)", mach_error_string(status
), status
); break;
76 Error::throwMe(status
);
80 void Error::throwMe(kern_return_t err
) { throw Error(err
); }
85 mach_port_urefs_t
Port::getRefs(mach_port_right_t right
)
87 mach_port_urefs_t count
;
88 check(::mach_port_get_refs(self(), mPort
, right
, &count
));
96 pid_t
TaskPort::pid() const
99 check(::pid_for_task(mPort
, &pid
));
103 TaskPort
TaskPort::forPid(pid_t pid
)
106 check(::task_for_pid(self(), pid
, &taskPort
.port()));
112 // Bootstrap port management
114 mach_port_t
Bootstrap::checkIn(const char *name
) const
117 check(::bootstrap_check_in(mPort
, makeName(name
), &port
));
121 mach_port_t
Bootstrap::checkInOptional(const char *name
) const
124 kern_return_t err
= ::bootstrap_check_in(mPort
, makeName(name
), &port
);
125 if (err
== BOOTSTRAP_UNKNOWN_SERVICE
|| err
== BOOTSTRAP_NOT_PRIVILEGED
)
131 void Bootstrap::registerAs(mach_port_t port
, const char *name
) const
133 check(::bootstrap_register(mPort
, makeName(name
), port
));
136 mach_port_t
Bootstrap::lookup(const char *name
) const
139 check(::bootstrap_look_up(mPort
, makeName(name
), &port
));
143 mach_port_t
Bootstrap::lookupOptional(const char *name
) const
146 kern_return_t err
= ::bootstrap_look_up(mPort
, makeName(name
), &port
);
147 if (err
== BOOTSTRAP_UNKNOWN_SERVICE
)
154 Bootstrap
Bootstrap::subset(Port requestor
)
157 check(::bootstrap_subset(mPort
, requestor
, &sub
));
165 ReceivePort::ReceivePort(const char *name
, const Bootstrap
&bootstrap
)
167 mPort
= bootstrap
.checkInOptional(name
);
171 insertRight(MACH_MSG_TYPE_MAKE_SEND
);
172 bootstrap
.registerAs(mPort
, name
);
178 // Stack-based bootstrap switcher
180 ModuleNexus
<Mutex
> StBootstrap::critical
;
182 StBootstrap::StBootstrap(const Bootstrap
&newBoot
, const TaskPort
&task
)
183 : mTask(task
), locker(critical())
185 mOldBoot
= Bootstrap();
186 mTask
.bootstrap(newBoot
);
187 debug("StBoot", "bootstrap for %d switched to %d", mTask
.port(), newBoot
.port());
190 StBootstrap::~StBootstrap()
192 mTask
.bootstrap(mOldBoot
);
193 debug("StBoot", "bootstrap for %d returned to %d", mTask
.port(), mOldBoot
.port());
198 // Mach message buffers
200 Message::Message(void *buffer
, size_t size
)
201 : mBuffer(reinterpret_cast<mig_reply_error_t
*>(buffer
)),
202 mSize(size
), mRelease(false)
204 assert(size
>= sizeof(mach_msg_header_t
));
207 Message::Message(size_t size
)
209 mSize
= size
+ MAX_TRAILER_SIZE
;
210 mBuffer
= (mig_reply_error_t
*)new char[mSize
];
221 void Message::send(mach_msg_option_t options
,
222 mach_msg_timeout_t timeout
,
223 mach_port_name_t notify
)
225 check(mach_msg_overwrite_trap(*this,
226 options
| MACH_SEND_MSG
,
233 void Message::receive(mach_port_t receivePort
,
234 mach_msg_option_t options
,
235 mach_msg_timeout_t timeout
,
236 mach_port_name_t notify
)
238 check(mach_msg_overwrite_trap(*this,
239 options
| MACH_RCV_MSG
,
246 void Message::sendReceive(mach_port_t receivePort
,
247 mach_msg_option_t options
,
248 mach_msg_timeout_t timeout
,
249 mach_port_name_t notify
)
251 check(mach_msg_overwrite_trap(*this,
252 options
| MACH_SEND_MSG
| MACH_RCV_MSG
,
261 // Debug dumping of ports etc.
263 #if defined(DEBUGDUMP)
265 void Port::dump(const char *descr
)
267 fprintf(stderr
, "[%s(%d)", descr
? descr
: "port", mPort
);
268 mach_port_type_t type
;
269 kern_return_t err
= mach_port_type(self(), mPort
, &type
);
270 if (err
!= KERN_SUCCESS
) {
271 fprintf(stderr
, " !%s", mach_error_string(err
));
273 if (type
& MACH_PORT_TYPE_SEND
) fprintf(stderr
, " send(%d)", getRefs(MACH_PORT_RIGHT_SEND
));
274 if (type
& MACH_PORT_TYPE_RECEIVE
) fprintf(stderr
, " rcv");
275 if (type
& MACH_PORT_TYPE_SEND_ONCE
) fprintf(stderr
, " once");
276 if (type
& MACH_PORT_TYPE_PORT_SET
) fprintf(stderr
, " set");
277 if (type
& MACH_PORT_TYPE_DEAD_NAME
) fprintf(stderr
, " dead");
278 if (type
& MACH_PORT_TYPE_DNREQUEST
) fprintf(stderr
, " dnreq");
280 fprintf(stderr
, "]\n");
284 void Bootstrap::dump()
286 name_array_t services
, servers
;
288 mach_msg_type_number_t nServices
, nServers
, nActive
;
289 check(bootstrap_info(mPort
, &services
, &nServices
,
290 &servers
, &nServers
, &active
, &nActive
));
291 fprintf(stderr
, "[port %d] %d services\n", mPort
, nServices
);
292 for (mach_msg_type_number_t n
= 0; n
< nServices
; n
++)
293 fprintf(stderr
, "%s\n", services
[n
]);
299 } // end namespace MachPlusPlus
300 } // end namespace Security