]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/mach++.h
Security-54.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / mach++.h
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
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
8 * using this file.
9 *
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.
16 */
17
18
19 //
20 // mach++ - C++ bindings for useful Mach primitives
21 //
22 #ifndef _H_MACHPP
23 #define _H_MACHPP
24
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>
30 #include <set>
31
32 // yes, we use some UNIX (non-mach) headers...
33 #include <sys/types.h>
34 #include <unistd.h>
35
36 namespace Security {
37 namespace MachPlusPlus {
38
39
40 //
41 // Exceptions thrown by the mach++ interface.
42 //
43 class Error : public CssmCommonError {
44 protected:
45 // actually, kern_return_t can be just about any subsystem type return code
46 Error(kern_return_t err);
47 public:
48 virtual ~Error() throw();
49
50 virtual CSSM_RETURN cssmError() const;
51 virtual OSStatus osStatus() const;
52
53 const kern_return_t error;
54
55 static void check(kern_return_t err);
56 static void throwMe(kern_return_t err) __attribute__((noreturn));
57
58 private:
59 IFDEBUG(void debugDiagnose(const void *id) const);
60 };
61
62 // generic return code checker
63 inline void check(kern_return_t status)
64 { Error::check(status); }
65
66
67 //
68 // Simple vm_allocate/deallocate glue
69 //
70 void *allocate(size_t size);
71 void deallocate(vm_address_t addr, size_t size);
72
73 inline void deallocate(const void *addr, size_t size)
74 { deallocate(reinterpret_cast<vm_address_t>(addr), size); }
75
76
77 //
78 // An encapsulation of a Mach 3 port
79 //
80 class Port {
81 protected:
82 static mach_port_t self() { return mach_task_self(); }
83
84 public:
85 Port() { mPort = 0; }
86 Port(mach_port_t port) { mPort = port; }
87
88 // devolve to Mach primitive type
89 operator mach_port_t () const { return mPort; }
90
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; }
94
95 // status checks
96 mach_port_type_t type() const
97 { mach_port_type_t typ; check(mach_port_type(self(), mPort, &typ)); return typ; }
98
99 bool isType(mach_port_type_t typ) const { return type() & typ; }
100 bool isDead() const { return isType(MACH_PORT_TYPE_DEAD_NAME); }
101
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)); }
107
108 void insertRight(mach_msg_type_name_t type)
109 { check(mach_port_insert_right(self(), mPort, mPort, type)); }
110
111 void modRefs(mach_port_right_t right, mach_port_delta_t delta = 1)
112 { check(mach_port_mod_refs(self(), mPort, right, delta)); }
113
114 mach_port_urefs_t getRefs(mach_port_right_t right);
115
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);
119
120 IFDUMP(void dump(const char *name = NULL));
121
122 protected:
123 mach_port_t mPort;
124 };
125
126
127 //
128 // Ports representing PortSets
129 //
130 class PortSet : public Port {
131 public:
132 PortSet() { allocate(MACH_PORT_RIGHT_PORT_SET); }
133 ~PortSet() { destroy(); }
134
135 void operator += (const Port &port)
136 { check(mach_port_move_member(self(), port, mPort)); }
137
138 void operator -= (const Port &port)
139 { check(mach_port_move_member(self(), port, MACH_PORT_NULL)); }
140
141 set<Port> members() const;
142 bool contains(Port member) const; // relatively slow
143 };
144
145
146 //
147 // Ports that are bootstrap ports
148 //
149 class Bootstrap : public Port {
150 public:
151 Bootstrap() { check(task_get_bootstrap_port(mach_task_self(), &mPort)); }
152 Bootstrap(mach_port_t bootp) : Port(bootp) { }
153
154 mach_port_t checkIn(const char *name) const;
155 mach_port_t checkInOptional(const char *name) const;
156
157 void registerAs(mach_port_t port, const char *name) const;
158
159 mach_port_t lookup(const char *name) const;
160 mach_port_t lookupOptional(const char *name) const;
161
162 Bootstrap subset(Port requestor);
163
164 IFDUMP(void dump());
165
166 private:
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];
169
170 protected:
171 char *Bootstrap::makeName(const char *s) const
172 { return strncpy(nameBuffer, s, BOOTSTRAP_MAX_NAME_LEN); }
173 };
174
175
176 //
177 // Ports that are Task Ports
178 //
179 class TaskPort : public Port {
180 public:
181 TaskPort() { mPort = self(); }
182 TaskPort(const Port &p) { mPort = p; }
183
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)); }
188
189 pid_t pid() const;
190 static TaskPort forPid(pid_t pid);
191 };
192
193
194 //
195 // Ports that are are self-allocated and have receive rights
196 //
197 class ReceivePort : public Port {
198 public:
199 ReceivePort() { allocate(); }
200 ReceivePort(const char *name, const Bootstrap &bootstrap);
201 ~ReceivePort() { destroy(); }
202 };
203
204
205 //
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.
211 //
212 class StBootstrap {
213 public:
214 StBootstrap(const Bootstrap &boot, const TaskPort &task = TaskPort());
215 ~StBootstrap();
216
217 private:
218 Bootstrap mOldBoot;
219 TaskPort mTask;
220 StLock<Mutex> locker;
221 static ModuleNexus<Mutex> critical; // critical region guard (of a sort)
222 };
223
224
225 //
226 // A Mach-level memory guard.
227 // This will vm_deallocate its argument when it gets destroyed.
228 //
229 class VMGuard {
230 public:
231 VMGuard(void *addr, size_t length) : mAddr(addr), mLength(length) { }
232 ~VMGuard() { deallocate(mAddr, mLength); }
233
234 private:
235 void *mAddr;
236 size_t mLength;
237 };
238
239
240 //
241 // Message buffers for Mach messages.
242 // This class is for relatively simple uses.
243 //
244 class Message {
245 public:
246 Message(void *buffer, size_t size);
247 Message(size_t size);
248 virtual ~Message();
249
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; }
255
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; }
263
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; }
266
267 public:
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);
279
280 void destroy() { mach_msg_destroy(*this); }
281
282 private:
283 bool check(kern_return_t status);
284
285 private:
286 mig_reply_error_t *mBuffer;
287 size_t mSize;
288 bool mRelease;
289 };
290
291
292 } // end namespace MachPlusPlus
293 } // end namespace Security
294
295 #endif //_H_MACHPP