1/* 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25// 26// mach++ - C++ bindings for useful Mach primitives 27// 28#ifndef _H_MACHPP 29#define _H_MACHPP 30 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 <mach/mach.h> 36#include <servers/bootstrap.h> 37#include <set> 38 39// yes, we use some UNIX (non-mach) headers... 40#include <sys/types.h> 41#include <unistd.h> 42 43namespace Security { 44namespace MachPlusPlus { 45 46 47// 48// Exceptions thrown by the mach++ interface. 49// 50class Error : public CommonError { 51protected: 52 // actually, kern_return_t can be just about any subsystem type return code 53 Error(kern_return_t err); 54public: 55 virtual ~Error() throw(); 56 57 virtual OSStatus osStatus() const; 58 virtual int unixError() const; 59 60 const kern_return_t error; 61 62 static void check(kern_return_t err); 63 static void throwMe(kern_return_t err) __attribute__((noreturn)); 64}; 65 66// generic return code checker 67inline void check(kern_return_t status) 68{ Error::check(status); } 69 70 71// 72// Simple vm_allocate/deallocate glue 73// 74void *allocate(size_t size); 75void deallocate(vm_address_t addr, size_t size); 76 77inline void deallocate(const void *addr, size_t size) 78{ deallocate(reinterpret_cast<vm_address_t>(addr), size); } 79 80 81// 82// An encapsulation of a Mach 3 port 83// 84class Port { 85protected: 86 static mach_port_t self() { return mach_task_self(); } 87 88public: 89 Port() { mPort = MACH_PORT_NULL; } 90 Port(mach_port_t port) { mPort = port; } 91 92 // devolve to Mach primitive type 93 operator mach_port_t () const { return mPort; } 94 95 // access reference (for primitives storing into &mach_port_t) 96 mach_port_t &port () { return mPort; } 97 const mach_port_t &port () const { return mPort; } 98 99 // status checks 100 mach_port_type_t type() const 101 { mach_port_type_t typ; check(mach_port_type(self(), mPort, &typ)); return typ; } 102 103 bool isType(mach_port_type_t typ) const { return type() & typ; } 104 bool isDead() const { return isType(MACH_PORT_TYPE_DEAD_NAME); } 105 106 // port allocation and management 107 void allocate(mach_port_right_t right = MACH_PORT_RIGHT_RECEIVE) 108 { check(mach_port_allocate(self(), right, &mPort)); } 109 void deallocate() { check(mach_port_deallocate(self(), mPort)); } 110 void destroy() { check(mach_port_destroy(self(), mPort)); } 111 112 void insertRight(mach_msg_type_name_t type) 113 { check(mach_port_insert_right(self(), mPort, mPort, type)); } 114 115 void modRefs(mach_port_right_t right, mach_port_delta_t delta = 1) 116 { check(mach_port_mod_refs(self(), mPort, right, delta)); } 117 118 mach_port_urefs_t getRefs(mach_port_right_t right); 119 120 // port notification interface 121 mach_port_t requestNotify(mach_port_t notify, 122 mach_msg_id_t type = MACH_NOTIFY_DEAD_NAME, mach_port_mscount_t sync = 1); 123 mach_port_t cancelNotify(mach_msg_id_t type = MACH_NOTIFY_DEAD_NAME); 124 125 // queue state management 126 mach_port_msgcount_t qlimit() const; 127 void qlimit(mach_port_msgcount_t limit); 128 129 IFDUMP(void dump(const char *name = NULL)); 130 131protected: 132 mach_port_t mPort; 133}; 134 135 136// 137// A simple Port that deallocates itself on destruction. 138// If you need a subclass of Port, just assign it to a separate AutoPort. 139// 140class AutoPort : public Port { 141public: 142 AutoPort() { } 143 AutoPort(mach_port_t port) : Port(port) { } 144 ~AutoPort() { if (mPort != MACH_PORT_NULL) deallocate(); } 145}; 146 147 148// 149// Ports representing PortSets 150// 151class PortSet : public Port { 152public: 153 PortSet() { allocate(MACH_PORT_RIGHT_PORT_SET); } 154 ~PortSet() { destroy(); } 155 156 void operator += (const Port &port) 157 { check(mach_port_move_member(self(), port, mPort)); } 158 159 void operator -= (const Port &port) 160 { check(mach_port_move_member(self(), port, MACH_PORT_NULL)); } 161 162 set<Port> members() const; 163 bool contains(Port member) const; // relatively slow 164}; 165 166 167// 168// Ports that are bootstrap ports 169// 170class Bootstrap : public Port { 171public: 172 Bootstrap() { check(task_get_bootstrap_port(mach_task_self(), &mPort)); } 173 Bootstrap(mach_port_t bootp) : Port(bootp) { } 174 175 mach_port_t checkIn(const char *name) const; 176 mach_port_t checkInOptional(const char *name) const; 177 178 void registerAs(mach_port_t port, const char *name) const; 179 180 mach_port_t lookup(const char *name) const; 181 mach_port_t lookup2(const char *name) const; 182 mach_port_t lookupOptional(const char *name) const; 183 184 Bootstrap subset(Port requestor); 185 186 IFDUMP(void dump()); 187 188private: 189 // officially, the register/lookup IPCs take an array of 128 characters (not a zero-end string) 190 mutable char nameBuffer[BOOTSTRAP_MAX_NAME_LEN]; 191 192protected: 193 char *makeName(const char *s) const 194 { return strncpy(nameBuffer, s, BOOTSTRAP_MAX_NAME_LEN); } 195}; 196 197 198// 199// Ports that are Task Ports 200// 201class TaskPort : public Port { 202public: 203 TaskPort() { mPort = self(); } 204 TaskPort(mach_port_t p) : Port(p) { } 205 TaskPort(const Port &p) : Port(p) { } 206 TaskPort(pid_t pid); 207 208 Bootstrap bootstrap() const 209 { mach_port_t boot; check(task_get_bootstrap_port(mPort, &boot)); return boot; } 210 void bootstrap(Bootstrap boot) 211 { check(task_set_bootstrap_port(mPort, boot)); } 212 213 pid_t pid() const; 214}; 215 216 217// 218// Ports that are are self-allocated and have receive rights 219// 220class ReceivePort : public Port { 221public: 222 ReceivePort() { allocate(); } 223 ReceivePort(const char *name, const Bootstrap &bootstrap, bool tryCheckin = true); 224 ~ReceivePort() { destroy(); } 225}; 226 227 228// 229// A little stack utility for temporarily switching your bootstrap around. 230// Essentially, it restores your bootstrap port when it dies. Since the 231// "current bootstrap port" is a process-global item, this uses a global 232// zone of exclusion (aka critical region). There's no protection against 233// someone else calling the underlying system service, of course. 234// 235class StBootstrap { 236public: 237 StBootstrap(const Bootstrap &boot, const TaskPort &task = TaskPort()); 238 ~StBootstrap(); 239 240private: 241 Bootstrap mOldBoot; 242 TaskPort mTask; 243 StLock<Mutex> locker; 244 static ModuleNexus<Mutex> critical; // critical region guard (of a sort) 245}; 246 247 248// 249// A Mach-level memory guard. 250// This will vm_deallocate its argument when it gets destroyed. 251// 252class VMGuard { 253public: 254 VMGuard(void *addr, size_t length) : mAddr(addr), mLength(length) { } 255 ~VMGuard() { deallocate(mAddr, mLength); } 256 257private: 258 void *mAddr; 259 size_t mLength; 260}; 261 262 263// 264// Message buffers for Mach messages. 265// The logic here is somewhat inverted from the usual: send/receive 266// are methods on the buffers (rather than buffers being arguments to send/receive). 267// It's rather handy once you get used to that view. 268// 269class Message { 270public: 271 Message(void *buffer, mach_msg_size_t size); // use buffer with size 272 Message(mach_msg_size_t size); // allocate buffer with size 273 Message(); // set buffer later 274 virtual ~Message(); 275 276 void setBuffer(void *buffer, mach_msg_size_t size); // use buffer with size 277 void setBuffer(mach_msg_size_t size); // allocate buffer with size 278 void release(); // discard buffer (if any) 279 280 operator mig_reply_error_t & () const { return *mBuffer; } 281 operator mach_msg_header_t & () const { return mBuffer->Head; } 282 operator mig_reply_error_t * () const { return mBuffer; } 283 operator mach_msg_header_t * () const { return &mBuffer->Head; } 284 operator NDR_record_t & () const { return mBuffer->NDR; } 285 286 void *data() const { return mBuffer; } 287 mach_msg_size_t length() const { return mBuffer->Head.msgh_size; } 288 Port localPort() const { return mBuffer->Head.msgh_local_port; } 289 Port remotePort() const { return mBuffer->Head.msgh_remote_port; } 290 mach_msg_id_t msgId() const { return mBuffer->Head.msgh_id; } 291 mach_msg_bits_t bits() const { return mBuffer->Head.msgh_bits; } 292 kern_return_t returnCode() const { return mBuffer->RetCode; } 293 294 void localPort(mach_port_t p) { mBuffer->Head.msgh_local_port = p; } 295 void remotePort(mach_port_t p) { mBuffer->Head.msgh_remote_port = p; } 296 297public: 298 bool send(mach_msg_option_t options = 0, 299 mach_msg_timeout_t timeout = MACH_MSG_TIMEOUT_NONE, 300 mach_port_name_t notify = MACH_PORT_NULL); 301 bool receive(mach_port_t receivePort, 302 mach_msg_option_t options = 0, 303 mach_msg_timeout_t timeout = MACH_MSG_TIMEOUT_NONE, 304 mach_port_name_t notify = MACH_PORT_NULL); 305 bool sendReceive(mach_port_t receivePort, 306 mach_msg_option_t options = 0, 307 mach_msg_timeout_t timeout = MACH_MSG_TIMEOUT_NONE, 308 mach_port_name_t notify = MACH_PORT_NULL); 309 310 void destroy() { mach_msg_destroy(*this); } 311 312protected: 313 bool check(kern_return_t status); 314 315private: 316 mig_reply_error_t *mBuffer; 317 mach_msg_size_t mSize; 318 bool mRelease; 319}; 320 321 322} // end namespace MachPlusPlus 323} // end namespace Security 324 325#endif //_H_MACHPP 326