]> git.saurik.com Git - apple/xnu.git/blob - libsyscall/mach/mach_msg.c
xnu-3789.21.4.tar.gz
[apple/xnu.git] / libsyscall / mach / mach_msg.c
1 /*
2 * Copyright (c) 1999-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * Mach Operating System
30 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
31 * All Rights Reserved.
32 *
33 * Permission to use, copy, modify and distribute this software and its
34 * documentation is hereby granted, provided that both the copyright
35 * notice and this permission notice appear in all copies of the
36 * software, derivative works or modified versions, and any portions
37 * thereof, and that both notices appear in supporting documentation.
38 *
39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
42 *
43 * Carnegie Mellon requests users of this software to return to
44 *
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
49 *
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
52 */
53
54 #include <stdlib.h>
55 #include <mach/mach.h>
56 #include <mach/boolean.h>
57 #include <mach/kern_return.h>
58 #include <mach/message.h>
59 #include <mach/mig_errors.h>
60 #include <mach/vm_statistics.h>
61 #include <TargetConditionals.h>
62
63 extern int proc_importance_assertion_begin_with_msg(mach_msg_header_t * msg, mach_msg_trailer_t * trailer, uint64_t * assertion_handlep);
64 extern int proc_importance_assertion_complete(uint64_t assertion_handle);
65
66 #define MACH_MSG_TRAP(msg, opt, ssize, rsize, rname, to, not) \
67 mach_msg_trap((msg), (opt), (ssize), (rsize), (rname), (to), (not))
68
69 #define LIBMACH_OPTIONS (MACH_SEND_INTERRUPT|MACH_RCV_INTERRUPT)
70
71 /*
72 * Routine: mach_msg
73 * Purpose:
74 * Send and/or receive a message. If the message operation
75 * is interrupted, and the user did not request an indication
76 * of that fact, then restart the appropriate parts of the
77 * operation.
78 */
79 mach_msg_return_t
80 mach_msg(msg, option, send_size, rcv_size, rcv_name, timeout, notify)
81 mach_msg_header_t *msg;
82 mach_msg_option_t option;
83 mach_msg_size_t send_size;
84 mach_msg_size_t rcv_size;
85 mach_port_t rcv_name;
86 mach_msg_timeout_t timeout;
87 mach_port_t notify;
88 {
89 mach_msg_return_t mr;
90
91 /*
92 * Consider the following cases:
93 * 1) Errors in pseudo-receive (eg, MACH_SEND_INTERRUPTED
94 * plus special bits).
95 * 2) Use of MACH_SEND_INTERRUPT/MACH_RCV_INTERRUPT options.
96 * 3) RPC calls with interruptions in one/both halves.
97 *
98 * We refrain from passing the option bits that we implement
99 * to the kernel. This prevents their presence from inhibiting
100 * the kernel's fast paths (when it checks the option value).
101 */
102
103 mr = MACH_MSG_TRAP(msg, option &~ LIBMACH_OPTIONS,
104 send_size, rcv_size, rcv_name,
105 timeout, notify);
106 if (mr == MACH_MSG_SUCCESS)
107 return MACH_MSG_SUCCESS;
108
109 if ((option & MACH_SEND_INTERRUPT) == 0)
110 while (mr == MACH_SEND_INTERRUPTED)
111 mr = MACH_MSG_TRAP(msg,
112 option &~ LIBMACH_OPTIONS,
113 send_size, rcv_size, rcv_name,
114 timeout, notify);
115
116 if ((option & MACH_RCV_INTERRUPT) == 0)
117 while (mr == MACH_RCV_INTERRUPTED)
118 mr = MACH_MSG_TRAP(msg,
119 option &~ (LIBMACH_OPTIONS|MACH_SEND_MSG),
120 0, rcv_size, rcv_name,
121 timeout, notify);
122
123 return mr;
124 }
125
126 /*
127 * Routine: mach_msg_overwrite
128 * Purpose:
129 * Send and/or receive a message. If the message operation
130 * is interrupted, and the user did not request an indication
131 * of that fact, then restart the appropriate parts of the
132 * operation.
133 *
134 * Distinct send and receive buffers may be specified. If
135 * no separate receive buffer is specified, the msg parameter
136 * will be used for both send and receive operations.
137 *
138 * In addition to a distinct receive buffer, that buffer may
139 * already contain scatter control information to direct the
140 * receiving of the message.
141 */
142 mach_msg_return_t
143 mach_msg_overwrite(msg, option, send_size, rcv_limit, rcv_name, timeout,
144 notify, rcv_msg, rcv_scatter_size)
145 mach_msg_header_t *msg;
146 mach_msg_option_t option;
147 mach_msg_size_t send_size;
148 mach_msg_size_t rcv_limit;
149 mach_port_t rcv_name;
150 mach_msg_timeout_t timeout;
151 mach_port_t notify;
152 mach_msg_header_t *rcv_msg;
153 mach_msg_size_t rcv_scatter_size;
154 {
155 mach_msg_return_t mr;
156
157 /*
158 * Consider the following cases:
159 * 1) Errors in pseudo-receive (eg, MACH_SEND_INTERRUPTED
160 * plus special bits).
161 * 2) Use of MACH_SEND_INTERRUPT/MACH_RCV_INTERRUPT options.
162 * 3) RPC calls with interruptions in one/both halves.
163 *
164 * We refrain from passing the option bits that we implement
165 * to the kernel. This prevents their presence from inhibiting
166 * the kernel's fast paths (when it checks the option value).
167 */
168
169 mr = mach_msg_overwrite_trap(msg, option &~ LIBMACH_OPTIONS,
170 send_size, rcv_limit, rcv_name,
171 timeout, notify, rcv_msg, rcv_scatter_size);
172 if (mr == MACH_MSG_SUCCESS)
173 return MACH_MSG_SUCCESS;
174
175 if ((option & MACH_SEND_INTERRUPT) == 0)
176 while (mr == MACH_SEND_INTERRUPTED)
177 mr = mach_msg_overwrite_trap(msg,
178 option &~ LIBMACH_OPTIONS,
179 send_size, rcv_limit, rcv_name,
180 timeout, notify, rcv_msg, rcv_scatter_size);
181
182 if ((option & MACH_RCV_INTERRUPT) == 0)
183 while (mr == MACH_RCV_INTERRUPTED)
184 mr = mach_msg_overwrite_trap(msg,
185 option &~ (LIBMACH_OPTIONS|MACH_SEND_MSG),
186 0, rcv_limit, rcv_name,
187 timeout, notify, rcv_msg, rcv_scatter_size);
188
189 return mr;
190 }
191
192
193 mach_msg_return_t
194 mach_msg_send(mach_msg_header_t *msg)
195 {
196 return mach_msg(msg, MACH_SEND_MSG,
197 msg->msgh_size, 0, MACH_PORT_NULL,
198 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
199 }
200
201 mach_msg_return_t
202 mach_msg_receive(mach_msg_header_t *msg)
203 {
204 return mach_msg(msg, MACH_RCV_MSG,
205 0, msg->msgh_size, msg->msgh_local_port,
206 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
207 }
208
209
210 static void
211 mach_msg_destroy_port(mach_port_t port, mach_msg_type_name_t type)
212 {
213 if (MACH_PORT_VALID(port)) switch (type) {
214 case MACH_MSG_TYPE_MOVE_SEND:
215 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
216 /* destroy the send/send-once right */
217 (void) mach_port_deallocate(mach_task_self_, port);
218 break;
219
220 case MACH_MSG_TYPE_MOVE_RECEIVE:
221 /* destroy the receive right */
222 (void) mach_port_mod_refs(mach_task_self_, port,
223 MACH_PORT_RIGHT_RECEIVE, -1);
224 break;
225
226 case MACH_MSG_TYPE_MAKE_SEND:
227 /* create a send right and then destroy it */
228 (void) mach_port_insert_right(mach_task_self_, port,
229 port, MACH_MSG_TYPE_MAKE_SEND);
230 (void) mach_port_deallocate(mach_task_self_, port);
231 break;
232
233 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
234 /* create a send-once right and then destroy it */
235 (void) mach_port_extract_right(mach_task_self_, port,
236 MACH_MSG_TYPE_MAKE_SEND_ONCE,
237 &port, &type);
238 (void) mach_port_deallocate(mach_task_self_, port);
239 break;
240 }
241 }
242
243 static void
244 mach_msg_destroy_memory(vm_offset_t addr, vm_size_t size)
245 {
246 if (size != 0)
247 (void) vm_deallocate(mach_task_self_, addr, size);
248 }
249
250
251 /*
252 * Routine: mach_msg_destroy
253 * Purpose:
254 * mach_msg_destroy is useful in two contexts.
255 *
256 * First, it can deallocate all port rights and
257 * out-of-line memory in a received message.
258 * When a server receives a request it doesn't want,
259 * it needs this functionality.
260 *
261 * Second, it can mimic the side-effects of a msg-send
262 * operation. The effect is as if the message were sent
263 * and then destroyed inside the kernel. When a server
264 * can't send a reply (because the client died),
265 * it needs this functionality.
266 */
267 void
268 mach_msg_destroy(mach_msg_header_t *msg)
269 {
270 mach_msg_bits_t mbits = msg->msgh_bits;
271
272 /*
273 * The msgh_local_port field doesn't hold a port right.
274 * The receive operation consumes the destination port right.
275 */
276
277 mach_msg_destroy_port(msg->msgh_remote_port, MACH_MSGH_BITS_REMOTE(mbits));
278 mach_msg_destroy_port(msg->msgh_voucher_port, MACH_MSGH_BITS_VOUCHER(mbits));
279
280 if (mbits & MACH_MSGH_BITS_COMPLEX) {
281 mach_msg_base_t *base;
282 mach_msg_type_number_t count, i;
283 mach_msg_descriptor_t *daddr;
284
285 base = (mach_msg_base_t *) msg;
286 count = base->body.msgh_descriptor_count;
287
288 daddr = (mach_msg_descriptor_t *) (base + 1);
289 for (i = 0; i < count; i++) {
290
291 switch (daddr->type.type) {
292
293 case MACH_MSG_PORT_DESCRIPTOR: {
294 mach_msg_port_descriptor_t *dsc;
295
296 /*
297 * Destroy port rights carried in the message
298 */
299 dsc = &daddr->port;
300 mach_msg_destroy_port(dsc->name, dsc->disposition);
301 daddr = (mach_msg_descriptor_t *)(dsc + 1);
302 break;
303 }
304
305 case MACH_MSG_OOL_DESCRIPTOR: {
306 mach_msg_ool_descriptor_t *dsc;
307
308 /*
309 * Destroy memory carried in the message
310 */
311 dsc = &daddr->out_of_line;
312 if (dsc->deallocate) {
313 mach_msg_destroy_memory((vm_offset_t)dsc->address,
314 dsc->size);
315 }
316 daddr = (mach_msg_descriptor_t *)(dsc + 1);
317 break;
318 }
319
320 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR: {
321 mach_msg_ool_descriptor_t *dsc;
322
323 /*
324 * Just skip it.
325 */
326 dsc = &daddr->out_of_line;
327 daddr = (mach_msg_descriptor_t *)(dsc + 1);
328 break;
329 }
330
331 case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
332 mach_port_t *ports;
333 mach_msg_ool_ports_descriptor_t *dsc;
334 mach_msg_type_number_t j;
335
336 /*
337 * Destroy port rights carried in the message
338 */
339 dsc = &daddr->ool_ports;
340 ports = (mach_port_t *) dsc->address;
341 for (j = 0; j < dsc->count; j++, ports++) {
342 mach_msg_destroy_port(*ports, dsc->disposition);
343 }
344
345 /*
346 * Destroy memory carried in the message
347 */
348 if (dsc->deallocate) {
349 mach_msg_destroy_memory((vm_offset_t)dsc->address,
350 dsc->count * sizeof(mach_port_t));
351 }
352 daddr = (mach_msg_descriptor_t *)(dsc + 1);
353 break;
354 }
355 }
356 }
357 }
358 }
359
360 /*
361 * Routine: mach_msg_server_once
362 * Purpose:
363 * A simple generic server function. It allows more flexibility
364 * than mach_msg_server by processing only one message request
365 * and then returning to the user. Note that more in the way
366 * of error codes are returned to the user; specifically, any
367 * failing error from mach_msg calls will be returned
368 * (though errors from the demux routine or the routine it
369 * calls will not be).
370 */
371 mach_msg_return_t
372 mach_msg_server_once(
373 boolean_t (*demux)(mach_msg_header_t *, mach_msg_header_t *),
374 mach_msg_size_t max_size,
375 mach_port_t rcv_name,
376 mach_msg_options_t options)
377 {
378 mig_reply_error_t *bufRequest, *bufReply;
379 mach_msg_size_t request_size;
380 mach_msg_size_t request_alloc;
381 mach_msg_size_t trailer_alloc;
382 mach_msg_size_t reply_alloc;
383 mach_msg_return_t mr;
384 kern_return_t kr;
385 mach_port_t self = mach_task_self_;
386 voucher_mach_msg_state_t old_state = VOUCHER_MACH_MSG_STATE_UNCHANGED;
387
388 options &= ~(MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_VOUCHER);
389
390 trailer_alloc = REQUESTED_TRAILER_SIZE(options);
391 request_alloc = (mach_msg_size_t)round_page(max_size + trailer_alloc);
392
393 request_size = (options & MACH_RCV_LARGE) ?
394 request_alloc : max_size + trailer_alloc;
395
396 reply_alloc = (mach_msg_size_t)round_page((options & MACH_SEND_TRAILER) ?
397 (max_size + MAX_TRAILER_SIZE) :
398 max_size);
399
400 kr = vm_allocate(self,
401 (vm_address_t *)&bufReply,
402 reply_alloc,
403 VM_MAKE_TAG(VM_MEMORY_MACH_MSG)|TRUE);
404 if (kr != KERN_SUCCESS)
405 return kr;
406
407 for (;;) {
408 mach_msg_size_t new_request_alloc;
409
410 kr = vm_allocate(self,
411 (vm_address_t *)&bufRequest,
412 request_alloc,
413 VM_MAKE_TAG(VM_MEMORY_MACH_MSG)|TRUE);
414 if (kr != KERN_SUCCESS) {
415 vm_deallocate(self,
416 (vm_address_t)bufReply,
417 reply_alloc);
418 return kr;
419 }
420
421 mr = mach_msg(&bufRequest->Head, MACH_RCV_MSG|MACH_RCV_VOUCHER|options,
422 0, request_size, rcv_name,
423 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
424
425 if (!((mr == MACH_RCV_TOO_LARGE) && (options & MACH_RCV_LARGE)))
426 break;
427
428 new_request_alloc = (mach_msg_size_t)round_page(bufRequest->Head.msgh_size +
429 trailer_alloc);
430 vm_deallocate(self,
431 (vm_address_t) bufRequest,
432 request_alloc);
433 request_size = request_alloc = new_request_alloc;
434 }
435
436 if (mr == MACH_MSG_SUCCESS) {
437 /* we have a request message */
438
439 old_state = voucher_mach_msg_adopt(&bufRequest->Head);
440
441 (void) (*demux)(&bufRequest->Head, &bufReply->Head);
442
443 if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
444 if (bufReply->RetCode == MIG_NO_REPLY)
445 bufReply->Head.msgh_remote_port = MACH_PORT_NULL;
446 else if ((bufReply->RetCode != KERN_SUCCESS) &&
447 (bufRequest->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
448 /* destroy the request - but not the reply port */
449 bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
450 mach_msg_destroy(&bufRequest->Head);
451 }
452 }
453
454 /*
455 * We don't want to block indefinitely because the client
456 * isn't receiving messages from the reply port.
457 * If we have a send-once right for the reply port, then
458 * this isn't a concern because the send won't block.
459 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
460 * To avoid falling off the kernel's fast RPC path unnecessarily,
461 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
462 */
463 if (bufReply->Head.msgh_remote_port != MACH_PORT_NULL) {
464
465 mr = mach_msg(&bufReply->Head,
466 (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) ==
467 MACH_MSG_TYPE_MOVE_SEND_ONCE) ?
468 MACH_SEND_MSG|options :
469 MACH_SEND_MSG|MACH_SEND_TIMEOUT|options,
470 bufReply->Head.msgh_size, 0, MACH_PORT_NULL,
471 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
472
473 if ((mr != MACH_SEND_INVALID_DEST) &&
474 (mr != MACH_SEND_TIMED_OUT))
475 goto done_once;
476 mr = MACH_MSG_SUCCESS;
477 }
478 if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
479 mach_msg_destroy(&bufReply->Head);
480 }
481
482 done_once:
483 voucher_mach_msg_revert(old_state);
484
485 (void)vm_deallocate(self,
486 (vm_address_t) bufRequest,
487 request_alloc);
488 (void)vm_deallocate(self,
489 (vm_address_t) bufReply,
490 reply_alloc);
491 return mr;
492 }
493
494 /*
495 * Routine: mach_msg_server
496 * Purpose:
497 * A simple generic server function. Note that changes here
498 * should be considered for duplication above.
499 */
500 mach_msg_return_t
501 mach_msg_server(
502 boolean_t (*demux)(mach_msg_header_t *, mach_msg_header_t *),
503 mach_msg_size_t max_size,
504 mach_port_t rcv_name,
505 mach_msg_options_t options)
506 {
507 mig_reply_error_t *bufRequest, *bufReply;
508 mach_msg_size_t request_size;
509 mach_msg_size_t new_request_alloc;
510 mach_msg_size_t request_alloc;
511 mach_msg_size_t trailer_alloc;
512 mach_msg_size_t reply_alloc;
513 mach_msg_return_t mr;
514 kern_return_t kr;
515 mach_port_t self = mach_task_self_;
516 voucher_mach_msg_state_t old_state = VOUCHER_MACH_MSG_STATE_UNCHANGED;
517 boolean_t buffers_swapped = FALSE;
518
519 options &= ~(MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_VOUCHER|MACH_RCV_OVERWRITE);
520
521 reply_alloc = (mach_msg_size_t)round_page((options & MACH_SEND_TRAILER) ?
522 (max_size + MAX_TRAILER_SIZE) : max_size);
523
524 kr = vm_allocate(self,
525 (vm_address_t *)&bufReply,
526 reply_alloc,
527 VM_MAKE_TAG(VM_MEMORY_MACH_MSG)|TRUE);
528 if (kr != KERN_SUCCESS)
529 return kr;
530
531 request_alloc = 0;
532 trailer_alloc = REQUESTED_TRAILER_SIZE(options);
533 new_request_alloc = (mach_msg_size_t)round_page(max_size + trailer_alloc);
534
535 request_size = (options & MACH_RCV_LARGE) ?
536 new_request_alloc : max_size + trailer_alloc;
537
538 for (;;) {
539 if (request_alloc < new_request_alloc) {
540 request_alloc = new_request_alloc;
541 kr = vm_allocate(self,
542 (vm_address_t *)&bufRequest,
543 request_alloc,
544 VM_MAKE_TAG(VM_MEMORY_MACH_MSG)|TRUE);
545 if (kr != KERN_SUCCESS) {
546 vm_deallocate(self,
547 (vm_address_t)bufReply,
548 reply_alloc);
549 return kr;
550 }
551 }
552
553 mr = mach_msg(&bufRequest->Head, MACH_RCV_MSG|MACH_RCV_VOUCHER|options,
554 0, request_size, rcv_name,
555 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
556
557 while (mr == MACH_MSG_SUCCESS) {
558 /* we have another request message */
559
560 buffers_swapped = FALSE;
561 old_state = voucher_mach_msg_adopt(&bufRequest->Head);
562
563 (void) (*demux)(&bufRequest->Head, &bufReply->Head);
564
565 if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
566 if (bufReply->RetCode == MIG_NO_REPLY)
567 bufReply->Head.msgh_remote_port = MACH_PORT_NULL;
568 else if ((bufReply->RetCode != KERN_SUCCESS) &&
569 (bufRequest->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
570 /* destroy the request - but not the reply port */
571 bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
572 mach_msg_destroy(&bufRequest->Head);
573 }
574 }
575
576 /*
577 * We don't want to block indefinitely because the client
578 * isn't receiving messages from the reply port.
579 * If we have a send-once right for the reply port, then
580 * this isn't a concern because the send won't block.
581 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
582 * To avoid falling off the kernel's fast RPC path,
583 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
584 */
585 if (bufReply->Head.msgh_remote_port != MACH_PORT_NULL) {
586 if (request_alloc == reply_alloc) {
587 mig_reply_error_t *bufTemp;
588
589 mr = mach_msg(
590 &bufReply->Head,
591 (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) ==
592 MACH_MSG_TYPE_MOVE_SEND_ONCE) ?
593 MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_TIMEOUT|MACH_RCV_VOUCHER|options :
594 MACH_SEND_MSG|MACH_RCV_MSG|MACH_SEND_TIMEOUT|MACH_RCV_TIMEOUT|MACH_RCV_VOUCHER|options,
595 bufReply->Head.msgh_size, request_size, rcv_name,
596 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
597
598 /* swap request and reply */
599 bufTemp = bufRequest;
600 bufRequest = bufReply;
601 bufReply = bufTemp;
602 buffers_swapped = TRUE;
603 } else {
604 mr = mach_msg_overwrite(
605 &bufReply->Head,
606 (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) ==
607 MACH_MSG_TYPE_MOVE_SEND_ONCE) ?
608 MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_TIMEOUT|MACH_RCV_VOUCHER|options :
609 MACH_SEND_MSG|MACH_RCV_MSG|MACH_SEND_TIMEOUT|MACH_RCV_TIMEOUT|MACH_RCV_VOUCHER|options,
610 bufReply->Head.msgh_size, request_size, rcv_name,
611 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL,
612 &bufRequest->Head, 0);
613 }
614
615 if ((mr != MACH_SEND_INVALID_DEST) &&
616 (mr != MACH_SEND_TIMED_OUT) &&
617 (mr != MACH_RCV_TIMED_OUT)) {
618
619 voucher_mach_msg_revert(old_state);
620 old_state = VOUCHER_MACH_MSG_STATE_UNCHANGED;
621
622 continue;
623 }
624 }
625 /*
626 * Need to destroy the reply msg in case if there was a send timeout or
627 * invalid destination. The reply msg would be swapped with request msg
628 * if buffers_swapped is true, thus destroy request msg instead of
629 * reply msg in such cases.
630 */
631 if (mr != MACH_RCV_TIMED_OUT) {
632 if (buffers_swapped) {
633 if (bufRequest->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
634 mach_msg_destroy(&bufRequest->Head);
635 } else {
636 if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
637 mach_msg_destroy(&bufReply->Head);
638 }
639 }
640 voucher_mach_msg_revert(old_state);
641 old_state = VOUCHER_MACH_MSG_STATE_UNCHANGED;
642
643 mr = mach_msg(&bufRequest->Head, MACH_RCV_MSG|MACH_RCV_VOUCHER|options,
644 0, request_size, rcv_name,
645 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
646
647 } /* while (mr == MACH_MSG_SUCCESS) */
648
649 if ((mr == MACH_RCV_TOO_LARGE) && (options & MACH_RCV_LARGE)) {
650 new_request_alloc = (mach_msg_size_t)round_page(bufRequest->Head.msgh_size +
651 trailer_alloc);
652 request_size = new_request_alloc;
653 vm_deallocate(self,
654 (vm_address_t) bufRequest,
655 request_alloc);
656 continue;
657 }
658
659 break;
660
661 } /* for(;;) */
662
663 (void)vm_deallocate(self,
664 (vm_address_t) bufRequest,
665 request_alloc);
666 (void)vm_deallocate(self,
667 (vm_address_t) bufReply,
668 reply_alloc);
669 return mr;
670 }
671
672 /*
673 * Routine: mach_msg_server_importance
674 * Purpose:
675 * A simple generic server function which handles importance
676 * promotion assertions for adaptive daemons.
677 */
678 mach_msg_return_t
679 mach_msg_server_importance(
680 boolean_t (*demux)(mach_msg_header_t *, mach_msg_header_t *),
681 mach_msg_size_t max_size,
682 mach_port_t rcv_name,
683 mach_msg_options_t options)
684 {
685 return mach_msg_server(demux, max_size, rcv_name, options);
686 }
687
688 kern_return_t
689 mach_voucher_deallocate(
690 mach_voucher_t voucher)
691 {
692 return mach_port_deallocate(mach_task_self(), voucher);
693 }